diff --git a/odb/guild/placeholder.txt b/odb/guild/placeholder.txt new file mode 100644 index 00000000..e69de29b diff --git a/scripts/demo.py b/scripts/demo.py index b2b49987..52c71f28 100644 --- a/scripts/demo.py +++ b/scripts/demo.py @@ -12,12 +12,6 @@ def CreateStartingCharacter(core, object): testObject.setMaxDamage(1150) testObject.setElementalDamage(50) testObject.setIntAttribute('cat_wpn_damage.weapon_dps', testObject.getDamagePerSecond()) - object.addSkillMod('constitution_modified' , 350) - object.addSkillMod('strength_modified' , 350) - object.addSkillMod('precision_modified' , 350) - object.addSkillMod('luck_modified' , 350) - object.addSkillMod('agility_modified' , 350) - object.addSkillMod('stamina_modified' , 350) object.addSkillMod('kinetic' , 10000) object.addSkillMod('energy' , 10000) object.addSkillMod('heat' , 6000) diff --git a/scripts/roadmap/bothan.py b/scripts/roadmap/bothan.py new file mode 100644 index 00000000..ffa89ff7 --- /dev/null +++ b/scripts/roadmap/bothan.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 60 + +def getPrecision(): + return 65 + +def getStrength(): + return 0 + +def getConstitution(): + return 25 + +def getStamina(): + return 0 + +def getAgility(): + return 50 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/bounty_hunter_1a.py b/scripts/roadmap/bounty_hunter_1a.py new file mode 100644 index 00000000..7bb425e3 --- /dev/null +++ b/scripts/roadmap/bounty_hunter_1a.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 20 + +def getPrecision(): + return 60 + +def getStrength(): + return 40 + +def getConstitution(): + return 80 + +def getStamina(): + return 80 + +def getAgility(): + return 80 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/commando_1a.py b/scripts/roadmap/commando_1a.py new file mode 100644 index 00000000..8d9253ae --- /dev/null +++ b/scripts/roadmap/commando_1a.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 60 + +def getPrecision(): + return 120 + +def getStrength(): + return 120 + +def getConstitution(): + return 60 + +def getStamina(): + return 0 + +def getAgility(): + return 0 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/entertainer_1a.py b/scripts/roadmap/entertainer_1a.py new file mode 100644 index 00000000..0541cc93 --- /dev/null +++ b/scripts/roadmap/entertainer_1a.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 80 + +def getPrecision(): + return 0 + +def getStrength(): + return 0 + +def getConstitution(): + return 40 + +def getStamina(): + return 120 + +def getAgility(): + return 120 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/force_sensitive_1a.py b/scripts/roadmap/force_sensitive_1a.py new file mode 100644 index 00000000..2d9241b0 --- /dev/null +++ b/scripts/roadmap/force_sensitive_1a.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 30 + +def getPrecision(): + return 30 + +def getStrength(): + return 100 + +def getConstitution(): + return 40 + +def getStamina(): + return 40 + +def getAgility(): + return 120 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/human.py b/scripts/roadmap/human.py new file mode 100644 index 00000000..8bda8fd7 --- /dev/null +++ b/scripts/roadmap/human.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 0 + +def getPrecision(): + return 50 + +def getStrength(): + return 50 + +def getConstitution(): + return 0 + +def getStamina(): + return 50 + +def getAgility(): + return 50 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/ithorian.py b/scripts/roadmap/ithorian.py new file mode 100644 index 00000000..7d0c2b34 --- /dev/null +++ b/scripts/roadmap/ithorian.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 30 + +def getPrecision(): + return 40 + +def getStrength(): + return 60 + +def getConstitution(): + return 0 + +def getStamina(): + return 70 + +def getAgility(): + return 0 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/medic_1a.py b/scripts/roadmap/medic_1a.py new file mode 100644 index 00000000..6b84327b --- /dev/null +++ b/scripts/roadmap/medic_1a.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 80 + +def getPrecision(): + return 50 + +def getStrength(): + return 50 + +def getConstitution(): + return 60 + +def getStamina(): + return 120 + +def getAgility(): + return 0 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/moncalamari.py b/scripts/roadmap/moncalamari.py new file mode 100644 index 00000000..83d0d04c --- /dev/null +++ b/scripts/roadmap/moncalamari.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 40 + +def getPrecision(): + return 60 + +def getStrength(): + return 0 + +def getConstitution(): + return 40 + +def getStamina(): + return 60 + +def getAgility(): + return 0 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/roadmap_rewards.py b/scripts/roadmap/roadmap_rewards.py new file mode 100644 index 00000000..2f11d77e --- /dev/null +++ b/scripts/roadmap/roadmap_rewards.py @@ -0,0 +1,4 @@ +import sys + +def get(name): + return "" diff --git a/scripts/roadmap/rodian.py b/scripts/roadmap/rodian.py new file mode 100644 index 00000000..9187fd12 --- /dev/null +++ b/scripts/roadmap/rodian.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 20 + +def getPrecision(): + return 80 + +def getStrength(): + return 0 + +def getConstitution(): + return 0 + +def getStamina(): + return 20 + +def getAgility(): + return 80 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/smuggler_1a.py b/scripts/roadmap/smuggler_1a.py new file mode 100644 index 00000000..8084fcd2 --- /dev/null +++ b/scripts/roadmap/smuggler_1a.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 120 + +def getPrecision(): + return 20 + +def getStrength(): + return 20 + +def getConstitution(): + return 70 + +def getStamina(): + return 30 + +def getAgility(): + return 100 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/spy_1a.py b/scripts/roadmap/spy_1a.py new file mode 100644 index 00000000..6fe7c37a --- /dev/null +++ b/scripts/roadmap/spy_1a.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 40 + +def getPrecision(): + return 50 + +def getStrength(): + return 50 + +def getConstitution(): + return 80 + +def getStamina(): + return 40 + +def getAgility(): + return 100 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/sullustan.py b/scripts/roadmap/sullustan.py new file mode 100644 index 00000000..c02f8dcc --- /dev/null +++ b/scripts/roadmap/sullustan.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 40 + +def getPrecision(): + return 0 + +def getStrength(): + return 40 + +def getConstitution(): + return 60 + +def getStamina(): + return 0 + +def getAgility(): + return 60 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/trader_0a.py b/scripts/roadmap/trader_0a.py new file mode 100644 index 00000000..2846dee7 --- /dev/null +++ b/scripts/roadmap/trader_0a.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 90 + +def getPrecision(): + return 140 + +def getStrength(): + return 140 + +def getConstitution(): + return 0 + +def getStamina(): + return 50 + +def getAgility(): + return 140 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/trader_0b.py b/scripts/roadmap/trader_0b.py new file mode 100644 index 00000000..2846dee7 --- /dev/null +++ b/scripts/roadmap/trader_0b.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 90 + +def getPrecision(): + return 140 + +def getStrength(): + return 140 + +def getConstitution(): + return 0 + +def getStamina(): + return 50 + +def getAgility(): + return 140 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/trader_0c.py b/scripts/roadmap/trader_0c.py new file mode 100644 index 00000000..2846dee7 --- /dev/null +++ b/scripts/roadmap/trader_0c.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 90 + +def getPrecision(): + return 140 + +def getStrength(): + return 140 + +def getConstitution(): + return 0 + +def getStamina(): + return 50 + +def getAgility(): + return 140 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/trader_0d.py b/scripts/roadmap/trader_0d.py new file mode 100644 index 00000000..2846dee7 --- /dev/null +++ b/scripts/roadmap/trader_0d.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 90 + +def getPrecision(): + return 140 + +def getStrength(): + return 140 + +def getConstitution(): + return 0 + +def getStamina(): + return 50 + +def getAgility(): + return 140 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/trandoshan.py b/scripts/roadmap/trandoshan.py new file mode 100644 index 00000000..6bc9697e --- /dev/null +++ b/scripts/roadmap/trandoshan.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 0 + +def getPrecision(): + return 0 + +def getStrength(): + return 50 + +def getConstitution(): + return 65 + +def getStamina(): + return 65 + +def getAgility(): + return 20 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/twilek.py b/scripts/roadmap/twilek.py new file mode 100644 index 00000000..41903237 --- /dev/null +++ b/scripts/roadmap/twilek.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 40 + +def getPrecision(): + return 40 + +def getStrength(): + return 0 + +def getConstitution(): + return 0 + +def getStamina(): + return 60 + +def getAgility(): + return 60 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/wookiee.py b/scripts/roadmap/wookiee.py new file mode 100644 index 00000000..3fe24070 --- /dev/null +++ b/scripts/roadmap/wookiee.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 0 + +def getPrecision(): + return 10 + +def getStrength(): + return 85 + +def getConstitution(): + return 85 + +def getStamina(): + return 40 + +def getAgility(): + return 0 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/zabrak.py b/scripts/roadmap/zabrak.py new file mode 100644 index 00000000..6e8226de --- /dev/null +++ b/scripts/roadmap/zabrak.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 0 + +def getPrecision(): + return 50 + +def getStrength(): + return 50 + +def getConstitution(): + return 50 + +def getStamina(): + return 0 + +def getAgility(): + return 50 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/skillMods/agility.py b/scripts/skillMods/agility.py new file mode 100644 index 00000000..80b31400 --- /dev/null +++ b/scripts/skillMods/agility.py @@ -0,0 +1,16 @@ +import sys + +def add(core, actor, name, base): + actor.addSkillMod(name, base) + actor.addSkillMod('display_only_dodge', base) + actor.addSkillMod('display_only_parry', base / 2) + actor.addSkillMod('display_only_evasion', base) + return + +def deduct(core, actor, name, base): + actor.deductSkillMod(name, base) + actor.deductSkillMod('display_only_dodge', base) + actor.deductSkillMod('display_only_parry', base / 2) + actor.deductSkillMod('display_only_evasion', base) + return + \ No newline at end of file diff --git a/scripts/skillMods/constitution.py b/scripts/skillMods/constitution.py new file mode 100644 index 00000000..edf5e01c --- /dev/null +++ b/scripts/skillMods/constitution.py @@ -0,0 +1,14 @@ +import sys + +def add(core, actor, name, base): + actor.addSkillMod(name, base) + actor.setMaxHealth(actor.getMaxHealth() + base * 8) + actor.setMaxAction(actor.getMaxAction() + base * 2) + return + +def deduct(core, actor, name, base): + actor.deductSkillMod(name, base) + actor.setMaxHealth(actor.getMaxHealth() - base * 8) + actor.setMaxAction(actor.getMaxAction() - base * 2) + return + diff --git a/scripts/skillMods/luck.py b/scripts/skillMods/luck.py new file mode 100644 index 00000000..d036f779 --- /dev/null +++ b/scripts/skillMods/luck.py @@ -0,0 +1,18 @@ +import sys + +def add(core, actor, name, base): + actor.addSkillMod(name, base) + actor.addSkillMod('display_only_dodge', base / 3) + actor.addSkillMod('display_only_evasion', base / 3) + actor.addSkillMod('display_only_critical', base / 3) + actor.addSkillMod('display_only_strikethrough', base / 2) + return + +def deduct(core, actor, name, base): + actor.deductSkillMod(name, base) + actor.deductSkillMod('display_only_dodge', base / 3) + actor.deductSkillMod('display_only_evasion', base / 3) + actor.deductSkillMod('display_only_critical', base / 3) + actor.deductSkillMod('display_only_strikethrough', base / 2) + return + \ No newline at end of file diff --git a/scripts/skillMods/precision.py b/scripts/skillMods/precision.py new file mode 100644 index 00000000..6d31b77e --- /dev/null +++ b/scripts/skillMods/precision.py @@ -0,0 +1,18 @@ +import sys + +def add(core, actor, name, base): + actor.addSkillMod(name, base) + actor.addSkillMod('display_only_block', base / 2) + actor.addSkillMod('display_only_parry', base / 2) + actor.addSkillMod('display_only_critical', base) + actor.addSkillMod('display_only_strikethrough', base / 2) + return + +def deduct(core, actor, name, base): + actor.deductSkillMod(name, base) + actor.deductSkillMod('display_only_block', base / 2) + actor.deductSkillMod('display_only_parry', base / 2) + actor.deductSkillMod('display_only_critical', base) + actor.deductSkillMod('display_only_strikethrough', base / 2) + return + \ No newline at end of file diff --git a/scripts/skillMods/stamina.py b/scripts/skillMods/stamina.py new file mode 100644 index 00000000..b58840b6 --- /dev/null +++ b/scripts/skillMods/stamina.py @@ -0,0 +1,14 @@ +import sys + +def add(core, actor, name, base): + actor.addSkillMod(name, base) + actor.setMaxHealth(actor.getMaxHealth() + base * 2) + actor.setMaxAction(actor.getMaxAction() + base * 8) + return + +def deduct(core, actor, name, base): + actor.deductSkillMod(name, base) + actor.setMaxHealth(actor.getMaxHealth() - base * 2) + actor.setMaxAction(actor.getMaxAction() - base * 8) + return + diff --git a/scripts/skillMods/strength.py b/scripts/skillMods/strength.py new file mode 100644 index 00000000..4e702217 --- /dev/null +++ b/scripts/skillMods/strength.py @@ -0,0 +1,12 @@ +import sys + +def add(core, actor, name, base): + actor.addSkillMod(name, base) + actor.addSkillMod('display_only_block', base / 2) + return + +def deduct(core, actor, name, base): + actor.deductSkillMod(name, base) + actor.deductSkillMod('display_only_block', base / 2) + return + \ No newline at end of file diff --git a/src/main/NGECore.java b/src/main/NGECore.java index 0ebb0880..e8b651a3 100644 --- a/src/main/NGECore.java +++ b/src/main/NGECore.java @@ -43,6 +43,7 @@ import services.PlayerService; import services.ScriptService; import services.SimulationService; import services.SkillModService; +import services.SkillService; import services.StaticService; import services.TerrainService; import services.chat.ChatService; @@ -119,6 +120,7 @@ public class NGECore { public BuffService buffService; public StaticService staticService; public GroupService groupService; + public SkillService skillService; public SkillModService skillModService; // Login Server @@ -172,6 +174,7 @@ public class NGECore { playerService = new PlayerService(this); buffService = new BuffService(this); groupService = new GroupService(this); + skillService = new SkillService(this); skillModService = new SkillModService(this); // Ping Server @@ -236,6 +239,8 @@ public class NGECore { tradeService = new TradeService(this); zoneDispatch.addService(tradeService); + zoneDispatch.addService(skillService); + didServerCrash = false; System.out.println("Started Server."); setGalaxyStatus(2); diff --git a/src/protocol/swg/ChatSystemMessage.java b/src/protocol/swg/ChatSystemMessage.java index 0c973ad4..e12aa1f4 100644 --- a/src/protocol/swg/ChatSystemMessage.java +++ b/src/protocol/swg/ChatSystemMessage.java @@ -25,16 +25,26 @@ import java.nio.ByteOrder; import org.apache.mina.core.buffer.IoBuffer; -public class ChatSystemMessage extends SWGMessage{ +import resources.common.Opcodes; +public class ChatSystemMessage extends SWGMessage{ + + private String stfFilename; + private String stfName; + private int stat; private String message; private byte displayType; - + public ChatSystemMessage(String message, byte displayType) { - this.message = message; this.displayType = displayType; - + } + + public ChatSystemMessage(String stfFilename, String stfName, int stat, byte displayType) { + this.stfFilename = stfFilename; + this.stfName = stfName; + this.stat = stat; + this.displayType = displayType; } public void deserialize(IoBuffer data) { @@ -42,18 +52,40 @@ public class ChatSystemMessage extends SWGMessage{ } public IoBuffer serialize() { - - IoBuffer result = IoBuffer.allocate(15 + message.length() * 2).order(ByteOrder.LITTLE_ENDIAN); - - result.putShort((short) 2); - result.putInt(0x6D2A6413); - - result.put(displayType); // 0x00 = Chat and Screen // 0x02 = Chat only - result.put(getUnicodeString(message)); - result.putInt(0); // unk - - return result.flip(); - + if (message != null) { + IoBuffer result = IoBuffer.allocate(15 + message.length() * 2).order(ByteOrder.LITTLE_ENDIAN); + result.putShort((short) 2); + result.putInt(Opcodes.ChatSystemMessage); + result.put(displayType); // 0x00 = Chat and Screen // 0x02 = Chat only + result.put(getUnicodeString(message)); + result.putInt(0); + return result.flip(); + } else { + IoBuffer result = IoBuffer.allocate(99 + stfFilename.length() + stfName.length()).order(ByteOrder.LITTLE_ENDIAN); + result.putShort((short) 4); + result.putInt(Opcodes.ChatSystemMessage); + result.put((byte) 0); //result.put((byte) displayType); // 0x00 = Chat and Screen // 0x02 = Chat only + result.putInt(0); + result.putInt(54); + result.putShort((short) 0); + result.put((byte) 1); + result.putInt(-1); + result.put(getAsciiString(stfFilename)); + result.putInt(0); + result.put(getAsciiString(stfName)); + result.putInt(0); + result.putLong(0); + result.putLong(0); + result.putLong(0); + result.putLong(0); + result.putLong(0); + result.putLong(0); + result.putLong(0); + result.putInt(stat); + result.putInt(0); + result.put((byte) 0); + return result.flip(); + } } - + } diff --git a/src/protocol/swg/ClientMfdStatusUpdateMessage.java b/src/protocol/swg/ClientMfdStatusUpdateMessage.java new file mode 100644 index 00000000..98330d77 --- /dev/null +++ b/src/protocol/swg/ClientMfdStatusUpdateMessage.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * 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; + +import java.nio.ByteOrder; + +import org.apache.mina.core.buffer.IoBuffer; + +import resources.common.Opcodes; + +public class ClientMfdStatusUpdateMessage extends SWGMessage { + + private float mfdStatus; + private String mfdSetting; + + public ClientMfdStatusUpdateMessage(float mfdStatus, String mfdSetting) { + this.mfdStatus = mfdStatus; + this.mfdSetting = mfdSetting; + } + + @Override + public IoBuffer serialize() { + IoBuffer result = IoBuffer.allocate(12 + mfdSetting.length()).order(ByteOrder.LITTLE_ENDIAN); + result.putShort((short) 3); + result.putInt(Opcodes.ClientMfdStatusUpdateMessage); + result.putFloat(mfdStatus); + result.put(getAsciiString(mfdSetting)); + return result.flip(); + } + + @Override + public void deserialize(IoBuffer data) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/protocol/swg/PlayMusicMessage.java b/src/protocol/swg/PlayMusicMessage.java new file mode 100644 index 00000000..e2346f94 --- /dev/null +++ b/src/protocol/swg/PlayMusicMessage.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; + +import java.nio.ByteOrder; + +import org.apache.mina.core.buffer.IoBuffer; + +import resources.common.Opcodes; + +public class PlayMusicMessage extends SWGMessage { + + private long targetId; + private String sndFile; + private int repetitions; + private boolean flag; + + public PlayMusicMessage(String sndFile, long targetId, int repetitions, boolean flag) { + this.targetId = targetId; + this.sndFile = sndFile; + this.repetitions = repetitions; + this.flag = flag; + } + + @Override + public IoBuffer serialize() { + IoBuffer result = IoBuffer.allocate(21 + sndFile.length()).order(ByteOrder.LITTLE_ENDIAN); + result.putShort((short) 5); + result.putInt(Opcodes.PlayMusicMessage); + result.put(getAsciiString(sndFile)); + result.putLong(targetId); + result.putInt(repetitions); + result.put((byte) ((flag) ? 1 : 0)); + return result.flip(); + } + + @Override + public void deserialize(IoBuffer data) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/protocol/swg/objectControllerObjects/ShowFlyText.java b/src/protocol/swg/objectControllerObjects/ShowFlyText.java index 083d97b2..b4f73d31 100644 --- a/src/protocol/swg/objectControllerObjects/ShowFlyText.java +++ b/src/protocol/swg/objectControllerObjects/ShowFlyText.java @@ -26,53 +26,103 @@ import java.nio.ByteOrder; import org.apache.mina.core.buffer.IoBuffer; import protocol.swg.ObjControllerMessage; +import resources.common.RGB; public class ShowFlyText extends ObjControllerObject { private long recieverId; private long objectId; + private int unknownInt1; + private short unknownShort1; + private byte unknownByte1; + private int unknownInt2; private String stfFile; private String stfString; + private short unknownShort2; private float scale; - private float color; - - public ShowFlyText(long recieverId, long objectId, String stfFile, String stfString, float scale, float color) { + private RGB color; + private int displayType; + private boolean alternativeStructure; + + public ShowFlyText(long recieverId, long objectId, String stfFile, String stfString, float scale, RGB color, int displayType) { this.recieverId = recieverId; this.objectId = objectId; this.stfFile = stfFile; this.stfString = stfString; this.scale = scale; this.color = color; + this.displayType = displayType; + this.alternativeStructure = false; } - + + public ShowFlyText(long recieverId, long objectId, int unknownInt1, int unknownShort1, int unknownByte1, int unknownInt2, String stfFile, String stfString, int unknownShort2, float scale, RGB color, int displayType) { + this.recieverId = recieverId; + this.objectId = objectId; + this.unknownInt1 = unknownInt1; + this.unknownShort1 = (short) unknownShort1; + this.unknownByte1 = (byte) unknownByte1; + this.unknownInt2 = unknownInt2; + this.stfFile = stfFile; + this.stfString = stfString; + this.unknownShort2 = (short) unknownShort2; + this.scale = scale; + this.color = color; + this.alternativeStructure = true; + } + @Override public void deserialize(IoBuffer data) { // TODO Auto-generated method stub } - + @Override - public IoBuffer serialize() { - - IoBuffer result = IoBuffer.allocate(47 + stfFile.length() + stfString.length()).order(ByteOrder.LITTLE_ENDIAN); - result.setAutoExpand(true); - - result.putInt(ObjControllerMessage.SHOW_FLY_TEXT); - result.putLong(recieverId); - result.putInt(0); - result.putLong(objectId); - - result.put(getAsciiString(stfFile)); - result.putInt(0); - result.put(getAsciiString(stfString)); - result.putInt(0); - result.putFloat(scale); - result.putFloat(color); // color - result.putShort((short) 0); - result.put((byte) 0); - - return result.flip(); - + public IoBuffer serialize() { + if (!alternativeStructure) { + IoBuffer result = IoBuffer.allocate(47 + stfFile.length() + stfString.length()).order(ByteOrder.LITTLE_ENDIAN); + result.setAutoExpand(true); + result.putInt(ObjControllerMessage.SHOW_FLY_TEXT); + result.putLong(recieverId); + result.putInt(0); + result.putLong(objectId); + result.put(getAsciiString(stfFile)); + result.putInt(0); + result.put(getAsciiString(stfString)); + result.putInt(0); + result.putFloat(scale); + result.put(color.getBytes()); + result.putInt(displayType); + return result.flip(); + } else { + IoBuffer result = IoBuffer.allocate(124 + stfFile.length() + stfString.length()).order(ByteOrder.LITTLE_ENDIAN); + result.setAutoExpand(true); + result.putInt(ObjControllerMessage.SHOW_FLY_TEXT); + result.putLong(recieverId); + result.putInt(0); + result.putLong(objectId); + result.putLong(0); + result.putInt(unknownInt1); + result.putShort(unknownShort1); + result.put(unknownByte1); + result.putInt(unknownInt2); + result.put(getAsciiString(stfFile)); + result.putInt(0); + result.put(getAsciiString(stfString)); + result.putLong(0); + result.putLong(0); + result.putLong(0); + result.putLong(0); + result.putLong(0); + result.putLong(0); + result.putLong(0); + result.putInt(0); + result.putShort((short) unknownShort2); + result.putLong(0); + result.putFloat(scale); + result.put(color.getBytes()); + result.putInt(displayType); + return result.flip(); + } } } diff --git a/src/protocol/swg/objectControllerObjects/StartTask.java b/src/protocol/swg/objectControllerObjects/StartTask.java index f59ed3d7..c9946e73 100644 --- a/src/protocol/swg/objectControllerObjects/StartTask.java +++ b/src/protocol/swg/objectControllerObjects/StartTask.java @@ -25,8 +25,6 @@ import java.nio.ByteOrder; import org.apache.mina.core.buffer.IoBuffer; -import engine.resources.common.CRC; - import protocol.swg.ObjControllerMessage; public class StartTask extends ObjControllerObject { diff --git a/src/resources/common/Opcodes.java b/src/resources/common/Opcodes.java index 9b66fa41..3a99b664 100644 --- a/src/resources/common/Opcodes.java +++ b/src/resources/common/Opcodes.java @@ -29,6 +29,7 @@ public class Opcodes { public static int ChatInstantMessageToCharacter = 0x84BB21F7; public static int ChatPersistentMessageToServer = 0x25A29FA6; public static int ChatRequestPersistentMessage = 0x07E3559F; + public static int ChatSystemMessage = CRC.StringtoCRC("ChatSystemMessage"); public static int ClientOpenContainerMessage = 0x2D2D6EE1; public static int CmdSceneReady = 0x43FD1C22; public static int ConnectPlayerMessage = 0x2E365218; @@ -51,5 +52,7 @@ public class Opcodes { public static int GcwRegionsRsp = CRC.StringtoCRC("GcwRegionsRsp"); public static int GcwGroupsRsp = CRC.StringtoCRC("GcwGroupsRsp"); public static int ExpertiseRequestMessage = 0xC19085D5; + public static int ClientMfdStatusUpdateMessage = CRC.StringtoCRC("ClientMdfStatusUpdateMessage"); + public static int PlayMusicMessage = CRC.StringtoCRC("PlayMusicMessage"); } diff --git a/src/resources/common/RGB.java b/src/resources/common/RGB.java new file mode 100644 index 00000000..d5d62dde --- /dev/null +++ b/src/resources/common/RGB.java @@ -0,0 +1,37 @@ +package resources.common; + +import resources.objects.ListObject; + +public class RGB extends ListObject { + + private byte red, green, blue; + + public RGB(byte red, byte green, byte blue) { + this.red = red; + this.green = green; + this.blue = blue; + } + + public RGB(int red, int green, int blue) { + this.red = (byte) red; + this.green = (byte) green; + this.blue = (byte) blue; + } + + public byte getRed() { + return red; + } + + public byte getGreen() { + return green; + } + + public byte getBlue() { + return blue; + } + + public byte[] getBytes() { + return new byte[] { red, green, blue }; + } + +} diff --git a/src/resources/objects/creature/CreatureMessageBuilder.java b/src/resources/objects/creature/CreatureMessageBuilder.java index aba6bf2c..f8a6470c 100644 --- a/src/resources/objects/creature/CreatureMessageBuilder.java +++ b/src/resources/objects/creature/CreatureMessageBuilder.java @@ -57,7 +57,13 @@ public class CreatureMessageBuilder extends ObjectMessageBuilder { buffer.putInt(creature.getBankCredits()); buffer.putInt(creature.getCashCredits()); - buffer.putInt(0); // Base HAM List most likely unused in NGE + buffer.putInt(6); // Base HAM List - so leveling knows the base HAM, before equipment etc + buffer.putInt(6); + buffer.putInt(creature.getHealth()); + buffer.putInt(0); + buffer.putInt(creature.getAction()); + buffer.putInt(0); + buffer.putInt(0x2C01); buffer.putInt(0); if(creature.getSkills().isEmpty()) { @@ -225,7 +231,7 @@ public class CreatureMessageBuilder extends ObjectMessageBuilder { buffer.putShort(creature.getLevel()); //buffer.putShort((short) 90); - buffer.putInt(0xD007); // unk + buffer.putInt(creature.getGrantedHealth()); // From player_level.iff. Ranges from 0-2000 as you level, consistent with that table. if(creature.getCurrentAnimation() == null || creature.getCurrentAnimation().length() == 0) buffer.putShort((short) 0); @@ -570,6 +576,15 @@ public class CreatureMessageBuilder extends ObjectMessageBuilder { } + public IoBuffer buildGrantedHealthDelta(int grantedHealth) { + IoBuffer buffer = bufferPool.allocate(4, false).order(ByteOrder.LITTLE_ENDIAN); + buffer.putInt(grantedHealth); + int size = buffer.position(); + buffer.flip(); + buffer = createDelta("CREO", (byte) 6, (short) 1, (short) 9, buffer, size + 4); + return buffer; + } + public IoBuffer buildLevelDelta(short level) { IoBuffer buffer = bufferPool.allocate(2, false).order(ByteOrder.LITTLE_ENDIAN); diff --git a/src/resources/objects/creature/CreatureObject.java b/src/resources/objects/creature/CreatureObject.java index 48663806..0d953575 100644 --- a/src/resources/objects/creature/CreatureObject.java +++ b/src/resources/objects/creature/CreatureObject.java @@ -30,14 +30,11 @@ import org.apache.mina.core.buffer.IoBuffer; import protocol.swg.ChatSystemMessage; import protocol.swg.ObjControllerMessage; -import protocol.swg.PlayClientEffectObjectMessage; -import protocol.swg.StopClientEffectObjectByLabel; +import protocol.swg.PlayMusicMessage; import protocol.swg.UpdatePVPStatusMessage; import protocol.swg.UpdatePostureMessage; import protocol.swg.objectControllerObjects.Posture; - - import com.sleepycat.je.Environment; import com.sleepycat.je.Transaction; import com.sleepycat.persist.model.Entity; @@ -104,7 +101,8 @@ public class CreatureObject extends TangibleObject implements IPersistent { // CREO6 private byte combatFlag = 0; - private short level = 90; + private short level = 1; + private int grantedHealth = 0; private String currentAnimation; private String moodAnimation; private long weaponId = 0; @@ -117,12 +115,12 @@ public class CreatureObject extends TangibleObject implements IPersistent { private byte moodId = 0; private int performanceCounter = 0; private int performanceId = 0; - private int health = 20000; - private int action = 12500; + private int health = 1000; + private int action = 300; @NotPersistent private int HAMListCounter = 0; - private int maxHealth = 20000; - private int maxAction = 12500; + private int maxHealth = 1000; + private int maxAction = 300; @NotPersistent private int maxHAMListCounter = 0; @@ -202,6 +200,18 @@ public class CreatureObject extends TangibleObject implements IPersistent { return skills; } + public boolean hasSkill(String name) { + synchronized(objectMutex) { + for (String skill : skills) { + if (skill.equals(name)) { + return true; + } + } + + return false; + } + } + public short getSkillsUpdateCounter() { synchronized(objectMutex) { return (short) skillsUpdateCounter; @@ -394,11 +404,16 @@ public class CreatureObject extends TangibleObject implements IPersistent { return skillMod; } } + return null; } + public int getSkillModBase(String name) { + SkillMod skillMod = getSkillMod(name); + return ((skillMod == null) ? 0 : skillMod.getBase()); + } + public void addSkillMod(String name, int base) { - if(getSkillMod(name) == null) { SkillMod skillMod = new SkillMod(); skillMod.setBase(base); @@ -579,6 +594,16 @@ public class CreatureObject extends TangibleObject implements IPersistent { public SWGList getAbilities() { return abilities; } + + public boolean hasAbility(String name) { + for (String ability : abilities) { + if (ability.equals(name)) { + return true; + } + } + + return false; + } public int getAbilitiesUpdateCounter() { synchronized(objectMutex) { @@ -657,6 +682,20 @@ public class CreatureObject extends TangibleObject implements IPersistent { notifyObservers(levelDelta, true); } + + public int getGrantedHealth() { + synchronized(objectMutex) { + return grantedHealth; + } + } + + public void setGrantedHealth(int grantedHealth) { + synchronized(objectMutex) { + this.grantedHealth = grantedHealth; + } + + notifyObservers(messageBuilder.buildGrantedHealthDelta(grantedHealth), true); + } public String getCurrentAnimation() { synchronized(objectMutex) { @@ -912,6 +951,15 @@ public class CreatureObject extends TangibleObject implements IPersistent { } } + + public void sendSystemMessage(String stfFilename, String stfName, int stat, int displayType) { + + if(getClient() != null && getClient().getSession() != null) { + ChatSystemMessage systemMsg = new ChatSystemMessage(stfFilename, stfName, stat, (byte) displayType); + getClient().getSession().write(systemMsg.serialize()); + } + + } public int getHealth() { synchronized(objectMutex) { @@ -1099,14 +1147,6 @@ public class CreatureObject extends TangibleObject implements IPersistent { } } - public void playEffectObject(String effectFile, String commandString) { - notifyObservers(new PlayClientEffectObjectMessage(effectFile, getObjectID(), commandString), true); - } - - public void stopEffectObject(String commandString) { - notifyObservers(new StopClientEffectObjectByLabel(getObjectID(), commandString), true); - } - public SWGList getDotList() { return dotList; } @@ -1162,4 +1202,25 @@ public class CreatureObject extends TangibleObject implements IPersistent { if(incapTask != null) incapTask.cancel(true); } + + public void playMusic(String sndFile) { + playMusic(sndFile, 0, 1, false); + } + + public void playMusic(String sndFile, long targetId) { + playMusic(sndFile, targetId, 1, false); + } + + public void playMusic(String sndFile, int repetitions) { + playMusic(sndFile, 0, repetitions, false); + } + + public void playMusic(String sndFile, long targetId, int repetitions) { + playMusic(sndFile, targetId, repetitions, false); + } + + public void playMusic(String sndFile, long targetId, int repetitions, boolean flag) { + getClient().getSession().write(new PlayMusicMessage(sndFile, targetId, 1, false)); + } + } diff --git a/src/resources/objects/group/GroupObject.java b/src/resources/objects/group/GroupObject.java index 168897bd..e87a0950 100644 --- a/src/resources/objects/group/GroupObject.java +++ b/src/resources/objects/group/GroupObject.java @@ -23,9 +23,6 @@ package resources.objects.group; import java.util.Vector; -import org.apache.mina.core.buffer.IoBuffer; - -import resources.objects.SWGList; import engine.clients.Client; import engine.resources.objects.SWGObject; import engine.resources.scene.Point3D; diff --git a/src/resources/objects/player/PlayerMessageBuilder.java b/src/resources/objects/player/PlayerMessageBuilder.java index d3775ea2..cb480a88 100644 --- a/src/resources/objects/player/PlayerMessageBuilder.java +++ b/src/resources/objects/player/PlayerMessageBuilder.java @@ -26,6 +26,8 @@ import java.util.Map.Entry; import org.apache.mina.core.buffer.IoBuffer; +import engine.resources.common.CRC; + import resources.objects.ObjectMessageBuilder; import resources.objects.waypoint.WaypointObject; @@ -375,6 +377,30 @@ public class PlayerMessageBuilder extends ObjectMessageBuilder { } + public IoBuffer buildXPListDelta(String type, int amount, boolean alreadyExists) { + PlayerObject player = (PlayerObject) object; + player.setXpListUpdateCounter(player.getXpListUpdateCounter() + 1); + + // Some problem with createDelta() + IoBuffer result = bufferPool.allocate(42 + type.length(), false).order(ByteOrder.LITTLE_ENDIAN); + result.putShort((short) 5); + result.putInt(CRC.StringtoCRC("BaselinesMessage")); + result.putLong(object.getContainer().getObjectID()); + result.put("YALP".getBytes()); + result.put((byte) 8); + result.putInt(19 + type.length()); + result.putShort((short) 1); + result.putShort((short) 0); + result.putInt(1); + result.putInt(player.getXpListUpdateCounter()); + result.put((byte) ((alreadyExists) ? 2 : 0)); + result.putShort((short) type.length()); + result.put(type.getBytes()); + result.putInt(amount); + + return result.flip(); + } + public IoBuffer buildWaypointAddDelta(WaypointObject waypoint) { PlayerObject player = (PlayerObject) object; diff --git a/src/resources/objects/player/PlayerObject.java b/src/resources/objects/player/PlayerObject.java index 75ee468e..4995dfb0 100644 --- a/src/resources/objects/player/PlayerObject.java +++ b/src/resources/objects/player/PlayerObject.java @@ -201,7 +201,39 @@ public class PlayerObject extends SWGObject { public Map getXpList() { return xpList; } - + + public int getXp(String type) { + synchronized(objectMutex) { + return ((!xpList.containsKey(type)) ? 0 : xpList.get(type)); + } + } + + // Temporary + public void setXp(String type, int amount) { + boolean xpExists; + + synchronized(objectMutex) { + xpExists = xpList.containsKey(type); + xpList.put(type, amount); + } + + if (getContainer() != null && getContainer().getClient() != null && getContainer().getClient().getSession() != null) { + getContainer().getClient().getSession().write(messageBuilder.buildXPListDelta(type, amount, xpExists)); + } + } + + public int getXpListUpdateCounter() { + synchronized(objectMutex) { + return xpListUpdateCounter; + } + } + + public void setXpListUpdateCounter(int xpListUpdateCounter) { + synchronized(objectMutex) { + this.xpListUpdateCounter = xpListUpdateCounter; + } + } + public List getWaypoints() { return waypoints; } diff --git a/src/resources/objects/staticobject/StaticMessageBuilder.java b/src/resources/objects/staticobject/StaticMessageBuilder.java index be3afa20..696954f3 100644 --- a/src/resources/objects/staticobject/StaticMessageBuilder.java +++ b/src/resources/objects/staticobject/StaticMessageBuilder.java @@ -26,7 +26,6 @@ import java.nio.ByteOrder; import org.apache.mina.core.buffer.IoBuffer; import resources.objects.ObjectMessageBuilder; -import resources.objects.tangible.TangibleObject; public class StaticMessageBuilder extends ObjectMessageBuilder { diff --git a/src/resources/objects/tangible/TangibleObject.java b/src/resources/objects/tangible/TangibleObject.java index 157ef125..1c6eb9f7 100644 --- a/src/resources/objects/tangible/TangibleObject.java +++ b/src/resources/objects/tangible/TangibleObject.java @@ -23,8 +23,15 @@ package resources.objects.tangible; import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.Vector; +import protocol.swg.ObjControllerMessage; +import protocol.swg.PlayClientEffectObjectMessage; +import protocol.swg.StopClientEffectObjectByLabel; +import protocol.swg.objectControllerObjects.ShowFlyText; + +import resources.common.RGB; import resources.objects.creature.CreatureObject; @@ -221,8 +228,39 @@ public class TangibleObject extends SWGObject { return getPvPBitmask() == 1 || getPvPBitmask() == 2; } - - + + public void showFlyText(String stfFile, String stfString, float scale, RGB color, int displayType) { + Set observers = getObservers(); + + if (getClient() != null) { + getClient().getSession().write((new ObjControllerMessage(0x0000000B, new ShowFlyText(getObjectID(), getObjectID(), stfFile, stfString, scale, color, displayType))).serialize()); + } + + for (Client client : observers) { + client.getSession().write((new ObjControllerMessage(0x0000000B, new ShowFlyText(client.getParent().getObjectID(), getObjectID(), stfFile, stfString, scale, color, displayType))).serialize()); + } + } + + public void showFlyText(String stfFile, String stfString, int xp, float scale, RGB color, int displayType) { + Set observers = getObservers(); + + if (getClient() != null) { + getClient().getSession().write((new ObjControllerMessage(0x0000000B, new ShowFlyText(getObjectID(), getObjectID(), 56, 1, 1, -1, stfFile, stfString, xp, scale, color, displayType))).serialize()); + } + + for (Client client : observers) { + client.getSession().write((new ObjControllerMessage(0x0000000B, new ShowFlyText(client.getParent().getObjectID(), getObjectID(), 56, 1, 1, -1, stfFile, stfString, xp, scale, color, displayType))).serialize()); + } + } + + public void playEffectObject(String effectFile, String commandString) { + notifyObservers(new PlayClientEffectObjectMessage(effectFile, getObjectID(), commandString), true); + } + + public void stopEffectObject(String commandString) { + notifyObservers(new StopClientEffectObjectByLabel(getObjectID(), commandString), true); + } + @Override public void sendBaselines(Client destination) { diff --git a/src/services/BuffService.java b/src/services/BuffService.java index 87e5d77b..8ba2894f 100644 --- a/src/services/BuffService.java +++ b/src/services/BuffService.java @@ -36,7 +36,6 @@ import resources.objects.player.PlayerObject; import main.NGECore; -import engine.resources.common.CRC; import engine.resources.service.INetworkDispatch; import engine.resources.service.INetworkRemoteEvent; diff --git a/src/services/CharacterService.java b/src/services/CharacterService.java index 362446ba..953e2dce 100644 --- a/src/services/CharacterService.java +++ b/src/services/CharacterService.java @@ -45,6 +45,7 @@ import engine.resources.service.INetworkRemoteEvent; import resources.common.*; import protocol.swg.ClientCreateCharacter; +import protocol.swg.ClientMfdStatusUpdateMessage; import protocol.swg.ClientRandomNameRequest; import protocol.swg.ClientRandomNameResponse; import protocol.swg.ClientVerifyAndLockNameRequest; @@ -218,6 +219,18 @@ public class CharacterService implements INetworkDispatch { object.setBankCredits(1000); //object.setPosition(new Point3D(0, 0, 0)); object.setOrientation(new Quaternion(1, 0, 0, 0)); + float luck = (((((float) (core.scriptService.getMethod("scripts/roadmap/", clientCreateCharacter.getProfession(), "getLuck").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", object.getStfName(), "getLuck").__call__().asInt())) / ((float) 90)) * ((float) object.getLevel())) - ((float) object.getSkillModBase("luck"))); + float precision = (((((float) (core.scriptService.getMethod("scripts/roadmap/", clientCreateCharacter.getProfession(), "getPrecision").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", object.getStfName(), "getPrecision").__call__().asInt())) / ((float) 90)) * ((float) object.getLevel())) - ((float) object.getSkillModBase("precision"))); + float strength = (((((float) (core.scriptService.getMethod("scripts/roadmap/", clientCreateCharacter.getProfession(), "getStrength").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", object.getStfName(), "getStrength").__call__().asInt())) / ((float) 90)) * ((float) object.getLevel())) - ((float) object.getSkillModBase("strength"))); + float constitution = (((((float) (core.scriptService.getMethod("scripts/roadmap/", clientCreateCharacter.getProfession(), "getConstitution").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", object.getStfName(), "getConstitution").__call__().asInt())) / ((float) 90)) * ((float) object.getLevel())) - ((float) object.getSkillModBase("constitution"))); + float stamina = (((((float) (core.scriptService.getMethod("scripts/roadmap/", clientCreateCharacter.getProfession(), "getStamina").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", object.getStfName(), "getStamina").__call__().asInt())) / ((float) 90)) * ((float) object.getLevel())) - ((float) object.getSkillModBase("stamina"))); + float agility = (((((float) (core.scriptService.getMethod("scripts/roadmap/", clientCreateCharacter.getProfession(), "getAgility").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", object.getStfName(), "getAgility").__call__().asInt())) / ((float) 90)) * ((float) object.getLevel())) - ((float) object.getSkillModBase("agility"))); + if (luck >= 1) core.skillModService.addSkillMod(object, "luck", (int) luck); + if (precision >= 1) core.skillModService.addSkillMod(object, "precision", (int) precision); + if (strength >= 1) core.skillModService.addSkillMod(object, "strength", (int) strength); + if (constitution >= 1) core.skillModService.addSkillMod(object, "constitution", (int) constitution); + if (stamina >= 1) core.skillModService.addSkillMod(object, "stamina", (int) stamina); + if (agility >= 1) core.skillModService.addSkillMod(object, "agility", (int) agility); object.createTransaction(core.getCreatureODB().getEnvironment()); PlayerObject player = (PlayerObject) core.objectService.createObject("object/player/shared_player.iff", object.getPlanet()); @@ -266,7 +279,7 @@ public class CharacterService implements INetworkDispatch { core.scriptService.callScript("scripts/", "starterclothing", "CreateStarterClothing", core, object, clientCreateCharacter.getStarterProfession(), clientCreateCharacter.getRaceTemplate()); core.scriptService.callScript("scripts/", "CreateStartingCharacter", "demo", core, object); - + core.getCreatureODB().put(object, Long.class, CreatureObject.class, object.getTransaction()); // might not need to commit transaction but better safe than sorry object.getTransaction().commitSync(); @@ -288,7 +301,7 @@ public class CharacterService implements INetworkDispatch { session.write(core.loginService.getLoginClusterStatus().serialize()); session.write(success.serialize()); - + session.write((new ClientMfdStatusUpdateMessage((float) 2, "/GroundHUD.MFDStatus.vsp.role.targetLevel")).serialize()); } }); diff --git a/src/services/PlayerService.java b/src/services/PlayerService.java index 6f2d3beb..8e97f5de 100644 --- a/src/services/PlayerService.java +++ b/src/services/PlayerService.java @@ -36,10 +36,13 @@ import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.session.IoSession; import protocol.swg.ClientIdMsg; +import protocol.swg.ClientMfdStatusUpdateMessage; import protocol.swg.ExpertiseRequestMessage; import protocol.swg.ServerTimeMessage; +import protocol.swg.objectControllerObjects.ShowFlyText; import resources.common.FileUtilities; import resources.common.Opcodes; +import resources.common.RGB; import resources.common.SpawnPoint; import resources.objects.Buff; import resources.objects.building.BuildingObject; @@ -53,7 +56,12 @@ import services.sui.SUIWindow.SUICallback; import main.NGECore; +import engine.clientdata.ClientFileManager; +import engine.clientdata.visitors.CrcStringTableVisitor; +import engine.clientdata.visitors.DatatableVisitor; import engine.clients.Client; +import engine.resources.common.CRC; +import engine.resources.objects.DraftSchematic; import engine.resources.objects.SWGObject; import engine.resources.scene.Point3D; import engine.resources.service.INetworkDispatch; @@ -65,7 +73,9 @@ public class PlayerService implements INetworkDispatch { private NGECore core; private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); - + + protected final Object objectMutex = new Object(); + public PlayerService(final NGECore core) { this.core = core; scheduler.scheduleAtFixedRate(new Runnable() { @@ -293,7 +303,189 @@ public class PlayerService implements INetworkDispatch { core.buffService.addBuffToCreature(creature, "cloning_sickness"); } - + + /* + * Gives experience. If they have enough experience, it auto-levels them up. + * + * First, it adds the experience. + * Second, it sees if they need to level up. + * Third, if they do, it adds the relevant stat/health/action increases & expertise points. + * Fourth, if their roadmap increased, it adds the relevant roadmap update, roadmap items, skillmods, abilities, and profession quests. + * ALL of this info is contained in the client files, so we don't need to bother with scripts. + */ + public void giveExperience(CreatureObject creature, int experience) { + DatatableVisitor experienceTable; + PlayerObject player = (PlayerObject) creature.getSlottedObject("ghost"); + + synchronized(objectMutex) { + try { + experienceTable = ClientFileManager.loadFile("datatables/player/player_level.iff", DatatableVisitor.class); + + // Cannot gain more than half of the XP needed for the next level in one go + // Do check + + // 1. Add the experience. + if (experience > 0) { + creature.showFlyText("base_player", "prose_flytext_xp", experience, (float) 2.5, new RGB(180, 60, 240), 1); + } + + String xpType = ((player.getProfession().contains("entertainer")) ? "entertainer" : ((player.getProfession().contains("trader")) ? "crafting" : "combat_general")); + + if (player.getXpList().containsKey(xpType)) { + experience += player.getXp(xpType); + } + + player.setXp(xpType, experience); + + // 2. See if they need to level up. + for (int i = 0; i < experienceTable.getRowCount(); i++) { + if (experienceTable.getObject(i, 0) != null) { + if (experience >= ((Integer) experienceTable.getObject(i, 1))) { + if (creature.getLevel() < (Integer) experienceTable.getObject(i, 0)) { + creature.playEffectObject("clienteffect/level_granted.cef", ""); + creature.getClient().getSession().write((new ClientMfdStatusUpdateMessage((float) ((creature.getLevel() == 90) ? 90 : (creature.getLevel() + 1)), "/GroundHUD.MFDStatus.vsp.role.targetLevel")).serialize()); + creature.setLevel(((Integer) experienceTable.getObject(i, 0)).shortValue()); + + // 3. Add the relevant health/action and expertise points. + float luck = (((((float) (core.scriptService.getMethod("scripts/roadmap/", player.getProfession(), "getLuck").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", creature.getStfName(), "getLuck").__call__().asInt())) / ((float) 90)) * ((float) creature.getLevel())) - ((float) creature.getSkillModBase("luck"))); + float precision = (((((float) (core.scriptService.getMethod("scripts/roadmap/", player.getProfession(), "getPrecision").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", creature.getStfName(), "getPrecision").__call__().asInt())) / ((float) 90)) * ((float) creature.getLevel())) - ((float) creature.getSkillModBase("precision"))); + float strength = (((((float) (core.scriptService.getMethod("scripts/roadmap/", player.getProfession(), "getStrength").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", creature.getStfName(), "getStrength").__call__().asInt())) / ((float) 90)) * ((float) creature.getLevel())) - ((float) creature.getSkillModBase("strength"))); + float constitution = (((((float) (core.scriptService.getMethod("scripts/roadmap/", player.getProfession(), "getConstitution").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", creature.getStfName(), "getConstitution").__call__().asInt())) / ((float) 90)) * ((float) creature.getLevel())) - ((float) creature.getSkillModBase("constitution"))); + float stamina = (((((float) (core.scriptService.getMethod("scripts/roadmap/", player.getProfession(), "getStamina").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", creature.getStfName(), "getStamina").__call__().asInt())) / ((float) 90)) * ((float) creature.getLevel())) - ((float) creature.getSkillModBase("stamina"))); + float agility = (((((float) (core.scriptService.getMethod("scripts/roadmap/", player.getProfession(), "getAgility").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", creature.getStfName(), "getAgility").__call__().asInt())) / ((float) 90)) * ((float) creature.getLevel())) - ((float) creature.getSkillModBase("agility"))); + float health = 100; + float action = 75; + + int healthGranted = ((Integer) experienceTable.getObject(i, 4)); + + if (luck >= 1) { + core.skillModService.addSkillMod(creature, "luck", (int) luck); + creature.sendSystemMessage("spam", "level_up_stat_gain_0", (int) luck, 0); + } + + if (precision >= 1) { + core.skillModService.addSkillMod(creature, "precision", (int) precision); + creature.sendSystemMessage("spam", "level_up_stat_gain_1", (int) precision, 0); + } + + if (strength >= 1) { + core.skillModService.addSkillMod(creature, "strength", (int) strength); + creature.sendSystemMessage("spam", "level_up_stat_gain_2", (int) strength, 0); + } + + if (constitution >= 1) { + core.skillModService.addSkillMod(creature, "constitution", (int) constitution); + creature.sendSystemMessage("spam", "level_up_stat_gain_3", (int) constitution, 0); + } + + if (stamina >= 1) { + core.skillModService.addSkillMod(creature, "stamina", (int) stamina); + creature.sendSystemMessage("spam", "level_up_stat_gain_4", (int) stamina, 0); + } + + if (agility >= 1) { + core.skillModService.addSkillMod(creature, "agility", (int) agility); + creature.sendSystemMessage("spam", "level_up_stat_gain_5", (int) agility, 0); + } + + if (health >= 1) { + creature.setMaxHealth((creature.getMaxHealth() + (int) health + (healthGranted - creature.getGrantedHealth()))); + creature.setHealth(creature.getMaxHealth()); + creature.sendSystemMessage("spam", "level_up_stat_gain_6", (((int) health) + (((int) constitution) * 8) + (((int) stamina) * 2)), 0); + } + + if (action >= 1) { + creature.setMaxAction((creature.getMaxAction() + (int) action)); + creature.setAction(creature.getMaxAction()); + creature.sendSystemMessage("spam", "level_up_stat_gain_7", (((int) action) + (((int) stamina) * 8) + (((int) constitution) * 2)), 0); + } + + creature.setGrantedHealth(((Integer) experienceTable.getObject(i, 4))); + // -> Expertise point added automatically by client + creature.showFlyText("cbt_spam", "level_up", (float) 2.5, new RGB(100, 149, 237), 0); + + // 4. Adds roadmap rewards + int level = creature.getLevel(); + + if ((level == 4 || level == 7 || level == 10) || ((level > 10) && (((creature.getLevel() - 10) % 4) == 0))) { + int skill = ((level <= 10) ? ((level - 1) / 3) : ((((level - 10) / 4)) + 3)); + String roadmapSkillName = ""; + DatatableVisitor skillTemplate, roadmap; + + try { + skillTemplate = ClientFileManager.loadFile("datatables/skill_template/skill_template.iff", DatatableVisitor.class); + + for (int s = 0; s < skillTemplate.getRowCount(); s++) { + if (skillTemplate.getObject(s, 0) != null) { + if (((String) skillTemplate.getObject(s, 0)).equals(player.getProfession())) { + String[] skillArray = ((String) skillTemplate.getObject(s, 4)).split(","); + roadmapSkillName = skillArray[skill]; + break; + } + } + } + + creature.showFlyText("cbt_spam", "skill_up", (float) 2.5, new RGB(154, 205, 50), 0); + creature.playEffectObject("clienteffect/skill_granted.cef", ""); + creature.playMusic("sound/music_acq_bountyhunter.snd"); + core.skillService.addSkill(creature, roadmapSkillName); + player.setProfessionWheelPosition(roadmapSkillName); + } catch (InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + + try { + roadmap = ClientFileManager.loadFile("datatables/roadmap/item_rewards.iff", DatatableVisitor.class); + + for (int s = 0; s < roadmap.getRowCount(); s++) { + if (roadmap.getObject(s, 0) != null) { + if (((String) roadmap.getObject(s, 1)).equals(roadmapSkillName)) { + String[] apts = ((String) roadmap.getObject(s, 2)).split(","); + String[] items = ((String) roadmap.getObject(s, 4)).split(","); + String[] wookieeItems = ((String) roadmap.getObject(s, 5)).split(","); + String[] ithorianItems = ((String) roadmap.getObject(s, 6)).split(","); + + for (int n = 0; n < items.length; n++) { + String item = items[n]; + + if (wookieeItems.length > 0 && creature.getStfName().contains("wookiee")) { + item = wookieeItems[n]; + } else if (ithorianItems.length > 0 && creature.getStfName().contains("ithorian")) { + item = ithorianItems[n]; + } + + try { + if (!item.contains("/")) { + item = core.scriptService.callScript("scripts/roadmap/", "roadmap_rewards", "get", item).asString(); + } + + if (item != null && item != "") { + creature.getSlottedObject("inventory").add(core.objectService.createObject(item, creature.getPlanet())); + } else { + //System.out.println("Can't find template: " + item); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + } + } + } + } catch (InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + } + } + } + } + } + } catch (InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + } + } + @Override public void shutdown() { // TODO Auto-generated method stub diff --git a/src/services/ScriptService.java b/src/services/ScriptService.java index beac5ff5..440a9c5e 100644 --- a/src/services/ScriptService.java +++ b/src/services/ScriptService.java @@ -38,7 +38,7 @@ public class ScriptService { this.core = core; } - public void callScript(String path, String module, String method) { + public PyObject callScript(String path, String module, String method) { /*PythonInterpreter interpreter = new PythonInterpreter(); interpreter.cleanup(); interpreter.exec("import sys\nsys.path.append('" + path + "')\nfrom " + module + " import " + method); @@ -46,10 +46,10 @@ public class ScriptService { func.__call__(Py.java2py(core));*/ PythonInterpreter python = new PythonInterpreter(); python.execfile(path + module + ".py"); - python.get(method).__call__(); + return python.get(method).__call__(); } - public void callScript(String path, String module, String method, Object arg1) { + public PyObject callScript(String path, String module, String method, Object arg1) { /*PythonInterpreter interpreter = new PythonInterpreter(); interpreter.cleanup(); interpreter.exec("import sys\nsys.path.append('" + path + "')\nfrom " + module + " import " + method); @@ -57,10 +57,10 @@ public class ScriptService { func.__call__(Py.java2py(core), Py.java2py(arg1));*/ PythonInterpreter python = new PythonInterpreter(); python.execfile(path + module + ".py"); - python.get(method).__call__(Py.java2py(arg1)); + return python.get(method).__call__(Py.java2py(arg1)); } - public void callScript(String path, String method, String module, Object arg1, Object arg2) { + public PyObject callScript(String path, String method, String module, Object arg1, Object arg2) { /*PythonInterpreter interpreter = new PythonInterpreter(); interpreter.cleanup(); interpreter.exec("import sys\nsys.path.append('" + path + "')\nfrom " + module + " import " + method); @@ -68,10 +68,10 @@ public class ScriptService { func.__call__(Py.java2py(arg1), Py.java2py(arg2));*/ PythonInterpreter python = new PythonInterpreter(); python.execfile(path + module + ".py"); - python.get(method).__call__(Py.java2py(arg1), Py.java2py(arg2)); + return python.get(method).__call__(Py.java2py(arg1), Py.java2py(arg2)); } - public void callScript(String path, String method, String module, Object arg1, Object arg2, Object arg3) { + public PyObject callScript(String path, String method, String module, Object arg1, Object arg2, Object arg3) { /*PythonInterpreter interpreter = new PythonInterpreter(); interpreter.cleanup(); interpreter.exec("import sys\nsys.path.append('" + path + "')\nfrom " + module + " import " + method); @@ -79,11 +79,11 @@ public class ScriptService { func.__call__(Py.java2py(arg1), Py.java2py(arg2), Py.java2py(arg3));*/ PythonInterpreter python = new PythonInterpreter(); python.execfile(path + module + ".py"); - python.get(method).__call__(Py.java2py(arg1), Py.java2py(arg2), Py.java2py(arg3)); + return python.get(method).__call__(Py.java2py(arg1), Py.java2py(arg2), Py.java2py(arg3)); } - public void callScript(String path, String module, String method, Object arg1, Object arg2, Object arg3, Object arg4) { + public PyObject callScript(String path, String module, String method, Object arg1, Object arg2, Object arg3, Object arg4) { /*PythonInterpreter interpreter = new PythonInterpreter(); interpreter.cleanup(); interpreter.exec("import sys\nsys.path.append('" + path + "')\nfrom " + module + " import " + method); @@ -91,7 +91,7 @@ public class ScriptService { func.__call__(Py.java2py(arg1), Py.java2py(arg2), Py.java2py(arg3), Py.java2py(arg4));*/ PythonInterpreter python = new PythonInterpreter(); python.execfile(path + module + ".py"); - python.get(method).__call__(Py.java2py(arg1), Py.java2py(arg2), Py.java2py(arg3), Py.java2py(arg4)); + return python.get(method).__call__(Py.java2py(arg1), Py.java2py(arg2), Py.java2py(arg3), Py.java2py(arg4)); } public PyObject getMethod(String path, String module, String method) { diff --git a/src/services/SimulationService.java b/src/services/SimulationService.java index 83b80a8a..8287a389 100644 --- a/src/services/SimulationService.java +++ b/src/services/SimulationService.java @@ -548,7 +548,14 @@ public class SimulationService implements INetworkDispatch { } } } - + + if (!object.hasSkill(ghost.getProfessionWheelPosition())) { + object.showFlyText("cbt_spam", "skill_up", (float) 2.5, new RGB(154, 205, 50), 0); + object.playEffectObject("clienteffect/skill_granted.cef", ""); + object.playMusic("sound/music_acq_bountyhunter.snd"); + core.skillService.addSkill(object, ghost.getProfessionWheelPosition()); + } + } public void transferToPlanet(SWGObject object, Planet planet, Point3D newPos, Quaternion newOrientation, SWGObject newParent) { diff --git a/src/services/SkillService.java b/src/services/SkillService.java new file mode 100644 index 00000000..7d3a358d --- /dev/null +++ b/src/services/SkillService.java @@ -0,0 +1,228 @@ +/******************************************************************************* + * 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 services; + +import java.util.Map; + +import resources.objects.creature.CreatureObject; +import resources.objects.player.PlayerObject; + +import main.NGECore; + +import engine.clientdata.ClientFileManager; +import engine.clientdata.visitors.DatatableVisitor; +import engine.resources.service.INetworkDispatch; +import engine.resources.service.INetworkRemoteEvent; + +public class SkillService implements INetworkDispatch { + + private NGECore core; + + public SkillService(NGECore core) { + this.core = core; + } + + public void addSkill(CreatureObject creature, String skill) { + PlayerObject player = (PlayerObject) creature.getSlottedObject("ghost"); + DatatableVisitor skillTable; + + if (player == null) { + return; + } + + if (creature.hasSkill(skill)) { + return; + } + + try { + skillTable = ClientFileManager.loadFile("datatables/skill/skills.iff", DatatableVisitor.class); + + for (int s = 0; s < skillTable.getRowCount(); s++) { + if (skillTable.getObject(s, 0) != null) { + if (((String) skillTable.getObject(s, 0)).equals(skill)) { + //String parent = ((String) skillTable.getObject(s, 1)); + //int graphType = ((Integer) skillTable.getObject(s, 2)); + boolean godOnly = ((Boolean) skillTable.getObject(s, 3)); + //boolean isTitle = ((Boolean) skillTable.getObject(s, 4)); + boolean isProfession = ((Boolean) skillTable.getObject(s, 5)); + boolean isHidden = ((Boolean) skillTable.getObject(s, 6)); + int pointsRequired = ((Integer) skillTable.getObject(s, 8)); + int skillsRequiredCount = ((Integer) skillTable.getObject(s, 9)); + String[] skillsRequired = ((String) skillTable.getObject(s, 10)).split(","); + String[] preclusionSkills = ((String) skillTable.getObject(s, 11)).split(","); + String xpType = ((String) skillTable.getObject(s, 12)); + int xpCost = ((Integer) skillTable.getObject(s, 13)); + //int xpCap = ((Integer) skillTable.getObject(s, 14)); + String[] statsRequired = ((String) skillTable.getObject(s, 17)).split(","); + String speciesRequired = (String) skillTable.getObject(s, 18); + String[] abilities = ((String) skillTable.getObject(s, 21)).split(","); + String[] skillMods = ((String) skillTable.getObject(s, 22)).split(","); + String[] schematicsGranted = ((String) skillTable.getObject(s, 23)).split(","); + String[] schematicsRevoked = ((String) skillTable.getObject(s, 24)).split(","); + + if (isProfession) { + return; + } + + if (godOnly || isHidden) { + return; + } + + if (pointsRequired > 0) { + //if (creature.getExpertisePoints() > pointsRequired) { + //creature.deductExpertisePoints(pointsRequired); + //} else { + //return; + //} + } + + if (creature.getSkills().size() < skillsRequiredCount) { + return; + } + + for (String skillName : skillsRequired) { + if (skillName != "" && !creature.hasSkill(skillName)) { + System.out.println("Skill Name: " + skillName); + return; + } + } + + for (String skillName : preclusionSkills) { + if (creature.hasSkill(skillName)) { + return; + } + } + + for (String stat : statsRequired) { + if ((stat != "") && (creature.getSkillMod(stat) == null || creature.getSkillMod(stat).getBase() < 1)) { + return; + } + } + + if (!creature.getStfName().contains(speciesRequired)) { + return; + } + + if (xpType != null || xpType != "") { + if (xpCost > 0) { + if (player.getXp(xpType) >= xpCost) { + //player.setXp(xpType, (player.getXp(xpType) - xpCost)); + } else { + //return; + } + } + } + + for (String ability : abilities) { + creature.addAbility(ability); + } + + for (String skillMod : skillMods) { + if (skillMod != "" && skillMod != null && skillMod.contains("=")) { + core.skillModService.addSkillMod(creature, skillMod.split("=")[0], new Integer(skillMod.split("=")[1])); + } + } + + for (String schematic : schematicsGranted) { + //player.getDraftSchematicList().add(new DraftSchematic()); + } + + for (String schematic : schematicsRevoked) { + //player.getDraftSchematicList().remove(new DraftSchematic()); + } + + creature.addSkill(skill); + } + } + } + } catch (InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + public void removeSkill(CreatureObject creature, String skill) { + PlayerObject player = (PlayerObject) creature.getSlottedObject("ghost"); + DatatableVisitor skillTable; + + if (creature.getClient() == null) { + return; + } + + if (!creature.hasSkill(skill)) { + return; + } + + try { + skillTable = ClientFileManager.loadFile("datatables/skills/skills.iff", DatatableVisitor.class); + + for (int s = 0; s < skillTable.getRowCount(); s++) { + if (skillTable.getObject(s, 0) != null) { + if (((String) skillTable.getObject(s, 0)).equals(skill)) { + String parent = ((String) skillTable.getObject(s, 1)); + //int graphType = ((Integer) skillTable.getObject(s, 2)); + boolean godOnly = ((Boolean) skillTable.getObject(s, 3)); + //boolean isTitle = ((Boolean) skillTable.getObject(s, 4)); + boolean isHidden = ((Boolean) skillTable.getObject(s, 6)); + int pointsRequired = ((Integer) skillTable.getObject(s, 8)); + String[] abilities = ((String) skillTable.getObject(s, 21)).split(","); + String[] skillMods = ((String) skillTable.getObject(s, 22)).split(","); + String[] schematicsGranted = ((String) skillTable.getObject(s, 23)).split(","); + String[] schematicsRevoked = ((String) skillTable.getObject(s, 24)).split(","); + + if (pointsRequired > 0) { + //creature.addExpertisePoints(pointsRequired); + } + + for (String ability : abilities) { + creature.removeAbility(ability); + } + + for (String skillMod : skillMods) { + core.skillModService.deductSkillMod(creature, skillMod.split("=")[0], new Integer(skillMod.split("=")[1])); + } + + for (String schematic : schematicsGranted) { + //player.getDraftSchematicList().remove(new DraftSchematic()); + } + + for (String schematic : schematicsRevoked) { + //player.getDraftSchematicList().add(new DraftSchematic()); + } + } + } + } + } catch (InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + @Override + public void insertOpcodes(Map arg0, Map arg1) { + + } + + @Override + public void shutdown() { + + } + +} diff --git a/src/services/combat/CombatService.java b/src/services/combat/CombatService.java index 08ac32e3..fc2bf692 100644 --- a/src/services/combat/CombatService.java +++ b/src/services/combat/CombatService.java @@ -43,7 +43,6 @@ import protocol.swg.objectControllerObjects.StartTask; import resources.common.FileUtilities; import resources.objects.Buff; import resources.objects.DamageOverTime; -import resources.objects.cell.CellObject; import resources.objects.creature.CreatureObject; import resources.objects.player.PlayerObject; import resources.objects.tangible.TangibleObject; diff --git a/src/services/command/CommandService.java b/src/services/command/CommandService.java index 0bee3a29..9b4eab2e 100644 --- a/src/services/command/CommandService.java +++ b/src/services/command/CommandService.java @@ -152,6 +152,13 @@ public class CommandService implements INetworkDispatch { public void processCombatCommand(CreatureObject attacker, SWGObject target, CombatCommand command, int actionCounter, String commandArgs) { + // Check if the person has access to this ability. + // Abilities (inc expertise ones) are added automatically as they level + // by reading the datatables. + if (!attacker.hasAbility(command.getCommandName())) { + return; + } + if(FileUtilities.doesFileExist("scripts/commands/combat/" + command.getCommandName() + ".py")) core.scriptService.callScript("scripts/commands/combat/", command.getCommandName(), "setup", core, attacker, target, command); @@ -213,7 +220,7 @@ public class CommandService implements INetworkDispatch { if(target != attacker && success && !core.simulationService.checkLineOfSight(attacker, target)) { - ShowFlyText los = new ShowFlyText(attacker.getObjectID(), attacker.getObjectID(), "combat_effects", "cant_see", (float) 1.5, (float) 429664.031250); + ShowFlyText los = new ShowFlyText(attacker.getObjectID(), attacker.getObjectID(), "combat_effects", "cant_see", (float) 1.5, new RGB(72, 209, 204), 1); ObjControllerMessage objController = new ObjControllerMessage(0x1B, los); attacker.getClient().getSession().write(objController.serialize()); success = false; diff --git a/src/services/object/ObjectTransactionManager.java b/src/services/object/ObjectTransactionManager.java index caba44ec..f4fcfc6a 100644 --- a/src/services/object/ObjectTransactionManager.java +++ b/src/services/object/ObjectTransactionManager.java @@ -23,7 +23,6 @@ package services.object; import java.util.Collection; import java.util.Iterator; -import java.util.List; import com.sleepycat.je.Transaction;