From 79d56ca4efaae26e0463ae0b5a792d73d3f4cb4b Mon Sep 17 00:00:00 2001 From: CharonInferar Date: Wed, 6 Aug 2014 22:26:24 +0200 Subject: [PATCH] Fixed a few bugs - Fixed KBT90 - Added simulationService method for nearby players - Fixed an AI State issue --- scripts/commands/setgodmode.py | 15 ++ .../imp_invasion_demoralized_soldier.py | 45 ++++++ .../imperial/imp_invasion_disabled_atst.py | 45 ++++++ .../imperial/imp_invasion_soldier_cl90.py | 44 ++++++ .../rebel_invasion_demoralized_soldier.py | 46 ++++++ .../rebel/rebel_invasion_disabled_atxt.py | 44 ++++++ .../objects/creature/CreatureObject.java | 4 +- .../objects/tangible/TangibleObject.java | 17 +- src/services/SimulationService.java | 36 ++++- src/services/ai/AIService.java | 80 ++++++++++ src/services/ai/states/AIState.java | 14 +- src/services/ai/states/TurretAttackState.java | 2 +- src/services/gcw/GCWPylon.java | 7 +- src/services/gcw/GCWSpawner.java | 27 +++- src/services/gcw/InvasionService.java | 147 +++++++++++++++--- 15 files changed, 519 insertions(+), 54 deletions(-) create mode 100644 scripts/mobiles/generic/faction/imperial/imp_invasion_demoralized_soldier.py create mode 100644 scripts/mobiles/generic/faction/imperial/imp_invasion_disabled_atst.py create mode 100644 scripts/mobiles/generic/faction/imperial/imp_invasion_soldier_cl90.py create mode 100644 scripts/mobiles/generic/faction/rebel/rebel_invasion_demoralized_soldier.py create mode 100644 scripts/mobiles/generic/faction/rebel/rebel_invasion_disabled_atxt.py diff --git a/scripts/commands/setgodmode.py b/scripts/commands/setgodmode.py index 9d93e5d7..502668e2 100644 --- a/scripts/commands/setgodmode.py +++ b/scripts/commands/setgodmode.py @@ -214,6 +214,12 @@ def run(core, actor, target, commandString): if latarget.getAttachment('AI'): actor.sendSystemMessage('Checking AI progression %s' % latarget.getAttachment('AI').getProgressionMarker(), 0) + elif command == 'checkwithdrawn': + latargetID = long(actor.getIntendedTarget()) + latarget = core.objectService.getObject(latargetID) + if latarget.getAttachment('isWithdrawn'): + actor.sendSystemMessage('Checking AIisWithdrawn %s' % latarget.getAttachment('isWithdrawn'), 0) + elif command == 'showbitmask': latargetID = long(actor.getIntendedTarget()) latarget = core.objectService.getObject(latargetID) @@ -269,6 +275,15 @@ def run(core, actor, target, commandString): positionY = core.terrainService.getHeight(inst.getPlanetId(), inst.getPosition().x, inst.getPosition().z) instpos = Point3D(inst.getPosition().x,positionY+2, inst.getPosition().z) inst.setPosition(instpos) + + elif command == 'los': + latargetID = long(actor.getIntendedTarget()) + latarget = core.objectService.getObject(latargetID) + los = core.simulationService.checkLineOfSight(actor, latarget) + if los: + actor.sendSystemMessage('Line of sight between player and target', 0) + else: + actor.sendSystemMessage('NO Line of sight between player and target', 0) elif command == 'unknownAbilityPacket' and arg1: packet = UnknownAbilityPacket(arg1) diff --git a/scripts/mobiles/generic/faction/imperial/imp_invasion_demoralized_soldier.py b/scripts/mobiles/generic/faction/imperial/imp_invasion_demoralized_soldier.py new file mode 100644 index 00000000..62962707 --- /dev/null +++ b/scripts/mobiles/generic/faction/imperial/imp_invasion_demoralized_soldier.py @@ -0,0 +1,45 @@ +import sys +from services.spawn import MobileTemplate +from services.spawn import WeaponTemplate +from resources.datatables import WeaponType +from resources.datatables import Difficulty +from resources.datatables import Options +from resources.datatables import FactionStatus +from java.util import Vector + + +def addTemplate(core): + mobileTemplate = MobileTemplate() + + mobileTemplate.setCustomName('A demoralized imperial soldier') + mobileTemplate.setLevel(90) + mobileTemplate.setDifficulty(Difficulty.ELITE) + + mobileTemplate.setMinSpawnDistance(4) + mobileTemplate.setMaxSpawnDistance(8) + mobileTemplate.setDeathblow(True) + mobileTemplate.setSocialGroup("imperial") + mobileTemplate.setAssistRange(0) + mobileTemplate.setStalker(False) + mobileTemplate.setFaction("imperial") + mobileTemplate.setFactionStatus(FactionStatus.Combatant) + mobileTemplate.setAIEnabled(False) + + templates = Vector() + templates.add('object/mobile/shared_dressed_stormtrooper_black_white.iff') + templates.add('object/mobile/shared_dressed_stormtrooper_white_black.iff') + templates.add('object/mobile/shared_dressed_stormtrooper_white_white.iff') + templates.add('object/mobile/shared_dark_trooper.iff') + mobileTemplate.setTemplates(templates) + + weaponTemplates = Vector() + weapontemplate = WeaponTemplate('object/weapon/ranged/carbine/shared_carbine_e11.iff', WeaponType.CARBINE, 1.0, 15, 'energy') + weaponTemplates.add(weapontemplate) + mobileTemplate.setWeaponTemplateVector(weaponTemplates) + + attacks = Vector() + mobileTemplate.setDefaultAttack('rangedShot') + mobileTemplate.setAttacks(attacks) + + core.spawnService.addMobileTemplate('imp_invasion_demoralized_soldier', mobileTemplate) + return \ No newline at end of file diff --git a/scripts/mobiles/generic/faction/imperial/imp_invasion_disabled_atst.py b/scripts/mobiles/generic/faction/imperial/imp_invasion_disabled_atst.py new file mode 100644 index 00000000..62d01f40 --- /dev/null +++ b/scripts/mobiles/generic/faction/imperial/imp_invasion_disabled_atst.py @@ -0,0 +1,45 @@ +import sys +from services.spawn import MobileTemplate +from services.spawn import WeaponTemplate +from resources.datatables import WeaponType +from resources.datatables import Difficulty +from resources.datatables import Options +from resources.datatables import FactionStatus +from java.util import Vector + + +def addTemplate(core): + mobileTemplate = MobileTemplate() + + mobileTemplate.setCustomName('A disabled AT-ST') + mobileTemplate.setLevel(90) + mobileTemplate.setDifficulty(Difficulty.ELITE) + + mobileTemplate.setMinSpawnDistance(4) + mobileTemplate.setMaxSpawnDistance(8) + mobileTemplate.setDeathblow(True) + mobileTemplate.setScale(1) + mobileTemplate.setSocialGroup("imperial") + mobileTemplate.setAssistRange(0) + mobileTemplate.setStalker(False) + mobileTemplate.setFaction("imperial") + mobileTemplate.setFactionStatus(FactionStatus.Combatant) + mobileTemplate.setOptionsBitmask(Options.ATTACKABLE) + mobileTemplate.setAIEnabled(False) + + templates = Vector() + templates.add('object/mobile/shared_atst.iff') + mobileTemplate.setTemplates(templates) + + weaponTemplates = Vector() # object/weapon/ranged/turret/shared_turret_heat.iff object/weapon/ranged/vehicle/shared_vehicle_atst_ranged.iff + weapontemplate = WeaponTemplate('object/weapon/ranged/vehicle/shared_vehicle_atst_ranged.iff', WeaponType.CARBINE, 2.0, 55, 'energy') + #weapontemplate = WeaponTemplate('object/weapon/ranged/rifle/shared_rifle_t21.iff', WeaponType.RIFLE, 1.0, 24, 'energy') + weaponTemplates.add(weapontemplate) + mobileTemplate.setWeaponTemplateVector(weaponTemplates) + + attacks = Vector() + mobileTemplate.setDefaultAttack('gcw_atst_attack_tower') #gcw_atst_attack_tower #rangedShot + mobileTemplate.setAttacks(attacks) + + core.spawnService.addMobileTemplate('imp_invasion_at_st', mobileTemplate) + return \ No newline at end of file diff --git a/scripts/mobiles/generic/faction/imperial/imp_invasion_soldier_cl90.py b/scripts/mobiles/generic/faction/imperial/imp_invasion_soldier_cl90.py new file mode 100644 index 00000000..6ad094e2 --- /dev/null +++ b/scripts/mobiles/generic/faction/imperial/imp_invasion_soldier_cl90.py @@ -0,0 +1,44 @@ +import sys +from services.spawn import MobileTemplate +from services.spawn import WeaponTemplate +from resources.datatables import WeaponType +from resources.datatables import Difficulty +from resources.datatables import Options +from resources.datatables import FactionStatus +from java.util import Vector + + +def addTemplate(core): + mobileTemplate = MobileTemplate() + + mobileTemplate.setCreatureName('crackdown_stormtrooper_hard') + mobileTemplate.setLevel(90) + mobileTemplate.setDifficulty(Difficulty.ELITE) + + mobileTemplate.setMinSpawnDistance(4) + mobileTemplate.setMaxSpawnDistance(8) + mobileTemplate.setDeathblow(True) + mobileTemplate.setSocialGroup("imperial") + mobileTemplate.setAssistRange(0) + mobileTemplate.setStalker(False) + mobileTemplate.setFaction("imperial") + mobileTemplate.setFactionStatus(FactionStatus.Combatant) + + templates = Vector() + templates.add('object/mobile/shared_dressed_stormtrooper_black_white.iff') + templates.add('object/mobile/shared_dressed_stormtrooper_white_black.iff') + templates.add('object/mobile/shared_dressed_stormtrooper_white_white.iff') + templates.add('object/mobile/shared_dark_trooper.iff') + mobileTemplate.setTemplates(templates) + + weaponTemplates = Vector() + weapontemplate = WeaponTemplate('object/weapon/ranged/carbine/shared_carbine_e11.iff', WeaponType.CARBINE, 1.0, 15, 'energy') + weaponTemplates.add(weapontemplate) + mobileTemplate.setWeaponTemplateVector(weaponTemplates) + + attacks = Vector() + mobileTemplate.setDefaultAttack('rangedShot') + mobileTemplate.setAttacks(attacks) + + core.spawnService.addMobileTemplate('imp_invasion_soldier_cl90', mobileTemplate) + return \ No newline at end of file diff --git a/scripts/mobiles/generic/faction/rebel/rebel_invasion_demoralized_soldier.py b/scripts/mobiles/generic/faction/rebel/rebel_invasion_demoralized_soldier.py new file mode 100644 index 00000000..8af3c215 --- /dev/null +++ b/scripts/mobiles/generic/faction/rebel/rebel_invasion_demoralized_soldier.py @@ -0,0 +1,46 @@ +import sys +from services.spawn import MobileTemplate +from services.spawn import WeaponTemplate +from resources.datatables import WeaponType +from resources.datatables import Difficulty +from resources.datatables import Options +from resources.datatables import FactionStatus +from java.util import Vector + +def addTemplate(core): + mobileTemplate = MobileTemplate() + + mobileTemplate.setCreatureName('A demoralized rebel soldier') + mobileTemplate.setLevel(90) + mobileTemplate.setDifficulty(Difficulty.ELITE) + + mobileTemplate.setMinSpawnDistance(4) + mobileTemplate.setMaxSpawnDistance(8) + mobileTemplate.setDeathblow(True) + mobileTemplate.setSocialGroup("rebel") + mobileTemplate.setAssistRange(0) + mobileTemplate.setStalker(True) + mobileTemplate.setFaction("rebel") + mobileTemplate.setFactionStatus(FactionStatus.Combatant) + mobileTemplate.setAIEnabled(False) + + templates = Vector() + templates.add('object/mobile/shared_dressed_rebel_commando_human_female_01.iff') + templates.add('object/mobile/shared_dressed_rebel_commando_human_male_01.iff') + templates.add('object/mobile/shared_dressed_rebel_commando_moncal_male_01.iff') + templates.add('object/mobile/shared_dressed_rebel_commando_rodian_male_01.iff') + templates.add('object/mobile/shared_dressed_rebel_commando_twilek_female_01.iff') + templates.add('object/mobile/shared_dressed_rebel_commando_zabrak_female_01.iff') + mobileTemplate.setTemplates(templates) + + weaponTemplates = Vector() + weapontemplate = WeaponTemplate('object/weapon/ranged/carbine/shared_carbine_e5.iff', WeaponType.CARBINE, 1.0, 15, 'energy') + weaponTemplates.add(weapontemplate) + mobileTemplate.setWeaponTemplateVector(weaponTemplates) + + attacks = Vector() + mobileTemplate.setDefaultAttack('rangedShot') + mobileTemplate.setAttacks(attacks) + + core.spawnService.addMobileTemplate('rebel_invasion_demoralized_soldier', mobileTemplate) + return \ No newline at end of file diff --git a/scripts/mobiles/generic/faction/rebel/rebel_invasion_disabled_atxt.py b/scripts/mobiles/generic/faction/rebel/rebel_invasion_disabled_atxt.py new file mode 100644 index 00000000..bbc7b026 --- /dev/null +++ b/scripts/mobiles/generic/faction/rebel/rebel_invasion_disabled_atxt.py @@ -0,0 +1,44 @@ +import sys +from services.spawn import MobileTemplate +from services.spawn import WeaponTemplate +from resources.datatables import WeaponType +from resources.datatables import Difficulty +from resources.datatables import Options +from resources.datatables import FactionStatus +from java.util import Vector + + +def addTemplate(core): + mobileTemplate = MobileTemplate() + + mobileTemplate.setCustomName('A disabled AT-XT') + mobileTemplate.setLevel(90) + mobileTemplate.setDifficulty(Difficulty.ELITE) + + mobileTemplate.setMinSpawnDistance(4) + mobileTemplate.setMaxSpawnDistance(8) + mobileTemplate.setDeathblow(True) + mobileTemplate.setScale(1) + mobileTemplate.setSocialGroup("rebel") + mobileTemplate.setAssistRange(0) + mobileTemplate.setStalker(False) + mobileTemplate.setFaction("rebel") + mobileTemplate.setFactionStatus(FactionStatus.Combatant) + mobileTemplate.setOptionsBitmask(Options.ATTACKABLE) + mobileTemplate.setAIEnabled(False) + + templates = Vector() + templates.add('object/mobile/shared_atxt.iff') + mobileTemplate.setTemplates(templates) + + weaponTemplates = Vector() + weapontemplate = WeaponTemplate('object/weapon/ranged/vehicle/shared_vehicle_atst_ranged.iff', WeaponType.CARBINE, 1.0, 15, 'energy') + weaponTemplates.add(weapontemplate) + mobileTemplate.setWeaponTemplateVector(weaponTemplates) + + attacks = Vector() + mobileTemplate.setDefaultAttack('gcw_atst_attack_tower') + mobileTemplate.setAttacks(attacks) + + core.spawnService.addMobileTemplate('rebel_invasion_disabled_atxt', mobileTemplate) + return \ No newline at end of file diff --git a/src/resources/objects/creature/CreatureObject.java b/src/resources/objects/creature/CreatureObject.java index b64dbdda..a48be21c 100644 --- a/src/resources/objects/creature/CreatureObject.java +++ b/src/resources/objects/creature/CreatureObject.java @@ -1150,9 +1150,7 @@ public class CreatureObject extends TangibleObject implements Serializable { } //destination.getSession().write(messageBuilder.buildBaseline8()); //destination.getSession().write(messageBuilder.buildBaseline9()); - - - + if(destination != getClient()) { UpdatePVPStatusMessage upvpm = new UpdatePVPStatusMessage(getObjectID(), NGECore.getInstance().factionService.calculatePvpStatus((CreatureObject) destination.getParent(), this), getFaction()); destination.getSession().write(upvpm.serialize()); diff --git a/src/resources/objects/tangible/TangibleObject.java b/src/resources/objects/tangible/TangibleObject.java index 5cca5e91..d6e8d6d9 100644 --- a/src/resources/objects/tangible/TangibleObject.java +++ b/src/resources/objects/tangible/TangibleObject.java @@ -408,7 +408,6 @@ public class TangibleObject extends SWGObject implements Serializable { observer.getSession().write(new UpdatePVPStatusMessage(this.getObjectID(), NGECore.getInstance().factionService.calculatePvpStatus((CreatureObject) observer.getParent(), this), getFaction()).serialize()); if(getClient() != null){ getClient().getSession().write(new UpdatePVPStatusMessage(observer.getParent().getObjectID(), NGECore.getInstance().factionService.calculatePvpStatus((CreatureObject) this, (CreatureObject) observer.getParent()), getFaction()).serialize()); - //System.out.println("SENT TO CLIENT!"); } } } @@ -420,17 +419,6 @@ public class TangibleObject extends SWGObject implements Serializable { companion.updatePvpStatus(); } } - - - if (this instanceof CreatureObject){ - if (((CreatureObject)this).isPlayer()){ - // Here a specific CREO delta must be sent to update the faction info in character sheet and symbol in name - // If anyone knows which that would be, please replace it here! - - sendBaselines(this.getClient()); - - } - } } public boolean isAttackableBy(CreatureObject attacker) { @@ -623,7 +611,8 @@ public class TangibleObject extends SWGObject implements Serializable { } public void notifyClients(IoBuffer buffer, boolean notifySelf) { - notifyObservers(buffer, false); + // notifyObservers(buffer, false); // ??? Ignores the notifySelf argument. Was this done purposely? Faction Status etc. can't update the client without it + notifyObservers(buffer, notifySelf); } public ObjectMessageBuilder getMessageBuilder() { @@ -678,6 +667,8 @@ public class TangibleObject extends SWGObject implements Serializable { } } + + public void sendListDelta(byte viewType, short updateType, IoBuffer buffer) { switch (viewType) { case 3: diff --git a/src/services/SimulationService.java b/src/services/SimulationService.java index 90cc738a..ad62acd6 100644 --- a/src/services/SimulationService.java +++ b/src/services/SimulationService.java @@ -290,6 +290,28 @@ public class SimulationService implements INetworkDispatch { return foundCreatures; } + public Vector getAllNearPlayers(int distance, SWGObject value ){ + Vector foundCreatures = new Vector(); + core.simulationService.get(value.getPlanet(), value.getWorldPosition().x, value.getWorldPosition().z, distance).stream().forEach((objecta) -> { + if (objecta instanceof CreatureObject && objecta!=value) + if (((CreatureObject)objecta).isPlayer()) + foundCreatures.add((CreatureObject)objecta); + } + ); + return foundCreatures; + } + + public Vector getAllNearPlayers(int distance, Planet planet, Point3D pos ){ + Vector foundCreatures = new Vector(); + core.simulationService.get(planet, pos.x, pos.z, distance).stream().forEach((objecta) -> { + if (objecta instanceof CreatureObject) + if (((CreatureObject)objecta).isPlayer()) + foundCreatures.add((CreatureObject)objecta); + } + ); + return foundCreatures; + } + public Vector getAllNearNonSameFactionTargets(int distance, SWGObject center ){ Vector foundTargets = new Vector(); core.simulationService.get(center.getPlanet(), center.getWorldPosition().x, center.getWorldPosition().z, distance).stream().forEach((objecta) -> { @@ -987,8 +1009,18 @@ public class SimulationService implements INetworkDispatch { float cos = (float) Math.cos(radians); WB_M44 rotationMatrix = new WB_M44(cos, 0, sin, 0, 0, 1, 0, 0, -sin, 0, cos, 0, 0, 0, 0, 1); - - WB_M44 modelSpace = translateMatrix.mult(rotationMatrix).inverse(); + + WB_M44 modelSpace = null; + try { + modelSpace = translateMatrix.mult(rotationMatrix).inverse(); + } catch (Exception ex){ + // It's usually a bank terminal causing this + //System.out.println("The object " + object.getTemplate() + " at x:" + object.getWorldPosition().x + " z:" + object.getWorldPosition().z + " causes a problem during modelspaceconversion. Can be safely ignored."); + if (modelSpace==null) + return new Ray(origin, new Vector3D(0,0,0)); + } + + float originX = (float) (modelSpace.m11 * origin.x + modelSpace.m12 * origin.y + modelSpace.m13 * origin.z + modelSpace.m14); float originY = (float) (modelSpace.m21 * origin.x + modelSpace.m22 * origin.y + modelSpace.m23 * origin.z + modelSpace.m24); diff --git a/src/services/ai/AIService.java b/src/services/ai/AIService.java index ac63a35a..e66b82b8 100644 --- a/src/services/ai/AIService.java +++ b/src/services/ai/AIService.java @@ -21,8 +21,13 @@ ******************************************************************************/ package services.ai; +import java.lang.reflect.Method; import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import java.util.Random; import java.util.Vector; @@ -40,6 +45,7 @@ import services.ai.states.LoiterState; import services.ai.states.PatrolState; import engine.resources.objects.SWGObject; import engine.resources.scene.Point3D; +import engine.resources.service.INetworkDispatch; import main.NGECore; public class AIService { @@ -238,6 +244,80 @@ public class AIService { return (p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y) + (p2.z - p1.z) * (p2.z - p1.z); } + public void waitForEvent(AIActor actor, INetworkDispatch service, String serviceMethodName, boolean expectedValue, Class nextStateClass){ + + final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + final Future[] wfe = {null}; + wfe[0] = scheduler.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + try { + Class noParams[] = {}; + Method m = service.getClass().getMethod(serviceMethodName, noParams); + boolean value = (boolean) m.invoke(service); + if (value==expectedValue){ + actor.setCurrentState((AIState)nextStateClass.newInstance()); + System.out.println("condition true waitForEvent! " + nextStateClass.getName()); + Thread.yield(); + wfe[0].cancel(false); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }, 10, 3000, TimeUnit.MILLISECONDS); + } + + public void waitForEvent(AIActor actor, INetworkDispatch service, String serviceMethodName, int expectedValue, Class nextStateClass){ + final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + final Future[] wfe = {null}; + wfe[0] = scheduler.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + try { + Class noParams[] = {}; + Method m = service.getClass().getMethod(serviceMethodName, noParams); + int number = (int) m.invoke(service); + if (number==expectedValue){ + actor.setCurrentState((AIState)nextStateClass.newInstance()); + Thread.yield(); + wfe[0].cancel(false); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }, 10, 3000, TimeUnit.MILLISECONDS); + } + + // ToDo: Make an overloaded method with params + public void waitForEvent(INetworkDispatch service, String serviceMethodName, Object[] params){ + final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + final Future[] wfe = {null}; + wfe[0] = scheduler.scheduleAtFixedRate(new Runnable() { + + @Override + public void run() { + try { + boolean condition = true; + Object[] params; //The parameters for my method + Class noParams[] = {}; + Method m = service.getClass().getMethod(serviceMethodName, noParams); + m.invoke(service); + + if (condition){ + Thread.yield(); + wfe[0].cancel(false); + } + // do something + } catch (Exception e) { + e.printStackTrace(); + } + } + + }, 10, 2000, TimeUnit.MILLISECONDS); + } + public void logAI(String logMsg){ if (checkDeveloperIdentity()){ System.err.println("AI-LOG: " + logMsg); diff --git a/src/services/ai/states/AIState.java b/src/services/ai/states/AIState.java index 39ac0b2d..22be098c 100644 --- a/src/services/ai/states/AIState.java +++ b/src/services/ai/states/AIState.java @@ -27,6 +27,7 @@ import java.util.Vector; import main.NGECore; import engine.resources.scene.Point3D; import engine.resources.scene.Quaternion; +import engine.resources.service.INetworkDispatch; import resources.common.SpawnPoint; import resources.objects.cell.CellObject; import resources.objects.creature.CreatureObject; @@ -777,8 +778,11 @@ public abstract class AIState { if (isInvader==null) return; // If invader check for in weapon range general - if (core.invasionService.getInvasionPhase()==3 && core.invasionService.getDistanceToDefensiveGeneral(creature)<2500){ - actor.addDefender(core.invasionService.getDefensiveGeneral()); + if (core.invasionService.getDefensiveGeneral()!=null){ + if (core.invasionService.getInvasionPhase()==3 && core.invasionService.getDefensiveGeneral().getPosture()!=13 && core.invasionService.getDefensiveGeneral().getPosture()!=14 && core.invasionService.getDistanceToDefensiveGeneral(creature)<2500){ + actor.addDefender(core.invasionService.getDefensiveGeneral()); + return; + } } // Check if there are more than 5 invaders at same spot @@ -786,8 +790,14 @@ public abstract class AIState { actor.setAIactive(false); // switch off auto-target-recognition to counter lag actor.setCurrentState(new IdleState()); System.out.println("AI switched off!"); + return; } + //actor.setCurrentState(new IdleState()); + // Wait state() Since this state does not require move,recover and all that its simple task + + //NGECore.getInstance().aiService.waitForEvent(actor, NGECore.getInstance().invasionService, "isDefendingGeneralAlive", false, WithdrawalState.class); + return; // Last Patrol point reached and no loop } } diff --git a/src/services/ai/states/TurretAttackState.java b/src/services/ai/states/TurretAttackState.java index 530ed365..20840e8a 100644 --- a/src/services/ai/states/TurretAttackState.java +++ b/src/services/ai/states/TurretAttackState.java @@ -143,7 +143,7 @@ public class TurretAttackState extends TurretAIState { target = (CreatureObject) actor.getFollowObject(); if(target == null) { -// creature.setLookAtTarget(0); +// creature.setLookAtTarget(0); //Is only accessible from CreatureObject, not TANO // creature.setIntendedTarget(0); } diff --git a/src/services/gcw/GCWPylon.java b/src/services/gcw/GCWPylon.java index f00428bc..55ace633 100644 --- a/src/services/gcw/GCWPylon.java +++ b/src/services/gcw/GCWPylon.java @@ -235,13 +235,8 @@ public class GCWPylon extends TangibleObject{ turretWeapon.setMinDamage(minDamage); turretWeapon.setMaxDamage(maxDamage); - turret.add(turretWeapon); + //turret.add(turretWeapon); // Does not have to be added explicitly, would cause engine slot arrangement error message turret.setAttachment("TurretWeapon",turretWeapon.getObjectID()); -// Set newObservers = new HashSet(turret.getObservers()); -// for(Client c : newObservers) { -// UpdateContainmentMessage ucm = new UpdateContainmentMessage(turretWeapon.getObjectID(), turret.getObjectID(), 4); -// c.getSession().write(ucm.serialize()); -// } } public void createBarricade(){ diff --git a/src/services/gcw/GCWSpawner.java b/src/services/gcw/GCWSpawner.java index e692c1aa..9a4e92f4 100644 --- a/src/services/gcw/GCWSpawner.java +++ b/src/services/gcw/GCWSpawner.java @@ -196,25 +196,37 @@ public class GCWSpawner extends TangibleObject{ public void spawnSoldier(){ if (NGECore.getInstance().invasionService.getInvasionPhase()==2){ + String stfName = "gcw_city_rebel_specforce_defense"; if (spawnerFaction==Factions.Rebel){ switch (spawnLevel) { case 1: soldierTemplates = rebelSoldierTemplates1; + stfName = "gcw_city_rebel_grunt_assault"; + break; case 2: soldierTemplates = rebelSoldierTemplates2; + stfName = "gcw_city_rebel_grunt_assault"; + break; case 3: soldierTemplates = rebelSoldierTemplates3; + stfName = "gcw_city_rebel_specforce_assault"; + break; } } if (spawnerFaction==Factions.Imperial){ switch (spawnLevel) { case 1: soldierTemplates = imperialSoldierTemplates1; + break; case 2: soldierTemplates = imperialSoldierTemplates2; + break; case 3: soldierTemplates = imperialSoldierTemplates3; + break; } } String soldierTemplate = soldierTemplates[new Random().nextInt(soldierTemplates.length)]; //if (totalSpawnedUnits==0){ CreatureObject soldier = (CreatureObject)NGECore.getInstance().spawnService.spawnCreature(soldierTemplate, this.getPlanet().getName(), 0L, this.getPosition().x, this.getPosition().y, this.getPosition().z, this.getOrientation().w, this.getOrientation().x, this.getOrientation().y,this.getOrientation().z,-1); + if (spawnerFaction==Factions.Rebel) + soldier.setStfName(stfName); NGECore.getInstance().invasionService.registerInvader(soldier); - totalSpawnedUnits++; + totalSpawnedUnits++; soldier.setAttachment("IsInvader","yes"); NGECore.getInstance().aiService.setPatrol(soldier, patrolRoute); NGECore.getInstance().aiService.setPatrolLoop(soldier,false); @@ -226,18 +238,28 @@ public class GCWSpawner extends TangibleObject{ public void spawnSoldierDefender(){ if (NGECore.getInstance().invasionService.getInvasionPhase()==2){ + String stfName = "gcw_city_rebel_specforce_defense"; if (spawnerFaction==Factions.Rebel){ switch (spawnLevel) { case 1: soldierTemplates = rebelSoldierTemplates1; + stfName = "gcw_city_rebel_grunt_defense"; + break; case 2: soldierTemplates = rebelSoldierTemplates2; + stfName = "gcw_city_rebel_grunt_defense"; + break; case 3: soldierTemplates = rebelSoldierTemplates3; + stfName = "gcw_city_rebel_specforce_defense"; + break; } } if (spawnerFaction==Factions.Imperial){ switch (spawnLevel) { case 1: soldierTemplates = imperialSoldierTemplates1; + break; case 2: soldierTemplates = imperialSoldierTemplates2; + break; case 3: soldierTemplates = imperialSoldierTemplates3; + break; } } if (lastDefender!=null) @@ -245,7 +267,8 @@ public class GCWSpawner extends TangibleObject{ return; String soldierTemplate = soldierTemplates[new Random().nextInt(soldierTemplates.length)]; lastDefender = (CreatureObject)NGECore.getInstance().spawnService.spawnCreature(soldierTemplate, this.getPlanet().getName(), 0L, this.getPosition().x, this.getPosition().y, this.getPosition().z, this.getOrientation().w, this.getOrientation().x, this.getOrientation().y,this.getOrientation().z,-1); - + if (spawnerFaction==Factions.Rebel) + lastDefender.setStfName(stfName); NGECore.getInstance().invasionService.registerDefender(lastDefender); totalSpawnedUnits++; } diff --git a/src/services/gcw/InvasionService.java b/src/services/gcw/InvasionService.java index 24f7e211..1aae211b 100644 --- a/src/services/gcw/InvasionService.java +++ b/src/services/gcw/InvasionService.java @@ -24,7 +24,9 @@ package services.gcw; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Random; +import java.util.Set; import java.util.Vector; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; @@ -46,10 +48,13 @@ import resources.datatables.FactionStatus; import resources.datatables.Factions; import resources.datatables.GcwType; import resources.datatables.Options; +import resources.datatables.Posture; import resources.objects.building.BuildingObject; import resources.objects.creature.CreatureObject; import resources.objects.tangible.TangibleObject; import services.ai.AIActor; +import services.ai.states.AIState; +import services.ai.states.DeathState; import services.ai.states.WithdrawalState; import services.gcw.GCWSpawner.PatrolRoute; import services.gcw.GCWPylon.PylonType; @@ -84,6 +89,7 @@ public class InvasionService implements INetworkDispatch { private CreatureObject defendingGeneral = null; private CreatureObject defendingQuestOfficer = null; private Vector offensiveQuestOfficers = new Vector(); + private boolean defendingGeneralAlive = true; private int invasionLocation=-1; private String invasionPlanet="tatooine"; @@ -116,6 +122,10 @@ public class InvasionService implements INetworkDispatch { private int invaderRegistryCounter = 0; private Map defendingCreatures = new ConcurrentHashMap(); private int defenderRegistryCounter = 0; + private Map demoralizedSoldiers = new ConcurrentHashMap(); + private int demoralizedSoldierRegistryCounter = 0; + private Map disabledVehicles = new ConcurrentHashMap(); + private int disabledVehicleRegistryCounter = 0; private Map phase2Objects = new ConcurrentHashMap(); private int phase2ObjectRegistryCounter = 0; private Vector defensiveBanners = new Vector(); @@ -256,9 +266,9 @@ public class InvasionService implements INetworkDispatch { } // Message at 30:00 -> 1800000 seconds - if (invasionPhase==1 && System.currentTimeMillis()>temptimestartreference + 180000 && ! ph2_message1sent){ + if (invasionPhase==1 && System.currentTimeMillis()>temptimestartreference + 200000 && ! ph2_message1sent){ invasionPhase=2; - preparePhase2(); + preparePhase2(); System.out.println("PHASE 2"); send_Phase2_InvaderMessage1(); send_Phase2_DefenderMessage1(); @@ -267,7 +277,7 @@ public class InvasionService implements INetworkDispatch { } // Message at 45:00 -> 2700000 seconds - if (invasionPhase==2 && System.currentTimeMillis()>temptimestartreference + 900000 && ! ph2_message2sent){ // 1200000 + if (invasionPhase==2 && System.currentTimeMillis()>temptimestartreference + 400000 && ! ph2_message2sent){ // 1200000 send_Phase2_InvaderMessage2(); send_Phase2_DefenderMessage2(); ph2_message2sent = true; @@ -305,24 +315,28 @@ public class InvasionService implements INetworkDispatch { grantGCWTokens(invadingFaction,10); grantGCWTokens(defendingFaction,130); + playVictoryMusic(defendingFaction); + // set up delayed tasks //Clone Maps Map invadingCreaturesClone = new ConcurrentHashMap(); Map defendingCreaturesClone = new ConcurrentHashMap(); - for (Map.Entry entry : invadingCreatures.entrySet()) { + for (Map.Entry entry : getInvadingCreaturesEntrySet()) { invadingCreaturesClone.put(entry.getKey(), entry.getValue()); } - for (Map.Entry entry : defendingCreatures.entrySet()) { + for (Map.Entry entry : getDefendingCreaturesEntrySet()) { defendingCreaturesClone.put(entry.getKey(), entry.getValue()); } + withdrawInvaders(); + Executors.newSingleThreadScheduledExecutor().schedule(() -> { wipeInvaders(invadingCreaturesClone); wipeDefenders(defendingCreaturesClone); // Make sure all are deleted }, 360, TimeUnit.SECONDS); - withdrawInvaders(); + for (BuildingObject camp : offensiveCamps){ core.simulationService.remove(camp, camp.getWorldPosition().x, camp.getWorldPosition().z, true); core.objectService.destroyObject(camp.getObjectID()); @@ -373,6 +387,8 @@ public class InvasionService implements INetworkDispatch { grantGCWTokens(invadingFaction,130); grantGCWTokens(defendingFaction,10); + + playVictoryMusic(invadingFaction); // Clean Up // wipeInvaders(); @@ -382,20 +398,22 @@ public class InvasionService implements INetworkDispatch { //Clone Maps Map invadingCreaturesClone = new ConcurrentHashMap(); Map defendingCreaturesClone = new ConcurrentHashMap(); - for (Map.Entry entry : invadingCreatures.entrySet()) { + for (Map.Entry entry : getInvadingCreaturesEntrySet()) { invadingCreaturesClone.put(entry.getKey(), entry.getValue()); } - for (Map.Entry entry : defendingCreatures.entrySet()) { + for (Map.Entry entry : getDefendingCreaturesEntrySet()) { defendingCreaturesClone.put(entry.getKey(), entry.getValue()); } + withdrawInvaders(); + Executors.newSingleThreadScheduledExecutor().schedule(() -> { wipeInvaders(invadingCreaturesClone); wipeDefenders(defendingCreaturesClone); // Make sure all are deleted }, 360, TimeUnit.SECONDS); - withdrawInvaders(); + for (BuildingObject camp : offensiveCamps){ core.simulationService.remove(camp, camp.getWorldPosition().x, camp.getWorldPosition().z, true); core.objectService.destroyObject(camp.getObjectID()); @@ -442,7 +460,7 @@ public class InvasionService implements INetworkDispatch { } public void withdrawInvaders(){ - for (Map.Entry entry : invadingCreatures.entrySet()) { + for (Map.Entry entry : getInvadingCreaturesEntrySet()) { CreatureObject creature = entry.getValue(); if (creature!=null){ if (creature.getAttachment("AI")!=null){ @@ -452,6 +470,7 @@ public class InvasionService implements INetworkDispatch { actor.setAIactive(true); actor.setIntendedPrimaryAIState(new WithdrawalState()); actor.setCurrentState(new WithdrawalState()); + creature.setAttachment("isWithdrawn",1); } } } @@ -499,14 +518,34 @@ public class InvasionService implements INetworkDispatch { } public void registerInvader(CreatureObject registrant){ -// System.out.println("Registered! " + invaderRegistryCounter); - invadingCreatures.put(invaderRegistryCounter++, registrant); + synchronized(invadingCreatures) { + // System.out.println("Registered! " + invaderRegistryCounter); + invadingCreatures.put(invaderRegistryCounter++, registrant); + } } public void registerDefender(CreatureObject registrant){ - defendingCreatures.put(invaderRegistryCounter++, registrant); + synchronized(defendingCreatures) { + defendingCreatures.put(defenderRegistryCounter++, registrant); + } } + public void registerDemoralizedSoldier(CreatureObject registrant){ + synchronized(demoralizedSoldiers) { + // System.out.println("Registered! " + invaderRegistryCounter); + demoralizedSoldiers.put(demoralizedSoldierRegistryCounter++, registrant); + } + } + + public void registerDisabledVehicle(CreatureObject registrant){ + synchronized(disabledVehicles) { + // System.out.println("Registered! " + invaderRegistryCounter); + disabledVehicles.put(disabledVehicleRegistryCounter++, registrant); + } + } + + + public void wipeInvaders(Map invaderMap){ for (BuildingObject camp : offensiveCamps){ @@ -619,7 +658,9 @@ public class InvasionService implements INetworkDispatch { public void registerPhase2Objects(TangibleObject registrant){ - phase2Objects.put(phase2ObjectRegistryCounter++, registrant); + synchronized(phase2Objects){ + phase2Objects.put(phase2ObjectRegistryCounter++, registrant); + } } public void deletePhase2Objects(){ @@ -1280,7 +1321,7 @@ public class InvasionService implements INetworkDispatch { spawnPylon(PylonType.Barricade, defendingFaction, "naboo", new Point3D(1782.81F, 12, 2516.37F), 0.71F, 0.70F); spawnPylon(PylonType.Barricade, defendingFaction, "naboo", new Point3D(1991.90F, 30, 2713.51F), 0.25F, 0.96F); //spawnPylon(PylonType.Barricade, defendingFaction, "naboo", new Point3D(1990.17F, 30.29F, 2685.63F), 0.99F, 0.07F); // Makes patrols fall through the bridge - spawnPylon(PylonType.Barricade, defendingFaction, "naboo", new Point3D(1998.98F, 30.0F, 2670.41F), 0.94F, -0.32F); // works better. Do not change, it prevents clipping problems! + spawnPylon(PylonType.Barricade, defendingFaction, "naboo", new Point3D(1998.98F, 30.0F, 2670.41F), 0.94F, -0.32F); // works better. Do not change, it prevents client clipping problems! spawnPylon(PylonType.Barricade, defendingFaction, "naboo", new Point3D(1713.97F, 12, 2655.29F), 1.00F, 0.00F); spawnPylon(PylonType.Barricade, defendingFaction, "naboo", new Point3D(1693.40F, 12, 2636.64F), 0.72F, -0.69F); spawnPylon(PylonType.Barricade, defendingFaction, "naboo", new Point3D(1532.30F, 25, 2757.37F), -0.69F, 0.71F); @@ -1300,7 +1341,6 @@ public class InvasionService implements INetworkDispatch { spawnPylon(PylonType.SoldierDefense, defendingFaction, "naboo", new Point3D(1854.98F, 12, 2541.42F), 0.36F, 0.93F); spawnPylon(PylonType.SoldierDefense, defendingFaction, "naboo", new Point3D(1857.63F, 12, 2545.66F), 0.36F, 0.93F); spawnPylon(PylonType.SoldierDefense, defendingFaction, "naboo", new Point3D(1864.14F, 12, 2551.11F), 0.94F, 0.32F); - spawnPylon(PylonType.SoldierDefense, defendingFaction, "naboo", new Point3D(1864.14F, 12, 2551.11F), 0.94F, 0.32F); spawnPylon(PylonType.SoldierDefense, defendingFaction, "naboo", new Point3D(1875.09F, 12, 2556.38F), 0.95F, 0.29F); spawnPylon(PylonType.SoldierDefense, defendingFaction, "naboo", new Point3D(1875.03F, 12, 2522.12F), 0.93F, 0.36F); spawnPylon(PylonType.SoldierDefense, defendingFaction, "naboo", new Point3D(1878.19F, 12, 2524.03F), 0.94F, 0.33F); @@ -1426,7 +1466,6 @@ public class InvasionService implements INetworkDispatch { spawnPylon(PylonType.SoldierPatrol, PatrolRoute.Dearic9 ,invadingFaction, "talus", 90, new Point3D(315.93475F, 42.105118F, -3551.3157F), 0.95F, -0.30F); - spawnPylon(PylonType.SoldierDefense, defendingFaction, "talus", new Point3D(410.98F, 6, -2988.05F), -0.69F, 0.71F); spawnPylon(PylonType.SoldierDefense, defendingFaction, "talus", new Point3D(500, 6, -2954), -0.69F, 0.71F); spawnPylon(PylonType.SoldierDefense, defendingFaction, "talus", new Point3D(548, 6, -2941), -0.69F, 0.71F); @@ -1461,11 +1500,8 @@ public class InvasionService implements INetworkDispatch { spawnPylon(PylonType.Turret, defendingFaction, "talus", new Point3D(344.91F, 6, -2741.06F), 1F, 0F); spawnPylon(PylonType.Turret, defendingFaction, "talus", new Point3D(379.53F, 6, -2741.90F), 1F, 0F); spawnPylon(PylonType.Turret, defendingFaction, "talus", new Point3D(362.86F, 6, -2754.18F), 1F, 0F); - - // object/tangible/destructible/shared_gcw_rebel_turret.iff crashes the client, not fixable - } public void spawnPylonsBestine(){ @@ -1473,10 +1509,10 @@ public class InvasionService implements INetworkDispatch { spawnPylon(PylonType.Turret, defendingFaction, "tatooine", new Point3D(-1164.60F,12, -3643.42F), 0.42F, 0.9F); spawnPylon(PylonType.Turret, defendingFaction, "tatooine", new Point3D(-1278.45F,12, -3615.71F), 0.41F, 0.9F); spawnPylon(PylonType.Turret, defendingFaction, "tatooine", new Point3D(-1237.01F,12, -3640.84F), 0.89F, -0.44F); - spawnPylon(PylonType.Turret, defendingFaction, "tatooine", new Point3D(-1230.01F,12, -3647.99F), 0.89F, -0.44F); + spawnPylon(PylonType.Turret, defendingFaction, "tatooine", new Point3D(-1231.72F,12, -3646.87F), 0.89F, -0.44F); spawnPylon(PylonType.Turret, defendingFaction, "tatooine", new Point3D(-1330.74F,12, -3678.19F), 0F, 1F); spawnPylon(PylonType.Turret, defendingFaction, "tatooine", new Point3D(-1274.77F,12, -3572.47F), 0.28F, 0.95F); - spawnPylon(PylonType.Turret, defendingFaction, "tatooine", new Point3D(-1123.84F,12, -3727.56F), -0.17F, 0.98F); + spawnPylon(PylonType.Turret, defendingFaction, "tatooine", new Point3D(-1124.69F,8.89F, -3729.97F), -0.17F, 0.98F); spawnPylon(PylonType.Turret, defendingFaction, "tatooine", new Point3D(-1156.16F,12, -3704.48F), 0.02F, 0.99F); spawnPylon(PylonType.Turret, defendingFaction, "tatooine", new Point3D(-1108.44F,12, -3632.28F), 0.90F, 0.422F); @@ -1607,7 +1643,7 @@ public class InvasionService implements INetworkDispatch { defendingGeneral = (CreatureObject) NGECore.getInstance().staticService.spawnObject(generalTemplate, "talus", 0L, 480.071F, 6, -3006.851F, 1, 0); } - if (defendingGeneral==null){ + if (defendingGeneral==null || defendingGeneral.getTemplate()==null){ try { throw new Exception(); } catch (Exception e) { @@ -1615,14 +1651,20 @@ public class InvasionService implements INetworkDispatch { e.printStackTrace(); } } - + defendingGeneralAlive = true; - defendingGeneralTask = scheduler.scheduleAtFixedRate(new Runnable() { + final Future[] dgt = {null}; + dgt[0] = defendingGeneralTask = scheduler.scheduleAtFixedRate(new Runnable() { @Override public void run() { try { AIActor actor = (AIActor)defendingGeneral.getAttachment("AI"); + if (actor.getCurrentState().getClass().equals(DeathState.class)){ + defendingGeneralAlive = false; + Thread.yield(); + dgt[0].cancel(false); + } for (CreatureObject damager : actor.getDamageMap().keySet()){ if (damager.getOwnerId()>0){ // For pets doing damage damager = (CreatureObject)core.objectService.getObject(damager.getOwnerId()); @@ -2104,6 +2146,7 @@ public class InvasionService implements INetworkDispatch { AIActor actor = (AIActor)enemy.getAttachment("AI"); if (actor==null) return; + actor.setLastPositionBeforeStateChange(enemy.getWorldPosition()); actor.addDefender(defendingGeneral); } } @@ -2215,6 +2258,44 @@ public class InvasionService implements INetworkDispatch { offensiveClonerList.add(cloner3); } + private void spawnDemoralizedSoldier(int faction, Point3D pos, float qw, float qy){ + String soldierTemplate = "rebel_invasion_demoralized_soldier"; + if (faction==Factions.Imperial){ + soldierTemplate = "imp_invasion_demoralized_soldier"; + } + + CreatureObject soldier = (CreatureObject)NGECore.getInstance().spawnService.spawnCreature(soldierTemplate, getInvasionPlanet(invasionLocation).getName(), 0L, pos.x, pos.y, pos.z, qw,0F,qy,0F,-1); + NGECore.getInstance().invasionService.registerDemoralizedSoldier(soldier); + } + + private void spawnDisabledVehicle(int faction, Point3D pos, float qw, float qy){ + String vehicleTemplate = "rebel_invasion_disabled_atxt"; + if (faction==Factions.Imperial){ + vehicleTemplate = "imp_invasion_disabled_atst"; + } + + CreatureObject vehicle = (CreatureObject)NGECore.getInstance().spawnService.spawnCreature(vehicleTemplate, getInvasionPlanet(invasionLocation).getName(), 0L, pos.x, pos.y, pos.z, qw,0F,qy,0F,-1); + vehicle.setPosture((byte) Posture.Incapacitated); + NGECore.getInstance().invasionService.registerDisabledVehicle(vehicle); + } + + private void playVictoryMusic(int winnerFaction){ + String audioTemplate = "sound/music_themequest_victory_rebel.snd"; + if (winnerFaction==Factions.Imperial) + audioTemplate = "sound/music_themequest_victory_imperial.snd"; + +// Vector allPlayers = core.simulationService.getAllNearSameFactionPlayers(500,invasionLocationCenter, getInvasionPlanet(invasionLocation), getFactionName(winnerFaction)); +// for (CreatureObject player : allPlayers) { +// if (player.getFaction().length() > 0 && player.getFactionStatus() > FactionStatus.OnLeave) { +// player.playMusic(audioTemplate); +// } +// } + Vector allPlayers = core.simulationService.getAllNearPlayers(500, getInvasionPlanet(invasionLocation), invasionLocationCenter); + for (CreatureObject player : allPlayers) { + player.playMusic(audioTemplate); + } + } + // Utility method public void arrangePylons(Point3D center, int angle){ @@ -2262,6 +2343,17 @@ public class InvasionService implements INetworkDispatch { return result; } + private Set> getInvadingCreaturesEntrySet(){ + synchronized(invadingCreatures){ + return invadingCreatures.entrySet(); + } + } + + private Set> getDefendingCreaturesEntrySet(){ + synchronized(defendingCreatures){ + return defendingCreatures.entrySet(); + } + } public void setInvasionLocationCenter(){ @@ -2292,6 +2384,11 @@ public class InvasionService implements INetworkDispatch { return "neutral"; } + + public boolean isDefendingGeneralAlive() { + return defendingGeneralAlive; + } + @Override public void shutdown() {