diff --git a/ngengine_public.jar b/ngengine_public.jar index 63dc862e..06b32ef7 100644 Binary files a/ngengine_public.jar and b/ngengine_public.jar differ diff --git a/scripts/commands/transferitemarmor.py b/scripts/commands/transferitemarmor.py index 46a741f3..421c0f05 100644 --- a/scripts/commands/transferitemarmor.py +++ b/scripts/commands/transferitemarmor.py @@ -15,13 +15,16 @@ def run(core, actor, target, commandString): if container == oldContainer: print 'Error: New container is same as old container.' return; - - if oldContainer == actor.getSlottedObject('appearance_inventory'): - core.equipmentService.unequipAppearance(actor, target) - - oldContainer.transferTo(actor, container, target) - - if container == actor.getSlottedObject('appearance_inventory'): - core.equipmentService.equipAppearance(actor, target) - + + if oldContainer == actor: + core.equipmentService.unequip(actor, target) + elif oldContainer == actor.getSlottedObject('appearance_inventory'): + core.equipmentService.unequipAppearance(actor, target) + elif container == actor: + core.equipmentService.equip(actor, target) + elif container == actor.getSlottedObject('appearance_inventory'): + core.equipmentService.equipAppearance(actor, target) + else: + oldContainer.transferTo(actor, container, target) + return diff --git a/scripts/commands/transferitemmisc.py b/scripts/commands/transferitemmisc.py index c0708738..e7b5e32c 100644 --- a/scripts/commands/transferitemmisc.py +++ b/scripts/commands/transferitemmisc.py @@ -58,12 +58,15 @@ def run(core, actor, target, commandString): print 'Error: New container is same as old container.' return; - if oldContainer == actor.getSlottedObject('appearance_inventory'): + if oldContainer == actor: + core.equipmentService.unequip(actor, target) + elif oldContainer == actor.getSlottedObject('appearance_inventory'): core.equipmentService.unequipAppearance(actor, target) - - oldContainer.transferTo(actor, container, target) - - if container == actor.getSlottedObject('appearance_inventory'): + elif container == actor: + core.equipmentService.equip(actor, target) + elif container == actor.getSlottedObject('appearance_inventory'): core.equipmentService.equipAppearance(actor, target) + else: + oldContainer.transferTo(actor, container, target) return diff --git a/scripts/commands/transferitemweapon.py b/scripts/commands/transferitemweapon.py index 25b9378b..c5ec91b8 100644 --- a/scripts/commands/transferitemweapon.py +++ b/scripts/commands/transferitemweapon.py @@ -16,7 +16,11 @@ def run(core, actor, target, commandString): print 'Error: New container is same as old container.' return; - oldContainer.transferTo(actor, container, target) + if oldContainer == actor: + core.equipmentService.unequip(actor, target) + elif container == actor: + core.equipmentService.equip(actor, target) + else: + oldContainer.transferTo(actor, container, target) return - diff --git a/scripts/conversation/quests/tatooine/byxle.py b/scripts/conversation/quests/tatooine/byxle.py index 884f6cf5..bf632bb3 100644 --- a/scripts/conversation/quests/tatooine/byxle.py +++ b/scripts/conversation/quests/tatooine/byxle.py @@ -11,18 +11,25 @@ def startConversation(core, actor, npc): return quest = player.getQuest('tatooine_eisley_tdc') - if quest is None: options = Vector() options.add(ConversationOption(OutOfBand.ProsePackage('@conversation/tatooine_eisley_byxle:s_58'), 0)) core.conversationService.sendConversationMessage(actor, npc, OutOfBand.ProsePackage('@conversation/tatooine_eisley_byxle:s_56')) core.conversationService.sendConversationOptions(actor, npc, options, handleOptionsOne) - return -# if quest.isCompleted() == True: -# core.conversationService.sendStopConversation(actor, npc, 'conversation/tatooine_eisley_byxle', 's_48') -# return - core.conversationService.sendStopConversation(actor, npc, 'conversation/tatooine_eisley_byxle', 's_48') + return + if quest.getActiveTask() == 8: + options = Vector() + # I don't know. He seemed pretty mad. + options.add(ConversationOption(OutOfBand.ProsePackage('@conversation/tatooine_eisley_byxle:s_29'), 0)) + core.conversationService.sendConversationMessage(actor, npc, OutOfBand.ProsePackage('@conversation/tatooine_eisley_byxle:s_17')) + core.conversationService.sendConversationOptions(actor, npc, options, handleOptionsFive) + elif quest.isCompleted() == True: + core.conversationService.sendStopConversation(actor, npc, 'conversation/tatooine_eisley_byxle', 's_48') + else: + core.conversationService.sendStopConversation(actor, npc, 'conversation/tatooine_eisley_byxle', 's_48') + return + def handleOptionsOne(core, actor, npc, selection): options = Vector() # So what do I need to do? @@ -52,6 +59,24 @@ def handleOptionsFour(core, actor, npc, selection): core.questService.sendQuestAcceptWindow(actor, 'quest/tatooine_eisley_tdc') return +def handleOptionsFive(core, actor, npc, selection): + options = Vector() + # Thanks. + options.add(ConversationOption(OutOfBand.ProsePackage('@conversation/tatooine_eisley_byxle:s_69'), 0)) + core.conversationService.sendConversationMessage(actor, npc, OutOfBand.ProsePackage('@conversation/tatooine_eisley_byxle:s_30')) + core.conversationService.sendConversationOptions(actor, npc, options, handleOptionsSix) + return + +def handleOptionsSix(core, actor, npc, selection): + core.conversationService.sendStopConversation(actor, npc, 'conversation/tatooine_eisley_byxle', 's_70') + player = actor.getPlayerObject() + if player is None: + return + quest = player.getQuest('tatooine_eisley_tdc') + core.questService.completeActiveTask(actor, quest) + core.questService.sendQuestCompleteWindow(actor, 'quest/tatooine_eisley_tdc') + return + def endConversation(core, actor, npc): core.conversationService.sendStopConversation(actor, npc, 'conversation/tatooine_eisley_byxle', 's_48') return diff --git a/scripts/object/mobile/dressed_tatooine_opening_drixa.py b/scripts/object/mobile/dressed_tatooine_opening_drixa.py index ccad8904..ecf81bb6 100644 --- a/scripts/object/mobile/dressed_tatooine_opening_drixa.py +++ b/scripts/object/mobile/dressed_tatooine_opening_drixa.py @@ -1,4 +1,10 @@ import sys +from resources.datatables import Options def setup(core, object): + object.setAttachment('radial_filename', 'object/conversation'); + object.setAttachment('conversationFile','quests/tatooine/drixa') + object.setOptionsBitmask(Options.CONVERSABLE | Options.INVULNERABLE) + object.setStfFilename('mob/creature_names') + object.setStfName('tatooine_opening_drixa') return \ No newline at end of file diff --git a/scripts/object/mobile/dressed_tatooine_opening_jano.py b/scripts/object/mobile/dressed_tatooine_opening_jano.py index ccad8904..7bddcd27 100644 --- a/scripts/object/mobile/dressed_tatooine_opening_jano.py +++ b/scripts/object/mobile/dressed_tatooine_opening_jano.py @@ -1,4 +1,10 @@ import sys +from resources.datatables import Options def setup(core, object): + object.setAttachment('radial_filename', 'object/conversation'); + object.setAttachment('conversationFile','quests/tatooine/jano') + object.setOptionsBitmask(Options.CONVERSABLE | Options.INVULNERABLE) + object.setStfFilename('mob/creature_names') + object.setStfName('tatooine_opening_jano') return \ No newline at end of file diff --git a/scripts/object/mobile/dressed_tatooine_opening_nogri.py b/scripts/object/mobile/dressed_tatooine_opening_nogri.py index ccad8904..c2eb0202 100644 --- a/scripts/object/mobile/dressed_tatooine_opening_nogri.py +++ b/scripts/object/mobile/dressed_tatooine_opening_nogri.py @@ -1,4 +1,10 @@ import sys +from resources.datatables import Options def setup(core, object): + object.setAttachment('radial_filename', 'object/conversation'); + object.setAttachment('conversationFile','quests/tatooine/nogri') + object.setOptionsBitmask(Options.CONVERSABLE | Options.INVULNERABLE) + object.setStfFilename('mob/creature_names') + object.setStfName('tatooine_opening_nogri') return \ No newline at end of file diff --git a/scripts/quests/events/signals/tat_eisley_tdc_e2.py b/scripts/quests/events/signals/tat_eisley_tdc_e2.py deleted file mode 100644 index 2c219af1..00000000 --- a/scripts/quests/events/signals/tat_eisley_tdc_e2.py +++ /dev/null @@ -1,9 +0,0 @@ -def setup(core): - return - -def wait(core, actor): - return - -def activate(core, actor, quest): - core.questService.completeActiveTask(actor, quest) - return \ No newline at end of file diff --git a/scripts/static_spawns/tatooine/mos_eisley_quest.py b/scripts/static_spawns/tatooine/mos_eisley_quest.py index fb32adb9..b365360a 100644 --- a/scripts/static_spawns/tatooine/mos_eisley_quest.py +++ b/scripts/static_spawns/tatooine/mos_eisley_quest.py @@ -16,6 +16,15 @@ def addPlanetSpawns(core, planet): vourk = stcSvc.spawnObject('vourk', 'tatooine', long(0), float(3521.0), float(5.0), float(-4821.0), float(0.42), float(0.91)) # Byxle Pedette - byxlePedette = stcSvc.spawnObject('byxle', 'tatooine', long(0), float(3365), float(5), float(-4639), float(0.99), float(0.12)) - + byxle = stcSvc.spawnObject('byxle', 'tatooine', long(0), float(3365), float(5), float(-4639), float(0.99), float(0.12)) + + # Drixa Dreul + drixa = stcSvc.spawnObject('drixa', 'tatooine', long(0), float(3259), float(5), float(-4863), float(-0.38), float(0.92)) + + # Nogri Hessen + nogri = stcSvc.spawnObject('nogri', 'tatooine', long(0), float(3449), float(4), float(-5076), float(-0.38), float(0.92)) + + # Jano Bix + jano = stcSvc.spawnObject('jano', 'tatooine', long(0), float(3186), float(5), float(-4781), float(-0.38), float(0.92)) + return \ No newline at end of file diff --git a/src/resources/objects/creature/CreatureObject.java b/src/resources/objects/creature/CreatureObject.java index 32521beb..0eaaa13d 100644 --- a/src/resources/objects/creature/CreatureObject.java +++ b/src/resources/objects/creature/CreatureObject.java @@ -68,19 +68,19 @@ public class CreatureObject extends TangibleObject implements IPersistent { private transient CreatureMessageBuilder messageBuilder; private transient List duelList = Collections.synchronizedList(new ArrayList()); - private transient ScheduledFuture incapTask; - private transient ScheduledFuture entertainerExperience; - private transient ScheduledFuture inspirationTick; - private transient CreatureObject performanceWatchee; - private transient CreatureObject performanceListenee; + private transient ScheduledFuture incapTask = null; + private transient ScheduledFuture entertainerExperience = null; + private transient ScheduledFuture inspirationTick = null; + private transient CreatureObject performanceWatchee = null; + private transient CreatureObject performanceListenee = null; private transient List performanceAudience = new ArrayList(); - private transient ScheduledFuture spectatorTask; + private transient ScheduledFuture spectatorTask = null; private transient int flourishCount = 0; - private transient boolean performingEffect; - private transient boolean performingFlourish; - private transient TangibleObject conversingNpc; + private transient boolean performingEffect = false; + private transient boolean performingFlourish = false; + private transient TangibleObject conversingNpc = null; private transient long tefTime = 0; - private transient SWGObject useTarget; + private transient SWGObject useTarget = null; private transient boolean isConstructing = false; public CreatureObject(long objectID, Planet planet, Point3D position, Quaternion orientation, String Template) { @@ -107,6 +107,21 @@ public class CreatureObject extends TangibleObject implements IPersistent { public void initAfterDBLoad() { super.initAfterDBLoad(); + duelList = Collections.synchronizedList(new ArrayList()); + incapTask = null; + entertainerExperience = null; + inspirationTick = null; + performanceWatchee = null; + performanceListenee = null; + performanceAudience = new ArrayList(); + spectatorTask = null; + flourishCount = 0; + performingEffect = false; + performingFlourish = false; + conversingNpc = null; + tefTime = 0; + useTarget = null; + isConstructing = false; System.out.println("Name: " + getCustomName()); System.out.println(" Cash Credits: " + getCashCredits()); System.out.println(" Bank Credits: " + getBankCredits()); @@ -389,7 +404,7 @@ public class CreatureObject extends TangibleObject implements IPersistent { } public void setHeight(float height) { - height = (((height < 0.7) || (height > 1.5)) ? 1 : height); + // height = (((height < 0.7) || (height > 1.5)) ? 1 : height); Babies need height values smaller than that notifyObservers(getBaseline(3).set("height", height), true); } @@ -899,7 +914,7 @@ public class CreatureObject extends TangibleObject implements IPersistent { public boolean isWearing(SWGObject object) { for (Equipment equipment : getEquipmentList()) { - if (equipment.getObjectId() == object.getObjectId()) { + if (equipment.getObjectId() == object.getObjectID()) { return true; } } @@ -907,10 +922,26 @@ public class CreatureObject extends TangibleObject implements IPersistent { return false; } + public Equipment getEquipmentForObject(SWGObject object) { + for (Equipment equipment : getEquipmentList()) { + if (equipment.getObjectId() == object.getObjectID()) { + return equipment; + } + } + + for (Equipment equipment : getAppearanceEquipmentList()) { + if (equipment.getObjectId() == object.getObjectID()) { + return equipment; + } + } + + return null; + } + public void removeObjectFromEquipList(SWGObject object) { if (object instanceof TangibleObject) { for (Equipment equipment : getEquipmentList()) { - if (equipment.getObjectId() == object.getObjectId()) { + if (equipment.getObjectId() == object.getObjectID()) { getEquipmentList().remove(equipment); } } @@ -1131,7 +1162,7 @@ public class CreatureObject extends TangibleObject implements IPersistent { public boolean isWearingAppearance(SWGObject object) { for (Equipment equipment : getAppearanceEquipmentList()) { - if (equipment.getObjectId() == object.getObjectId()) { + if (equipment.getObjectId() == object.getObjectID()) { return true; } } @@ -1142,7 +1173,7 @@ public class CreatureObject extends TangibleObject implements IPersistent { public void removeObjectFromAppearanceEquipList(SWGObject object) { if (object instanceof TangibleObject) { for (Equipment equipment : getAppearanceEquipmentList()) { - if (equipment.getObjectId() == object.getObjectId()) { + if (equipment.getObjectId() == object.getObjectID()) { getAppearanceEquipmentList().remove(equipment); } } diff --git a/src/services/PlayerService.java b/src/services/PlayerService.java index be544185..dcc43e10 100644 --- a/src/services/PlayerService.java +++ b/src/services/PlayerService.java @@ -787,27 +787,24 @@ public class PlayerService implements INetworkDispatch { public void resetLevel(CreatureObject creature, boolean unequipItems) { PlayerObject player = (PlayerObject) creature.getSlottedObject("ghost"); SWGObject inventory = creature.getSlottedObject("inventory"); + SWGObject appearance = creature.getSlottedObject("appearance_inventory"); if (unequipItems) { try { - for (Equipment equipmentObject : new ArrayList(creature.getEquipmentList())) { - - SWGObject equipment = core.objectService.getObject(equipmentObject.getObjectId()); - - if (equipment == null || equipment.getTemplate().startsWith("object/tangible/hair/")) { - continue; + String[] slots = { "hat", "earring_r", "earring_l", "eyes", "mouth", "neck", "cloak", "back", "chest1", "chest2", "chest3_r", "chest3_l", "bicep_r", "bicep_l", "bracer_lower_r", "bracer_upper_r", "bracer_lower_l", "bracer_upper_l", "wrist_r", "wrist_l", "gloves", "hold_r", "hold_l", "ring_r", "ring_l", "utility_belt", "pants1", "pants2", "shoes" }; + + for (String slot : slots) { + if (creature.getSlottedObject(slot) != null) { + core.equipmentService.unequip(creature, creature.getSlottedObject(slot)); } - - switch (equipment.getTemplate()) { - case "object/tangible/inventory/shared_character_inventory.iff": - case "object/tangible/inventory/shared_appearance_inventory.iff": - case "object/tangible/datapad/shared_character_datapad.iff": - case "object/tangible/bank/shared_character_bank.iff": - case "object/tangible/mission_bag/shared_mission_bag.iff": - case "object/weapon/creature/shared_creature_default_weapon.iff": - continue; - default: - creature.transferTo(creature, inventory, equipment); + } + + + slots = new String[] { "hat", "earring_r", "earring_l", "eyes", "mouth", "neck", "cloak", "back", "chest1", "chest2", "chest3_r", "chest3_l", "bicep_r", "bicep_l", "bracer_lower_r", "bracer_upper_r", "bracer_lower_l", "bracer_upper_l", "wrist_r", "wrist_l", "gloves", "utility_belt", "pants1", "pants2", "shoes" }; + + for (String slot : slots) { + if (appearance.getSlottedObject(slot) != null) { + core.equipmentService.unequip(creature, creature.getSlottedObject(slot)); } } } catch (Exception e) { @@ -815,10 +812,6 @@ public class PlayerService implements INetworkDispatch { } } - //for (SWGObject equipment : creature.getAppearanceEquipmentList()) { - //core.equipmentService.unequip(creature, equipment); - //} - for (Buff buff : creature.getBuffList().values().toArray(new Buff[] { })) { if (buff.isRemoveOnRespec()) { core.buffService.removeBuffFromCreature(creature, buff); diff --git a/src/services/ai/LairActor.java b/src/services/ai/LairActor.java index 44e7e1be..11a9fd2b 100644 --- a/src/services/ai/LairActor.java +++ b/src/services/ai/LairActor.java @@ -21,15 +21,24 @@ ******************************************************************************/ package services.ai; +import java.util.Collections; +import java.util.Map; import java.util.Random; import java.util.Vector; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import engine.resources.scene.Point3D; import main.NGECore; import net.engio.mbassy.listener.Handler; import resources.common.SpawnPoint; +import resources.datatables.Posture; import resources.objects.creature.CreatureObject; import resources.objects.tangible.TangibleObject; +import services.ai.states.RetreatState; import services.combat.CombatEvents.DamageTaken; import tools.DevLog; @@ -45,11 +54,13 @@ public class LairActor { private short level; private String bossTemplate; private boolean bossSpawned = false; + private Map attackerMap = new ConcurrentHashMap(); public LairActor(TangibleObject lairObject, String creatureTemplate) { this.lairObject = lairObject; this.creatureTemplate = creatureTemplate; lairObject.getEventBus().subscribe(this); + checkAttackerTask(); } public LairActor(TangibleObject lairObject, String creatureTemplate, int maxSpawns, short level) { @@ -58,6 +69,7 @@ public class LairActor { this.maxSpawns = maxSpawns; this.level = level; lairObject.getEventBus().subscribe(this); + checkAttackerTask(); } public LairActor(TangibleObject lairObject, Vector creatureTemplates, int maxSpawns, short level) { @@ -66,6 +78,7 @@ public class LairActor { this.maxSpawns = maxSpawns; this.level = level; lairObject.getEventBus().subscribe(this); + checkAttackerTask(); } @@ -90,40 +103,55 @@ public class LairActor { ai.addDefender((CreatureObject)event.attacker); ((CreatureObject)event.attacker).addDefender(ai.getCreature()); } - - + attackerMap.put(((CreatureObject)event.attacker), System.currentTimeMillis()); } public void spawnNewCreatures() { + // remove dead creatures from collection + creatures.removeAll(Collections.singleton(null)); + Vector removers = new Vector(); + for (AIActor act : creatures){ + if (act!=null ){ + if (act.getCreature().getPosture()==Posture.Dead) + removers.add(act); + else if (lairObject.getPosition().getDistance2D(act.getCreature().getPosition())>80) + removers.add(act); + } + } + creatures.removeAll(removers); + if(creatures.size() >= maxSpawns) return; int currentCondition = lairObject.getConditionDamage(); int maxCondition = lairObject.getMaximumCondition(); - + //System.out.println("spawnWave " + spawnWave + " currentCondition " + currentCondition + " maxCondition " + maxCondition + "quot " + ((float)currentCondition / (float)maxCondition)); switch(spawnWave) { // TODO: play damage effect case 0: spawnWave++; break; case 1: - if((currentCondition / maxCondition) < 0.7) { + if(((float)currentCondition / (float)maxCondition) < 0.7) { spawnWave++; + break; } else { return; } case 2: - if((currentCondition / maxCondition) < 0.3) { + if(((float)currentCondition / (float)maxCondition) < 0.3) { spawnWave++; + break; } else { return; } - break; + case 3: if (bossTemplate!=null && ! bossSpawned){ - //CreatureObject boss = (CreatureObject)NGECore.getInstance().spawnService.spawnCreature(bossTemplate, lairObject.getPlanet().getName(), 0L, lairObject.getPosition().x + 3, lairObject.getPosition().y, lairObject.getPosition().z, lairObject.getOrientation().w, lairObject.getOrientation().x, lairObject.getOrientation().y,lairObject.getOrientation().z,-1); + CreatureObject boss = (CreatureObject)NGECore.getInstance().spawnService.spawnCreature(bossTemplate, lairObject.getPlanet().getName(), 0L, lairObject.getPosition().x + 3, lairObject.getPosition().y, lairObject.getPosition().z, lairObject.getOrientation().w, lairObject.getOrientation().x, lairObject.getOrientation().y,lairObject.getOrientation().z,-1); bossSpawned = true; + break; } return; @@ -138,7 +166,9 @@ public class LairActor { creatureAmount = new Random().nextInt(4) + (maxSpawns / 5); tries++; } - while(creatureAmount > maxSpawns && tries < 10); + while(tries < 10); + + //while(creatureAmount > maxSpawns && tries < 10); for(int i = 0; i < creatureAmount; i++) { Point3D position = SpawnPoint.getRandomPosition(lairObject.getPosition(), 5, 30, lairObject.getPlanetId()); @@ -211,4 +241,48 @@ public class LairActor { public void setBossTemplate(String bossTemplate) { this.bossTemplate = bossTemplate; } + + private void checkAttackerTask(){ + final Future[] fut1 = {null}; + final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + fut1[0] = scheduler.scheduleAtFixedRate(new Runnable() { + @Override public void run() { + try { + if (lairObject==null){ + Thread.yield(); + fut1[0].cancel(false); + } else { + int currentCondition = lairObject.getConditionDamage(); + int maxCondition = lairObject.getMaximumCondition(); + if (currentCondition>maxCondition){ + Thread.yield(); + fut1[0].cancel(false); + } + } + checkAttackers(); + } catch (Exception e) { + System.err.println("Exception in checkAttackerTask->scheduleAtFixedRate->checkAttackers() " + e.getMessage()); + } + } + }, 0, 10, TimeUnit.SECONDS); + } + + private void checkAttackers(){ + Map attackerMapClone = new ConcurrentHashMap(attackerMap); + for (CreatureObject attacker : attackerMapClone.keySet()) { + Long lastAttackTime = attackerMapClone.get(attacker); + if (attacker.getWorldPosition().getDistance2D(lairObject.getWorldPosition())>100 || System.currentTimeMillis()-lastAttackTime>10000) + removeDefender(attacker); + } + attackerMapClone = null; + } + + private void removeDefender(TangibleObject defender) { + if (defender==null){ + return; + } + lairObject.removeDefender(defender); + if (attackerMap.containsKey(defender)) attackerMap.remove(defender); + defender.removeDefender(lairObject); + } } diff --git a/src/services/combat/CombatService.java b/src/services/combat/CombatService.java index f251144f..98438d95 100644 --- a/src/services/combat/CombatService.java +++ b/src/services/combat/CombatService.java @@ -1533,8 +1533,13 @@ public class CombatService implements INetworkDispatch { public boolean areInDuel(CreatureObject creature1, CreatureObject creature2) { - if(creature1.getDuelList().contains(creature2) && creature2.getDuelList().contains(creature1)) - return true; + // Vehicles are going through this too, but dont have duellists, so null checks must be done or NPE + if (creature1.getDuelList()!=null && creature2.getDuelList()!=null) { + if(creature1.getDuelList().contains(creature2) && creature2.getDuelList().contains(creature1)) + return true; + } else { + return false; + } return false; } diff --git a/src/services/equipment/EquipmentService.java b/src/services/equipment/EquipmentService.java index 45196f96..4f96bd6e 100644 --- a/src/services/equipment/EquipmentService.java +++ b/src/services/equipment/EquipmentService.java @@ -30,6 +30,7 @@ import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; @@ -62,8 +63,43 @@ public class EquipmentService implements INetworkDispatch { public void equip(CreatureObject actor, SWGObject item) { SWGObject container = actor; + SWGObject oldContainer = item.getContainer(); if (canWear(actor, container, item)) { + List replacedEquipment = new ArrayList(); + + for (String slotName : container.getSlotNamesForObject(item)) { + if (container.getSlottedObject(slotName) != null) { + replacedEquipment.add(actor.getEquipmentForObject(container.getSlottedObject(slotName))); + container.transferTo(actor, actor.getSlottedObject("inventory"), container.getSlottedObject(slotName)); + } + } + + if (oldContainer == null) { + container.add(item); + } else { + oldContainer.transferTo(actor, container, item); + } + + for (Equipment equipment : replacedEquipment) { + SWGObject replacedItem = core.objectService.getObject(equipment.getObjectId()); + + if (actor.isWearing(replacedItem)) { + String template = ((replacedItem.getAttachment("customServerTemplate") == null) ? replacedItem.getTemplate() : (replacedItem.getTemplate().split("shared_")[0] + "shared_" + ((String) replacedItem.getAttachment("customServerTemplate")) + ".iff")); + String serverTemplate = template.replace(".iff", ""); + + PyObject func = core.scriptService.getMethod("scripts/" + serverTemplate.split("shared_" , 2)[0].replace("shared_", ""), serverTemplate.split("shared_" , 2)[1], "unequip"); + + if (func != null) { + func.__call__(Py.java2py(core), Py.java2py(actor), Py.java2py(replacedItem)); + } + + processItemAtrributes(actor, replacedItem, false); + } else { + replacedEquipment.remove(equipment); + } + } + String template = ((item.getAttachment("customServerTemplate") == null) ? item.getTemplate() : (item.getTemplate().split("shared_")[0] + "shared_" + ((String) item.getAttachment("customServerTemplate")) + ".iff")); String serverTemplate = template.replace(".iff", ""); @@ -73,15 +109,13 @@ public class EquipmentService implements INetworkDispatch { func.__call__(Py.java2py(core), Py.java2py(actor), Py.java2py(item)); } - for (String slotName : container.getSlotNamesForObject(item)) { - if (container.getSlottedObject(slotName) != null && !container.getSlotNamesForObject(item).iterator().hasNext()) { - container.transferTo(actor, actor.getSlottedObject("inventory"), item); - break; - } + processItemAtrributes(actor, item, true); + + if (replacedEquipment.size() > 0) { + actor.getEquipmentList().removeAll(replacedEquipment); } actor.addObjectToEquipList(item); - processItemAtrributes(actor, item, true); if (item instanceof WeaponObject) { actor.setWeaponId(item.getObjectID()); @@ -90,7 +124,16 @@ public class EquipmentService implements INetworkDispatch { } public void unequip(CreatureObject actor, SWGObject item) { + SWGObject container = actor.getSlottedObject("inventory"); + SWGObject oldContainer = item.getContainer(); + if (actor.isWearing(item)) { + if (item instanceof WeaponObject) { + actor.setWeaponId(actor.getSlottedObject("default_weapon").getObjectID()); + } + + oldContainer.transferTo(actor, container, item); + String template = ((item.getAttachment("customServerTemplate") == null) ? item.getTemplate() : (item.getTemplate().split("shared_")[0] + "shared_" + ((String) item.getAttachment("customServerTemplate")) + ".iff")); String serverTemplate = template.replace(".iff", ""); @@ -100,33 +143,40 @@ public class EquipmentService implements INetworkDispatch { func.__call__(Py.java2py(core), Py.java2py(actor), Py.java2py(item)); } - if (item instanceof WeaponObject) { - actor.setWeaponId(actor.getSlottedObject("default_weapon").getObjectID()); - } + processItemAtrributes(actor, item, false); actor.removeObjectFromEquipList(item); - processItemAtrributes(actor, item, false); } } public void equipAppearance(CreatureObject actor, SWGObject item) { SWGObject container = actor.getSlottedObject("appearance_inventory"); + SWGObject oldContainer = item.getContainer(); if (canWear(actor, container, item)) { for (String slotName : container.getSlotNamesForObject(item)) { - if (container.getSlottedObject(slotName) != null && !container.getSlotNamesForObject(item).iterator().hasNext()) { - unequipAppearance(actor, item); - container.transferTo(actor, actor.getSlottedObject("inventory"), item); - break; + if (container.getSlottedObject(slotName) != null) { + return; } } + if (oldContainer == null) { + container.add(item); + } else { + oldContainer.transferTo(actor, container, item); + } + actor.addObjectToAppearanceEquipList(item); } } public void unequipAppearance(CreatureObject actor, SWGObject item) { - if (actor.isWearingAppearance(item) ) { + SWGObject container = actor.getSlottedObject("inventory"); + SWGObject oldContainer = item.getContainer(); + + if (actor.isWearingAppearance(item)) { + oldContainer.transferTo(actor, container, item); + actor.removeObjectFromAppearanceEquipList(item); } } @@ -151,9 +201,7 @@ public class EquipmentService implements INetworkDispatch { } if (item.getAttributes().toString().contains("cat_armor")) { - if (actor.hasAbility("wear_all_armor")) { - return true; - } else { + if (!actor.hasAbility("wear_all_armor")) { actor.sendSystemMessage("@error_message:insufficient_skill", DisplayType.Broadcast); // I am unsure if this is the right message return false; } @@ -163,27 +211,21 @@ public class EquipmentService implements INetworkDispatch { String classRequired = item.getStringAttribute("class_required"); String profession = ((PlayerObject) actor.getSlottedObject("ghost")).getProfession(); - if (classRequired.contains(core.playerService.getFormalProfessionName(profession)) || classRequired.equals("None")) { - return true; - } else { + if (!classRequired.contains(core.playerService.getFormalProfessionName(profession)) && !classRequired.equals("None")) { actor.sendSystemMessage("@error_message:insufficient_skill", DisplayType.Broadcast); // I am unsure if this is the right message return false; } } if (item.getStringAttribute("faction_restriction") != null) { - if (item.getStringAttribute("faction_restriction").toLowerCase().contentEquals(actor.getFaction()) && actor.getFactionStatus() >= FactionStatus.Combatant) { - return true; - } else { + if (!item.getStringAttribute("faction_restriction").toLowerCase().contentEquals(actor.getFaction()) || actor.getFactionStatus() < FactionStatus.Combatant) { actor.sendSystemMessage("@faction_recruiter:must_be_faction_member_use", DisplayType.Broadcast); // will have to somehow manage prose %TO for faction name return false; } } if (item.getAttributes().containsKey("required_combat_level")) { - if (actor.getLevel() >= item.getIntAttribute("required_combat_level")) { - return true; - } else { + if (actor.getLevel() < item.getIntAttribute("required_combat_level")) { actor.sendSystemMessage("@error_message:insufficient_skill", DisplayType.Broadcast); // I am unsure if this is the right message return false; } @@ -620,7 +662,7 @@ public class EquipmentService implements INetworkDispatch { FileVisitor fv = new SimpleFileVisitor() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - core.scriptService.callScript("scripts/equipment/bonus_sets/", file.getFileName().toString().replace(".py", ""), "addBonusSet", core); + core.scriptService.callScript("scripts/equipment/bonus_sets/", file.getFileName().toString().replace(".py", ""), "addBonusSet", core); return FileVisitResult.CONTINUE; } }; diff --git a/src/services/quest/QuestService.java b/src/services/quest/QuestService.java index 900b24f2..48a2c867 100644 --- a/src/services/quest/QuestService.java +++ b/src/services/quest/QuestService.java @@ -147,11 +147,7 @@ public class QuestService implements INetworkDispatch { // quest.task.ground.go_to_location case "go_to_location": - Point3D location = new Point3D(task.getLocationX(), task.getLocationY(), task.getLocationZ()); - WaypointObject wpGoTo = createWaypoint(task.getWaypointName(), location, task.getPlanet()); - player.getWaypoints().put(wpGoTo.getObjectID(), wpGoTo); - - quest.setWaypointId(wpGoTo.getObjectID()); + // Waypoint created below now break; // quest.task.ground.comm_player @@ -172,10 +168,7 @@ public class QuestService implements INetworkDispatch { ObjControllerMessage itemCount = new ObjControllerMessage(11, new QuestTaskCounterMessage(quester.getObjectID(), quest, "@quest/groundquests:retrieve_item_counter")); quester.getClient().getSession().write(itemCount.serialize()); - WaypointObject wpRetrieve = createWaypoint(task.getWaypointName(), new Point3D(task.getLocationX(), task.getLocationY(), task.getLocationZ()), task.getPlanet()); - player.getWaypoints().put(wpRetrieve.getObjectID(), wpRetrieve); - - quest.setWaypointId(wpRetrieve.getObjectID()); + // Waypoint created below now break; // quest.task.ground.timer @@ -240,6 +233,13 @@ public class QuestService implements INetworkDispatch { break; } + if (task.createsWaypoint()) { + Point3D location = new Point3D(task.getLocationX(), task.getLocationY(), task.getLocationZ()); + WaypointObject wpGoTo = createWaypoint(task.getWaypointName(), location, task.getPlanet()); + player.getWaypoints().put(wpGoTo.getObjectID(), wpGoTo); + quest.setWaypointId(wpGoTo.getObjectID()); + } + if (!task.isVisible()) { completeActiveTask(quester, quest); return; @@ -628,6 +628,12 @@ public class QuestService implements INetworkDispatch { if (visitor.getObjectByColumnNameAndIndex("SIGNALS_ON_FAIL", r) != null) task.setSignalsOnFail((String) visitor.getObjectByColumnNameAndIndex("SIGNALS_ON_FAIL", r)); if (visitor.getObjectByColumnNameAndIndex("COMM_MESSAGE_TEXT", r) != null) task.setCommMessageText((String) visitor.getObjectByColumnNameAndIndex("COMM_MESSAGE_TEXT", r)); if (visitor.getObjectByColumnNameAndIndex("NPC_APPEARANCE_SERVER_TEMPLATE", r) != null) task.setNpcAppearanceTemplate(convertToSharedFile((String) visitor.getObjectByColumnNameAndIndex("NPC_APPEARANCE_SERVER_TEMPLATE", r))); + if (visitor.getObjectByColumnNameAndIndex("CREATURE_TYPE", r) != null) task.setCreatureType(convertToSharedFile((String) visitor.getObjectByColumnNameAndIndex("CREATURE_TYPE", r))); + if (visitor.getObjectByColumnNameAndIndex("COUNT", r) != null) task.setCount((int) visitor.getObjectByColumnNameAndIndex("COUNT", r)); + if (visitor.getObjectByColumnNameAndIndex("MIN_DISTANCE", r) != null) task.setMinDistance((int) visitor.getObjectByColumnNameAndIndex("MIN_DISTANCE", r)); + if (visitor.getObjectByColumnNameAndIndex("MAX_DISTANCE", r) != null) task.setMaxDistance((int) visitor.getObjectByColumnNameAndIndex("MAX_DISTANCE", r)); + if (visitor.getObjectByColumnNameAndIndex("RELATIVE_OFFSET_X", r) != null) task.setRelativeOffsetX(convertToSharedFile((String) visitor.getObjectByColumnNameAndIndex("RELATIVE_OFFSET_X", r))); + if (visitor.getObjectByColumnNameAndIndex("RELATIVE_OFFSET_Y", r) != null) task.setRelativeOffsetY(convertToSharedFile((String) visitor.getObjectByColumnNameAndIndex("RELATIVE_OFFSET_Y", r))); if (visitor.getObjectByColumnNameAndIndex("SERVER_TEMPLATE", r) != null) task.setServerTemplate(convertToSharedFile((String) visitor.getObjectByColumnNameAndIndex("SERVER_TEMPLATE", r))); if (visitor.getObjectByColumnNameAndIndex("NUM_REQUIRED", r) != null) task.setNumRequired((int) visitor.getObjectByColumnNameAndIndex("NUM_REQUIRED", r)); if (visitor.getObjectByColumnNameAndIndex("ITEM_NAME", r) != null) task.setItemName((String) visitor.getObjectByColumnNameAndIndex("ITEM_NAME", r)); diff --git a/src/services/quest/QuestTask.java b/src/services/quest/QuestTask.java index 4be8d00b..39b1f947 100644 --- a/src/services/quest/QuestTask.java +++ b/src/services/quest/QuestTask.java @@ -47,6 +47,12 @@ public class QuestTask { private String waitMarkerCellName; private String commMessageText; private String npcAppearanceTemplate; // NPC Appearance Server Template + private String creatureType; + private int count; + private int minDistance; + private int maxDistance; + private String relativeOffsetX; + private String relativeOffsetY; private String tasksOnComplete; private String serverTemplate; private String itemName; @@ -280,6 +286,54 @@ public class QuestTask { this.npcAppearanceTemplate = npcAppearanceTemplate; } + public String getCreatureType() { + return creatureType; + } + + public void setCreatureType(String creatureType) { + this.creatureType = creatureType; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } + + public int getMinDistance() { + return minDistance; + } + + public void setMinDistance(int minDistance) { + this.minDistance = minDistance; + } + + public int getMaxDistance() { + return maxDistance; + } + + public void setMaxDistance(int maxDistance) { + this.maxDistance = maxDistance; + } + + public String getRelativeOffsetX() { + return relativeOffsetX; + } + + public void setRelativeOffsetX(String relativeOffsetX) { + this.relativeOffsetX = relativeOffsetX; + } + + public String getRelativeOffsetY() { + return relativeOffsetY; + } + + public void setRelativeOffsetY(String relativeOffsetY) { + this.relativeOffsetY = relativeOffsetY; + } + public boolean isVisible() { return visible; } diff --git a/src/services/spawn/MixedSpawnArea.java b/src/services/spawn/MixedSpawnArea.java index 8a4a5d43..c7cc66f7 100644 --- a/src/services/spawn/MixedSpawnArea.java +++ b/src/services/spawn/MixedSpawnArea.java @@ -35,6 +35,7 @@ import resources.common.collidables.AbstractCollidable.ExitEvent; import resources.objects.creature.CreatureObject; import services.TerrainService; import services.SimulationService.MoveEvent; +import services.ai.AIActor; import services.ai.LairActor; import engine.resources.config.Config; import engine.resources.objects.SWGObject; @@ -213,13 +214,15 @@ public class MixedSpawnArea extends SpawnArea { } } if (this.spawnGroup instanceof LairGroupTemplate){ + object = event.object; //if(object == null || !(object instanceof CreatureObject) || object.getContainer() != null) // return; - if(object == null || !(object instanceof CreatureObject)) + if(object == null || !(object instanceof CreatureObject)){ return; + } creature = (CreatureObject) object; @@ -386,23 +389,26 @@ public class MixedSpawnArea extends SpawnArea { // LairSpawnArea class methods public void spawnLair(CreatureObject object) { - + NGECore core = NGECore.getInstance(); LairGroupTemplate lairGroup = (LairGroupTemplate)this.spawnGroup; Vector lairTemplates = lairGroup.getLairSpawnTemplates(); - if(lairGroup == null || lairTemplates.isEmpty()) + if(lairGroup == null || lairTemplates.isEmpty()){ return; + } - if((System.currentTimeMillis() - lastSpawnTime) < 10000) + if((System.currentTimeMillis() - lastSpawnTime) < 10000){ return; + } Point3D randomPosition = getRandomPosition(object.getWorldPosition(), 32.f, 200.f); - if(randomPosition == null) + if(randomPosition == null){ return; + } TerrainService terrainSvc = core.terrainService; @@ -410,29 +416,38 @@ public class MixedSpawnArea extends SpawnArea { randomPosition.y = height; for(LairActor otherLair : lairs) { - if(otherLair.getLairObject().getWorldPosition().getDistance(randomPosition) < 30) + if(otherLair.getLairObject().getWorldPosition().getDistance(randomPosition) < 30){ return; + } } - if(!terrainSvc.canBuildAtPosition(object, randomPosition.x, randomPosition.z)) + if(!terrainSvc.canBuildAtPosition(object, randomPosition.x, randomPosition.z)){ return; + } Random random = new Random(); - + LairSpawnTemplate lairSpawn = lairTemplates.get(random.nextInt(lairTemplates.size())); - + int level = -1; // If level equals -1 then the mobile template CL will be used! if (lairSpawn.getMinLevel() != -1 && lairSpawn.getMaxLevel()!=-1) level = random.nextInt((int) (lairSpawn.getMaxLevel() - lairSpawn.getMinLevel()) + 1) + lairSpawn.getMinLevel(); + AIActor actor = (AIActor) object.getAttachment("AI"); + + if (actor!=null) + level = actor.getMobileTemplate().getLevel(); - + if (level<0) + level = 10; + LairActor lairActor = core.spawnService.spawnLair(lairSpawn.getLairTemplate(), getPlanet(), randomPosition, (short) level); - if(lairActor == null) + + if(lairActor == null){ return; + } lairs.add(lairActor); lastSpawnTime = System.currentTimeMillis(); - } } diff --git a/src/services/spawn/SpawnService.java b/src/services/spawn/SpawnService.java index feeeb648..fbda0ebb 100644 --- a/src/services/spawn/SpawnService.java +++ b/src/services/spawn/SpawnService.java @@ -459,18 +459,23 @@ public class SpawnService { } public LairActor spawnLair(String lairSpawnTemplate, Planet planet, Point3D position, short level) { - + LairTemplate lairTemplate = lairTemplates.get(lairSpawnTemplate); if(lairTemplate == null) return null; + // adapt to terrain + float positionY = core.terrainService.getHeight(planet.getID(), position.x, position.z); + Point3D adaptedPosition = new Point3D(position.x, positionY, position.z); + TangibleObject lairObject = null; if (lairTemplate.getLairCRC()==null){ String lairCRC = lairTemplate.getLairCRCs().get(new Random().nextInt(lairTemplate.getLairCRCs().size())); - System.out.println("Lair CRC " + lairCRC); - lairObject = (TangibleObject) core.objectService.createObject(lairCRC, 0, planet, position, new Quaternion(1, 0, 0, 0)); + //System.out.println("Lair CRC " + lairCRC); + + lairObject = (TangibleObject) core.objectService.createObject(lairCRC, 0, planet, adaptedPosition, new Quaternion(1, 0, 0, 0)); } else { - lairObject = (TangibleObject) core.objectService.createObject(lairTemplate.getLairCRC().trim(), 0, planet, position, new Quaternion(1, 0, 0, 0)); + lairObject = (TangibleObject) core.objectService.createObject(lairTemplate.getLairCRC().trim(), 0, planet, adaptedPosition, new Quaternion(1, 0, 0, 0)); } if(lairObject == null) @@ -478,8 +483,17 @@ public class SpawnService { lairObject.setOptionsBitmask(Options.ATTACKABLE); lairObject.setPvpBitmask(PvpStatus.Attackable); - lairObject.setMaximumCondition(1000 * level); + + + + if (lairTemplate.getMobiles()!=null){ + MobileTemplate mobileTemplate = mobileTemplates.get(lairTemplate.getMobiles().get(0)); + level = mobileTemplate.getLevel(); + } + + lairObject.setMaximumCondition(1000 * level); + LairActor lairActor = new LairActor(lairObject, lairTemplate.getMobileName(), 10, level); if (lairTemplate.getMobiles()!=null)