diff --git a/scripts/commands/npcconversationselect.py b/scripts/commands/npcconversationselect.py new file mode 100644 index 00000000..01d6aa0d --- /dev/null +++ b/scripts/commands/npcconversationselect.py @@ -0,0 +1,10 @@ +import sys + +def setup(): + return + +def run(core, actor, target, commandString): + print int(commandString) + core.conversationService.handleConversationSelection(actor, int(commandString)) + return + \ No newline at end of file diff --git a/scripts/commands/npcconversationstop.py b/scripts/commands/npcconversationstop.py new file mode 100644 index 00000000..f7b6b21b --- /dev/null +++ b/scripts/commands/npcconversationstop.py @@ -0,0 +1,10 @@ +import sys + +def setup(): + return + +def run(core, actor, target, commandString): + if actor.getConversingNpc(): + core.conversationService.handleEndConversation(actor, actor.getConversingNpc()) + return + \ No newline at end of file diff --git a/scripts/conversation/respec.py b/scripts/conversation/respec.py new file mode 100644 index 00000000..f929002e --- /dev/null +++ b/scripts/conversation/respec.py @@ -0,0 +1,96 @@ +from resources.common import ConversationOption +from resources.common import OutOfBand +from resources.common import ProsePackage +from java.util import Vector +import sys + +def startConversation(core, actor, npc): + convSvc = core.conversationService + prose = ProsePackage('conversation/respecseller', 's_31') + outOfBand = OutOfBand() + outOfBand.addProsePackage(prose) + convSvc.sendConversationMessage(actor, npc, outOfBand) + prose2 = ProsePackage('conversation/respecseller', 's_32') + outOfBand2 = OutOfBand() + outOfBand2.addProsePackage(prose2) + prose3 = ProsePackage('conversation/respecseller', 's_33') + outOfBand3 = OutOfBand() + outOfBand3.addProsePackage(prose3) + option1 = ConversationOption(outOfBand2, 0) + option2 = ConversationOption(outOfBand3, 1) + options = Vector() + options.add(option1) + options.add(option2) + convSvc.sendConversationOptions(actor, npc, options, handleFirstScreen) + return + +def handleFirstScreen(core, actor, npc, selection): + + if selection == 0: + # respec + # TODO: check for prices + convSvc = core.conversationService + prose = ProsePackage('conversation/respecseller', 's_58') + outOfBand = OutOfBand() + outOfBand.addProsePackage(prose) + convSvc.sendConversationMessage(actor, npc, outOfBand) + prose2 = ProsePackage('conversation/respecseller', 's_60') + outOfBand2 = OutOfBand() + outOfBand2.addProsePackage(prose2) + prose3 = ProsePackage('conversation/respecseller', 's_64') + outOfBand3 = OutOfBand() + outOfBand3.addProsePackage(prose3) + option1 = ConversationOption(outOfBand2, 0) + option2 = ConversationOption(outOfBand3, 1) + options = Vector() + options.add(option1) + options.add(option2) + convSvc.sendConversationOptions(actor, npc, options, handleRespecScreen) + return + if selection == 1: + # expertise reset + # TODO: check for prices + convSvc = core.conversationService + prose = ProsePackage('conversation/respecseller', 's_35') + outOfBand = OutOfBand() + outOfBand.addProsePackage(prose) + convSvc.sendConversationMessage(actor, npc, outOfBand) + prose2 = ProsePackage('conversation/respecseller', 's_71') + outOfBand2 = OutOfBand() + outOfBand2.addProsePackage(prose2) + prose3 = ProsePackage('conversation/respecseller', 's_72') + outOfBand3 = OutOfBand() + outOfBand3.addProsePackage(prose3) + option1 = ConversationOption(outOfBand2, 0) + option2 = ConversationOption(outOfBand3, 1) + options = Vector() + options.add(option1) + options.add(option2) + convSvc.sendConversationOptions(actor, npc, options, handleResetScreen) + + + return + +def handleRespecScreen(core, actor, npc, selection): + + if selection == 0: + core.skillService.sendRespecWindow(actor) + + core.conversationService.handleEndConversation(actor, npc) + + return + + +def handleResetScreen(core, actor, npc, selection): + + if selection == 0: + core.skillService.resetExpertise(actor) + + core.conversationService.handleEndConversation(actor, npc) + + return + +def endConversation(core, actor, npc): + core.conversationService.sendStopConversation(actor, npc, 'conversation/respecseller', 's_38') + return + \ No newline at end of file diff --git a/scripts/object/mobile/respec_seller_f_1.py b/scripts/object/mobile/respec_seller_f_1.py index 1ff6ade9..fce43dfc 100644 --- a/scripts/object/mobile/respec_seller_f_1.py +++ b/scripts/object/mobile/respec_seller_f_1.py @@ -4,6 +4,4 @@ from resources.datatables import Options def setup(core, object): object.setAttachment('radial_filename', 'conversation') object.setAttachment('conversationFile', 'respec') - object.setOptions(Options.CONVERSABLE, True) - object.setOptions(Options.INVULNERABLE, True) return \ No newline at end of file diff --git a/scripts/radial/conversation.py b/scripts/radial/conversation.py index 0603ecb1..ee774b7d 100644 --- a/scripts/radial/conversation.py +++ b/scripts/radial/conversation.py @@ -9,6 +9,7 @@ def createRadial(core, owner, target, radials): def handleSelection(core, owner, target, option): if option == 26 and target: + print 'test' core.conversationService.handleStartConversation(owner, target) return \ No newline at end of file diff --git a/scripts/static_spawns/tatooine.py b/scripts/static_spawns/tatooine.py index 58723194..b80e0af7 100644 --- a/scripts/static_spawns/tatooine.py +++ b/scripts/static_spawns/tatooine.py @@ -9,8 +9,9 @@ def addPlanetSpawns(core, planet): #stcSvc.spawnObject('object/mobile/shared_3po_protocol_droid_red.iff', 'tatooine', long(26582), float(-14.3), float(2.0), float(47.4), float(0.70), float(0.71)) stcSvc.spawnObject('object/tangible/terminal/shared_terminal_character_builder.iff', 'tatooine', long(0), float(3525), float(4), float(-4801), float(0.70), float(0.71)) - #stcSvc.spawnObject('object/mobile/shared_respec_seller_f_1.iff', 'tatooine', long(0), float(3533.14), float(5), float(-4788.86), float(-0.3327), float(0.9288)) - + object = stcSvc.spawnObject('object/mobile/shared_respec_seller_f_1.iff', 'tatooine', long(0), float(3533.14), float(5), float(-4788.86), float(-0.3327), float(0.9288)) + object.setOptionsBitmask(264) + return diff --git a/src/protocol/swg/ObjControllerMessage.java b/src/protocol/swg/ObjControllerMessage.java index d6edf15c..a8b3d10a 100644 --- a/src/protocol/swg/ObjControllerMessage.java +++ b/src/protocol/swg/ObjControllerMessage.java @@ -63,6 +63,10 @@ public class ObjControllerMessage extends SWGMessage { public static final int IMAGE_DESIGN_START = 0x023A; public static final int IMAGE_DESIGN_CHANGE = 0x0238; public static final int IMAGE_DESIGN_END = 0x0239; + public static final int START_CONVERSATION = 0x00DD; + public static final int STOP_CONVERSATION = 0x00DE; + public static final int CONVERSATION_MESSAGE = 0x00DF; + public static final int CONVERSATION_OPTIONS = 0x00E0; public ObjControllerMessage() { diff --git a/src/protocol/swg/objectControllerObjects/NpcConversationMessage.java b/src/protocol/swg/objectControllerObjects/NpcConversationMessage.java index 8c72d535..93a05982 100644 --- a/src/protocol/swg/objectControllerObjects/NpcConversationMessage.java +++ b/src/protocol/swg/objectControllerObjects/NpcConversationMessage.java @@ -25,6 +25,7 @@ import java.nio.ByteOrder; import org.apache.mina.core.buffer.IoBuffer; +import protocol.swg.ObjControllerMessage; import resources.common.ObjControllerOpcodes; import resources.common.OutOfBand; @@ -48,11 +49,11 @@ public class NpcConversationMessage extends ObjControllerObject { IoBuffer outOfBandBuffer = outOfBand.serialize(); IoBuffer buffer = IoBuffer.allocate(16 + outOfBandBuffer.array().length).order(ByteOrder.LITTLE_ENDIAN); - buffer.putInt(ObjControllerOpcodes.NPC_CONVERSATION_MESSAGE); + buffer.putInt(ObjControllerMessage.CONVERSATION_MESSAGE); buffer.putLong(objectId); buffer.putInt(0); - buffer.put(outOfBandBuffer); - + buffer.put(outOfBandBuffer.array()); + System.out.println(buffer.getInt(16)); return buffer.flip(); } diff --git a/src/protocol/swg/objectControllerObjects/NpcConversationOptions.java b/src/protocol/swg/objectControllerObjects/NpcConversationOptions.java index 3d838c5d..b85e42e2 100644 --- a/src/protocol/swg/objectControllerObjects/NpcConversationOptions.java +++ b/src/protocol/swg/objectControllerObjects/NpcConversationOptions.java @@ -26,6 +26,7 @@ import java.util.Vector; import org.apache.mina.core.buffer.IoBuffer; +import protocol.swg.ObjControllerMessage; import resources.common.ConversationOption; import resources.common.ObjControllerOpcodes; @@ -52,7 +53,7 @@ public class NpcConversationOptions extends ObjControllerObject { public IoBuffer serialize() { IoBuffer buffer = IoBuffer.allocate(17).order(ByteOrder.LITTLE_ENDIAN); buffer.setAutoExpand(true); - buffer.putInt(ObjControllerOpcodes.NPC_CONVERSATION_OPTIONS); + buffer.putInt(ObjControllerMessage.CONVERSATION_OPTIONS); buffer.putLong(objectId); buffer.putInt(0); @@ -61,8 +62,9 @@ public class NpcConversationOptions extends ObjControllerObject { for(ConversationOption option : conversationOptions) { buffer.put(option.getOutOfBand().serialize()); } - - return IoBuffer.allocate(buffer.position()).order(ByteOrder.LITTLE_ENDIAN).put(buffer).flip(); + int size = buffer.position(); + buffer.flip(); + return IoBuffer.allocate(size).order(ByteOrder.LITTLE_ENDIAN).put(buffer.array(), 0, size).flip(); } } diff --git a/src/protocol/swg/objectControllerObjects/SetProfessionTemplate.java b/src/protocol/swg/objectControllerObjects/SetProfessionTemplate.java new file mode 100644 index 00000000..775a8322 --- /dev/null +++ b/src/protocol/swg/objectControllerObjects/SetProfessionTemplate.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2013 + * + * This File is part of NGECore2. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Using NGEngine to work with NGECore2 is making a combined work based on NGEngine. + * Therefore all terms and conditions of the GNU Lesser General Public License cover the combination. + ******************************************************************************/ +package protocol.swg.objectControllerObjects; + +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; + +import org.apache.mina.core.buffer.IoBuffer; + +import engine.resources.common.Utilities; + +public class SetProfessionTemplate extends ObjControllerObject { + + private String profession; + + @Override + public void deserialize(IoBuffer data) { + data.getLong(); + data.getInt(); + short size = data.getShort(); + try { + profession = new String(ByteBuffer.allocate(size).put(data.array(), data.position(), size).array(), "US-ASCII"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + data.position(data.position() + size); + } + + @Override + public IoBuffer serialize() { + // TODO Auto-generated method stub + return null; + } + + public String getProfession() { + return profession; + } + + public void setProfession(String profession) { + this.profession = profession; + } + +} diff --git a/src/protocol/swg/objectControllerObjects/StartNpcConversation.java b/src/protocol/swg/objectControllerObjects/StartNpcConversation.java index e60d19ae..d4056d90 100644 --- a/src/protocol/swg/objectControllerObjects/StartNpcConversation.java +++ b/src/protocol/swg/objectControllerObjects/StartNpcConversation.java @@ -22,7 +22,10 @@ package protocol.swg.objectControllerObjects; import java.nio.ByteOrder; + import org.apache.mina.core.buffer.IoBuffer; + +import protocol.swg.ObjControllerMessage; import resources.common.ObjControllerOpcodes; public class StartNpcConversation extends ObjControllerObject { @@ -45,7 +48,7 @@ public class StartNpcConversation extends ObjControllerObject { public IoBuffer serialize() { IoBuffer buffer = IoBuffer.allocate(31).order(ByteOrder.LITTLE_ENDIAN); - buffer.putInt(ObjControllerOpcodes.START_NPC_CONVERSATION); + buffer.putInt(ObjControllerMessage.START_CONVERSATION); buffer.putLong(objectId); buffer.putInt(0); diff --git a/src/protocol/swg/objectControllerObjects/StopNpcConversation.java b/src/protocol/swg/objectControllerObjects/StopNpcConversation.java index 1ac52dd0..469b1725 100644 --- a/src/protocol/swg/objectControllerObjects/StopNpcConversation.java +++ b/src/protocol/swg/objectControllerObjects/StopNpcConversation.java @@ -25,6 +25,7 @@ import java.nio.ByteOrder; import org.apache.mina.core.buffer.IoBuffer; +import protocol.swg.ObjControllerMessage; import resources.common.ObjControllerOpcodes; public class StopNpcConversation extends ObjControllerObject { @@ -51,7 +52,7 @@ public class StopNpcConversation extends ObjControllerObject { public IoBuffer serialize() { IoBuffer buffer = IoBuffer.allocate(40 + stfFile.length() + stfLabel.length()).order(ByteOrder.LITTLE_ENDIAN); - buffer.putInt(ObjControllerOpcodes.STOP_NPC_CONVERSATION); + buffer.putInt(ObjControllerMessage.STOP_CONVERSATION); buffer.putLong(objectId); buffer.putInt(0); diff --git a/src/resources/common/ObjControllerOpcodes.java b/src/resources/common/ObjControllerOpcodes.java index 9bfbf542..c2d117bd 100644 --- a/src/resources/common/ObjControllerOpcodes.java +++ b/src/resources/common/ObjControllerOpcodes.java @@ -41,5 +41,6 @@ public class ObjControllerOpcodes { public static final int START_NPC_CONVERSATION = 0xDD000000; public static final int STOP_NPC_CONVERSATION = 0xDE000000; public static final int NPC_CONVERSATION_OPTIONS = 0xE0000000; + public static final int SET_PROFESSION_TEMPLATE = 0x5C040000; } diff --git a/src/resources/common/OutOfBand.java b/src/resources/common/OutOfBand.java index 21a08832..63505020 100644 --- a/src/resources/common/OutOfBand.java +++ b/src/resources/common/OutOfBand.java @@ -41,9 +41,9 @@ public class OutOfBand { IoBuffer buffer = IoBuffer.allocate(50).order(ByteOrder.LITTLE_ENDIAN); buffer.setAutoExpand(true); - buffer.putInt(2); - buffer.putShort(getCount()); + buffer.putInt(4); buffer.putShort((short) 0); // unk + buffer.putShort(getCount()); for(ProsePackage prosePackage : prosePackages) { @@ -74,22 +74,24 @@ public class OutOfBand { buffer.putInt(prosePackage.getDiInteger()); buffer.putFloat(prosePackage.getDfFloat()); - buffer.put(prosePackage.getDisplayFlag()); - + //buffer.put(prosePackage.getDisplayFlag()); + buffer.put((byte) 0); + int stfLength = prosePackage.getStfFile().length() + prosePackage.getStfLabel().length() + prosePackage.getTuStfFile().length() + prosePackage.getTuStfLabel().length() + prosePackage.getTtStfFile().length() + prosePackage.getTtStfLabel().length() + prosePackage.getToStfFile().length() + prosePackage.getToStfLabel().length(); - if(stfLength % 2 == 1) { + //if(stfLength % 2 == 1) { buffer.put((byte) 0); - } + //} } setLength(buffer); - - return IoBuffer.allocate(buffer.position()).order(ByteOrder.LITTLE_ENDIAN).put(buffer).flip(); + int size = buffer.position(); + buffer.flip(); + return IoBuffer.allocate(size).order(ByteOrder.LITTLE_ENDIAN).put(buffer.array(), 0, size).flip(); } public void setLength(IoBuffer buffer) { diff --git a/src/resources/common/ProsePackage.java b/src/resources/common/ProsePackage.java index aab8d08c..4a1ef88c 100644 --- a/src/resources/common/ProsePackage.java +++ b/src/resources/common/ProsePackage.java @@ -55,12 +55,12 @@ public class ProsePackage { // TODO: Add more constructors - private ProsePackage(String stfFile, String stfLabel) { + public ProsePackage(String stfFile, String stfLabel) { this.stfFile = stfFile; this.stfLabel = stfLabel; } - private ProsePackage(String stfFile, String stfLabel, long tuObjectId, String tuStfFile, String tuStfLabel, String tuCustomString) { + public ProsePackage(String stfFile, String stfLabel, long tuObjectId, String tuStfFile, String tuStfLabel, String tuCustomString) { this.stfFile = stfFile; this.stfLabel = stfLabel; this.tuObjectId = tuObjectId; diff --git a/src/resources/objects/creature/CreatureObject.java b/src/resources/objects/creature/CreatureObject.java index b0749e89..b7478f6a 100644 --- a/src/resources/objects/creature/CreatureObject.java +++ b/src/resources/objects/creature/CreatureObject.java @@ -261,7 +261,7 @@ public class CreatureObject extends TangibleObject implements IPersistent { } public boolean hasSkill(String name) { - synchronized(objectMutex) { + /*synchronized(objectMutex) { for (String skill : skills) { if (skill.equals(name)) { return true; @@ -269,7 +269,8 @@ public class CreatureObject extends TangibleObject implements IPersistent { } return false; - } + }*/ + return skills.contains(name); } public short getSkillsUpdateCounter() { diff --git a/src/services/ConversationService.java b/src/services/ConversationService.java index dac17b45..a4f624dc 100644 --- a/src/services/ConversationService.java +++ b/src/services/ConversationService.java @@ -57,6 +57,7 @@ public class ConversationService implements INetworkDispatch { if(player.getConversingNpc() != null && player.getConversingNpc() != npc) handleEndConversation(player, player.getConversingNpc()); + player.setConversingNpc(npc); sendStartConversation(player, npc); core.scriptService.callScript("scripts/conversation/", (String) npc.getAttachment("conversationFile"), "startConversation", core, player, npc); } @@ -65,16 +66,19 @@ public class ConversationService implements INetworkDispatch { TangibleObject npc = player.getConversingNpc(); - if(npc == null) + if(npc == null) { + System.out.println("npc is null"); return; + } PyObject func = conversationHandlers.get(player); - if(func == null) + if(func == null) { + System.out.println("handler func is null"); return; + } conversationHandlers.remove(player); - func.__call__(Py.java2py(core), Py.java2py(player), Py.java2py(npc), Py.java2py(selectionId)); } diff --git a/src/services/PlayerService.java b/src/services/PlayerService.java index 2d106485..f52a6a92 100644 --- a/src/services/PlayerService.java +++ b/src/services/PlayerService.java @@ -64,6 +64,7 @@ import resources.common.RGB; import resources.common.SpawnPoint; import resources.common.StringUtilities; import resources.datatables.PlayerFlags; +import resources.datatables.Professions; import resources.guild.Guild; import resources.objects.Buff; import resources.objects.building.BuildingObject; @@ -533,8 +534,8 @@ public class PlayerService implements INetworkDispatch { } player.setProfession(profession); - - String xpType = ((player.getProfession().contains("entertainer")) ? "entertainer" : ((player.getProfession().contains("trader")) ? "crafting" : "combat_general")); + + String xpType = ((profession.contains("entertainer")) ? "entertainer" : ((profession.contains("trader")) ? "crafting" : "combat_general")); int experience = player.getXp(xpType); @@ -544,7 +545,7 @@ public class PlayerService implements INetworkDispatch { for (int i = 0; i < experienceTable.getRowCount(); i++) { if (experienceTable.getObject(i, 0) != null) { if (experience >= ((Integer) experienceTable.getObject(i, 1))) { - level = (Integer) experienceTable.getObject(i, 1); + level = (Integer) experienceTable.getObject(i, 0); } } } @@ -553,6 +554,7 @@ public class PlayerService implements INetworkDispatch { } grantLevel(creature, level); + player.setProfessionIcon(Professions.get(profession)); } /* @@ -598,7 +600,7 @@ public class PlayerService implements INetworkDispatch { for (String skill : creature.getSkills()) { core.skillService.removeSkill(creature, skill); } - + String xpType = ((player.getProfession().contains("entertainer")) ? "entertainer" : ((player.getProfession().contains("trader")) ? "crafting" : "combat_general")); player.setXp(xpType, 0); diff --git a/src/services/SimulationService.java b/src/services/SimulationService.java index a7814884..5f38d4b7 100644 --- a/src/services/SimulationService.java +++ b/src/services/SimulationService.java @@ -168,6 +168,8 @@ public class SimulationService implements INetworkDispatch { core.commandService.registerCommand("eject"); core.commandService.registerGmCommand("broadcast"); core.commandService.registerGmCommand("teleporttarget"); + core.commandService.registerCommand("npcconversationselect"); + core.commandService.registerCommand("npcconversationstop"); } @@ -772,7 +774,8 @@ public class SimulationService implements INetworkDispatch { core.removeClient(session); object.setAttachment("disconnectTask", disconnectTask); - for(TangibleObject obj : object.getDefendersList()) object.removeDefender(obj); // temp fix for being stuck in combat + for(TangibleObject obj : new Vector(object.getDefendersList())) + object.removeDefender(obj); // temp fix for being stuck in combat } diff --git a/src/services/SkillService.java b/src/services/SkillService.java index 9eb13852..17461de6 100644 --- a/src/services/SkillService.java +++ b/src/services/SkillService.java @@ -22,6 +22,8 @@ package services; import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import org.apache.mina.core.buffer.IoBuffer; @@ -30,8 +32,12 @@ import org.python.core.Py; import org.python.core.PyObject; import protocol.swg.ExpertiseRequestMessage; +import protocol.swg.ObjControllerMessage; +import protocol.swg.objectControllerObjects.SetProfessionTemplate; +import protocol.swg.objectControllerObjects.UiPlayEffect; import resources.common.Console; import resources.common.FileUtilities; +import resources.common.ObjControllerOpcodes; import resources.common.Opcodes; import resources.objects.creature.CreatureObject; import resources.objects.player.PlayerObject; @@ -275,38 +281,63 @@ public class SkillService implements INetworkDispatch { @Override public void insertOpcodes(Map swgOpcodes, Map objControllerOpcodes) { - swgOpcodes.put(Opcodes.ExpertiseRequestMessage, new INetworkRemoteEvent() { + swgOpcodes.put(Opcodes.ExpertiseRequestMessage, (session, buffer) -> { - @Override - public void handlePacket(IoSession session, IoBuffer buffer) throws Exception { - - buffer = buffer.order(ByteOrder.LITTLE_ENDIAN); - buffer.position(0); - - ExpertiseRequestMessage expertise = new ExpertiseRequestMessage(); - expertise.deserialize(buffer); + buffer = buffer.order(ByteOrder.LITTLE_ENDIAN); + buffer.position(0); + + ExpertiseRequestMessage expertise = new ExpertiseRequestMessage(); + expertise.deserialize(buffer); - Client client = core.getClient(session); - if(client == null) { - System.out.println("NULL Client"); - return; - } - - if(client.getParent() == null) - return; - - CreatureObject creature = (CreatureObject) client.getParent(); - PlayerObject player = (PlayerObject) creature.getSlottedObject("ghost"); - - if(player == null) - return; - - for(String expertiseName : expertise.getExpertiseSkills()) { - if(expertiseName.startsWith("expertise_") && ((caluclateExpertisePoints(creature) - 1) >= 0) && validExpertiseSkill(player, expertiseName)) { // Prevent possible glitches/exploits - addSkill(creature, expertiseName); - } - } + Client client = core.getClient(session); + if(client == null) { + System.out.println("NULL Client"); + return; } + + if(client.getParent() == null) + return; + + CreatureObject creature = (CreatureObject) client.getParent(); + PlayerObject player = (PlayerObject) creature.getSlottedObject("ghost"); + + if(player == null) + return; + + for(String expertiseName : expertise.getExpertiseSkills()) { + if(expertiseName.startsWith("expertise_") && ((caluclateExpertisePoints(creature) - 1) >= 0) && validExpertiseSkill(player, expertiseName)) { // Prevent possible glitches/exploits + addSkill(creature, expertiseName); + } + } + + }); + + objControllerOpcodes.put(ObjControllerOpcodes.SET_PROFESSION_TEMPLATE, (session, buffer) -> { + + buffer = buffer.order(ByteOrder.LITTLE_ENDIAN); + + SetProfessionTemplate profTemplate = new SetProfessionTemplate(); + profTemplate.deserialize(buffer); + String profession = profTemplate.getProfession(); + + Client client = core.getClient(session); + if(client == null) { + System.out.println("NULL Client"); + return; + } + + if(client.getParent() == null) + return; + + CreatureObject creature = (CreatureObject) client.getParent(); + PlayerObject player = (PlayerObject) creature.getSlottedObject("ghost"); + + //System.out.println(profession); + if(player == null || player.getProfession().equals(profession) || profession == null) + return; + + core.playerService.respec(creature, profession); + }); } @@ -367,6 +398,19 @@ public class SkillService implements INetworkDispatch { return false; } + public void resetExpertise(CreatureObject creature) { + List skills = new ArrayList(creature.getSkills().get()); + skills.stream().filter(s -> s.contains("expertise")).forEach(s -> removeSkill(creature, s)); + } + + public void sendRespecWindow(CreatureObject creature) { + if(creature.getClient() == null) + return; + UiPlayEffect ui = new UiPlayEffect(creature.getObjectID(), "showMediator=ws_professiontemplateselect"); + ObjControllerMessage objController = new ObjControllerMessage(0x0B, ui); + creature.getClient().getSession().write(objController.serialize()); + } + @Override public void shutdown() { diff --git a/src/services/ai/states/AttackState.java b/src/services/ai/states/AttackState.java index dee11544..ab2323f6 100644 --- a/src/services/ai/states/AttackState.java +++ b/src/services/ai/states/AttackState.java @@ -94,12 +94,25 @@ public class AttackState extends AIState { @Override public byte recover(AIActor actor) { - if(actor.getTimeSinceLastAttack() < 2000) { + CreatureObject creature = actor.getCreature(); + float maxDistance = 0; + WeaponObject weapon = null; + if(creature.getWeaponId() != 0) { + weapon = (WeaponObject) NGECore.getInstance().objectService.getObject(creature.getWeaponId()); + if(weapon != null) + maxDistance = weapon.getMaxRange() - 1; + } else if(creature.getSlottedObject("default_weapon") != null) { + weapon = (WeaponObject) creature.getSlottedObject("default_weapon"); + if(weapon != null) + maxDistance = weapon.getMaxRange() - 1; + } + if(weapon == null) + return StateResult.FINISHED; + if(actor.getTimeSinceLastAttack() < weapon.getAttackSpeed() * 1000) { //actor.scheduleRecovery(); return StateResult.UNFINISHED; } NGECore core = NGECore.getInstance(); - CreatureObject creature = actor.getCreature(); if(creature.getPosture() == 14) return StateResult.DEAD; if(creature.getCombatFlag() == 0 || creature.getDefendersList().size() == 0 || actor.getFollowObject() == null) @@ -135,16 +148,6 @@ public class AttackState extends AIState { actor.scheduleRecovery(); return StateResult.UNFINISHED; } - float maxDistance = 0; - if(creature.getWeaponId() != 0) { - WeaponObject weapon = (WeaponObject) NGECore.getInstance().objectService.getObject(creature.getWeaponId()); - if(weapon != null) - maxDistance = weapon.getMaxRange() - 1; - } else if(creature.getSlottedObject("default_weapon") != null) { - WeaponObject weapon = (WeaponObject) creature.getSlottedObject("default_weapon"); - if(weapon != null) - maxDistance = weapon.getMaxRange() - 1; - } if(target.getWorldPosition().getDistance2D(creature.getWorldPosition()) > maxDistance) { actor.scheduleRecovery(); return StateResult.UNFINISHED;