diff --git a/build/built-jar.properties b/build/built-jar.properties index f40fdfc874..d23193731c 100644 --- a/build/built-jar.properties +++ b/build/built-jar.properties @@ -1,4 +1,4 @@ -#Wed, 23 Aug 2017 17:38:01 -0300 +#Fri, 25 Aug 2017 21:04:38 -0300 C\:\\Nexon\\MapleSolaxia\\MapleSolaxiaV2= diff --git a/build/classes/client/MapleCharacter$1.class b/build/classes/client/MapleCharacter$1.class index 8a04954114..cb815d9caf 100644 Binary files a/build/classes/client/MapleCharacter$1.class and b/build/classes/client/MapleCharacter$1.class differ diff --git a/build/classes/client/MapleCharacter$10.class b/build/classes/client/MapleCharacter$10.class index b59676cd6c..f7082ba194 100644 Binary files a/build/classes/client/MapleCharacter$10.class and b/build/classes/client/MapleCharacter$10.class differ diff --git a/build/classes/client/MapleCharacter$11.class b/build/classes/client/MapleCharacter$11.class index cf86405a35..e4ee8e711f 100644 Binary files a/build/classes/client/MapleCharacter$11.class and b/build/classes/client/MapleCharacter$11.class differ diff --git a/build/classes/client/MapleCharacter$12.class b/build/classes/client/MapleCharacter$12.class index e47f162478..7e9fbb3794 100644 Binary files a/build/classes/client/MapleCharacter$12.class and b/build/classes/client/MapleCharacter$12.class differ diff --git a/build/classes/client/MapleCharacter$13.class b/build/classes/client/MapleCharacter$13.class index 5bcad92ca5..956fd12bba 100644 Binary files a/build/classes/client/MapleCharacter$13.class and b/build/classes/client/MapleCharacter$13.class differ diff --git a/build/classes/client/MapleCharacter$14.class b/build/classes/client/MapleCharacter$14.class index ee94bbe995..ad82781108 100644 Binary files a/build/classes/client/MapleCharacter$14.class and b/build/classes/client/MapleCharacter$14.class differ diff --git a/build/classes/client/MapleCharacter$15.class b/build/classes/client/MapleCharacter$15.class index 834acdfdec..7f5f81c0f0 100644 Binary files a/build/classes/client/MapleCharacter$15.class and b/build/classes/client/MapleCharacter$15.class differ diff --git a/build/classes/client/MapleCharacter$16.class b/build/classes/client/MapleCharacter$16.class index 2689fe7571..21cb4c82f1 100644 Binary files a/build/classes/client/MapleCharacter$16.class and b/build/classes/client/MapleCharacter$16.class differ diff --git a/build/classes/client/MapleCharacter$17.class b/build/classes/client/MapleCharacter$17.class index 4d569bc808..09839ca873 100644 Binary files a/build/classes/client/MapleCharacter$17.class and b/build/classes/client/MapleCharacter$17.class differ diff --git a/build/classes/client/MapleCharacter$18.class b/build/classes/client/MapleCharacter$18.class index 7cdba832b3..e52764fab7 100644 Binary files a/build/classes/client/MapleCharacter$18.class and b/build/classes/client/MapleCharacter$18.class differ diff --git a/build/classes/client/MapleCharacter$19.class b/build/classes/client/MapleCharacter$19.class index 7efe5ee4cc..7ecb6bcef2 100644 Binary files a/build/classes/client/MapleCharacter$19.class and b/build/classes/client/MapleCharacter$19.class differ diff --git a/build/classes/client/MapleCharacter$2.class b/build/classes/client/MapleCharacter$2.class index a56e5b0c1f..e99370990d 100644 Binary files a/build/classes/client/MapleCharacter$2.class and b/build/classes/client/MapleCharacter$2.class differ diff --git a/build/classes/client/MapleCharacter$20.class b/build/classes/client/MapleCharacter$20.class index 7dfb29abe7..d310e88ce9 100644 Binary files a/build/classes/client/MapleCharacter$20.class and b/build/classes/client/MapleCharacter$20.class differ diff --git a/build/classes/client/MapleCharacter$3.class b/build/classes/client/MapleCharacter$3.class index 667bdc97b2..e49457b31e 100644 Binary files a/build/classes/client/MapleCharacter$3.class and b/build/classes/client/MapleCharacter$3.class differ diff --git a/build/classes/client/MapleCharacter$4.class b/build/classes/client/MapleCharacter$4.class index fb8f243c1b..f9a70399d5 100644 Binary files a/build/classes/client/MapleCharacter$4.class and b/build/classes/client/MapleCharacter$4.class differ diff --git a/build/classes/client/MapleCharacter$5.class b/build/classes/client/MapleCharacter$5.class index 671aa574ef..3b38991e0b 100644 Binary files a/build/classes/client/MapleCharacter$5.class and b/build/classes/client/MapleCharacter$5.class differ diff --git a/build/classes/client/MapleCharacter$6.class b/build/classes/client/MapleCharacter$6.class index 0c0ce34325..2d7bc3be6f 100644 Binary files a/build/classes/client/MapleCharacter$6.class and b/build/classes/client/MapleCharacter$6.class differ diff --git a/build/classes/client/MapleCharacter$7.class b/build/classes/client/MapleCharacter$7.class index 5154e2edca..74bd24bd09 100644 Binary files a/build/classes/client/MapleCharacter$7.class and b/build/classes/client/MapleCharacter$7.class differ diff --git a/build/classes/client/MapleCharacter$8.class b/build/classes/client/MapleCharacter$8.class index bd09633639..9d6199559e 100644 Binary files a/build/classes/client/MapleCharacter$8.class and b/build/classes/client/MapleCharacter$8.class differ diff --git a/build/classes/client/MapleCharacter$9.class b/build/classes/client/MapleCharacter$9.class index b1e800c73a..64f8ea30bc 100644 Binary files a/build/classes/client/MapleCharacter$9.class and b/build/classes/client/MapleCharacter$9.class differ diff --git a/build/classes/client/MapleCharacter$CancelCooldownAction.class b/build/classes/client/MapleCharacter$CancelCooldownAction.class index 3bba687849..8d7099fe0c 100644 Binary files a/build/classes/client/MapleCharacter$CancelCooldownAction.class and b/build/classes/client/MapleCharacter$CancelCooldownAction.class differ diff --git a/build/classes/client/MapleCharacter$FameStatus.class b/build/classes/client/MapleCharacter$FameStatus.class index 0f2c458f65..254ec4376a 100644 Binary files a/build/classes/client/MapleCharacter$FameStatus.class and b/build/classes/client/MapleCharacter$FameStatus.class differ diff --git a/build/classes/client/MapleCharacter$MapleBuffStatValueHolder.class b/build/classes/client/MapleCharacter$MapleBuffStatValueHolder.class index 350cd71520..03df75415f 100644 Binary files a/build/classes/client/MapleCharacter$MapleBuffStatValueHolder.class and b/build/classes/client/MapleCharacter$MapleBuffStatValueHolder.class differ diff --git a/build/classes/client/MapleCharacter$MapleCoolDownValueHolder.class b/build/classes/client/MapleCharacter$MapleCoolDownValueHolder.class index bffdc5eeb5..32e16f0b18 100644 Binary files a/build/classes/client/MapleCharacter$MapleCoolDownValueHolder.class and b/build/classes/client/MapleCharacter$MapleCoolDownValueHolder.class differ diff --git a/build/classes/client/MapleCharacter$SkillEntry.class b/build/classes/client/MapleCharacter$SkillEntry.class index 3060f46d03..f29567dca5 100644 Binary files a/build/classes/client/MapleCharacter$SkillEntry.class and b/build/classes/client/MapleCharacter$SkillEntry.class differ diff --git a/build/classes/client/MapleCharacter.class b/build/classes/client/MapleCharacter.class index 795f923135..1e6e32cb05 100644 Binary files a/build/classes/client/MapleCharacter.class and b/build/classes/client/MapleCharacter.class differ diff --git a/build/classes/client/command/Commands$1.class b/build/classes/client/command/Commands$1.class index 4fc14fd5d0..136a5f5c02 100644 Binary files a/build/classes/client/command/Commands$1.class and b/build/classes/client/command/Commands$1.class differ diff --git a/build/classes/client/command/Commands.class b/build/classes/client/command/Commands.class index 4badeecabf..8052c50f91 100644 Binary files a/build/classes/client/command/Commands.class and b/build/classes/client/command/Commands.class differ diff --git a/build/classes/client/inventory/MaplePet.class b/build/classes/client/inventory/MaplePet.class index a620cb41d3..f12ed9aaf2 100644 Binary files a/build/classes/client/inventory/MaplePet.class and b/build/classes/client/inventory/MaplePet.class differ diff --git a/build/classes/constants/GameConstants$1.class b/build/classes/constants/GameConstants$1.class index 98b1548010..8b1f2f9423 100644 Binary files a/build/classes/constants/GameConstants$1.class and b/build/classes/constants/GameConstants$1.class differ diff --git a/build/classes/constants/GameConstants.class b/build/classes/constants/GameConstants.class index 7542b38edd..826f1a2748 100644 Binary files a/build/classes/constants/GameConstants.class and b/build/classes/constants/GameConstants.class differ diff --git a/build/classes/constants/ServerConstants.class b/build/classes/constants/ServerConstants.class index e95e0769ad..0c66bb6638 100644 Binary files a/build/classes/constants/ServerConstants.class and b/build/classes/constants/ServerConstants.class differ diff --git a/build/classes/constants/skills/Beginner.class b/build/classes/constants/skills/Beginner.class index f20cca1f6c..ed37ea3bca 100644 Binary files a/build/classes/constants/skills/Beginner.class and b/build/classes/constants/skills/Beginner.class differ diff --git a/build/classes/constants/skills/Evan.class b/build/classes/constants/skills/Evan.class index b54aa15317..2a7c9d1500 100644 Binary files a/build/classes/constants/skills/Evan.class and b/build/classes/constants/skills/Evan.class differ diff --git a/build/classes/constants/skills/Legend.class b/build/classes/constants/skills/Legend.class index 3068b47e57..c89e3e6be9 100644 Binary files a/build/classes/constants/skills/Legend.class and b/build/classes/constants/skills/Legend.class differ diff --git a/build/classes/constants/skills/Noblesse.class b/build/classes/constants/skills/Noblesse.class index 89da94ba7f..43d587f40a 100644 Binary files a/build/classes/constants/skills/Noblesse.class and b/build/classes/constants/skills/Noblesse.class differ diff --git a/build/classes/net/server/channel/handlers/CloseRangeDamageHandler.class b/build/classes/net/server/channel/handlers/CloseRangeDamageHandler.class index 65cb28fee0..c0da010cbb 100644 Binary files a/build/classes/net/server/channel/handlers/CloseRangeDamageHandler.class and b/build/classes/net/server/channel/handlers/CloseRangeDamageHandler.class differ diff --git a/build/classes/net/server/channel/handlers/MagicDamageHandler.class b/build/classes/net/server/channel/handlers/MagicDamageHandler.class index c3f897e924..3877e97ac3 100644 Binary files a/build/classes/net/server/channel/handlers/MagicDamageHandler.class and b/build/classes/net/server/channel/handlers/MagicDamageHandler.class differ diff --git a/build/classes/net/server/channel/handlers/PetCommandHandler.class b/build/classes/net/server/channel/handlers/PetCommandHandler.class index e068f98676..808392b7fd 100644 Binary files a/build/classes/net/server/channel/handlers/PetCommandHandler.class and b/build/classes/net/server/channel/handlers/PetCommandHandler.class differ diff --git a/build/classes/net/server/channel/handlers/RangedAttackHandler.class b/build/classes/net/server/channel/handlers/RangedAttackHandler.class index ea8f04528e..d7ab7779c0 100644 Binary files a/build/classes/net/server/channel/handlers/RangedAttackHandler.class and b/build/classes/net/server/channel/handlers/RangedAttackHandler.class differ diff --git a/build/classes/net/server/channel/handlers/SpawnPetHandler.class b/build/classes/net/server/channel/handlers/SpawnPetHandler.class index ce7ffa202c..18763cb400 100644 Binary files a/build/classes/net/server/channel/handlers/SpawnPetHandler.class and b/build/classes/net/server/channel/handlers/SpawnPetHandler.class differ diff --git a/build/classes/net/server/channel/handlers/SpecialMoveHandler.class b/build/classes/net/server/channel/handlers/SpecialMoveHandler.class index a1139c38b1..f8706d30df 100644 Binary files a/build/classes/net/server/channel/handlers/SpecialMoveHandler.class and b/build/classes/net/server/channel/handlers/SpecialMoveHandler.class differ diff --git a/build/classes/net/server/channel/handlers/TakeDamageHandler.class b/build/classes/net/server/channel/handlers/TakeDamageHandler.class index e592c02b39..075d9bae59 100644 Binary files a/build/classes/net/server/channel/handlers/TakeDamageHandler.class and b/build/classes/net/server/channel/handlers/TakeDamageHandler.class differ diff --git a/build/classes/scripting/AbstractPlayerInteraction.class b/build/classes/scripting/AbstractPlayerInteraction.class index 94af2a9164..ed758b4655 100644 Binary files a/build/classes/scripting/AbstractPlayerInteraction.class and b/build/classes/scripting/AbstractPlayerInteraction.class differ diff --git a/build/classes/server/MapleStatEffect$CancelEffectAction.class b/build/classes/server/MapleStatEffect$CancelEffectAction.class index 88f23b4acb..0218f09b8b 100644 Binary files a/build/classes/server/MapleStatEffect$CancelEffectAction.class and b/build/classes/server/MapleStatEffect$CancelEffectAction.class differ diff --git a/build/classes/server/MapleStatEffect.class b/build/classes/server/MapleStatEffect.class index be38693637..91f7e090ff 100644 Binary files a/build/classes/server/MapleStatEffect.class and b/build/classes/server/MapleStatEffect.class differ diff --git a/build/classes/server/life/MobSkill.class b/build/classes/server/life/MobSkill.class index c232c5fae9..7c2b69fd59 100644 Binary files a/build/classes/server/life/MobSkill.class and b/build/classes/server/life/MobSkill.class differ diff --git a/build/classes/tools/DatabaseConnection.class b/build/classes/tools/DatabaseConnection.class index 42ec1c9e25..096ce3f255 100644 Binary files a/build/classes/tools/DatabaseConnection.class and b/build/classes/tools/DatabaseConnection.class differ diff --git a/cores/HikariCP-java7-2.4.12.jar b/cores/HikariCP-java7-2.4.12.jar new file mode 100644 index 0000000000..792b690564 Binary files /dev/null and b/cores/HikariCP-java7-2.4.12.jar differ diff --git a/cores/commons-dbcp2-2.1.1.jar b/cores/commons-dbcp2-2.1.1.jar deleted file mode 100644 index 674f367638..0000000000 Binary files a/cores/commons-dbcp2-2.1.1.jar and /dev/null differ diff --git a/cores/commons-pool2-2.4.2.jar b/cores/commons-pool2-2.4.2.jar deleted file mode 100644 index fdf8b6faaf..0000000000 Binary files a/cores/commons-pool2-2.4.2.jar and /dev/null differ diff --git a/dist/MapleSolaxia.jar b/dist/MapleSolaxia.jar index 279355d04a..bfdf48261b 100644 Binary files a/dist/MapleSolaxia.jar and b/dist/MapleSolaxia.jar differ diff --git a/dist/lib/HikariCP-java7-2.4.12.jar b/dist/lib/HikariCP-java7-2.4.12.jar new file mode 100644 index 0000000000..792b690564 Binary files /dev/null and b/dist/lib/HikariCP-java7-2.4.12.jar differ diff --git a/dist/lib/commons-dbcp2-2.1.1.jar b/dist/lib/commons-dbcp2-2.1.1.jar deleted file mode 100644 index 674f367638..0000000000 Binary files a/dist/lib/commons-dbcp2-2.1.1.jar and /dev/null differ diff --git a/dist/lib/commons-pool2-2.4.2.jar b/dist/lib/commons-pool2-2.4.2.jar deleted file mode 100644 index fdf8b6faaf..0000000000 Binary files a/dist/lib/commons-pool2-2.4.2.jar and /dev/null differ diff --git a/docs/feature_list.txt b/docs/feature_list.txt index 7cc3325526..9ca9083159 100644 --- a/docs/feature_list.txt +++ b/docs/feature_list.txt @@ -22,6 +22,7 @@ PQs: * Expeditions: Scarga/Horntail/Showa/Zakum/Pinkbean 100%. * GuildPQ 100% + Guild queue with multi-lobby systems available. * Brand-new PQ: Boss Rush PQ 100%. +* Mu Lung Dojo 100%. * BalrogPQ semi-functional. * Capt. Latanica remade as an event (parties can now fight the boss). @@ -55,6 +56,7 @@ Server potentials: * Every monsterbook card is now droppable by overworld mobs. * Monsterbook displays drop data info conformant with the underlying DB (needs custom wz). See more on the MobBookUpdate feature. * Mastery book announcer displaying droppers of needed books of a player, read underlying DB. +* Every skill/mastery book is now droppable by mobs. * Inventory auto-gather and auto-sorting feature. * Enhanced AP auto-assigner: exactly matches AP with the needed for the player's current level, surplus assigned to the primary attribute. * Added Boss HP Bar for dozens of bosses (needs provided custom wz). diff --git a/docs/mcpq/MCBattlefield.java b/docs/mcpq/MCBattlefield.java new file mode 100644 index 0000000000..48b733b648 --- /dev/null +++ b/docs/mcpq/MCBattlefield.java @@ -0,0 +1,453 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +package server.partyquest.mcpq; + +import java.awt.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import packet.creators.CarnivalPackets; +import packet.creators.PacketCreator; +import client.player.Player; +import server.life.MapleLifeFactory; +import server.life.MapleMonster; +import server.life.MobSkill; +import server.life.MobSkillFactory; +import server.life.SpawnPoint; +import server.life.Spawns; +import server.maps.Field; +import server.maps.FieldObject; +import server.maps.FieldObjectType; +import server.maps.reactors.MapleReactor; +import server.maps.reactors.MapleReactorFactory; +import server.partyquest.mcpq.MCField.MCTeam; +import static server.partyquest.mcpq.MCField.MCTeam.RED; +import server.partyquest.mcpq.MCWZData.MCGuardianGenPos; +import server.partyquest.mcpq.MCWZData.MCMobGenPos; + + +/** + * Keeps track of guardians and spawns in MCPQ. + * + * @author s4nta + */ +public class MCBattlefield { + + private Field map; + private MCWZData wzData; + private int numGuardiansSpawned = 0; + private int numMonstersSpawned = 0; + // These map Guardian IDs (aka codes for status) to the guardian position. + private Map redGuardianIdToPos = new HashMap<>(); + private Map blueGuardianIdToPos = new HashMap<>(); + // These map Reactor Object IDs to guardian objects. + private Map redReactors = new HashMap<>(); + private Map blueReactors = new HashMap<>(); + // used for divided maps + // we use an arraylist here for easier random element lookup. + private List originalRedGuardianSpawns = new ArrayList<>(); + private List originalBlueGuardianSpawns = new ArrayList<>(); + // used for undivided map + private List originalGuardianSpawns = new ArrayList<>(); + + // used for divided maps + // we use an arraylist here for easier random element lookup. + private List originalRedSpawns = new ArrayList<>(); + private List originalBlueSpawns = new ArrayList<>(); + // use for undivided map + private List originalUnifiedSpawns = new ArrayList<>(); + + private List originalSpawns = new ArrayList<>(); + private List addedSpawns = new ArrayList<>(); + + public MCBattlefield(Field battleInstance) { + this.map = battleInstance; + fetchCarnivalData(); + getOriginalSpawnPoints(); + populateGuardianSpawns(); + populateMobSpawns(); + } + + private void fetchCarnivalData() { + wzData = this.map.getMCPQData(); + if (wzData == null) { + MCTracker.log("[MCPQ] Fetching carnival failed for map " + map.getId()); + } + } + + private void getOriginalSpawnPoints() { + for (Spawns sp : this.map.getSpawnPoints()) { + originalSpawns.add((SpawnPoint) sp); + } + } + + private void populateGuardianSpawns() { + for (MCWZData.MCGuardianGenPos gpos : wzData.guardianGenPosList) { + switch (gpos.team) { + case 0: + originalRedGuardianSpawns.add(gpos); + break; + case 1: + originalBlueGuardianSpawns.add(gpos); + break; + default: + originalGuardianSpawns.add(gpos); + } + } + } + + private void populateMobSpawns() { + for (MCWZData.MCMobGenPos mpos : wzData.mobGenPosList) { + switch (mpos.team) { + case 0: + originalRedSpawns.add(mpos); + break; + case 1: + originalBlueSpawns.add(mpos); + break; + default: + originalUnifiedSpawns.add(mpos); + break; + } + } + } + + public void addSpawn(Player chr, int num) { + if (numMonstersSpawned > wzData.mobGenMax) { + chr.getClient().announce(CarnivalPackets.CarnivalMessage(3)); + return; + } + + MCWZData.MCSummonMob mobToSummon = wzData.summons.get(num); + MCWZData.MCMobGenPos spawnPos = getRandomSpawnPos(chr.getMCPQTeam()); + + MCField.MCTeam team = chr.getMCPQTeam(); + if (spawnPos == null) { + chr.getClient().announce(CarnivalPackets.CarnivalMessage(2)); + return; + } + + int spendCp = mobToSummon.spendCP; + if (spendCp > chr.getAvailableCP()) { + readdSpawn(spawnPos, team); + chr.getClient().announce(CarnivalPackets.CarnivalMessage(1)); + return; + } + + chr.getMCPQField().loseCP(chr, spendCp); + this.map.broadcastMessage(CarnivalPackets.PlayerSummoned(MonsterCarnival.TAB_SPAWNS, num, chr.getName())); + numMonstersSpawned++; // TODO: AtomicInteger this + + MapleMonster monster = MapleLifeFactory.getMonster(mobToSummon.id); + Point pos = new Point(spawnPos.x, spawnPos.y); + SpawnPoint sp = new SpawnPoint(monster, pos, mobToSummon.mobTime, chr.getTeam()); + + addedSpawns.add(sp); + updateMonsterBuffs(); + } + + public void useSkill(Player chr, int num) { + if (!wzData.skills.containsKey(num)) { + MCTracker.log("Attempting to use a null skill."); + return; + } + int realSkill = wzData.skills.get(num); + MCSkill skill = MCSkillFactory.getMCSkill(realSkill); + // TODO: add skill cooldowns + + int spendCp = skill.getSpendCP(); + if (spendCp > chr.getAvailableCP()) { + chr.getClient().announce(CarnivalPackets.CarnivalMessage(1)); + return; + } + + MCParty teamToApply = chr.getMCPQParty().getEnemy(); + boolean success = teamToApply.applyMCSkill(skill); + + if (success) { + chr.getMCPQField().loseCP(chr, spendCp); + map.broadcastMessage(CarnivalPackets.PlayerSummoned(MonsterCarnival.TAB_DEBUFF, num, chr.getName())); + } else { + chr.getClient().getSession().write(CarnivalPackets.CarnivalMessage(5)); + } + } + + public void readdSpawn(MCWZData.MCMobGenPos pos, MCField.MCTeam team) { + List lst = null; + if (this.wzData.mapDivided) { + if (null == team) { + return; + } else switch (team) { + case RED: + lst = originalRedSpawns; + break; + case BLUE: + lst = originalBlueSpawns; + break; + default: + return; + } + } else { + lst = originalUnifiedSpawns; + } + + if (lst == null) { + return; + } + lst.add(pos); + } + + public void spawnGuardian(Player chr, int num) { + if (numGuardiansSpawned > wzData.guardianGenMax) { + chr.getClient().announce(CarnivalPackets.CarnivalMessage(3)); + return; + } + + int guardianId = wzData.guardians.get(num); + MCGuardian guardian = MCSkillFactory.getMCGuardian(guardianId); + if (guardian == null) { + MCTracker.log("Attempting to spawn invalid guardian."); + return; + } + + MCField.MCTeam team = chr.getMCPQTeam(); + if (team == MCField.MCTeam.RED) { + if (redGuardianIdToPos.containsKey(guardianId)) { + chr.getClient().announce(CarnivalPackets.CarnivalMessage(4)); + return; + } + } else if (team == MCField.MCTeam.BLUE) { + if (blueGuardianIdToPos.containsKey(guardianId)) { + chr.getClient().announce(CarnivalPackets.CarnivalMessage(4)); + return; + } + } + int spendCp = guardian.getSpendCP(); + if (spendCp > chr.getAvailableCP()) { + chr.getClient().announce(CarnivalPackets.CarnivalMessage(1)); + return; + } + + chr.getMCPQField().loseCP(chr, spendCp); + this.map.broadcastMessage(CarnivalPackets.PlayerSummoned(MonsterCarnival.TAB_GUARDIAN, num, chr.getName())); + numGuardiansSpawned++; // TODO: AtomicInteger this + MCWZData.MCGuardianGenPos genPos = getRandomGuardianPos(team); + Point spawnPos = new Point(genPos.x, genPos.y); + + MapleReactor reactor; + if (null == team) { + return; + } else switch (team) { + case RED: + reactor = new MapleReactor(MapleReactorFactory.getReactor(MonsterCarnival.GUARDIAN_RED), MonsterCarnival.GUARDIAN_RED); + reactor.setPosition(spawnPos); + redGuardianIdToPos.put(num, genPos); + break; + case BLUE: + reactor = new MapleReactor(MapleReactorFactory.getReactor(MonsterCarnival.GUARDIAN_BLUE), MonsterCarnival.GUARDIAN_BLUE); + reactor.setPosition(spawnPos); + blueGuardianIdToPos.put(num, genPos); + break; + default: + return; + } + + reactor.setDelay(-1); + map.spawnReactor(reactor); + + if (team == MCField.MCTeam.RED) { + redReactors.put(reactor.getObjectId(), MCSkillFactory.getMCGuardian(num)); + } else { + blueReactors.put(reactor.getObjectId(), MCSkillFactory.getMCGuardian(num)); + } + + map.setReactorState(reactor, (byte) 1); + updateMonsterBuffs(); + } + + public void onGuardianHit(Player chr, MapleReactor reactor) { + if (MonsterCarnival.DEBUG) { + System.out.println("STATE: " + reactor.getState()); + } + MCField.MCTeam team = chr.getMCPQTeam(); + if (team == MCField.MCTeam.RED && reactor.getId() == MonsterCarnival.GUARDIAN_RED) { + return; + } + if (team == MCField.MCTeam.BLUE && reactor.getId() == MonsterCarnival.GUARDIAN_BLUE) { + return; + } + reactor.setState((byte) (reactor.getState() + 1)); + map.broadcastMessage(PacketCreator.TriggerReactor(reactor, reactor.getState())); + + if (reactor.getState() > 3) { + int reactorObjId = reactor.getObjectId(); + map.destroyReactor(reactorObjId); + + MCGuardian guard; + MCWZData.MCGuardianGenPos guardianGenPos; + if (team == MCField.MCTeam.RED) { + guard = blueReactors.remove(reactorObjId); + guardianGenPos = blueGuardianIdToPos.remove(guard.getType()); + } else { + guard = redReactors.remove(reactorObjId); + guardianGenPos = redGuardianIdToPos.remove(guard.getType()); + } + numGuardiansSpawned--; + + if (MonsterCarnival.DEBUG) { + System.out.println("Removing reactor with x = " + guardianGenPos.x); + } + if (wzData.mapDivided) { + if (team == MCField.MCTeam.RED) { + originalBlueGuardianSpawns.add(guardianGenPos); + } else { + originalRedGuardianSpawns.add(guardianGenPos); + } + } else { + originalGuardianSpawns.add(guardianGenPos); + } + + if (MonsterCarnival.DEBUG) { + System.out.println("Attempting to remove buff " + guard.getName()); + } + updateMonsterBuffs(); + } + } + + private MCGuardianGenPos getRandomGuardianPos(MCTeam team) { + if (this.wzData.mapDivided) { + if (null == team) { + return null; + } else switch (team) { + case RED: { + int randIndex = (int) Math.floor(Math.random() * this.originalRedGuardianSpawns.size()); + return originalRedGuardianSpawns.remove(randIndex); + } + case BLUE: { + int randIndex = (int) Math.floor(Math.random() * this.originalBlueGuardianSpawns.size()); + return originalBlueGuardianSpawns.remove(randIndex); + } + default: + return null; + } + } else { + int randIndex = (int) Math.floor(Math.random() * this.originalGuardianSpawns.size()); + return originalGuardianSpawns.remove(randIndex); + } + } + + private MCMobGenPos getRandomSpawnPos(MCTeam team) { + List lst = null; + if (this.wzData.mapDivided) { + if (null == team) { + return null; + } else switch (team) { + case RED: + lst = originalRedSpawns; + break; + case BLUE: + lst = originalBlueSpawns; + break; + default: + return null; + } + } else { + lst = originalUnifiedSpawns; + } + + if (lst == null) { + return null; + } + if (lst.isEmpty()) { + return null; + } + int randIndex = (int) Math.floor(Math.random() * lst.size()); + return lst.remove(randIndex); + } + + private void updateMonsterBuffs() { + List redGuardians = new ArrayList<>(); + List blueGuardians = new ArrayList<>(); + + for (MCGuardian g : this.redReactors.values()) { + redGuardians.add(g); + if (MonsterCarnival.DEBUG) { + System.out.println("update buff red " + g.getMobSkillID()); + } + } + for (MCGuardian g : this.blueReactors.values()) { + blueGuardians.add(g); + if (MonsterCarnival.DEBUG) { + System.out.println("update buff blue " + g.getMobSkillID()); + } + } + + for (FieldObject mmo : map.getAllMonsters()) { + if (mmo.getType() == FieldObjectType.MONSTER) { + MapleMonster mob = ((MapleMonster) mmo); + mob.dispel(); + + if (mob.getTeam() == MCField.MCTeam.RED.code) { + applyGuardians(mob, redGuardians); + } else if (mob.getTeam() == MCField.MCTeam.BLUE.code) { + applyGuardians(mob, blueGuardians); + } else { + MCTracker.log("[MCPQ] Attempting to give guardians to mob without team."); + } + } + } + } + + private void giveMonsterBuffs(MapleMonster mob) { + List redGuardians = new ArrayList<>(); + List blueGuardians = new ArrayList<>(); + + for (MCGuardian g : this.redReactors.values()) { + redGuardians.add(g); + if (MonsterCarnival.DEBUG) { + System.out.println("update buff red " + g.getMobSkillID()); + } + } + for (MCGuardian g : this.blueReactors.values()) { + blueGuardians.add(g); + if (MonsterCarnival.DEBUG) { + System.out.println("update buff blue " + g.getMobSkillID()); + } + } + + if (mob.getTeam() == MCField.MCTeam.RED.code) { + applyGuardians(mob, redGuardians); + } else if (mob.getTeam() == MCField.MCTeam.BLUE.code) { + applyGuardians(mob, blueGuardians); + } else { + MCTracker.log("[MCPQ] Attempting to give guardians to mob without team."); + } + } + + private void applyGuardians(MapleMonster mob, List guardians) { + for (MCGuardian g : guardians) { + MobSkill sk = MobSkillFactory.getMobSkill(g.getMobSkillID(), g.getLevel()); + sk.applyEffect(null, mob, true); + } + } + + public void spawningTask() { + for (SpawnPoint sp : originalSpawns) { + if (sp.shouldSpawn()) { + MapleMonster mob = sp.spawnMonster(this.map); + giveMonsterBuffs(mob); + } + } + for (SpawnPoint sp : addedSpawns) { + if (sp.shouldSpawn()) { + MapleMonster mob = sp.spawnMonster(this.map); + giveMonsterBuffs(mob); + } + } + } +} diff --git a/docs/mcpq/MCField.java b/docs/mcpq/MCField.java new file mode 100644 index 0000000000..ad2ba9aa37 --- /dev/null +++ b/docs/mcpq/MCField.java @@ -0,0 +1,850 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +package server.partyquest.mcpq; + +import handling.channel.ChannelServer; +import java.util.*; +import java.util.concurrent.ScheduledFuture; +import packet.creators.CarnivalPackets; +import packet.creators.EffectPackets; +import packet.creators.PacketCreator; +import packet.transfer.write.OutPacket; +import client.player.Player; +import server.MapleStatEffect; +import server.itens.MapleItemInformationProvider; +import server.maps.Field; +import server.maps.FieldItem; +import server.maps.reactors.MapleReactor; +import server.maps.portal.Portal; +import tools.TimerTools.EventTimer; + +/** + * Keeps track of a specific field (1-6). Handles all packet broadcasting, etc. + * @author s4nta + */ +public class MCField { + + /** + * Different teams for MCPQ. + */ + public enum MCTeam { + RED(0), + BLUE(1), + NONE(-1); + public final int code; + + MCTeam(int code) { + this.code = code; + } + + public final int getEnemyTeamCode() { + return Math.abs(this.code - 1); + } + } + + /** + * Represents the current state of the field. + */ + public enum MCState { + LOBBY, + BATTLE, + END; + } + + /** + * Keys to access different map instances relating to this field. + */ + public enum MCMaps { + LOBBY(0), + BATTLEFIELD(1), + RESURRECT(2), + VICTORY(3), + DEFEAT(4), + NONE(-1); + private final int code; + + MCMaps(int code) { + this.code = code; + } + + public static MCMaps getByCode(int code) { + for (MCMaps m : values()) { + if (m.code == code) { + return m; + } + } + return NONE; + } + } + + private int arena; + private ChannelServer cserv; + private MCParty red, blue; + private List requests = new ArrayList<>(); + private MCState state; + private Map mapInstances = new HashMap<>(); + private long startTime; + private MCBattlefield battlefield; + + // Timer Tasks + private ScheduledFuture acceptRequestsTask, validateRoomTask, startBattleTask, + validateBattleTask, runBattleTask, endBattleTask, + spawnMonstersTask; + + public MCField(int arena, ChannelServer cserv, MCParty red, MCParty blue) { + this.arena = arena; + this.cserv = cserv; + this.red = red; + this.blue = blue; + this.state = MCState.LOBBY; + } + + public boolean isFull() { + if (MonsterCarnival.DEBUG) { + return false; + } + return this.red != null && this.blue != null; + } + + public boolean needsRequest() { + return this.red != null && this.blue == null; + } + + /** + * Resets the state of the field, warping out players and resetting tasks. + * [MENTION=2000183830]para[/MENTION]m warpPlayers Warp out players or not + * @param warpPlayers + */ + public void deregister(boolean warpPlayers) { + if (warpPlayers) { + if (this.red != null) { + this.red.deregisterPlayers(); + } + if (this.blue != null) { + this.blue.deregisterPlayers(); + } + } + + + this.red = null; + this.blue = null; + this.requests.clear(); + this.state = MCState.LOBBY; + + if (this.acceptRequestsTask != null) { + this.acceptRequestsTask.cancel(true); + this.acceptRequestsTask = null; + } + + if (this.validateRoomTask != null) { + this.validateRoomTask.cancel(true); + this.validateRoomTask = null; + } + + if (this.startBattleTask != null) { + this.startBattleTask.cancel(true); + this.startBattleTask = null; + } + + if (this.endBattleTask != null) { + this.endBattleTask.cancel(true); + this.endBattleTask = null; + } + + if (this.runBattleTask != null) { + this.runBattleTask.cancel(true); + this.runBattleTask = null; + } + + if (this.validateBattleTask != null) { + this.validateBattleTask.cancel(true); + this.validateBattleTask = null; + } + + if (this.spawnMonstersTask != null) { + this.spawnMonstersTask.cancel(true); + this.spawnMonstersTask = null; + } + + for (MCMaps mapType : MCMaps.values()) { + this.mapInstances.remove(mapType); + } + } + + public MCParty getRed() { + return red; + } + + public MCParty getBlue() { + return blue; + } + + public void announce(OutPacket pkt) { + if (this.red != null) { + red.broadcast(pkt); + } else { + MCTracker.log("[MCPQ] Trying to announce packet to red when it is null."); + } + + if (this.blue != null) { + blue.broadcast(pkt); + } else { + MCTracker.log("[MCPQ] Trying to announce packet to blue when it is null."); + } + } + + /** + * Gets a string representing the status of this room for the Spiegelmann NPC. + * [MENTION=850422]return[/MENTION] String representing the room's status. + * @return + */ + public String getStatus() { + if (isFull()) { + return ""; + } + if (this.state != MCState.LOBBY) { + return ""; + } + String waitingParty = ""; + if (this.red != null) { + String fmt = " "; + waitingParty = String.format(fmt, this.red.getSize(), this.red.getAverageLevel()); + } + String fmt = "#L%d#Carnival Field %d%s#l\r\n"; + return String.format(fmt, this.arena, this.arena, waitingParty); + } + + /** + * Attempts to register a party in this field. If success, then all players in the party + * will be warped to the waiting lobby. All players in the party will also have relevant + * CPQ information assigned to them. + * + * [MENTION=2000183830]para[/MENTION]m party The party to register. + */ + public void register(MCParty party, MCTeam team) { + if (this.red == null && team == MCTeam.RED) { + party.setTeam(team); + this.red = party; + } else if (this.blue == null && team == MCTeam.BLUE) { + party.setTeam(team); + this.blue = party; + } else { + MCTracker.log("Attempting to register party when team is already set."); + return; + } + party.setField(this); + party.updatePlayers(); + party.warp(MCMaps.LOBBY); + onPartyRegistered(party, team); + } + + /** + * Sends a challenge to the party in this field. + * + * [MENTION=2000183830]para[/MENTION]m party The party requesting a challenge. + */ + public void request(MCParty party) { + if (this.red == null) { + MCTracker.log("Attempting to request when waiting team is null."); + this.deregister(true); + return; + } + requests.add(party); + this.red.notice("[MCPQ] A challenge has arrived! Click on the Assistant in your room to view it."); + } + + /** + * Accepts a challenge from a team. + * [MENTION=2000183830]para[/MENTION]m index Index of team in requests. + * [MENTION=850422]return[/MENTION] 1 if the challenge was accepted successfully, 0 otherwise. + */ + public int acceptRequest(int index) { + MCParty toAccept = this.requests.get(index); + register(toAccept, MCTeam.BLUE); + return 1; + } + + /** + * Checks for pending requests. + * + * [MENTION=850422]return[/MENTION] True if there are pending requests. + */ + public boolean hasPendingRequests() { + return requests.size() > 0; + } + + /** + * Gets a pending list of requests, formatted for use in a NPC. Also cleans up the requests, + * getting rid of MCParties that no longer exist. + * + * [MENTION=850422]return[/MENTION] Formatted list of requests for NPC. + * @return + */ + public String getNPCRequestString() { + StringBuilder sb = new StringBuilder("Here is the list of pending requests:\r\n\r\n#b"); + for (MCParty pty : requests) { + if (!pty.exists()) { + continue; + } + sb.append("#L").append(requests.indexOf(pty)).append("#"); + String fmt = ""; + fmt = String.format(fmt, pty.getSize(), pty.getAverageLevel()); + sb.append(fmt); + sb.append("#l\r\n"); + } + return sb.toString(); + } + + /** + * Starts a R3 minute waiting timer in the lobby for teams to accept requests. + * If the timer completes the countdown, teams are deregistered and sent back to the lobby. + */ + private void startLobbyTask(MCParty host) { + host.clock(MonsterCarnival.TIME_LOBBYWAIT); + this.acceptRequestsTask = EventTimer.getInstance().schedule(new AcceptingRequestsTask(this, host), 1000 * MonsterCarnival.TIME_LOBBYWAIT); // 3 minutes + this.validateRoomTask = EventTimer.getInstance().register(new ValidateLobbyTask(this), 1000, 1000); // repeat every second + } + + /** + * Event handling for when a team registers. + * + * [MENTION=2000183830]para[/MENTION]m party Party that registers. + * [MENTION=2000183830]para[/MENTION]m team Team of party. + */ + private void onPartyRegistered(MCParty party, MCTeam team) { + if (team == MCTeam.RED) { + startLobbyTask(party); + } + if (team == MCTeam.BLUE) { // both teams are in + this.validateRoomTask.cancel(true); + this.acceptRequestsTask.cancel(true); + blue.clock(10); + red.clock(10); + + this.startBattleTask = EventTimer.getInstance().schedule(new GoBattlefieldTask(this), 1000 * 10); // 10 seconds + + red.notice("[MCPQ] The Carnival PQ will start in 10 seconds!"); + blue.notice("[MCPQ] The Carnival PQ will start in 10 seconds!"); + } + } + + /** + * Warps both parties in the field to the battlefield map. + */ + private void goBattle() { + Field map = getMap(MCMaps.BATTLEFIELD); + if (MonsterCarnival.DEBUG) + System.out.println("warping to battle " + map + " " + map.getId()); + if (red != null) { + red.warp(map, "red00"); + } else { + MCTracker.log("[MCPQ] Trying to warp red party when it is null."); + } + + if (blue != null) { + blue.warp(map, "blue00"); + } else { + MCTracker.log("[MCPQ] Trying to warp blue party when it is null."); + } + + red.clock(MonsterCarnival.TIME_PREBATTLE); + blue.clock(MonsterCarnival.TIME_PREBATTLE); + + red.notice("[MCPQ] The battle will start in 10 seconds!"); + blue.notice("[MCPQ] The battle will start in 10 seconds!"); + + startBattleTask = EventTimer.getInstance().schedule(new BeginCarnivalTask(this), 1000 * MonsterCarnival.TIME_PREBATTLE); // 10 seconds + + validateBattleTask = EventTimer.getInstance().register(new ValidateBattlefieldTask(this), 1000, 500); // check every second + + battlefield = new MCBattlefield(getMap(MCMaps.BATTLEFIELD)); + + red.setEnemy(blue); + blue.setEnemy(red); + } + + private void beginCarnival() { + red.clock(MonsterCarnival.TIME_BATTLE); + blue.clock(MonsterCarnival.TIME_BATTLE); + startTime = System.currentTimeMillis(); + + getMap(MCMaps.BATTLEFIELD).broadcastMessage(PacketCreator.ServerNotice(6, "[MCPQ] You have 10 minutes to kill monsters!")); + + endBattleTask = EventTimer.getInstance().schedule(new EndBattleTask(this), 1000 * MonsterCarnival.TIME_BATTLE); + spawnMonstersTask = EventTimer.getInstance().register(new SpawnTask(this.battlefield), 1000 * 5); + + } + + public void endBattle(MCParty winner, MCParty loser) { + endBattle(winner, loser, false); + } + + public void endBattle(MCParty winner, MCParty loser, boolean abnormal) { + // TODO: Abnormal win codes to prevent exploits + + validateBattleTask.cancel(true); + spawnMonstersTask.cancel(true); + + MCWZData cpqData = this.getMap(MCMaps.BATTLEFIELD).getMCPQData(); + String effectWin = cpqData.effectWin; + String effectLose = cpqData.effectLose; + String soundWin = cpqData.soundWin; + String soundLose = cpqData.soundLose; + + winner.broadcast(EffectPackets.ShowEffect(effectWin)); + winner.broadcast(EffectPackets.PlaySound(soundWin)); + loser.broadcast(EffectPackets.ShowEffect(effectLose)); + loser.broadcast(EffectPackets.PlaySound(soundLose)); + + this.getMap(MCMaps.BATTLEFIELD).killAllMonsters(false); + this.getMap(MCMaps.BATTLEFIELD).clearDrops(); + this.deregister(false); + + EventTimer.getInstance().schedule(new WarpEndBattleTask(this, winner, loser), 1000 * 3); + } + + /** + * Handles CP gain and packet updates when a monster is killed. + * [MENTION=2000183830]para[/MENTION]m chr Character that kills the monster. + * [MENTION=2000183830]para[/MENTION]m cp CP gained. + */ + public void monsterKilled(Player chr, int cp) { + if (MonsterCarnival.DEBUG) { + // System.out.println(chr.getName() + " killed for +" + cp + " CP"); + } + // TODO: Personal stats for CP gain + this.gainCP(chr, cp); + } + + /** + * Handles game logic and packet broadcasting for CP gain. + * Broadcasts personal CP update to chr, and broadcasts party CP update + * to the entire field. + * + * [MENTION=2000183830]para[/MENTION]m chr Character that gains CP. + * [MENTION=2000183830]para[/MENTION]m cp CP gained. + */ + public void gainCP(Player chr, int cp) { + if (cp < 0) { + MCTracker.log("[MCPQ] Adding negative CP."); + if (MonsterCarnival.DEBUG) { + System.out.println("Adding negative CP: stacktrace"); + new Exception().printStackTrace(); + } + } + MCParty pty = chr.getMCPQParty(); + chr.gainCP(cp); + pty.gainCP(cp); + chr.getClient().announce(CarnivalPackets.UpdatePersonalCP(chr)); + this.announce(CarnivalPackets.UpdatePartyCP(pty)); + } + + /** + * Subtracts from available CP while leaving total CP untouched. + * + * [MENTION=2000183830]para[/MENTION]m chr Character that loses CP. + * [MENTION=2000183830]para[/MENTION]m cp CP lost (should be positive number). + */ + public void loseCP(Player chr, int cp) { + if (cp < 0) { + MCTracker.log("[MCPQ] Losing negative CP."); + if (MonsterCarnival.DEBUG) { + System.out.println("Adding negative CP: stacktrace"); + new Exception().printStackTrace(); + } + } + MCParty pty = chr.getMCPQParty(); + chr.loseCP(cp); + pty.loseCP(cp); + chr.getClient().announce(CarnivalPackets.UpdatePersonalCP(chr)); + this.announce(CarnivalPackets.UpdatePartyCP(pty)); + } + + /** + * Handles a player looting an item. + * [MENTION=2000183830]para[/MENTION]m player Player that picked up the object. + * [MENTION=2000183830]para[/MENTION]m mapitem Object picked up. + * + * [MENTION=850422]return[/MENTION] True if pickup was successful, false otherwise. + */ + public boolean onItemPickup(Player player, FieldItem mapitem) { + if (mapitem == null) { + MCTracker.log("[MCPQ] Attempting to loot null object."); + return false; + } + int itemid = mapitem.getItem().getItemId(); + if (!MonsterCarnival.isCPQConsumeItem(itemid)) { + return false; + } + MCParty pty = player.getMCPQParty(); + MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); + MapleStatEffect itemEffect = ii.getItemEffect(itemid); + if (!itemEffect.isConsumeOnPickup()) { + return false; + } + + if (itemEffect.isParty()) { + for (Player chr : pty.getMembers()) { + if (chr.getStat().getCurrentHp() > 0) { + itemEffect.applyTo(chr); + } + } + } else { // Single Target Item + itemEffect.applyTo(player); + } + // Status items + if (itemEffect.getNuffSkill() != -1) { + MCSkill debuff = MCSkillFactory.getMCSkill(itemEffect.getNuffSkill()); + if (debuff == null) { + MCTracker.log("[MCPQ] debuff skill is null " + itemEffect.getNuffSkill()); + return false; + } + + pty.getEnemy().applyMCSkill(debuff); + } + + if (itemEffect.getCP() > 0) { + this.gainCP(player, itemEffect.getCP()); + } + + return true; + } + + public void onPlayerRespawn(Player player) { + int cpLoss = Math.min(player.getAvailableCP(), MonsterCarnival.CP_LOSS_ON_DEATH); + this.announce(CarnivalPackets.PlayerDiedMessage(player, cpLoss)); + this.loseCP(player, cpLoss); + player.getStat().addMPHP(30000, 30000); + player.changeMap(this.getMap(MCMaps.RESURRECT), this.getMap(MCMaps.RESURRECT).getPortal(0)); + player.getClient().getSession().write(PacketCreator.GetClock(getTimeRemaining())); + player.getClient().getSession().write(CarnivalPackets.StartMonsterCarnival(player)); + } + + public void onPlayerDisconnected(Player player) { + MCParty pty = player.getMCPQParty(); + if (pty != null) { + pty.removePlayer(player); + } else { + MCTracker.log("[MCPQ] Attempting to run player disconnect event when party is null for character " + player.getName()); + } + } + + public void onAddSpawn(Player chr, int num) { + if (this.battlefield != null) { + battlefield.addSpawn(chr, num); + } else { + MCTracker.log("[MCPQ] Summoning guardian with null battlefield."); + } + } + + public void onUseSkill(Player chr, int num) { + if (this.battlefield != null) { + battlefield.useSkill(chr, num); + } else { + MCTracker.log("[MCPQ] Summoning guardian with null battlefield."); + } + } + + public void onGuardianSummon(Player chr, int num) { + if (this.battlefield != null) { + battlefield.spawnGuardian(chr, num); + } else { + MCTracker.log("[MCPQ] Summoning guardian with null battlefield."); + } + } + + public void onGuardianHit(Player chr, MapleReactor reactor) { + if (this.battlefield != null) { + battlefield.onGuardianHit(chr, reactor); + } else { + MCTracker.log("[MCPQ] Hitting reactor with null battlefield."); + } + } + + public void onRevive(Player player) { + MCTeam team = player.getMCPQTeam(); + Portal portal; + if (team == MCTeam.RED) { + portal = getMap(MCMaps.BATTLEFIELD).getPortal("red_revive"); + } else { + portal = getMap(MCMaps.BATTLEFIELD).getPortal("blue_revive"); + } + + player.changeMap(getMap(MCMaps.BATTLEFIELD), portal); + player.getClient().getSession().write(PacketCreator.GetClock(getTimeRemaining())); + player.getClient().getSession().write(CarnivalPackets.StartMonsterCarnival(player)); + } + + public int getTimeRemaining() { + // TODO: add support for setting an explicit endTime instead of using the hack with MonsterCarnival variables + return (int) ((startTime + 1000 * MonsterCarnival.TIME_BATTLE) - System.currentTimeMillis()) / 1000; + } + + + // Map Instances + + /** + * Returns the map instance for a requested map. Creates a new map instance if unavailable. + * [MENTION=2000183830]para[/MENTION]m type Map instance to return. + * [MENTION=850422]return[/MENTION] The instanced map. + */ + public Field getMap(MCMaps type) { + if (this.mapInstances.containsKey(type)) { + return this.mapInstances.get(type); + } + return createInstanceMap(type); + } + + /** + * Attempts to create an instanced map, based on the type passed in. Also creates a mapping in + * this.mapInstances. + * + * [MENTION=2000183830]para[/MENTION]m type Type of map to generate. + * [MENTION=850422]return[/MENTION] MapleMap for the instanced map if type is supported, otherwise null. + */ + private Field createInstanceMap(MCMaps type) { + int mapid = -1; + switch (type) { + case LOBBY: + mapid = MonsterCarnival.getLobbyMap(this.arena); + break; + case BATTLEFIELD: + mapid = MonsterCarnival.getBattleFieldMap(this.arena); + break; + case RESURRECT: + mapid = MonsterCarnival.getResurrectionMap(this.arena); + break; + case VICTORY: + mapid = MonsterCarnival.getVictoriousMap(this.arena); + break; + case DEFEAT: + mapid = MonsterCarnival.getDefeatedMap(this.arena); + break; + } + if (mapid == -1) return null; + Field mapInstance = this.cserv.getMapFactory().instanceMap(mapid, true, true); + this.mapInstances.put(type, mapInstance); + return mapInstance; + } + + // Timer Tasks + + public class ValidateLobbyTask implements Runnable { + + private final MCField field; + + /** + * Timer task to ensure all players are on the right field. + * If anything is wrong with the parties, the field is deregistered. + * [MENTION=2000183830]para[/MENTION]m field Field to run the validation task on. + * @param field + */ + public ValidateLobbyTask(MCField field) { + this.field = field; + } + + @Override + public void run() { + if (this.field.red == null) { + this.field.deregister(true); + return; + } + for (Player c : field.red.getMembers()) { + if (c.getMap() != field.getMap(MCMaps.LOBBY)) { + this.field.deregister(true); + return; + } + } + if (this.field.blue != null) { + for (Player c : field.blue.getMembers()) { + if (c.getMap() != field.getMap(MCMaps.LOBBY)) { + this.field.deregister(true); + return; + } + } + } + } + } + + public class ValidateBattlefieldTask implements Runnable { + + private final MCField field; + + /** + * Timer task to ensure all players are on the right field. + * If anything is wrong with the parties, the field is deregistered. + * [MENTION=2000183830]para[/MENTION]m field Field to run the validation task on. + */ + + public ValidateBattlefieldTask(MCField field) { + this.field = field; + } + + @Override + public void run() { + if (this.field.red == null || field.red.getSize() == 0) { + MCTracker.log("[MCPQ] Red team null when validating battlefield"); + field.endBattle(blue, red); + return; + } + Collection members = Collections.unmodifiableCollection(field.red.getMembers()); + for (Player c : members) { + if (c.getMap() != field.getMap(MCMaps.BATTLEFIELD) && c.getMap() != field.getMap(MCMaps.RESURRECT)) { + this.field.announce(CarnivalPackets.CarnivalLeave(MCTeam.RED.code, c.getName())); + red.removePlayer(c); // TODO: fix concurrent modification + } + if (c.getMap() == field.getMap(MCMaps.BATTLEFIELD) && !c.isAlive()) { + this.field.onPlayerRespawn(c); + } + } + if (this.field.blue == null || field.blue.getSize() == 0) { + MCTracker.log("[MCPQ] Blue team null when validating battlefield"); + field.endBattle(red, blue); + return; + } + members = Collections.unmodifiableCollection(field.blue.getMembers()); + for (Player c : members) { + if (c.getMap() != field.getMap(MCMaps.BATTLEFIELD) && c.getMap() != field.getMap(MCMaps.RESURRECT)) { + this.field.announce(CarnivalPackets.CarnivalLeave(MCTeam.BLUE.code, c.getName())); + blue.removePlayer(c); + } + if (c.getMap() == field.getMap(MCMaps.BATTLEFIELD) && !c.isAlive()) { + this.field.onPlayerRespawn(c); + } + } + } + } + + public class AcceptingRequestsTask implements Runnable { + + private final MCField field; + private final MCParty host; + + /** + * Runs a task that counts down for 3 minutes, then warps the hosting party out. + * + * [MENTION=2000183830]para[/MENTION]m field Field to accept requests on. + * [MENTION=2000183830]para[/MENTION]m host Hosting party that will be warped out if they do not accept a request + * within 3 minutes. + */ + public AcceptingRequestsTask(MCField field, MCParty host) { + this.field = field; + this.host = host; + } + + @Override + public void run() { + Collection chrs = this.host.getMembers(); + for (Player c : chrs) { + c.changeMap(MonsterCarnival.MAP_LOBBY); + } + this.field.deregister(true); + } + } + + public class GoBattlefieldTask implements Runnable { + + private final MCField field; + + public GoBattlefieldTask(MCField field) { + this.field = field; + } + + @Override + public void run() { + field.goBattle(); + + field.red.startBattle(); + field.blue.startBattle(); + + field.state = MCState.BATTLE; + } + } + + public class BeginCarnivalTask implements Runnable { + + private final MCField field; + + public BeginCarnivalTask(MCField field) { + this.field = field; + } + + @Override + public void run() { + Field map = field.getMap(MCMaps.BATTLEFIELD); + map.beginSpawning(); + field.beginCarnival(); + } + } + + /* I have no idea why this doesn't work normally :/ */ + public class SpawnTask implements Runnable { + + private final MCBattlefield battleMap; + + public SpawnTask(MCBattlefield field) { + this.battleMap = field; + } + + @Override + public void run() { + // TODO: adjust spawn rates based on cp + battleMap.spawningTask(); + } + } + + public class EndBattleTask implements Runnable { + private final MCField field; + + public EndBattleTask(MCField field) { + this.field = field; + } + + @Override + public void run() { + MCParty winner, loser; + if (field.red.getTotalCP() > field.blue.getTotalCP()) { + winner = field.red; + loser = field.blue; + } else if (field.red.getTotalCP() < field.blue.getTotalCP()) { + winner = field.blue; + loser = field.red; + } else { + // if tied: random chance + // TODO: proper extension of time + if (Math.random() < .5) { + winner = field.red; + loser = field.blue; + } else { + winner = field.blue; + loser = field.red; + } + } + + field.state = MCState.END; + field.endBattle(winner, loser); + } + } + + public class WarpEndBattleTask implements Runnable { + + private final MCField field; + private final MCParty winner, loser; + + public WarpEndBattleTask(MCField field, MCParty winner, MCParty loser) { + this.field = field; + this.winner = winner; + this.loser = loser; + } + + @Override + public void run() { + winner.warp(field.getMap(MCMaps.VICTORY)); + loser.warp(field.getMap(MCMaps.DEFEAT)); + } + } +} \ No newline at end of file diff --git a/docs/mcpq/MCGuardian.java b/docs/mcpq/MCGuardian.java new file mode 100644 index 0000000000..d53f1ab485 --- /dev/null +++ b/docs/mcpq/MCGuardian.java @@ -0,0 +1,57 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +package server.partyquest.mcpq; + +/** + * Object representing MCGuardian in Skill.wz/MCGuardian.img. + * + * @author s4nta + */ + +public class MCGuardian { + private final int type, spendCP, mobSkillID, level; + private String name, desc; + + public MCGuardian(int type, int spendCP, int mobSkillID, int level) { + this.type = type; + this.mobSkillID = mobSkillID; + this.level = level; + this.spendCP = spendCP; + } + + public int getType() { + return type; + } + + public int getSpendCP() { + return spendCP; + } + + public int getMobSkillID() { + return mobSkillID; + } + + public int getLevel() { + return level; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } +} diff --git a/docs/mcpq/MCParty.java b/docs/mcpq/MCParty.java new file mode 100644 index 0000000000..7796073550 --- /dev/null +++ b/docs/mcpq/MCParty.java @@ -0,0 +1,315 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +package server.partyquest.mcpq; + +import community.MapleParty; +import community.MaplePartyCharacter; +import handling.channel.ChannelServer; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Random; +import packet.creators.CarnivalPackets; +import packet.creators.PacketCreator; +import packet.transfer.write.OutPacket; +import client.player.Player; +import client.player.buffs.Disease; +import server.life.MobSkill; +import server.life.MobSkillFactory; +import server.maps.Field; +import server.partyquest.mcpq.MCField.MCTeam; + + + +/** + * + * @author Sammy Guergachi + */ +/** + * Provides an interface for Monster Carnival-specific party methods and variables. + * + * @author s4nta + */ +public class MCParty { + + private MapleParty party; + private List characters = new ArrayList<>(); + private int availCP = 0; + private int totalCP = 0; + private MCField.MCTeam team = MCField.MCTeam.NONE; + private MCField field; + private MCParty enemy; + + public MCParty(MapleParty party) { + this.party = party; + for (MaplePartyCharacter chr : party.getMembers()) { + if (!chr.isOnline()) continue; + Player c = ChannelServer.getInstance(chr.getChannel()).getPlayerStorage().getCharacterById(chr.getId()); + + characters.add(c); + } + } + + public int getSize() { + return this.characters.size(); + } + + /** + * Checks if the underlying MapleParty still exists in the same way it did when it was created. + * That is, if there were no players who left the party. + * + * [MENTION=850422]return[/MENTION] True if the underlying MapleParty still exists in its original format. + */ + public boolean exists() { + Collection members = getMembers(); + for (Player chr : members) { + if (chr.getParty() == null || chr.getParty() != this.party) { + return false; + } + } + return true; + } + + public int getAverageLevel() { + int sum = 0, num = 0; + for (Player chr : getMembers()) { + sum += chr.getLevel(); + num += 1; + } + return sum / num; + } + + public boolean checkLevels() { + if (MonsterCarnival.DEBUG) { + return true; + } + for (Player chr : getMembers()) { + int lv = chr.getLevel(); + if (lv < MonsterCarnival.MIN_LEVEL || lv > MonsterCarnival.MAX_LEVEL) { + return false; + } + } + return true; + } + + public boolean checkChannels() { + if (MonsterCarnival.DEBUG) { + return true; + } + for (Player chr : getMembers()) { + if (chr.getClient().getChannel() != party.getLeader().getChannel()) return false; + } + return true; + } + + public boolean checkMaps() { + if (MonsterCarnival.DEBUG) { + return true; + } + for (Player chr : getMembers()) { + if (chr.getMapId() != MonsterCarnival.MAP_LOBBY) return false; + } + return true; + } + + public void warp(int map) { + for (Player chr : getMembers()) { + chr.changeMap(map); + } + } + + public void warp(Field map) { + for (Player chr : getMembers()) { + chr.changeMap(map, map.getPortal(0)); + } + } + + public void warp(Field map, String portal) { + for (Player chr : getMembers()) { + chr.changeMap(map, map.getPortal(portal)); + } + } + + public void warp(MCField.MCMaps type) { + Field m = this.field.getMap(type); + for (Player chr : getMembers()) { + chr.changeMap(m, m.getPortal(0)); + } + } + + public void clock(int secs) { + for (Player chr : getMembers()) { + chr.getClient().announce(PacketCreator.GetClock(secs)); + } + } + + public void notice(String msg) { + broadcast(PacketCreator.ServerNotice(6, msg)); + } + + public void broadcast(OutPacket pkt) { + for (Player chr : getMembers()) { + chr.getClient().announce(pkt); + } + } + + /** + * Sets MCPQTeam, MCPQParty, and MCPQField for a given character. + * [MENTION=2000183830]para[/MENTION]m chr Character to update. + */ + public void updatePlayer(Player chr) { + chr.setMCPQTeam(this.team); + chr.setMCPQParty(this); + chr.setMCPQField(this.field); + } + + /** + * Sets MCPQTeam, MCPQParty, and MCPQ field for all characters in the party. + * Unlike deregisterPlayers, this method does NOT warp players to the lobby map. + */ + public void updatePlayers() { + for (Player chr : getMembers()) { + this.updatePlayer(chr); + } + } + + /** + * Resets MCPQ variables for a given character. + * [MENTION=2000183830]para[/MENTION]m chr Character to reset. + */ + public static void deregisterPlayer(Player chr) { + chr.setMCPQTeam(MCTeam.NONE); + chr.setMCPQParty(null); + chr.setMCPQField(null); + + chr.setAvailableCP(0); + chr.setTotalCP(0); + } + + /** + * Resets MCPQ variables for all characters in the party. + * Unlike updatePlayers, this method DOES warp players to the lobby map. + */ + public void deregisterPlayers() { + for (Player chr : getMembers()) { + MCParty.deregisterPlayer(chr); + chr.changeMap(MonsterCarnival.MAP_EXIT); + } + } + + public void removePlayer(Player chr) { + characters.remove(chr); + deregisterPlayer(chr); + } + + public void startBattle() { + for (Player chr : characters) { + chr.getClient().getSession().write(CarnivalPackets.StartMonsterCarnival(chr)); + } + } + + /** + * Uses some amount of available CP. + * [MENTION=2000183830]para[/MENTION]m use A positive integer to be subtracted from available CP. + */ + public void loseCP(int use) { + // TODO: locks? + if (use < 0) { + System.err.println("Attempting to use negative CP."); + } + this.availCP -= use; + } + + public void gainCP(int gain) { + // TODO: locks? + this.availCP += gain; + this.totalCP += gain; + } + + public MCParty getEnemy() { + return enemy; + } + + public void setEnemy(MCParty enemy) { + this.enemy = enemy; + } + + /** + * Applies a MCSkill to the entire team. This is used on the team's own players + * because it is called when the enemy team uses a debuff/cube of darkness. + * [MENTION=2000183830]para[/MENTION]m skill Skill to apply. + * [MENTION=850422]return[/MENTION] True if skill was applied, false otherwise. + */ + public boolean applyMCSkill(MCSkill skill) { + MobSkill s = MobSkillFactory.getMobSkill(skill.getMobSkillID(), skill.getLevel()); + Disease disease = Disease.getType(skill.getMobSkillID()); + if (disease == null) { + disease = Disease.DARKNESS; + s = MobSkillFactory.getMobSkill(121, 6); // HACK: darkness + } else if (disease == Disease.POISON) { + return false; + } + + // We only target players on the battlefield map. + if (skill.getTarget() == 2) { + for (Player chr : getMembers()) { + if (MonsterCarnival.isBattlefieldMap(chr.getMapId())) { + chr.giveDebuff(disease, s); + } + } + return true; + } else { + if (getRandomMember() != null) { + getRandomMember().giveDebuff(disease, 1, 30000L, disease.getDisease(), 1); + return true; + } else { + return false; + } + } + } + + public void setField(MCField field) { + this.field = field; + } + + public void setTeam(MCTeam newTeam) { + this.team = newTeam; + } + + public MCTeam getTeam() { + return team; + } + + /** + * Returns a collection of online members in the party. + * [MENTION=850422]return[/MENTION] Online MCParty members. + */ + public Collection getMembers() { + return this.characters; + } + + public Player getRandomMember() { + List chrsOnMap = new ArrayList<>(); + for (Player chr : this.characters) { + if (MonsterCarnival.isBattlefieldMap(chr.getMapId())) { + chrsOnMap.add(chr); + } + } + if (chrsOnMap.isEmpty()) { + return null; + } + return chrsOnMap.get(new Random().nextInt(chrsOnMap.size())); + } + + public int getAvailableCP() { + return availCP; + } + + public int getTotalCP() { + return totalCP; + } +} \ No newline at end of file diff --git a/docs/mcpq/MCSkill.java b/docs/mcpq/MCSkill.java new file mode 100644 index 0000000000..43b6c7bb6f --- /dev/null +++ b/docs/mcpq/MCSkill.java @@ -0,0 +1,61 @@ +package server.partyquest.mcpq; + +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +/** + * Object representing MCSkill in Skill.wz/MCSkill.img. + * + * @author s4nta + */ +public class MCSkill { + private final int id, target, mobSkillID, level, spendCP; + private String name, desc; + + public MCSkill(int id, int target, int mobSkillID, int level, int spendCP) { + this.id = id; + this.target = target; + this.mobSkillID = mobSkillID; + this.level = level; + this.spendCP = spendCP; + } + + public int getId() { + return id; + } + + public int getTarget() { + return target; + } + + public int getMobSkillID() { + return mobSkillID; + } + + public int getLevel() { + return level; + } + + public int getSpendCP() { + return spendCP; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } +} \ No newline at end of file diff --git a/docs/mcpq/MCSkillFactory.java b/docs/mcpq/MCSkillFactory.java new file mode 100644 index 0000000000..9f6a314008 --- /dev/null +++ b/docs/mcpq/MCSkillFactory.java @@ -0,0 +1,107 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +package server.partyquest.mcpq; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import provider.MapleData; +import provider.MapleDataProvider; +import provider.MapleDataProviderFactory; +import provider.MapleDataTool; + +/** + * + * @author Sammy Guergachi + */ +public class MCSkillFactory { + + private static Map mcSkills = new HashMap<>(); + private static Map mcGuardians = new HashMap<>(); + private static MapleDataProvider dataSource = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Skill.wz")); + private static MapleData mcSkillRoot = dataSource.getData("MCSkill.img"); + private static MapleData mcGuardianRoot = dataSource.getData("MCGuardian.img"); + private static ReentrantReadWriteLock skillLock = new ReentrantReadWriteLock(); + private static ReentrantReadWriteLock guardianLock = new ReentrantReadWriteLock(); + + public static MCSkill getMCSkill(int skillId) { + skillLock.readLock().lock(); + try { + MCSkill ret = mcSkills.get(skillId); + if (ret != null) { + return ret; + } + } finally { + skillLock.readLock().unlock(); + } + skillLock.writeLock().lock(); + try { + MCSkill ret; + ret = mcSkills.get(skillId); + if (ret == null) { + MapleData skillData = mcSkillRoot.getChildByPath(String.valueOf(skillId)); + if (skillData != null) { + int target = MapleDataTool.getInt("target", skillData, 0); + int spendCP = MapleDataTool.getInt("spendCP", skillData, 0); + int mobSkillID = MapleDataTool.getInt("mobSkillID", skillData, 0); + int level = MapleDataTool.getInt("level", skillData, 0); + ret = new MCSkill(skillId, target, mobSkillID, level, spendCP); + + if (MonsterCarnival.DEBUG) { + String name = MapleDataTool.getString("name", skillData, ""); + String desc = MapleDataTool.getString("desc", skillData, ""); + ret.setName(name); + ret.setDesc(desc); + } + mcSkills.put(skillId, ret); + } + } + return ret; + } finally { + skillLock.writeLock().unlock(); + } + } + + public static MCGuardian getMCGuardian(int id) { + guardianLock.readLock().lock(); + try { + MCGuardian ret = mcGuardians.get(id); + if (ret != null) { + return ret; + } + } finally { + guardianLock.readLock().unlock(); + } + guardianLock.writeLock().lock(); + try { + MCGuardian ret; + ret = mcGuardians.get(id); + if (ret == null) { + MapleData skillData = mcGuardianRoot.getChildByPath(String.valueOf(id)); + if (skillData != null) { + int type = MapleDataTool.getInt("type", skillData, 0); + int spendCP = MapleDataTool.getInt("spendCP", skillData, 0); + int mobSkillID = MapleDataTool.getInt("mobSkillID", skillData, 0); + int level = MapleDataTool.getInt("level", skillData, 0); + ret = new MCGuardian(type, spendCP, mobSkillID, level); + + if (MonsterCarnival.DEBUG) { + String name = MapleDataTool.getString("name", skillData, ""); + String desc = MapleDataTool.getString("desc", skillData, ""); + ret.setName(name); + ret.setDesc(desc); + } + mcGuardians.put(type, ret); + } + } + return ret; + } finally { + guardianLock.writeLock().unlock(); + } + } +} diff --git a/docs/mcpq/MCTracker.java b/docs/mcpq/MCTracker.java new file mode 100644 index 0000000000..6d8e4912bd --- /dev/null +++ b/docs/mcpq/MCTracker.java @@ -0,0 +1,30 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +package server.partyquest.mcpq; + +import org.slf4j.LoggerFactory; + +/** + * Logs various errors and also keeps data on Carnival PQ runs. + * @author s4nta + */ +public class MCTracker { + + static org.slf4j.Logger log = LoggerFactory.getLogger(MCTracker.class); + + // TODO: + // Add field-specific info + // Add methods for calls from different files + // Maybe write own version of FilePrinter? + + static final String PATH = "Reports/MCPQ.txt"; + + public static void log(String msg) { + System.out.println(msg); + log.debug(msg); + } +} diff --git a/docs/mcpq/MCWZData.java b/docs/mcpq/MCWZData.java new file mode 100644 index 0000000000..8835e75619 --- /dev/null +++ b/docs/mcpq/MCWZData.java @@ -0,0 +1,153 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +package server.partyquest.mcpq; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import provider.MapleData; +import provider.MapleDataTool; + +/** + * Representation of the data tree inside of the Map.wz file. + * + * @author s4nta + */ +public class MCWZData { + + public List mobGenPosList = new ArrayList<>(); + public List guardianGenPosList = new ArrayList<>(); + public Map summons = new HashMap<>(); + public Map skills = new HashMap<>(); + public Map guardians = new HashMap<>(); + + public String effectWin, effectLose, soundWin, soundLose; + public int rewardMapWin, rewardMapLose; + + public int mobGenMax, guardianGenMax; + public boolean mapDivided; + public int deathCP; + public int reactorRed, reactorBlue; + + public MCWZData(MapleData src) { + parse(src); + } + + public void parse(MapleData src) { + populateMobGenPos(src.getChildByPath("mobGenPos")); + populateSummonMobs(src.getChildByPath("mob")); + effectWin = MapleDataTool.getString("effectWin", src); + effectLose = MapleDataTool.getString("effectLose", src); + soundWin = MapleDataTool.getString("soundWin", src); + soundLose = MapleDataTool.getString("soundLose", src); + + rewardMapWin = MapleDataTool.getInt("rewardMapWin", src); + rewardMapLose = MapleDataTool.getInt("rewardMapLose", src); + + populateSkills(src.getChildByPath("skill")); + populateGuardianGenPos(src.getChildByPath("guardianGenPos")); + populateGuardians(src.getChildByPath("guardian")); + + mobGenMax = MapleDataTool.getInt("mobGenMax", src, 20); // HACK: 20 default + guardianGenMax = MapleDataTool.getInt("guardianGenMax", src, 20); // HACK: 20 default + + mapDivided = MapleDataTool.getInt("mapDivided", src) > 0; + + deathCP = MapleDataTool.getInt("deathCP", src); + reactorRed = MapleDataTool.getInt("reactorRed", src); + reactorBlue = MapleDataTool.getInt("reactorBlue", src); + } + + private void populateMobGenPos(MapleData src) { + for (MapleData n : src) { + MCMobGenPos nn = new MCMobGenPos(MapleDataTool.getInt("x", n, 0), + MapleDataTool.getInt("y", n, 0), + MapleDataTool.getInt("fh", n, 0), + MapleDataTool.getInt("cy", n, 0), + MapleDataTool.getInt("team", n, -1)); + mobGenPosList.add(nn); + } + } + + private void populateSummonMobs(MapleData src) { + for (MapleData n : src) { + int id = Integer.parseInt(n.getName()); + MCSummonMob mcs = new MCSummonMob( + MapleDataTool.getInt("id", n, 0), + MapleDataTool.getInt("spendCP", n, 0), + MapleDataTool.getInt("mobTime", n, 0) + ); + + this.summons.put(id, mcs); + } + } + + private void populateSkills(MapleData src) { + for (MapleData n : src) { + int key = Integer.parseInt(n.getName()); + int val = MapleDataTool.getInt(n); + + skills.put(key, val); + } + } + + private void populateGuardianGenPos(MapleData src) { + for (MapleData n : src) { + MCGuardianGenPos nn = new MCGuardianGenPos(MapleDataTool.getInt("x", n, 0), + MapleDataTool.getInt("y", n, 0), + MapleDataTool.getInt("f", n, 0), + MapleDataTool.getInt("team", n, -1)); + guardianGenPosList.add(nn); + } + } + + private void populateGuardians(MapleData src) { + for (MapleData n : src) { + int key = Integer.parseInt(n.getName()); + int val = MapleDataTool.getInt(n); + + guardians.put(key, val); + } + } + + public class MCMobGenPos { + + public final int x, y, fh, cy, team; + + private MCMobGenPos(int x, int y, int fh, int cy, int team) { + this.x = x; + this.y = y; + this.fh = fh; + this.cy = cy; + this.team = team; + } + } + + public class MCGuardianGenPos { + + public final int x, y, f, team; + + private MCGuardianGenPos(int x, int y, int f, int team) { + this.x = x; + this.y = y; + this.f = f; + this.team = team; + } + } + + public class MCSummonMob { + + public final int id, spendCP, mobTime; + + private MCSummonMob(int id, int spendCP, int mobTime) { + this.id = id; + this.spendCP = spendCP; + this.mobTime = mobTime; + } + } +} \ No newline at end of file diff --git a/docs/mcpq/MonsterCarnival.java b/docs/mcpq/MonsterCarnival.java new file mode 100644 index 0000000000..208790d1bf --- /dev/null +++ b/docs/mcpq/MonsterCarnival.java @@ -0,0 +1,360 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +package server.partyquest.mcpq; + +import community.MapleParty; +import handling.channel.ChannelServer; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import org.slf4j.LoggerFactory; +import client.player.Player; +import client.player.buffs.Disease; + + +/** + * + * @author Sammy Guergachi + */ +/** + * Processes game logic for Monster Carnival PQ. + * + * TODO: Display IGNs/Jobs/Level in Pending Requests + * TODO: fix reactor handling and make it less hacky + * TODO: fix cube of darkness and make it less hacky + * + * @author s4nta + */ +public class MonsterCarnival { + + // Logger + static org.slf4j.Logger log = LoggerFactory.getLogger(MonsterCarnival.class); + + // Map of channel to a MonsterCarnival instance. + private static final HashMap instances = new HashMap<>(); + + /** + * Returns the MonsterCarnival instance for a channel. Creates a new one and maps it + * if it does not exist. + * [MENTION=2000183830]para[/MENTION]m channel Channel to check for. + * [MENTION=850422]return[/MENTION] MonsterCarnival instance for a channel. + * @param channel + * @return + */ + public static MonsterCarnival getMonsterCarnival(int channel) { + // TODO: synchronization? + if (channel < 1 || channel > 20) { + log.warn("Attempting to get a Monster Carnival instance for invalid channel."); + return null; + } + if (instances.containsKey(channel)) { + return instances.get(channel); + } + ChannelServer cserv = ChannelServer.getInstance(channel); + if (cserv == null) { + log.error("ChannelServer instance for channel " + channel + " is null."); + return null; + } + MonsterCarnival inst = new MonsterCarnival(cserv); + instances.put(channel, inst); + return inst; + } + + // Instance variables + private ChannelServer cserv; + private Map fields = new HashMap<>(); + + /** + * Constructor for a MonsterCarnival instance. + * [MENTION=2000183830]para[/MENTION]m cserv Channel server for this instance. + */ + public MonsterCarnival(ChannelServer cserv) { + this.cserv = cserv; + this.initFields(); + } + + /** + * Initializes empty fields for the instance. + */ + private void initFields() { + for (int i = 1; i <= NUM_FIELDS; i++) { + fields.put(i, new MCField(i, this.cserv, null, null)); + } + } + + /** + * Gets the field with a specified ID. + * [MENTION=2000183830]para[/MENTION]m id ID of field to retrieve. + * [MENTION=850422]return[/MENTION] + */ + public MCField getField(int id) { + if (id >= 1 && id <= NUM_FIELDS) { + return fields.get(id); + } + return null; + } + + /** + * Checks if a party can join a field or not. + * + * [MENTION=2000183830]para[/MENTION]m pty Party to register. + * [MENTION=2000183830]para[/MENTION]m room Room to join. + * [MENTION=850422]return[/MENTION] Different code based on status. OK if successful. + */ + public int registerStatus(MapleParty pty, int room) { + if (!isValidField(room)) { + return STATUS_FIELD_INVALID; + } + MCField field = this.getField(room); + if (field.isFull()) { + return STATUS_FIELD_FULL; + } + MCParty party = new MCParty(pty); + if (!sizeCheck(party.getSize(), room)) { + return STATUS_PARTY_SIZE; + } + boolean levelCheck = party.checkLevels(); + if (!levelCheck) { + return STATUS_PARTY_LEVEL; + } + boolean chanCheck = party.checkChannels(); + if (!chanCheck) { + return STATUS_PARTY_MISSING; + } + boolean mapCheck = party.checkMaps(); + if (!mapCheck) { + return STATUS_PARTY_MISSING; + } + if (field.needsRequest()) { + return STATUS_REQUEST; + } + return STATUS_PROCEED; + } + + /** + * Creates a new MCParty based on a regular MapleParty object. + * [MENTION=2000183830]para[/MENTION]m pty Party to base off of. + * [MENTION=850422]return[/MENTION] Newly created MCParty. + */ + public MCParty createParty(MapleParty pty) { + return new MCParty(pty); + } + + public void resetPlayer(Player chr) { + MCParty.deregisterPlayer(chr); + chr.changeMap(MAP_LOBBY); + } + + /** + * Returns a String containing information about lobby waiting rooms. + * + * [MENTION=850422]return[/MENTION] String containing lobby information formatted for NPC. + */ + public String getNPCAvailableFields() { + StringBuilder sb = new StringBuilder(); + sb.append("Welcome to the #bCarnival PQ#k! Rooms 1-4 can hold 2-4 people, and rooms 5-6 can hold 3-6.\r\n#b"); + for (int i = 1; i <= NUM_FIELDS; i++) { + MCField field = this.fields.get(i); + sb.append(field.getStatus()); + } + + return sb.toString(); + } + + // Reference Information + + // Game Constants + public static final int CP_LOSS_ON_DEATH = 10; + public static final int TIME_PREBATTLE = 10; + public static final int TIME_BATTLE = 600; + public static final int TIME_LOBBYWAIT = 180; + + public static final int TAB_SPAWNS = 0; + public static final int TAB_DEBUFF = 1; + public static final int TAB_GUARDIAN = 2; + + /** + * Gets a random debuff for (Mini) Cube of Darkness. + * [MENTION=850422]return[/MENTION] Random MapleDisease. + */ + public static Disease getRandomDebuff() { + return DEBUFFS[new Random().nextInt(DEBUFFS.length)]; + } + + /** + * Checks party size. Information from hidden-street MCPQ page. + * [MENTION=2000183830]para[/MENTION]m size Size of the party. + * [MENTION=2000183830]para[/MENTION]m field Field to check for. + * [MENTION=850422]return[/MENTION] True if party size is okay, False otherwise. + */ + public static final boolean sizeCheck(int size, int field) { + if (DEBUG) { + return true; + } + switch (field) { + case 1: + case 2: + case 3: + case 4: + // return size >= 2 && size <= 4; + return size >= 1 && size <= 4; + case 5: + case 6: + // return size >= 3 && size <= 6; + return size >= 1 && size <= 6; + default: + return false; + } + } + + public static final boolean isValidField(int field) { + return field >= 1 && field <= 6; + } + + public static final int getLobbyMap(int field) { + if (field < 1 || field > NUM_FIELDS) { + log.warn("Attempting to get lobby map for invalid field."); + return MAP_EXIT; + } + return 980000000 + field * 100; + } + + public static final boolean isLobbyMap(int mapid) { + switch (mapid) { + case 980000100: + case 980000200: + case 980000300: + case 980000400: + case 980000500: + case 980000600: + return true; + default: + return false; + } + } + + public static final int getBattleFieldMap(int field) { + if (field < 1 || field > NUM_FIELDS) { + log.warn("Attempting to get battlefield map for invalid field."); + return MAP_EXIT; + } + return 980000000 + field * 100 + 1; + } + + public static final boolean isBattlefieldMap(int mapid) { + switch (mapid) { + case 980000101: + case 980000201: + case 980000301: + case 980000401: + case 980000501: + case 980000601: + return true; + default: + return false; + } + } + + public static final int getResurrectionMap(int field) { + if (field < 1 || field > NUM_FIELDS) { + log.warn("Attempting to get resurrection map for invalid field."); + return MAP_EXIT; + } + return 980000000 + field * 100 + 2; + } + + public static final int getVictoriousMap(int field) { + if (field < 1 || field > NUM_FIELDS) { + log.warn("Attempting to get victory map for invalid field."); + return MAP_EXIT; + } + return 980000000 + field * 100 + 3; + } + + public static final int getDefeatedMap(int field) { + if (field < 1 || field > NUM_FIELDS) { + log.warn("Attempting to get defeat map for invalid field."); + return MAP_EXIT; + } + return 980000000 + field * 100 + 4; + } + + public static final boolean isCPQConsumeItem(int itemid) { + switch (itemid) { + case ITEM_CP_1: + case ITEM_CP_2: + case ITEM_CP_3: + case ITEM_PTY_ELIX: + case ITEM_PTY_PELIX: + case ITEM_PTY_ALLC: + case ITEM_MINICUBE: + case ITEM_DARKCUBE: + case ITEM_STUNNER: + case ITEM_IND_WHITE: + case ITEM_IND_MANA: + case ITEM_IND_ELIX: + case ITEM_IND_PELIX: + case ITEM_IND_ALLC: + case ITEM_PTY_MANA: + return true; + } + return false; + } + + // Error Codes + // Note: These would be in an enum, but since these will be used in a NPC, they are not. + public static final int STATUS_FIELD_FULL = 0; + public static final int STATUS_PARTY_SIZE = 1; + public static final int STATUS_PARTY_LEVEL = 2; + public static final int STATUS_PARTY_MISSING = 3; + public static final int STATUS_FIELD_INVALID = 4; + public static final int STATUS_REQUEST = 98; + public static final int STATUS_PROCEED = 99; + + // Maps + public static final int MAP_LOBBY = 980000000; + public static final int MAP_EXIT = 980000010; + + // NPCs + public static final int NPC_LOBBY = 2042000; + public static final int NPC_ENTER = 2042001; // Warp in from outside + public static final int NPC_INFO = 2042002; + public static final int NPC_ASST_RED = 2042003; + public static final int NPC_ASST_BLUE = 2042004; + + // Items + public static final int ITEM_CP_1 = 2022157; + public static final int ITEM_CP_2 = 2022158; + public static final int ITEM_CP_3 = 2022159; + public static final int ITEM_PTY_MANA = 2022160; + public static final int ITEM_PTY_ELIX = 2022161; + public static final int ITEM_PTY_PELIX = 2022162; + public static final int ITEM_PTY_ALLC = 2022163; + public static final int ITEM_MINICUBE = 2022164; + public static final int ITEM_DARKCUBE = 2022165; + public static final int ITEM_STUNNER = 2022166; + public static final int ITEM_IND_WHITE = 2022174; + public static final int ITEM_IND_ELIX = 2022175; + public static final int ITEM_IND_PELIX = 2022176; + public static final int ITEM_IND_MANA = 2022177; + public static final int ITEM_IND_ALLC = 2022178; + + // Guardians + public static final int GUARDIAN_RED = 9980000; + public static final int GUARDIAN_BLUE = 9980001; + + // Debuffs + public static final Disease[] DEBUFFS = {Disease.STUN, Disease.DARKNESS, Disease.WEAKEN}; // intentionally leave out a few + + // Miscellaneous + public static final int MIN_LEVEL = 30; + public static final int MAX_LEVEL = 50; + public static final int NUM_FIELDS = 6; + + // Debug + public static final boolean DEBUG = false; +} diff --git a/docs/mcpq/readme.txt b/docs/mcpq/readme.txt new file mode 100644 index 0000000000..940af38fdd --- /dev/null +++ b/docs/mcpq/readme.txt @@ -0,0 +1 @@ +Extra classes for Monster Carnival. Can possibly be used for implementing MCPQ. \ No newline at end of file diff --git a/docs/mychanges_ptbr.txt b/docs/mychanges_ptbr.txt index 61c1e76156..854b90cc17 100644 --- a/docs/mychanges_ptbr.txt +++ b/docs/mychanges_ptbr.txt @@ -475,4 +475,10 @@ Mais drop data e HPBar em bosses. 23 Agosto 2017, Consertado problema com overflow ao scrollar equips resultando em equips com stats negativos. -Consertado pets no expirando corretamente (possivelmente crashando o cliente se no meio do jogo). \ No newline at end of file +Consertado pets no expirando corretamente (possivelmente crashando o cliente se no meio do jogo). + +24 - 25 Agosto 2017, +Acesso DB usando HikariCP (melhor ganho em desempenho e cdigo mais enxuto). +Resolvido bugs com hatch egg e evolvePet. +Adicionado energy bar e skills funcionais no Dojo. +Consertado cash pet food retirando stats de mount em Character Info. \ No newline at end of file diff --git a/docs/todo.txt b/docs/todo.txt index 225067fe60..d20aa1c50b 100644 --- a/docs/todo.txt +++ b/docs/todo.txt @@ -31,7 +31,6 @@ ToDo / Missing features list: - Ariant Party Quest - Monster Carnival 1/2 Party Quest - Nett's Pyramid Party Quest -- Dojo bar and skills combo (Bamboo Rain, Invincibility and Power Explosion) --------------------------- diff --git a/nbproject/private/private.xml b/nbproject/private/private.xml index 8123295f7c..efe765aa62 100644 --- a/nbproject/private/private.xml +++ b/nbproject/private/private.xml @@ -3,27 +3,8 @@ - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/inventory/MaplePet.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/command/Commands.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/inventory/Item.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/PacketProcessor.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/scripting/AbstractPlayerInteraction.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/constants/GameConstants.java file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/constants/ServerConstants.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/SpawnPetHandler.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/quest/2230.js - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/MapleItemInformationProvider.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/tools/MaplePacketCreator.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/inventory/MapleInventory.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/inventory/Equip.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/ItemRewardHandler.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/ItemMoveHandler.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/NPC%20Base.js - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/tools/Randomizer.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/MapleRing.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/MapleQuestStatus.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/scripting/event/EventInstanceManager.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/MapleInventoryManipulator.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/scripting/npc/NPCConversationManager.java file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/MapleCharacter.java diff --git a/nbproject/project.properties b/nbproject/project.properties index 51265dab74..38877527dd 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -28,8 +28,7 @@ dist.jar=${dist.dir}/MapleSolaxia.jar dist.javadoc.dir=${dist.dir}/javadoc endorsed.classpath= excludes= -file.reference.commons-dbcp2-2.1.1.jar=cores/commons-dbcp2-2.1.1.jar -file.reference.commons-pool2-2.4.2.jar=cores/commons-pool2-2.4.2.jar +file.reference.HikariCP-java7-2.4.12.jar=cores/HikariCP-java7-2.4.12.jar file.reference.MapleSolaxia-src=src file.reference.mina-core-2.0.7.jar=C:\\Users\\Tyler\\Desktop\\MoopleDev\\dist\\mina-core-2.0.7.jar file.reference.mysql-connector-java-bin.jar=C:\\Users\\Tyler\\Desktop\\MoopleDev\\dist\\mysql-connector-java-bin.jar @@ -44,8 +43,7 @@ javac.classpath=\ ${file.reference.mysql-connector-java-bin.jar}:\ ${file.reference.slf4j-api-1.6.6.jar}:\ ${file.reference.slf4j-jdk14-1.7.5.jar}:\ - ${file.reference.commons-dbcp2-2.1.1.jar}:\ - ${file.reference.commons-pool2-2.4.2.jar} + ${file.reference.HikariCP-java7-2.4.12.jar} # Space-separated list of extra javac options javac.compilerargs= javac.deprecation=false diff --git a/scripts/event/Boats.js b/scripts/event/Boats.js index e6d5507640..5888edea63 100644 --- a/scripts/event/Boats.js +++ b/scripts/event/Boats.js @@ -6,7 +6,8 @@ importPackage(Packages.server.life); var closeTime = 50 * 1000; //The time to close the gate var beginTime = 60 * 1000; //The time to begin the ride var rideTime = 120 * 1000; //The time that require move to destination -var invasionTime = 30 * 1000; //The time to balrog ship approach +var invasionStartTime = 30 * 1000; //The time to balrog ship approach +var invasionDelayTime = 15 * 1000; //The time to balrog ship approach var invasionDelay = 5 * 1000; //The time that spawn balrog var Orbis_btf; var Boat_to_Orbis; @@ -56,7 +57,7 @@ function takeoff() { em.setProperty("docked","false"); - em.schedule("approach", invasionTime); + if(Math.random() < 0.42) em.schedule("approach", (invasionStartTime + (Math.random() * invasionDelayTime))); em.schedule("arrived", rideTime); } diff --git a/scripts/npc/1012005.js b/scripts/npc/1012005.js index 5c01ee1a28..e71f466e7f 100644 --- a/scripts/npc/1012005.js +++ b/scripts/npc/1012005.js @@ -24,122 +24,131 @@ Map(s): Victoria Road : Henesys Park (100000200) Description: Pet Master */ -var status = -1; +var status = -2; var sel; function start() { - cm.sendNext("Hmm... are you raising one of my kids by any chance? I perfected a spell that uses Water of Life to blow life into a doll. People call it the #bPet#k. If you have one with you, feel free to ask me questions."); + status = -2 + action(1, 0, 0); } function action(mode, type, selection) { - status++; - if (mode != 1) { - if(mode == 0 && status >= 2) - status -= 2; - else{ - cm.dispose(); - return; - } - } - if (status == 0) - cm.sendSimple("What do you want to know more of?#b\r\n#L0#Tell me more about Pets.#l\r\n#L1#How do I raise Pets?#l\r\n#L2#Do Pets die too?#l\r\n#L3#What are the commands for Brown and Black Kitty?#l\r\n#L4#What are the commands for Brown Puppy?#l\r\n#L5#What are the commands for Pink and White Bunny?#l\r\n#L6#What are the commands for Mini Kargo?#l\r\n#L7#What are the commands for Rudolph and Dasher?#l\r\n#L8#What are the commands for Black Pig?#l\r\n#L9#What are the commands for Panda?#l\r\n#L10#What are the commands for Husky?#l\r\n#L11#What are the commands for Dino Boy and Dino Girl?#l\r\n#L12#What are the commands for Monkey?#l\r\n#L13#What are the commands for Turkey?#l\r\n#L14#What are the commands for White Tiger?#l\r\n#L15#What are the commands for Penguin?#l\r\n#L16#What are the commands for Golden Pig?#l\r\n#L17#What are the commands for Robot?#l\r\n#L18#What are the commands for Mini Yeti?#l\r\n#L19#What are the commands for Jr. Balrog?#l\r\n#L20#What are the commands for Baby Dragon?#l\r\n#L21#What are the commands for Green/Red/Blue Dragon?#l\r\n#L22#What are the commands for Black Dragon?#l\r\n#L23#What are the commands for Jr. Reaper?#l\r\n#L24#What are the commands for Porcupine?#l\r\n#L25#What are the commands for Snowman?#l\r\n#L26#What are the commands for Skunk?#l\r\n#L27#Please teach me about transferring pet ability points.#l"); - else if (status == 1) { - sel = selection; - if (selection == 0) { - status = 3; - cm.sendNext("So you want to know more about Pets. Long ago I made a doll, sprayed Water of Life on it, and cast spell on it to create a magical animal. I know it sounds unbelievable, but it's a doll that became an actual living thing. They understand and follow people very well."); - } else if (selection == 1) { - status = 6; - cm.sendNext("Depending on the command you give, pets can love it, hate, and display other kinds of reactions to it. If you give the pet a command and it follows you well, your intimacy goes up. Double click on the pet and you can check the intimacy, level, fullness and etc..."); - } else if (selection == 2) { - status = 11; - cm.sendNext("Dying... well, they aren't technically ALIVE per se, so I don't know if dying is the right term to use. They are dolls with my magical power and the power of Water of Life to become a live object. Of course while it's alive, it's just like a live animal..."); - } else if (selection == 3) - cm.sendNext("These are the commands for #rBrown Kitty and Black Kitty#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badgirl, badboy#k (Level 1 ~ 30)\r\n#bstupid, ihateyou, dummy#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1~30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#btalk, say, chat#k (Level 10 ~ 30)\r\n#bcutie#k (Level 10 ~ 30)\r\n#bup, stand, rise#k (Level 20 ~ 30)"); - else if (selection == 4) - cm.sendNext("These are the commands for #rBrown Puppy#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badgirl, badboy#k (Level 1 ~ 30)\r\n#bstupid, ihateyou, baddog, dummy#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1~30)\r\n#bpee#k (Level 1 ~ 30)\r\n#btalk, say, chat#k (Level 10 ~ 30)\r\n#bdown#k (Level 10 ~ 30)\r\n#bup, stand, rise#k (Level 20 ~ 30)"); - else if (selection == 5) - cm.sendNext("These are the commands for #rPink Bunny and White Bunny#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badgirl, badboy#k (Level 1 ~ 30)\r\n#bup, stand, rise#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1~30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#btalk, say, chat#k (Level 10 ~ 30)\r\n#bhug#k (Level 10 ~ 30)\r\n#bsleep, sleepy, gotobed#k (Level 20 ~ 30)"); - else if (selection == 6) - cm.sendNext("These are the commands for #rMini Kargo#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badgirl, badboy#k (Level 1 ~ 30)\r\n#bup, stand, rise#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1~30)\r\n#bpee#k (Level 1 ~ 30)\r\n#btalk, say, chat#k (Level 10 ~ 30)\r\n#bthelook, charisma#k (Level 10 ~ 30)\r\n#bdown#k (Level 10 ~ 30)\r\n#bgoodboy, goodgirl#k (Level 20 ~ 30)"); - else if (selection == 7) - cm.sendNext("These are the commands for #rRudolph and Dasher#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badgirl, badboy#k (Level 1 ~ 30)\r\n#bup, stand#k (Level 1 ~ 30)\r\n#bstupid, ihateyou, dummy#k (Level 1 ~ 30)\r\n#bmerryxmas, merrychristmas#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1~30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#btalk, say, chat#k (Level 11 ~ 30)\r\n#blonely, alone#k (Level 11 ~ 30)\r\n#bcutie#k (Level 11 ~ 30)\r\n#bmush, go#k (Level 21 ~ 30)"); - else if (selection == 8) - cm.sendNext("These are the commands for #rBlack Pig#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badgirl, badboy#k (Level 1 ~ 30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1~30)\r\n#bhand#k (Level 1 ~ 30)\r\n#bstupid, ihateyou, dummy#k (Level 1 ~ 30)\r\n#btalk, chat, say#k (Level 10 ~ 30)\r\n#bsmile#k (Level 10 ~ 30)\r\n#bthelook, charisma#k (Level 20 ~ 30)"); - else if (selection == 9) - cm.sendNext("These are the commands for #rPanda#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bchill, relax#k (Level 1 ~ 30)\r\n#bbad, no, badgirl, badboy#k (Level 1 ~ 30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1 ~ 30)\r\n#bup, stand, rise#k (Level 1 ~ 30)\r\n#btalk, chat, say#k (Level 10 ~ 30)\r\n#bletsplay#k (Level 10 ~ 30)\r\n#bmeh, bleh#k (Level 10 ~ 30)\r\n#bsleep#k (Level 20 ~ 30)"); - else if (selection == 10) - cm.sendNext("These are the commands for #rHusky#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badgirl, badboy#k (Level 1 ~ 30)\r\n#bstupid, ihateyou, baddog, dummy#k (Level 1 ~ 30)\r\n#bhand#k (Level 1 ~ 30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1 ~ 30)\r\n#bdown#k (Level 10 ~ 30)\r\n#btalk, chat, say#k (Level 10 ~ 30)\r\n#bup, stand, rise#k (Level 20 ~ 30)"); - else if (selection == 11) - cm.sendNext("These are the commands for #rDino Boy and Dino Girl#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badboy, badgirl#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1 ~ 30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#bsmile, laugh#k (Level 1 ~ 30)\r\n#bstupid, ihateyou, dummy#k (Level 1 ~ 30)\r\n#btalk, chat, say#k (Level 10 ~ 30)\r\n#bcutie#k (Level 10 ~ 30)\r\n#bsleep, nap, sleepy#k (Level 20 ~ 30)"); - else if (selection == 12) - cm.sendNext("These are the commands for #rMonkey#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#brest#k (Level 1 ~ 30)\r\n#bbad, no, badboy, badgirl#k (Level 1 ~ 30)\r\n#bpee#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1 ~ 30)\r\n#bup, stand#k (Level 1 ~ 30)\r\n#btalk, chat, say#k (Level 10 ~ 30)\r\n#bplay#k (Level 10 ~ 30)\r\n#bmelong#k (Level 10 ~ 30)\r\n#bsleep, gotobed, sleepy#k (Level 20 ~ 30)"); - else if (selection == 13) - cm.sendNext("These are the commands for #rTurkey#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bno, rudeboy, mischief#k (Level 1 ~ 30)\r\n#bstupid#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1 ~ 30)\r\n#bup, stand#k (Level 1 ~ 30)\r\n#btalk, chat, gobble#k (Level 10 ~ 30)\r\n#byes, goodboy#k (Level 10 ~ 30)\r\n#bsleepy, birdnap, doze#k (Level 20 ~ 30)\r\n#bbirdeye, thanksgiving, fly, friedbird, imhungry#k (Level 30)"); - else if (selection == 14) - cm.sendNext("These are the commands for #rWhite Tiger#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badboy, badgirl#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1 ~ 30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#brest, chill#k (Level 1 ~ 30)\r\n#bstupid, ihateyou, dummy#k (Level 1 ~ 30)\r\n#btalk, chat, say#k (Level 10 ~ 30)\r\n#bactsad, sadlook#k (Level 10 ~ 30)\r\n#bwait#k (Level 20 ~ 30)"); - else if (selection == 15) - cm.sendNext("These are the commands for #rPenguin#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badboy, badgirl#k (Level 1 ~ 30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#bup, stand, rise#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1 ~ 30)\r\n#btalk, chat, say#k (Level 10 ~ 30)\r\n#bhug, hugme#k (Level 10 ~ 30)\r\n#bwing, hand#k (Level 10 ~ 30)\r\n#bsleep#k (Level 20 ~ 30)\r\n#bkiss, smooch, muah#k (Level 20 ~ 30)\r\n#bfly#k (Level 20 ~ 30)\r\n#bcute, adorable#k (Level 20 ~ 30)"); - else if (selection == 16) - cm.sendNext("These are the commands for #rGolden Pig#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badboy, badgirl#k (Level 1 ~ 30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1 ~ 30)\r\n#btalk, chat, say#k (Level 11 ~ 30)\r\n#bloveme, hugme#k (Level 11 ~ 30)\r\n#bsleep, sleepy, gotobed#k (Level 21 ~ 30)\r\n#bignore / impressed / outofhere#k (Level 21 ~ 30)\r\n#broll, showmethemoney#k (Level 21 ~ 30)"); - else if (selection == 17) - cm.sendNext("These are the commands for #rRobot#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bup, stand, rise#k (Level 1 ~ 30)\r\n#bstupid, ihateyou, dummy#k (Level 1 ~ 30)\r\n#bbad, no, badgirl, badboy#k (Level 1 ~ 30)\r\n#battack, charge#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1 ~ 30)\r\n#bgood, thelook, charisma#k (Level 11 ~ 30)\r\n#bspeack, talk, chat, say#k (Level 11 ~ 30)\r\n#bdisguise, change, transform#k (Level 11 ~ 30)"); - else if (selection == 18) - cm.sendNext("These are the commands for #rMini Yeti#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badboy, badgirl#k (Level 1 ~ 30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#bdance, boogie, shakeit#k (Level 1 ~ 30)\r\n#bcute, cutie, pretty, adorable#k (Level 1 ~ 30)\r\n#biloveyou, likeyou, mylove#k (Level 1 ~ 30)\r\n#btalk, chat, say#k (Level 11 ~ 30)\r\n#bsleep, nap, sleepy, gotobed#k (Level 11 ~ 30)"); - else if (selection == 19) - cm.sendNext("These are the commands for #rJr. Balrog#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bliedown#k (Level 1 ~ 30)\r\n#bno|bad|badgirl|badboy#k (Level 1 ~ 30)\r\n#biloveyou|mylove|likeyou#k (Level 1 ~ 30)\r\n#bcute|cutie|pretty|adorable#k (Level 1 ~ 30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#bsmirk|crooked|laugh#k (Level 1 ~ 30)\r\n#bmelong#k (Level 11 ~ 30)\r\n#bgood|thelook|charisma#k (Level 11 ~ 30)\r\n#bspeak|talk|chat|say#k (Level 11 ~ 30)\r\n#bsleep|nap|sleepy#k (Level 11 ~ 30)\r\n#bgas#k (Level 21 ~ 30)"); - else if (selection == 20) - cm.sendNext("These are the commands for #rBaby Dragon#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bno|bad|badgirl|badboy#k (Level 1 ~ 30)\r\n#biloveyou|loveyou#k (Level 1 ~ 30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#bstupid|ihateyou|dummy#k (Level 1 ~ 30)\r\n#bcutie#k (Level 11 ~ 30)\r\n#btalk|chat|say#k (Level 11 ~ 30)\r\n#bsleep|sleepy|gotobed#k (Level 11 ~ 30)"); - else if (selection == 21) - cm.sendNext("These are the commands for #rGreen/Red/Blue Dragon#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 15 ~ 30)\r\n#bno|bad|badgirl|badboy#k (Level 15 ~ 30)\r\n#biloveyou|loveyou#k (Level 15 ~ 30)\r\n#bpoop#k (Level 15 ~ 30)\r\n#bstupid|ihateyou|dummy#k (Level 15 ~ 30)\r\n#btalk|chat|say#k (Level 15 ~ 30)\r\n#bsleep|sleepy|gotobed#k (Level 15 ~ 30)\r\n#bchange#k (Level 21 ~ 30)"); - else if (selection == 22) - cm.sendNext("These are the commands for #rBlack Dragon#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 15 ~ 30)\r\n#bno|bad|badgirl|badboy#k (Level 15 ~ 30)\r\n#biloveyou|loveyou#k (Level 15 ~ 30)\r\n#bpoop#k (Level 15 ~ 30)\r\n#bstupid|ihateyou|dummy#k (Level 15 ~ 30)\r\n#btalk|chat|say#k (Level 15 ~ 30)\r\n#bsleep|sleepy|gotobed#k (Level 15 ~ 30)\r\n#bcutie, change#k (Level 21 ~ 30)"); - else if (selection == 23) - cm.sendNext("These are the commands for #rJr. Reaper#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bno|bad|badgirl|badboy#k (Level 1 ~ 30)\r\n#bplaydead, poop#k (Level 1 ~ 30)\r\n#btalk|chat|say#k (Level 1 ~ 30)\r\n#biloveyou, hug#k (Level 1 ~ 30)\r\n#bsmellmyfeet, rockout, boo#k (Level 1 ~ 30)\r\n#btrickortreat#k (Level 1 ~ 30)\r\n#bmonstermash#k (Level 1 ~ 30)"); - else if (selection == 24) - cm.sendNext("These are the commands for #rPorcupine#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bno|bad|badgirl|badboy#k (Level 1 ~ 30)\r\n#biloveyou|hug|goodboy#k (Level 1 ~ 30)\r\n#btalk|chat|say#k (Level 1 ~ 30)\r\n#bcushion|sleep|knit|poop#k (Level 1 ~ 30)\r\n#bcomb|beach#k (Level 10 ~ 30)\r\n#btreeninja#k (Level 20 ~ 30)\r\n#bdart#k (Level 20 ~ 30)"); - else if (selection == 25) - cm.sendNext("These are the commands for #rSnowman#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bstupid, ihateyou, dummy#k (Level 1 ~ 30)\r\n#bloveyou, mylove, ilikeyou#k (Level 1 ~ 30)\r\n#bmerrychristmas#k (Level 1 ~ 30)\r\n#bcutie, adorable, cute, pretty#k (Level 1 ~ 30)\r\n#bcomb, beach/bad, no, badgirl, badboy#k (Level 1 ~ 30)\r\n#btalk, chat, say/sleep, sleepy, gotobed#k (Level 10 ~ 30)\r\n#bchang#k (Level 20 ~ 30)"); - else if (selection == 26) - cm.sendNext("These are the commands for #rSkunk#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad/no/badgirl/badboy#k (Level 1 ~ 30)\r\n#brestandrelax, poop#k (Level 1 ~ 30)\r\n#btalk/chat/say, iloveyou#k (Level 1 ~ 30)\r\n#bsnuggle/hug, sleep, goodboy#k (Level 1 ~ 30)\r\n#bfatty, blind, badbreath#k (Level 10 ~ 30)\r\n#bsuitup, bringthefunk#k (Level 20 ~ 30)"); - else if (selection == 27) { - status = 14; - cm.sendNext("In order to transfer the pet ability points, closeness and level, Pet AP Reset Scroll is required. If you take this\r\nscroll to Mar the Fairy in Ellinia, she will transfer the level and closeness of the pet to another one. I am especially giving it to you because I can feel your heart for your pet. However, I can't give this out for free. I can give you this book for 250,000 mesos. Oh, I almost forgot! Even if you have this book, it is no use if you do not have a new pet to transfer the Ability points."); - } - if(selection > 2 && selection < 27) - cm.dispose(); - } else if (status == 2) { - if(sel == 0) - cm.sendNextPrev("But Water of Life only comes out little at the very bottom of the World Tree, so I can't give him too much time in life... I know, it's very unfortunate... but even if it becomes a doll again I can always bring life back into it so be good to it while you're with it."); - else if (sel == 1) - cm.sendNextPrev("Talk to the pet, pay attention to it and its intimacy level will go up and eventually his overall level will go up too. As the intimacy level rises, the pet's overall level will rise soon after. As the overall level rises, one day the pet may even talk like a person a little bit, so try hard raising it. Of course it won't be easy doing so..."); - else if (sel == 2) - cm.sendNextPrev("After some time... that's correct, they stop moving. They just turn back to being a doll, after the effect of magic dies down and Water of Life dries out. But that doesn't mean it's stopped forever, because once you pour Water of Life over, it's going to be back alive."); - else if (sel == 27) - cm.sendYesNo("250,000 mesos will be deducted. Do you really want to buy?"); - } else if (status == 3) { - if (sel == 0) - cm.sendNextPrev("Oh yeah, they'll react when you give them special commands. You can scold them, love them... it all\r\ndepends on how you take care of them. They are afraid to leave their masters so be nice to them, show them love. They can get sad and lonely fast..."); - else if (sel == 1){ - cm.sendNextPrev("It may be a live doll but they also have life so they can feel the hunger too. #bFullness#k shows the level of hunger the pet's in. 100 is the max, and the lower it gets, it means that the pet is getting hungrier. After a while, it won't even follow your command and be on the offensive, so watch out over that."); - return; - }else if (sel == 2) - cm.sendNextPrev("Even if it someday moves again, it's sad to see them stop altogether. Please be nice to them while they are alive and moving. Feed them well, too. Isn't it nice to know that there's something alive that follows and listens to only you?"); - else if (sel == 27){ - if (cm.getMeso() < 250000 || !cm.canHold(4160011)) - cm.sendOk("Please check if your inventory has empty slot or you don't have enough mesos."); - else { - cm.gainMeso(-250000); - cm.gainItem(4160011, 1); - } - cm.dispose(); - } - } else if (status == 4){ - if(sel != 1) - cm.dispose(); - cm.sendNextPrev("Oh yes! Pets can't eat the normal human food. Instead my disciple #bDoofus#k sells #bPet Food#k at the Henesys Market so if you need food for your pet, find Henesys. It'll be a good idea to buy the food in advance and feed the pet before it gets really hungry."); - } else if (status == 5) - cm.sendNextPrev("Oh, and if you don't feed the pet for a long period of time, it goes back home by itself. You can take it out of its home and feed it but it's not really good for the pet's health, so try feeding him on a regular basis so it doesn't go down to that level, alright? I think this will do."); - else if (status == 6) + + if (mode == -1) { cm.dispose(); + } else { + if (mode == 0 && type > 0) { + cm.dispose(); + return; + } + if (mode == 1) + status++; + else + status--; + + if(status == -1) { + cm.sendNext("Hmm... are you raising one of my kids by any chance? I perfected a spell that uses Water of Life to blow life into a doll. People call it the #bPet#k. If you have one with you, feel free to ask me questions."); + } + else if (status == 0) + cm.sendSimple("What do you want to know more of?#b\r\n#L0#Tell me more about Pets.#l\r\n#L1#How do I raise Pets?#l\r\n#L2#Do Pets die too?#l\r\n#L3#What are the commands for Brown and Black Kitty?#l\r\n#L4#What are the commands for Brown Puppy?#l\r\n#L5#What are the commands for Pink and White Bunny?#l\r\n#L6#What are the commands for Mini Kargo?#l\r\n#L7#What are the commands for Rudolph and Dasher?#l\r\n#L8#What are the commands for Black Pig?#l\r\n#L9#What are the commands for Panda?#l\r\n#L10#What are the commands for Husky?#l\r\n#L11#What are the commands for Dino Boy and Dino Girl?#l\r\n#L12#What are the commands for Monkey?#l\r\n#L13#What are the commands for Turkey?#l\r\n#L14#What are the commands for White Tiger?#l\r\n#L15#What are the commands for Penguin?#l\r\n#L16#What are the commands for Golden Pig?#l\r\n#L17#What are the commands for Robot?#l\r\n#L18#What are the commands for Mini Yeti?#l\r\n#L19#What are the commands for Jr. Balrog?#l\r\n#L20#What are the commands for Baby Dragon?#l\r\n#L21#What are the commands for Green/Red/Blue Dragon?#l\r\n#L22#What are the commands for Black Dragon?#l\r\n#L23#What are the commands for Jr. Reaper?#l\r\n#L24#What are the commands for Porcupine?#l\r\n#L25#What are the commands for Snowman?#l\r\n#L26#What are the commands for Skunk?#l\r\n#L27#Please teach me about transferring pet ability points.#l"); + else if (status == 1) { + sel = selection; + if (selection == 0) { + status = 3; + cm.sendNext("So you want to know more about Pets. Long ago I made a doll, sprayed Water of Life on it, and cast spell on it to create a magical animal. I know it sounds unbelievable, but it's a doll that became an actual living thing. They understand and follow people very well."); + } else if (selection == 1) { + status = 6; + cm.sendNext("Depending on the command you give, pets can love it, hate, and display other kinds of reactions to it. If you give the pet a command and it follows you well, your intimacy goes up. Double click on the pet and you can check the intimacy, level, fullness and etc..."); + } else if (selection == 2) { + status = 11; + cm.sendNext("Dying... well, they aren't technically ALIVE per se, so I don't know if dying is the right term to use. They are dolls with my magical power and the power of Water of Life to become a live object. Of course while it's alive, it's just like a live animal..."); + } else if (selection == 3) + cm.sendNext("These are the commands for #rBrown Kitty and Black Kitty#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badgirl, badboy#k (Level 1 ~ 30)\r\n#bstupid, ihateyou, dummy#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1~30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#btalk, say, chat#k (Level 10 ~ 30)\r\n#bcutie#k (Level 10 ~ 30)\r\n#bup, stand, rise#k (Level 20 ~ 30)"); + else if (selection == 4) + cm.sendNext("These are the commands for #rBrown Puppy#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badgirl, badboy#k (Level 1 ~ 30)\r\n#bstupid, ihateyou, baddog, dummy#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1~30)\r\n#bpee#k (Level 1 ~ 30)\r\n#btalk, say, chat#k (Level 10 ~ 30)\r\n#bdown#k (Level 10 ~ 30)\r\n#bup, stand, rise#k (Level 20 ~ 30)"); + else if (selection == 5) + cm.sendNext("These are the commands for #rPink Bunny and White Bunny#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badgirl, badboy#k (Level 1 ~ 30)\r\n#bup, stand, rise#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1~30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#btalk, say, chat#k (Level 10 ~ 30)\r\n#bhug#k (Level 10 ~ 30)\r\n#bsleep, sleepy, gotobed#k (Level 20 ~ 30)"); + else if (selection == 6) + cm.sendNext("These are the commands for #rMini Kargo#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badgirl, badboy#k (Level 1 ~ 30)\r\n#bup, stand, rise#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1~30)\r\n#bpee#k (Level 1 ~ 30)\r\n#btalk, say, chat#k (Level 10 ~ 30)\r\n#bthelook, charisma#k (Level 10 ~ 30)\r\n#bdown#k (Level 10 ~ 30)\r\n#bgoodboy, goodgirl#k (Level 20 ~ 30)"); + else if (selection == 7) + cm.sendNext("These are the commands for #rRudolph and Dasher#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badgirl, badboy#k (Level 1 ~ 30)\r\n#bup, stand#k (Level 1 ~ 30)\r\n#bstupid, ihateyou, dummy#k (Level 1 ~ 30)\r\n#bmerryxmas, merrychristmas#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1~30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#btalk, say, chat#k (Level 11 ~ 30)\r\n#blonely, alone#k (Level 11 ~ 30)\r\n#bcutie#k (Level 11 ~ 30)\r\n#bmush, go#k (Level 21 ~ 30)"); + else if (selection == 8) + cm.sendNext("These are the commands for #rBlack Pig#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badgirl, badboy#k (Level 1 ~ 30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1~30)\r\n#bhand#k (Level 1 ~ 30)\r\n#bstupid, ihateyou, dummy#k (Level 1 ~ 30)\r\n#btalk, chat, say#k (Level 10 ~ 30)\r\n#bsmile#k (Level 10 ~ 30)\r\n#bthelook, charisma#k (Level 20 ~ 30)"); + else if (selection == 9) + cm.sendNext("These are the commands for #rPanda#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bchill, relax#k (Level 1 ~ 30)\r\n#bbad, no, badgirl, badboy#k (Level 1 ~ 30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1 ~ 30)\r\n#bup, stand, rise#k (Level 1 ~ 30)\r\n#btalk, chat, say#k (Level 10 ~ 30)\r\n#bletsplay#k (Level 10 ~ 30)\r\n#bmeh, bleh#k (Level 10 ~ 30)\r\n#bsleep#k (Level 20 ~ 30)"); + else if (selection == 10) + cm.sendNext("These are the commands for #rHusky#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badgirl, badboy#k (Level 1 ~ 30)\r\n#bstupid, ihateyou, baddog, dummy#k (Level 1 ~ 30)\r\n#bhand#k (Level 1 ~ 30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1 ~ 30)\r\n#bdown#k (Level 10 ~ 30)\r\n#btalk, chat, say#k (Level 10 ~ 30)\r\n#bup, stand, rise#k (Level 20 ~ 30)"); + else if (selection == 11) + cm.sendNext("These are the commands for #rDino Boy and Dino Girl#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badboy, badgirl#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1 ~ 30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#bsmile, laugh#k (Level 1 ~ 30)\r\n#bstupid, ihateyou, dummy#k (Level 1 ~ 30)\r\n#btalk, chat, say#k (Level 10 ~ 30)\r\n#bcutie#k (Level 10 ~ 30)\r\n#bsleep, nap, sleepy#k (Level 20 ~ 30)"); + else if (selection == 12) + cm.sendNext("These are the commands for #rMonkey#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#brest#k (Level 1 ~ 30)\r\n#bbad, no, badboy, badgirl#k (Level 1 ~ 30)\r\n#bpee#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1 ~ 30)\r\n#bup, stand#k (Level 1 ~ 30)\r\n#btalk, chat, say#k (Level 10 ~ 30)\r\n#bplay#k (Level 10 ~ 30)\r\n#bmelong#k (Level 10 ~ 30)\r\n#bsleep, gotobed, sleepy#k (Level 20 ~ 30)"); + else if (selection == 13) + cm.sendNext("These are the commands for #rTurkey#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bno, rudeboy, mischief#k (Level 1 ~ 30)\r\n#bstupid#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1 ~ 30)\r\n#bup, stand#k (Level 1 ~ 30)\r\n#btalk, chat, gobble#k (Level 10 ~ 30)\r\n#byes, goodboy#k (Level 10 ~ 30)\r\n#bsleepy, birdnap, doze#k (Level 20 ~ 30)\r\n#bbirdeye, thanksgiving, fly, friedbird, imhungry#k (Level 30)"); + else if (selection == 14) + cm.sendNext("These are the commands for #rWhite Tiger#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badboy, badgirl#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1 ~ 30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#brest, chill#k (Level 1 ~ 30)\r\n#bstupid, ihateyou, dummy#k (Level 1 ~ 30)\r\n#btalk, chat, say#k (Level 10 ~ 30)\r\n#bactsad, sadlook#k (Level 10 ~ 30)\r\n#bwait#k (Level 20 ~ 30)"); + else if (selection == 15) + cm.sendNext("These are the commands for #rPenguin#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badboy, badgirl#k (Level 1 ~ 30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#bup, stand, rise#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1 ~ 30)\r\n#btalk, chat, say#k (Level 10 ~ 30)\r\n#bhug, hugme#k (Level 10 ~ 30)\r\n#bwing, hand#k (Level 10 ~ 30)\r\n#bsleep#k (Level 20 ~ 30)\r\n#bkiss, smooch, muah#k (Level 20 ~ 30)\r\n#bfly#k (Level 20 ~ 30)\r\n#bcute, adorable#k (Level 20 ~ 30)"); + else if (selection == 16) + cm.sendNext("These are the commands for #rGolden Pig#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badboy, badgirl#k (Level 1 ~ 30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1 ~ 30)\r\n#btalk, chat, say#k (Level 11 ~ 30)\r\n#bloveme, hugme#k (Level 11 ~ 30)\r\n#bsleep, sleepy, gotobed#k (Level 21 ~ 30)\r\n#bignore / impressed / outofhere#k (Level 21 ~ 30)\r\n#broll, showmethemoney#k (Level 21 ~ 30)"); + else if (selection == 17) + cm.sendNext("These are the commands for #rRobot#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bup, stand, rise#k (Level 1 ~ 30)\r\n#bstupid, ihateyou, dummy#k (Level 1 ~ 30)\r\n#bbad, no, badgirl, badboy#k (Level 1 ~ 30)\r\n#battack, charge#k (Level 1 ~ 30)\r\n#biloveyou#k (Level 1 ~ 30)\r\n#bgood, thelook, charisma#k (Level 11 ~ 30)\r\n#bspeack, talk, chat, say#k (Level 11 ~ 30)\r\n#bdisguise, change, transform#k (Level 11 ~ 30)"); + else if (selection == 18) + cm.sendNext("These are the commands for #rMini Yeti#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad, no, badboy, badgirl#k (Level 1 ~ 30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#bdance, boogie, shakeit#k (Level 1 ~ 30)\r\n#bcute, cutie, pretty, adorable#k (Level 1 ~ 30)\r\n#biloveyou, likeyou, mylove#k (Level 1 ~ 30)\r\n#btalk, chat, say#k (Level 11 ~ 30)\r\n#bsleep, nap, sleepy, gotobed#k (Level 11 ~ 30)"); + else if (selection == 19) + cm.sendNext("These are the commands for #rJr. Balrog#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bliedown#k (Level 1 ~ 30)\r\n#bno|bad|badgirl|badboy#k (Level 1 ~ 30)\r\n#biloveyou|mylove|likeyou#k (Level 1 ~ 30)\r\n#bcute|cutie|pretty|adorable#k (Level 1 ~ 30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#bsmirk|crooked|laugh#k (Level 1 ~ 30)\r\n#bmelong#k (Level 11 ~ 30)\r\n#bgood|thelook|charisma#k (Level 11 ~ 30)\r\n#bspeak|talk|chat|say#k (Level 11 ~ 30)\r\n#bsleep|nap|sleepy#k (Level 11 ~ 30)\r\n#bgas#k (Level 21 ~ 30)"); + else if (selection == 20) + cm.sendNext("These are the commands for #rBaby Dragon#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bno|bad|badgirl|badboy#k (Level 1 ~ 30)\r\n#biloveyou|loveyou#k (Level 1 ~ 30)\r\n#bpoop#k (Level 1 ~ 30)\r\n#bstupid|ihateyou|dummy#k (Level 1 ~ 30)\r\n#bcutie#k (Level 11 ~ 30)\r\n#btalk|chat|say#k (Level 11 ~ 30)\r\n#bsleep|sleepy|gotobed#k (Level 11 ~ 30)"); + else if (selection == 21) + cm.sendNext("These are the commands for #rGreen/Red/Blue Dragon#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 15 ~ 30)\r\n#bno|bad|badgirl|badboy#k (Level 15 ~ 30)\r\n#biloveyou|loveyou#k (Level 15 ~ 30)\r\n#bpoop#k (Level 15 ~ 30)\r\n#bstupid|ihateyou|dummy#k (Level 15 ~ 30)\r\n#btalk|chat|say#k (Level 15 ~ 30)\r\n#bsleep|sleepy|gotobed#k (Level 15 ~ 30)\r\n#bchange#k (Level 21 ~ 30)"); + else if (selection == 22) + cm.sendNext("These are the commands for #rBlack Dragon#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 15 ~ 30)\r\n#bno|bad|badgirl|badboy#k (Level 15 ~ 30)\r\n#biloveyou|loveyou#k (Level 15 ~ 30)\r\n#bpoop#k (Level 15 ~ 30)\r\n#bstupid|ihateyou|dummy#k (Level 15 ~ 30)\r\n#btalk|chat|say#k (Level 15 ~ 30)\r\n#bsleep|sleepy|gotobed#k (Level 15 ~ 30)\r\n#bcutie, change#k (Level 21 ~ 30)"); + else if (selection == 23) + cm.sendNext("These are the commands for #rJr. Reaper#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bno|bad|badgirl|badboy#k (Level 1 ~ 30)\r\n#bplaydead, poop#k (Level 1 ~ 30)\r\n#btalk|chat|say#k (Level 1 ~ 30)\r\n#biloveyou, hug#k (Level 1 ~ 30)\r\n#bsmellmyfeet, rockout, boo#k (Level 1 ~ 30)\r\n#btrickortreat#k (Level 1 ~ 30)\r\n#bmonstermash#k (Level 1 ~ 30)"); + else if (selection == 24) + cm.sendNext("These are the commands for #rPorcupine#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bno|bad|badgirl|badboy#k (Level 1 ~ 30)\r\n#biloveyou|hug|goodboy#k (Level 1 ~ 30)\r\n#btalk|chat|say#k (Level 1 ~ 30)\r\n#bcushion|sleep|knit|poop#k (Level 1 ~ 30)\r\n#bcomb|beach#k (Level 10 ~ 30)\r\n#btreeninja#k (Level 20 ~ 30)\r\n#bdart#k (Level 20 ~ 30)"); + else if (selection == 25) + cm.sendNext("These are the commands for #rSnowman#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bstupid, ihateyou, dummy#k (Level 1 ~ 30)\r\n#bloveyou, mylove, ilikeyou#k (Level 1 ~ 30)\r\n#bmerrychristmas#k (Level 1 ~ 30)\r\n#bcutie, adorable, cute, pretty#k (Level 1 ~ 30)\r\n#bcomb, beach/bad, no, badgirl, badboy#k (Level 1 ~ 30)\r\n#btalk, chat, say/sleep, sleepy, gotobed#k (Level 10 ~ 30)\r\n#bchang#k (Level 20 ~ 30)"); + else if (selection == 26) + cm.sendNext("These are the commands for #rSkunk#k. The level mentioned next to the command shows the pet level required for it to respond.\r\n#bsit#k (Level 1 ~ 30)\r\n#bbad/no/badgirl/badboy#k (Level 1 ~ 30)\r\n#brestandrelax, poop#k (Level 1 ~ 30)\r\n#btalk/chat/say, iloveyou#k (Level 1 ~ 30)\r\n#bsnuggle/hug, sleep, goodboy#k (Level 1 ~ 30)\r\n#bfatty, blind, badbreath#k (Level 10 ~ 30)\r\n#bsuitup, bringthefunk#k (Level 20 ~ 30)"); + else if (selection == 27) { + status = 14; + cm.sendNext("In order to transfer the pet ability points, closeness and level, Pet AP Reset Scroll is required. If you take this\r\nscroll to Mar the Fairy in Ellinia, she will transfer the level and closeness of the pet to another one. I am especially giving it to you because I can feel your heart for your pet. However, I can't give this out for free. I can give you this book for 250,000 mesos. Oh, I almost forgot! Even if you have this book, it is no use if you do not have a new pet to transfer the Ability points."); + } + if(selection > 2 && selection < 27) + cm.dispose(); + } else if (status == 2) { + if(sel == 0) + cm.sendNextPrev("But Water of Life only comes out little at the very bottom of the World Tree, so I can't give him too much time in life... I know, it's very unfortunate... but even if it becomes a doll again I can always bring life back into it so be good to it while you're with it."); + else if (sel == 1) + cm.sendNextPrev("Talk to the pet, pay attention to it and its intimacy level will go up and eventually his overall level will go up too. As the intimacy level rises, the pet's overall level will rise soon after. As the overall level rises, one day the pet may even talk like a person a little bit, so try hard raising it. Of course it won't be easy doing so..."); + else if (sel == 2) + cm.sendNextPrev("After some time... that's correct, they stop moving. They just turn back to being a doll, after the effect of magic dies down and Water of Life dries out. But that doesn't mean it's stopped forever, because once you pour Water of Life over, it's going to be back alive."); + else if (sel == 27) + cm.sendYesNo("250,000 mesos will be deducted. Do you really want to buy?"); + } else if (status == 3) { + if (sel == 0) + cm.sendNextPrev("Oh yeah, they'll react when you give them special commands. You can scold them, love them... it all\r\ndepends on how you take care of them. They are afraid to leave their masters so be nice to them, show them love. They can get sad and lonely fast..."); + else if (sel == 1){ + cm.sendNextPrev("It may be a live doll but they also have life so they can feel the hunger too. #bFullness#k shows the level of hunger the pet's in. 100 is the max, and the lower it gets, it means that the pet is getting hungrier. After a while, it won't even follow your command and be on the offensive, so watch out over that."); + return; + }else if (sel == 2) + cm.sendNextPrev("Even if it someday moves again, it's sad to see them stop altogether. Please be nice to them while they are alive and moving. Feed them well, too. Isn't it nice to know that there's something alive that follows and listens to only you?"); + else if (sel == 27){ + if (cm.getMeso() < 250000 || !cm.canHold(4160011)) + cm.sendOk("Please check if your inventory has empty slot or you don't have enough mesos."); + else { + cm.gainMeso(-250000); + cm.gainItem(4160011, 1); + } + cm.dispose(); + } + } else if (status == 4){ + if(sel != 1) + cm.dispose(); + cm.sendNextPrev("Oh yes! Pets can't eat the normal human food. Instead my disciple #bDoofus#k sells #bPet Food#k at the Henesys Market so if you need food for your pet, find Henesys. It'll be a good idea to buy the food in advance and feed the pet before it gets really hungry."); + } else if (status == 5) + cm.sendNextPrev("Oh, and if you don't feed the pet for a long period of time, it goes back home by itself. You can take it out of its home and feed it but it's not really good for the pet's health, so try feeding him on a regular basis so it doesn't go down to that level, alright? I think this will do."); + else + cm.dispose(); + } } \ No newline at end of file diff --git a/scripts/npc/1032102.js b/scripts/npc/1032102.js index 2d0e7a8acf..b443326afa 100644 --- a/scripts/npc/1032102.js +++ b/scripts/npc/1032102.js @@ -12,7 +12,7 @@ importPackage(Packages.client); importPackage(Packages.server); -var status = 0; +var status; function start() { status = -1; @@ -23,7 +23,7 @@ function action(mode, type, selection) { if (mode == -1) { cm.dispose(); } else { - if (mode == 0) { + if (mode == 0 && type > 0) { cm.sendOk("Alright, see you next time."); cm.dispose(); return; @@ -32,21 +32,22 @@ function action(mode, type, selection) { status++; else status--; + if (status == 0) { - cm.sendYesNo("I am Mar the Fairy. If you have a dragon at level 15 or higher and a rock of evolution. I can evolve your dragon. If you are lucky, you may even get a black one! Would you like me to do so?"); + cm.sendYesNo("I am Mar the Fairy. If you have a dragon at level 15 or higher and a rock of evolution, I can evolve your dragon. If you are lucky, you may even get a black one! Would you like me to do so?"); } else if (status == 1) { if (cm.haveItem(5000028, 1)) { cm.gainItem(5000028, -1); cm.gainItem(5000029, 1); cm.sendOk("I don't know how you got that egg, but it has hatched, apparently!"); cm.dispose(); - } else if (cm.getChar().getPet() == null) { - cm.sendOk("Make sure your pet is equipped."); + } else if (cm.getPlayer().getPet(0) == null) { + cm.sendOk("Make sure your pet is equipped on slot 1."); cm.dispose(); - } else if (cm.getChar().getPet().getItemId() < 5000029 || cm.getChar().getPet().getItemId() > 5000033 || !cm.haveItem(5380000,1)) { - cm.sendOk("You do not meet the requirements. You need #i5380000##t5380000#, as well as either one of #d#i5000029##t5000029##k, #g#i5000030##t5000030##k, #r#i5000031##t5000031##k, #b#i5000032##t5000032##k, or #e#i5000033##t5000033##n equipped. Please come back when you do."); + } else if (cm.getPlayer().getPet(0).getItemId() < 5000029 || cm.getPlayer().getPet(0).getItemId() > 5000033 || !cm.haveItem(5380000,1)) { + cm.sendOk("You do not meet the requirements. You need #i5380000##t5380000#, as well as either one of #d#i5000029##t5000029##k, #g#i5000030##t5000030##k, #r#i5000031##t5000031##k, #b#i5000032##t5000032##k, or #e#i5000033##t5000033##n equipped on slot 1. Please come back when you do."); cm.dispose(); - } else if (cm.getChar().getPet().getLevel() < 15) { + } else if (cm.getPlayer().getPet(0).getLevel() < 15) { cm.sendOk("Your pet must be level 15 or above to evolve."); cm.dispose(); } else if (cm.haveItem(5000029,2) || cm.haveItem(5000030,2) || cm.haveItem(5000031,2) || cm.haveItem(5000032,2) || cm.haveItem(5000033,2)) { @@ -61,15 +62,16 @@ function action(mode, type, selection) { } } if(i == 3) { - cm.getPlayer().message("Pet could not be evolved."); + cm.sendOk("You either don't have a pet dragon ready to evolve or you lack #b#t5380000##k."); + cm.dispose(); return; } - var id = cm.getPlayer().getPet().getItemId(); - var name = cm.getPlayer().getPet().getName(); - var level = cm.getPlayer().getPet().getLevel(); - var closeness = cm.getPlayer().getPet().getCloseness(); - var fullness = cm.getPlayer().getPet().getFullness(); + var id = cm.getPlayer().getPet(i).getItemId(); + //var name = cm.getPlayer().getPet(i).getName(); + //var level = cm.getPlayer().getPet(i).getLevel(); + //var closeness = cm.getPlayer().getPet(i).getCloseness(); + //var fullness = cm.getPlayer().getPet(i).getFullness(); //MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); if (id < 5000029 || id > 5000033) { cm.sendOk("Something wrong, try again."); @@ -94,10 +96,8 @@ function action(mode, type, selection) { name = MapleItemInformationProvider.getInstance().getName(after); }*/ - //cm.unequipPet(cm.getC()); - cm.getPlayer().unequipAllPets(); //IMPORTANT, you can bug/crash yourself if you don't unequip the pet to be deleted cm.gainItem(5380000, -1); - qm.evolvePet(i, after); + cm.evolvePet(i, after); cm.sendOk("Your dragon has now evolved!! It used to be a #i" + id + "##t" + id + "#, and now it's a #i" + after + "##t" + after + "#!"); cm.dispose(); diff --git a/scripts/npc/commands.js b/scripts/npc/commands.js index 6873c95743..62b088995f 100644 --- a/scripts/npc/commands.js +++ b/scripts/npc/commands.js @@ -124,6 +124,7 @@ function writeSolaxiaCommandsLv3() { //GM addCommand("expeds", ""); addCommand("kill", ""); addCommand("seed", ""); + addCommand("maxenergy", ""); addCommand("killall", ""); addCommand("notice", ""); addCommand("rip", ""); diff --git a/scripts/quest/21101.js b/scripts/quest/21101.js index 9db6ca9be6..f533215526 100644 --- a/scripts/quest/21101.js +++ b/scripts/quest/21101.js @@ -51,8 +51,8 @@ function start(mode, type, selection) { qm.getPlayer().setRemainingSp((qm.getPlayer().getLevel() - 10) * 3 + 1); qm.getPlayer().setMaxHp(qm.getPlayer().getMaxHp() + 275); qm.getPlayer().setMaxMp(qm.getPlayer().getMaxMp() + 15); - qm.teachSkill(21000000, 0, 10, -1); - qm.teachSkill(21001003, 0, 20, -1); + qm.teachSkill(21000000, 0, 10, -1); + qm.teachSkill(21001003, 0, 20, -1); //qm.getPlayer().changeSkillLevel(SkillFactory.getSkill(20009000), 0, -1); //qm.getPlayer().changeSkillLevel(SkillFactory.getSkill(20009000), 1, 0); //qm.showInfo("You have acquired the Pig's Weakness skill."); diff --git a/sql/db_drops.sql b/sql/db_drops.sql index f587678cea..29e4e9e8b2 100644 --- a/sql/db_drops.sql +++ b/sql/db_drops.sql @@ -19706,7 +19706,6 @@ USE `maplesolaxia`; (6090004, 0, 1000, 1100, 0, 400000), (5090000, 0, 800, 920, 0, 400000), (5090001, 0, 1700, 1750, 0, 400000), - (7090000, 1402015, 1, 1, 0, 8500), (7090000, 1092016, 1, 1, 0, 8500), (7090000, 1382039, 1, 1, 0, 8500), @@ -19746,7 +19745,31 @@ USE `maplesolaxia`; (8090000, 2044809, 1, 1, 0, 4500), (8090000, 2022130, 1, 1, 0, 200000), (8090000, 2022191, 1, 1, 0, 200000), -(8090000, 0, 1000, 1100, 0, 400000); +(8090000, 0, 1000, 1100, 0, 400000), +(9400549, 2290045, 1, 1, 0, 4000), +(8160000, 2290081, 1, 1, 0, 4000), +(9400575, 2290087, 1, 1, 0, 4000), +(8170000, 2290109, 1, 1, 0, 4000), +(8160000, 2290045, 1, 1, 0, 4000), +(9400575, 2290081, 1, 1, 0, 4000), +(8170000, 2290087, 1, 1, 0, 4000), +(9400549, 2290109, 1, 1, 0, 4000), +(8090000, 2290045, 1, 1, 0, 4000), +(8220002, 2290081, 1, 1, 0, 4000), +(7090000, 2290087, 1, 1, 0, 4000), +(8220009, 2290109, 1, 1, 0, 4000), +(8190003, 2290045, 1, 1, 0, 4000), +(9400582, 2290081, 1, 1, 0, 4000), +(9400580, 2290087, 1, 1, 0, 4000), +(8200008, 2290109, 1, 1, 0, 4000), +(9400120, 2290045, 1, 1, 0, 10000), +(9400300, 2290081, 1, 1, 0, 10000), +(9400121, 2290087, 1, 1, 0, 10000), +(9400014, 2290109, 1, 1, 0, 10000), +(9400300, 2290045, 1, 1, 0, 10000), +(9400121, 2290081, 1, 1, 0, 10000), +(9400014, 2290087, 1, 1, 0, 10000), +(9400120, 2290109, 1, 1, 0, 10000); # (dropperid, itemid, minqty, maxqty, questid, chance) diff --git a/src/client/MapleCharacter.java b/src/client/MapleCharacter.java index a2e92291ea..8245fe9b82 100644 --- a/src/client/MapleCharacter.java +++ b/src/client/MapleCharacter.java @@ -153,16 +153,6 @@ import server.maps.MapleMapItem; public class MapleCharacter extends AbstractAnimatedMapleMapObject { private static final String LEVEL_200 = "[Congrats] %s has reached Level 200! Congratulate %s on such an amazing achievement!"; - // MapleStory default keyset - private static final int[] DEFAULT_KEY = {18, 65, 2, 23, 3, 4, 5, 6, 16, 17, 19, 25, 26, 27, 31, 34, 35, 37, 38, 40, 43, 44, 45, 46, 50, 56, 59, 60, 61, 62, 63, 64, 57, 48, 29, 7, 24, 33, 41, 39}; - private static final int[] DEFAULT_TYPE = {4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 4, 4, 5, 6, 6, 6, 6, 6, 6, 5, 4, 5, 4, 4, 4, 4, 4}; - private static final int[] DEFAULT_ACTION = {0, 106, 10, 1, 12, 13, 18, 24, 8, 5, 4, 19, 14, 15, 2, 17, 11, 3, 20, 16, 9, 50, 51, 6, 7, 53, 100, 101, 102, 103, 104, 105, 54, 22, 52, 21, 25, 26, 23, 27}; - - // MapleSolaxiaV2 custom keyset - private static final int[] CUSTOM_KEY = {2, 3, 4, 5, 31, 56, 59, 32, 42, 6, 17, 29, 30, 41, 50, 60, 61, 62, 63, 64, 65, 16, 7, 8}; - private static final int[] CUSTOM_TYPE = {4, 4, 4, 4, 5, 5, 6, 5, 5, 4, 4, 4, 5, 4, 4, 6, 6, 6, 6, 6, 6, 4, 4, 4}; - private static final int[] CUSTOM_ACTION = {1, 0, 3, 2, 53, 54, 100, 52, 51, 19, 5, 9, 50, 7, 22, 101, 102, 103, 104, 105, 106, 8, 17, 26}; - private static final String[] BLOCKED_NAMES = {"admin", "owner", "moderator", "intern", "donor", "administrator", "help", "helper", "alert", "notice", "maplestory", "Solaxia", "fuck", "wizet", "fucking", "negro", "fuk", "fuc", "penis", "pussy", "asshole", "gay", "nigger", "homo", "suck", "cum", "shit", "shitty", "condom", "security", "official", "rape", "nigga", "sex", "tit", "boner", "orgy", "clit", "asshole", "fatass", "bitch", "support", "gamemaster", "cock", "gaay", "gm", "operate", "master", "sysop", "party", "GameMaster", "community", "message", "event", "test", "meso", "Scania", "renewal", "yata", "AsiaSoft", "henesys"}; @@ -380,14 +370,14 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { int[] selectedAction; if(ServerConstants.USE_CUSTOM_KEYSET) { - selectedKey = CUSTOM_KEY; - selectedType = CUSTOM_TYPE; - selectedAction = CUSTOM_ACTION; + selectedKey = GameConstants.getCustomKey(true); + selectedType = GameConstants.getCustomType(true); + selectedAction = GameConstants.getCustomAction(true); } else { - selectedKey = DEFAULT_KEY; - selectedType = DEFAULT_TYPE; - selectedAction = DEFAULT_ACTION; + selectedKey = GameConstants.getCustomKey(false); + selectedType = GameConstants.getCustomType(false); + selectedAction = GameConstants.getCustomAction(false); } for (int i = 0; i < selectedKey.length; i++) { @@ -5297,14 +5287,14 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { int[] selectedAction; if(ServerConstants.USE_CUSTOM_KEYSET) { - selectedKey = CUSTOM_KEY; - selectedType = CUSTOM_TYPE; - selectedAction = CUSTOM_ACTION; + selectedKey = GameConstants.getCustomKey(true); + selectedType = GameConstants.getCustomType(true); + selectedAction = GameConstants.getCustomAction(true); } else { - selectedKey = DEFAULT_KEY; - selectedType = DEFAULT_TYPE; - selectedAction = DEFAULT_ACTION; + selectedKey = GameConstants.getCustomKey(false); + selectedType = GameConstants.getCustomType(false); + selectedAction = GameConstants.getCustomAction(false); } ps = con.prepareStatement("INSERT INTO keymap (characterid, `key`, `type`, `action`) VALUES (?, ?, ?, ?)"); @@ -5736,7 +5726,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { } public void setDojoEnergy(int x) { - this.dojoEnergy = x; + this.dojoEnergy = Math.min(x, 10000); } public void setDojoPoints(int x) { diff --git a/src/client/command/Commands.java b/src/client/command/Commands.java index 5188b3f8a6..fce1a57df8 100644 --- a/src/client/command/Commands.java +++ b/src/client/command/Commands.java @@ -1655,6 +1655,12 @@ public class Commands { } } break; + + case "maxenergy": + c.getPlayer().setDojoEnergy(10000); + c.announce(MaplePacketCreator.getEnergy("energy", 10000)); + System.out.println("gauge " + player.getDojoEnergy()); + break; case "killall": List monsters = player.getMap().getMapObjectsInRange(player.getPosition(), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.MONSTER)); @@ -1976,7 +1982,6 @@ public class Commands { public static boolean executeSolaxiaCommandLv4(Channel cserv, Server srv, MapleClient c, String[] sub) { //SuperGM MapleCharacter player = c.getPlayer(); - MapleCharacter victim; switch(sub[0]) { case "servermessage": diff --git a/src/client/inventory/MaplePet.java b/src/client/inventory/MaplePet.java index c6bbf8c5dd..648d5cd213 100644 --- a/src/client/inventory/MaplePet.java +++ b/src/client/inventory/MaplePet.java @@ -81,6 +81,19 @@ public class MaplePet extends Item { } } + public void deleteFromDb() { + try { + Connection con = DatabaseConnection.getConnection(); + PreparedStatement ps = con.prepareStatement("DELETE FROM pets WHERE `petid` = ?"); + ps.setInt(1, this.getUniqueId()); + ps.executeUpdate(); + ps.close(); + con.close(); + } catch (SQLException ex) { + ex.printStackTrace(); + } + } + public void saveToDb() { try { Connection con = DatabaseConnection.getConnection(); @@ -210,6 +223,7 @@ public class MaplePet extends Item { } owner.getMap().broadcastMessage(MaplePacketCreator.commandResponse(owner.getId(), slot, type, enjoyed)); + if(owner.getMount() != null) owner.getMap().broadcastMessage(MaplePacketCreator.updateMount(owner.getId(), owner.getMount(), false)); saveToDb(); Item petz = owner.getInventory(MapleInventoryType.CASH).getItem(getPosition()); diff --git a/src/constants/GameConstants.java b/src/constants/GameConstants.java index 03c2197531..0a938e909a 100644 --- a/src/constants/GameConstants.java +++ b/src/constants/GameConstants.java @@ -12,18 +12,40 @@ public class GameConstants { private static final int[] MESO_RATE_GAIN = {1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 66, 78, 91, 105}; private static final int[] EXP_RATE_GAIN = {1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610}; //fibonacci :3 - public static int getPlayerBonusMesoRate(int slot) { - return(MESO_RATE_GAIN[slot]); - } - public static int getPlayerBonusDropRate(int slot) { return(DROP_RATE_GAIN[slot]); } + public static int getPlayerBonusMesoRate(int slot) { + return(MESO_RATE_GAIN[slot]); + } + public static int getPlayerBonusExpRate(int slot) { return(EXP_RATE_GAIN[slot]); } + // MapleStory default keyset + private static final int[] DEFAULT_KEY = {18, 65, 2, 23, 3, 4, 5, 6, 16, 17, 19, 25, 26, 27, 31, 34, 35, 37, 38, 40, 43, 44, 45, 46, 50, 56, 59, 60, 61, 62, 63, 64, 57, 48, 29, 7, 24, 33, 41, 39}; + private static final int[] DEFAULT_TYPE = {4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 4, 4, 5, 6, 6, 6, 6, 6, 6, 5, 4, 5, 4, 4, 4, 4, 4}; + private static final int[] DEFAULT_ACTION = {0, 106, 10, 1, 12, 13, 18, 24, 8, 5, 4, 19, 14, 15, 2, 17, 11, 3, 20, 16, 9, 50, 51, 6, 7, 53, 100, 101, 102, 103, 104, 105, 54, 22, 52, 21, 25, 26, 23, 27}; + + // MapleSolaxiaV2 custom keyset + private static final int[] CUSTOM_KEY = {2, 3, 4, 5, 31, 56, 59, 32, 42, 6, 17, 29, 30, 41, 50, 60, 61, 62, 63, 64, 65, 16, 7, 9, 13, 8}; + private static final int[] CUSTOM_TYPE = {4, 4, 4, 4, 5, 5, 6, 5, 5, 4, 4, 4, 5, 4, 4, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4}; + private static final int[] CUSTOM_ACTION = {1, 0, 3, 2, 53, 54, 100, 52, 51, 19, 5, 9, 50, 7, 22, 101, 102, 103, 104, 105, 106, 8, 17, 26, 20, 4}; + + public static int[] getCustomKey(boolean customKeyset) { + return(customKeyset ? CUSTOM_KEY : DEFAULT_KEY); + } + + public static int[] getCustomType(boolean customKeyset) { + return(customKeyset ? CUSTOM_TYPE : DEFAULT_TYPE); + } + + public static int[] getCustomAction(boolean customKeyset) { + return(customKeyset ? CUSTOM_ACTION : DEFAULT_ACTION); + } + private static final int[] mobHpVal = {0, 15, 20, 25, 35, 50, 65, 80, 95, 110, 125, 150, 175, 200, 225, 250, 275, 300, 325, 350, 375, 405, 435, 465, 495, 525, 580, 650, 720, 790, 900, 990, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2520, 2640, 2760, 2880, 3000, 3200, 3400, 3600, 3800, 4000, 4300, 4600, 4900, 5200, @@ -115,6 +137,10 @@ public class GameConstants { return skill >= 9001000 && skill <= 9101008 || skill >= 8001000 && skill <= 8001001; } + public static boolean isBossRush(int mapid) { + return mapid >= 970030100 && mapid <= 970042711; + } + public static boolean isDojo(int mapid) { return mapid >= 925020100 && mapid <= 925023814; } diff --git a/src/constants/ServerConstants.java b/src/constants/ServerConstants.java index 3090bc5b4e..b47b469c5d 100644 --- a/src/constants/ServerConstants.java +++ b/src/constants/ServerConstants.java @@ -8,7 +8,7 @@ public class ServerConstants { public static String DB_URL = ""; public static String DB_USER = ""; public static String DB_PASS = ""; - public static final short DB_EXPERIMENTAL_POOLS = 4; //[EXPERIMENTAL] Installs a set number of database drivers/pools to hub connections. Set 0 to default. + public static final boolean DB_EXPERIMENTAL_POOL = true; //[EXPERIMENTAL] Installs a connection pool to hub DB connections. Set false to default. //World And Version public static short VERSION = 83; @@ -30,7 +30,7 @@ public class ServerConstants { public static boolean JAVA_8; public static boolean SHUTDOWNHOOK; - //Gameplay Configuration + //Server Flags public static final boolean USE_CUSTOM_KEYSET = true; //Enables auto-setup of the MapleSolaxiaV2's custom keybindings when creating characters. public static final boolean USE_MAXRANGE_ECHO_OF_HERO = true; public static final boolean USE_MAXRANGE = true; //Will send and receive packets from all events of a map, rather than those of only view range. @@ -46,11 +46,19 @@ public class ServerConstants { public static final boolean USE_AUTOBAN = false; //Commands the server to detect infractors automatically. public static final boolean USE_ANOTHER_AUTOASSIGN = true; //Based on distributing AP accordingly to required secondary stat on equipments. public static final boolean USE_REFRESH_RANK_MOVE = true; - public static final boolean USE_PERFECT_PITCH = true; //For lvl 30 or above, each lvlup player gains 1 perfect pitch. public static final boolean USE_PERMISSIVE_BUFFS = false; //WARNING: Allows players that does not have increased certain buff-type skills to use it's effect. Used mainly on buff-cast commands, however making this active may generate a source for possible client-edited exploits. public static final boolean USE_ENFORCE_MDOOR_POSITION = true; //Forces mystic door to be spawned near spawnpoints. (since things bugs out other way, and this helps players locate the door faster) public static final boolean USE_ERASE_UNTRADEABLE_DROP = true; //Forces flagged untradeable items to disappear when dropped. + //Server Rates And Experience + public static final int EXP_RATE = 10; + public static final int MESO_RATE = 10; + public static final int DROP_RATE = 10; + public static final int BOSS_DROP_RATE = 20; + public static final int PARTY_EXPERIENCE_MOD = 1; //Change for event stuff. + public static final double EQUIP_EXPERIENCE_MOD = 10.0; //Rate for equipment exp needed, grows linearly. Set 1.0 for default (about 100~200 same-level range mobs killed to pass equip from level 1 to 2). + public static final double PQ_BONUS_EXP_MOD = 0.5; + public static final int MAX_AP = 20000; //Max AP allotted on the auto-assigner. public static final int MAX_EVENT_LEVELS = 8; //Event has different levels of rewarding system. public static final long BLOCK_NPC_RACE_CONDT = (long)(0.5 * 1000); //Time the player client must wait before reopening a conversation with an NPC. @@ -61,16 +69,26 @@ public class ServerConstants { public static final int ITEM_MONITOR_TIME = 5 * 60 * 1000; //Interval between item monitoring task on maps, which checks for dangling item objects on the map item history. public static final int ITEM_LIMIT_ON_MAP = 250; //Max number of items allowed on a map. - //Some Gameplay Enhancing Configuration + //Some Gameplay Enhancing Configurations + //Scroll Configuration public static final boolean USE_PERFECT_SCROLLING = true; //Scrolls doesn't use slots upon failure. public static final boolean USE_ENHANCED_CHSCROLL = true; //Equips even more powerful with chaos upgrade. public static final boolean USE_ENHANCED_CRAFTING = true; //Applys chaos scroll on every equip crafted. + + //Beginner Skills Configuration public static final boolean USE_ULTRA_NIMBLE_FEET = true; //Haste-like speed & jump upgrade. public static final boolean USE_ULTRA_RECOVERY = true; //Massive recovery amounts overtime. public static final boolean USE_ULTRA_THREE_SNAILS = true; //Massive damage on shell toss. + + //Character Configuration public static final boolean USE_ADD_SLOTS_BY_LEVEL = true; //Slots are added each 20 levels. public static final boolean USE_ADD_RATES_BY_LEVEL = true; //Rates are added each 20 levels. public static final boolean USE_STACK_COUPON_RATES = true; //Multiple coupons effects builds up together. + public static final boolean USE_PERFECT_PITCH = true; //For lvl 30 or above, each lvlup grants player 1 perfect pitch. + public static final int FAME_GAIN_BY_QUEST = 4; //Fame gain each N quest completes, set 0 to disable. + public static final int SCROLL_CHANCE_RATE = 10; //Number of rolls for success on a scroll, set 0 for default. + + //Equipment Configuration public static final boolean USE_EQUIPMNT_LVLUP_SLOTS = true;//Equips can upgrade slots at level up. public static final boolean USE_EQUIPMNT_LVLUP_POWER = true;//Enable more powerful stats upgrades at equip level up. public static final boolean USE_SPIKES_AVOID_BANISH = true; //Shoes equipped with spikes blocks mobs from banishing wearer. @@ -80,8 +98,6 @@ public class ServerConstants { public static final int USE_EQUIPMNT_LVLUP = 7; //All equips lvlup at max level of N, set 1 to disable. public static final byte CHAIR_EXTRA_HEAL_HP = 70; //Each chair extra heal proc increasing HP. public static final byte CHAIR_EXTRA_HEAL_MP = 42; //Each chair extra heal proc increasing MP. - public static final int FAME_GAIN_BY_QUEST = 4; //Fame gain each N quest completes, set 0 to disable. - public static final int SCROLL_CHANCE_RATE = 10; //Number of rolls for success on a scroll, set 0 for default. //Pet Auto-Pot Recovery Rates public static final double PET_AUTOHP_RATIO = 0.99; //Will automatically consume potions until given ratio of the MaxHP/MaxMP is reached. @@ -89,20 +105,13 @@ public class ServerConstants { //Dojo Configuration public static final boolean USE_DEADLY_DOJO = false; //Should bosses really use 1HP,1MP attacks in dojo? + public static final int DOJO_ENERGY_ATK = 100; //Dojo energy gain when deal attack + public static final int DOJO_ENERGY_DMG = 20; //Dojo energy gain when recv attack - //Pet Hungry Configuration + //Pet Hunger Configuration public static final boolean PETS_NEVER_HUNGRY = false; //If true, pets and mounts will never grow hungry. public static final boolean GM_PETS_NEVER_HUNGRY = true; //If true, pets and mounts owned by GMs will never grow hungry. - //Rates And Experience - public static final int EXP_RATE = 10; - public static final int MESO_RATE = 10; - public static final int DROP_RATE = 10; - public static final int BOSS_DROP_RATE = 20; - public static final int PARTY_EXPERIENCE_MOD = 1; //Change for event stuff. - public static final double EQUIP_EXPERIENCE_MOD = 10.0; //Rate for equipment exp needed, grows linearly. Set 1.0 for default (about 100~200 same-level range mobs killed to pass equip from level 1 to 2). - public static final double PQ_BONUS_EXP_MOD = 0.5; - //Event End Timestamp public static final long EVENT_END_TIMESTAMP = 1428897600000L; diff --git a/src/constants/skills/Beginner.java b/src/constants/skills/Beginner.java index ab8e1056da..5b943d525d 100644 --- a/src/constants/skills/Beginner.java +++ b/src/constants/skills/Beginner.java @@ -35,7 +35,7 @@ public class Beginner { public static final int ECHO_OF_HERO = 1005; public static final int BAMBOO_RAIN = 1009; public static final int INVINCIBLE_BARRIER = 1010; - public static final int BERSERK_FURY = 1011; + public static final int POWER_EXPLOSION = 1011; public static final int SPACESHIP = 1013; public static final int SPACE_DASH = 1014; public static final int YETI_MOUNT1 = 1017; diff --git a/src/constants/skills/Evan.java b/src/constants/skills/Evan.java index 79f9f18591..4a3537e849 100644 --- a/src/constants/skills/Evan.java +++ b/src/constants/skills/Evan.java @@ -13,7 +13,7 @@ public class Evan { public static final int MAKER = 20011007; public static final int BAMBOO_THRUST = 20011009; public static final int INVINCIBLE_BARRIER = 20011010; - public static final int BERSERK_FURY = 20011011; + public static final int POWER_EXPLOSION = 20011011; // EVAN2 public static final int DRAGON_SOUL = 22000000; public static final int MAGIC_MISSILE = 22001001; diff --git a/src/constants/skills/Legend.java b/src/constants/skills/Legend.java index a6f6c45a74..5f12caa540 100644 --- a/src/constants/skills/Legend.java +++ b/src/constants/skills/Legend.java @@ -35,7 +35,8 @@ public class Legend { public static final int JUMP_DOWN = 20001006; public static final int MAKER = 20001007; public static final int BAMBOO_THRUST = 20001009; - public static final int INVICIBLE_BARRIER = 20001010; + public static final int INVICIBLE_BARRIER = 20001010; + public static final int POWER_EXPLOSION = 20011011; public static final int METEO_SHOWER = 20001011; public static final int BLESSING_OF_THE_FAIRY = 20000012; public static final int TUTORIAL_SKILL1 = 20000014; diff --git a/src/constants/skills/Noblesse.java b/src/constants/skills/Noblesse.java index dc801d677e..1e9901ebaf 100644 --- a/src/constants/skills/Noblesse.java +++ b/src/constants/skills/Noblesse.java @@ -35,7 +35,7 @@ public class Noblesse { public static final int MAKER = 10001007; public static final int BAMBOO_RAIN = 10001009; public static final int INVINCIBLE_BARRIER = 10001010; - public static final int BERSERK_FURY = 10001011; + public static final int POWER_EXPLOSION = 10001011; public static final int SPACESHIP = 1001014; public static final int SPACE_DASH = 1001015; public static final int YETI_MOUNT1 = 10001019; diff --git a/src/net/server/channel/handlers/CloseRangeDamageHandler.java b/src/net/server/channel/handlers/CloseRangeDamageHandler.java index 2d11c8dec4..109bc677ec 100644 --- a/src/net/server/channel/handlers/CloseRangeDamageHandler.java +++ b/src/net/server/channel/handlers/CloseRangeDamageHandler.java @@ -68,6 +68,14 @@ public final class CloseRangeDamageHandler extends AbstractDealDamageHandler { } } + if (c.getPlayer().getDojoEnergy() < 10000 && (attack.skill == 1009 || attack.skill == 10001009 || attack.skill == 20001009)) // PE hacking or maybe just lagging + return; + if (player.getMap().isDojoMap() && attack.numAttacked > 0) { + player.setDojoEnergy(player.getDojoEnergy() + ServerConstants.DOJO_ENERGY_ATK); + c.announce(MaplePacketCreator.getEnergy("energy", player.getDojoEnergy())); + System.out.println("gauge " + player.getDojoEnergy()); + } + player.getMap().broadcastMessage(player, MaplePacketCreator.closeRangeAttack(player, attack.skill, attack.skilllevel, attack.stance, attack.numAttackedAndDamage, attack.allDamage, attack.speed, attack.direction, attack.display), false, true); int numFinisherOrbs = 0; Integer comboBuff = player.getBuffedValue(MapleBuffStat.COMBO); @@ -152,7 +160,16 @@ public final class CloseRangeDamageHandler extends AbstractDealDamageHandler { if (numFinisherOrbs == 0 && GameConstants.isFinisherSkill(attack.skill)) { return; } - if (attack.skill > 0) { + if (attack.skill % 10000000 == 1009) { // bamboo + if (c.getPlayer().getDojoEnergy() < 10000) { // PE hacking or maybe just lagging + return; + } + + player.setDojoEnergy(0); + c.announce(MaplePacketCreator.getEnergy("energy", player.getDojoEnergy())); + c.announce(MaplePacketCreator.serverNotice(5, "As you used the secret skill, your energy bar has been reset.")); + System.out.println("gauge " + player.getDojoEnergy()); + } else if (attack.skill > 0) { Skill skill = SkillFactory.getSkill(attack.skill); MapleStatEffect effect_ = skill.getEffect(player.getSkillLevel(skill)); if (effect_.getCooldown() > 0) { diff --git a/src/net/server/channel/handlers/MagicDamageHandler.java b/src/net/server/channel/handlers/MagicDamageHandler.java index 75a4993e50..befa2f34c7 100644 --- a/src/net/server/channel/handlers/MagicDamageHandler.java +++ b/src/net/server/channel/handlers/MagicDamageHandler.java @@ -31,6 +31,7 @@ import client.MapleCharacter.CancelCooldownAction; import client.MapleClient; import client.Skill; import client.SkillFactory; +import constants.ServerConstants; import constants.skills.Bishop; import constants.skills.Evan; import constants.skills.FPArchMage; @@ -49,7 +50,7 @@ public final class MagicDamageHandler extends AbstractDealDamageHandler { player.getAutobanManager().spam(8);*/ AttackInfo attack = parseDamage(slea, player, false, true); - + if (player.getBuffEffect(MapleBuffStat.MORPH) != null) { if(player.getBuffEffect(MapleBuffStat.MORPH).isMorphWithoutAttack()) { // How are they attacking when the client won't let them? @@ -57,6 +58,12 @@ public final class MagicDamageHandler extends AbstractDealDamageHandler { return; } } + + if (player.getMap().isDojoMap() && attack.numAttacked > 0) { + player.setDojoEnergy(player.getDojoEnergy() + + ServerConstants.DOJO_ENERGY_ATK); + c.announce(MaplePacketCreator.getEnergy("energy", player.getDojoEnergy())); + System.out.println("gauge " + player.getDojoEnergy()); + } int charge = (attack.skill == Evan.FIRE_BREATH || attack.skill == Evan.ICE_BREATH || attack.skill == FPArchMage.BIG_BANG || attack.skill == ILArchMage.BIG_BANG || attack.skill == Bishop.BIG_BANG) ? attack.charge : -1; byte[] packet = MaplePacketCreator.magicAttack(player, attack.skill, attack.skilllevel, attack.stance, attack.numAttackedAndDamage, attack.allDamage, charge, attack.speed, attack.direction, attack.display); diff --git a/src/net/server/channel/handlers/PetCommandHandler.java b/src/net/server/channel/handlers/PetCommandHandler.java index cafe8f8c51..3408425824 100644 --- a/src/net/server/channel/handlers/PetCommandHandler.java +++ b/src/net/server/channel/handlers/PetCommandHandler.java @@ -60,6 +60,7 @@ public final class PetCommandHandler extends AbstractMaplePacketHandler { } else { chr.getMap().broadcastMessage(MaplePacketCreator.commandResponse(chr.getId(), petIndex, command, false)); + if(chr.getMount() != null) chr.getMap().broadcastMessage(MaplePacketCreator.updateMount(chr.getId(), chr.getMount(), false)); } } } diff --git a/src/net/server/channel/handlers/RangedAttackHandler.java b/src/net/server/channel/handlers/RangedAttackHandler.java index 973a938538..3401de9493 100644 --- a/src/net/server/channel/handlers/RangedAttackHandler.java +++ b/src/net/server/channel/handlers/RangedAttackHandler.java @@ -39,6 +39,7 @@ import client.inventory.MapleInventory; import client.inventory.MapleInventoryType; import client.inventory.MapleWeaponType; import constants.ItemConstants; +import constants.ServerConstants; import constants.skills.Aran; import constants.skills.Buccaneer; import constants.skills.NightLord; @@ -70,6 +71,12 @@ public final class RangedAttackHandler extends AbstractDealDamageHandler { } } + if (player.getMap().isDojoMap() && attack.numAttacked > 0) { + player.setDojoEnergy(player.getDojoEnergy() + ServerConstants.DOJO_ENERGY_ATK); + c.announce(MaplePacketCreator.getEnergy("energy", player.getDojoEnergy())); + System.out.println("gauge " + player.getDojoEnergy()); + } + if (attack.skill == Buccaneer.ENERGY_ORB || attack.skill == ThunderBreaker.SPARK || attack.skill == Shadower.TAUNT || attack.skill == NightLord.TAUNT) { player.getMap().broadcastMessage(player, MaplePacketCreator.rangedAttack(player, attack.skill, attack.skilllevel, attack.stance, attack.numAttackedAndDamage, 0, attack.allDamage, attack.speed, attack.direction, attack.display), false); applyAttack(attack, player, 1); diff --git a/src/net/server/channel/handlers/SpawnPetHandler.java b/src/net/server/channel/handlers/SpawnPetHandler.java index c352d974b4..021746f168 100644 --- a/src/net/server/channel/handlers/SpawnPetHandler.java +++ b/src/net/server/channel/handlers/SpawnPetHandler.java @@ -66,19 +66,11 @@ public final class SpawnPetHandler extends AbstractMaplePacketHandler { if (petId == -1) { return; } - try { - Connection con = DatabaseConnection.getConnection(); - PreparedStatement ps = con.prepareStatement("DELETE FROM pets WHERE `petid` = ?"); - ps.setInt(1, pet.getUniqueId()); - ps.executeUpdate(); - ps.close(); - con.close(); - } catch (SQLException ex) { - ex.printStackTrace(); - } long expiration = chr.getInventory(MapleInventoryType.CASH).getItem(slot).getExpiration(); MapleInventoryManipulator.removeById(c, MapleInventoryType.CASH, petid, (short) 1, false, false); MapleInventoryManipulator.addById(c, evolveid, (short) 1, null, petId, expiration); + pet.deleteFromDb(); + c.announce(MaplePacketCreator.enableActions()); return; } diff --git a/src/net/server/channel/handlers/SpecialMoveHandler.java b/src/net/server/channel/handlers/SpecialMoveHandler.java index 0c121c5717..35a560e3d0 100644 --- a/src/net/server/channel/handlers/SpecialMoveHandler.java +++ b/src/net/server/channel/handlers/SpecialMoveHandler.java @@ -69,9 +69,13 @@ public final class SpecialMoveHandler extends AbstractMaplePacketHandler { Skill skill = SkillFactory.getSkill(skillid); int skillLevel = chr.getSkillLevel(skill); if (skillid % 10000000 == 1010 || skillid % 10000000 == 1011) { + if (c.getPlayer().getDojoEnergy() < 10000) { // PE hacking or maybe just lagging + return; + } skillLevel = 1; - chr.setDojoEnergy(0); - c.announce(MaplePacketCreator.getEnergy("energy", 0)); + c.getPlayer().setDojoEnergy(0); + c.announce(MaplePacketCreator.getEnergy("energy", c.getPlayer().getDojoEnergy())); + c.announce(MaplePacketCreator.serverNotice(5, "As you used the secret skill, your energy bar has been reset.")); } if (skillLevel == 0 || skillLevel != __skillLevel) return; diff --git a/src/net/server/channel/handlers/TakeDamageHandler.java b/src/net/server/channel/handlers/TakeDamageHandler.java index 33049d7141..23de7cb005 100644 --- a/src/net/server/channel/handlers/TakeDamageHandler.java +++ b/src/net/server/channel/handlers/TakeDamageHandler.java @@ -30,6 +30,7 @@ import client.inventory.Item; import client.inventory.MapleInventoryType; import client.status.MonsterStatus; import client.status.MonsterStatusEffect; +import constants.GameConstants; import constants.ServerConstants; import constants.skills.Aran; import constants.skills.Corsair; @@ -232,9 +233,10 @@ public final class TakeDamageHandler extends AbstractMaplePacketHandler { map.broadcastGMMessage(player, MaplePacketCreator.damagePlayer(damagefrom, monsteridfrom, player.getId(), damage, fake, direction, is_pgmr, pgmr, is_pg, oid, pos_x, pos_y), false); player.checkBerserk(false); } - if (map.getId() >= 925020000 && map.getId() < 925030000) { - player.setDojoEnergy(player.isGM() ? 300 : player.getDojoEnergy() < 300 ? player.getDojoEnergy() + 1 : 0); //Fking gm's - player.getClient().announce(MaplePacketCreator.getEnergy("energy", player.getDojoEnergy())); + if (GameConstants.isDojo(map.getId())) { + player.setDojoEnergy(player.getDojoEnergy() + ServerConstants.DOJO_ENERGY_DMG); + c.announce(MaplePacketCreator.getEnergy("energy", player.getDojoEnergy())); + System.out.println("gauge " + player.getDojoEnergy()); } for (MapleCharacter chr : banishPlayers) { // chill, if this list ever gets non-empty an attacker does exist, trust me :) diff --git a/src/scripting/AbstractPlayerInteraction.java b/src/scripting/AbstractPlayerInteraction.java index 19cd7c2415..064b28f99e 100644 --- a/src/scripting/AbstractPlayerInteraction.java +++ b/src/scripting/AbstractPlayerInteraction.java @@ -431,7 +431,7 @@ public class AbstractPlayerInteraction { evolved.setStance(0); evolved.setSummoned(true); - evolved.setName(from.getName()); + evolved.setName(from.getName().compareTo(MapleItemInformationProvider.getInstance().getName(from.getItemId())) != 0 ? from.getName() : MapleItemInformationProvider.getInstance().getName(id)); evolved.setCloseness(from.getCloseness()); evolved.setFullness(from.getFullness()); evolved.setLevel(from.getLevel()); diff --git a/src/server/MapleStatEffect.java b/src/server/MapleStatEffect.java index 299bdd32a4..c5d5291ed8 100644 --- a/src/server/MapleStatEffect.java +++ b/src/server/MapleStatEffect.java @@ -336,11 +336,6 @@ public class MapleStatEffect { case Legend.BALROG_MOUNT: statups.add(new Pair<>(MapleBuffStat.MONSTER_RIDING, Integer.valueOf(sourceid))); break; - case Beginner.BERSERK_FURY: - case Noblesse.BERSERK_FURY: - case Evan.BERSERK_FURY: - statups.add(new Pair<>(MapleBuffStat.BERSERK_FURY, Integer.valueOf(1))); - break; case Beginner.INVINCIBLE_BARRIER: case Noblesse.INVINCIBLE_BARRIER: case Legend.INVICIBLE_BARRIER: @@ -520,6 +515,9 @@ public class MapleStatEffect { case NightWalker.CLAW_BOOSTER: case ThunderBreaker.KNUCKLER_BOOSTER: case Evan.MAGIC_BOOSTER: + case Beginner.POWER_EXPLOSION: + case Noblesse.POWER_EXPLOSION: + case Legend.POWER_EXPLOSION: statups.add(new Pair<>(MapleBuffStat.BOOSTER, Integer.valueOf(x))); break; case Hero.MAPLE_WARRIOR: diff --git a/src/server/life/MobSkill.java b/src/server/life/MobSkill.java index 80159c4c02..619c32b6ba 100644 --- a/src/server/life/MobSkill.java +++ b/src/server/life/MobSkill.java @@ -29,6 +29,7 @@ import java.util.List; import client.MapleCharacter; import client.MapleDisease; import client.status.MonsterStatus; +import constants.GameConstants; import java.util.LinkedList; import java.util.Map; import tools.Randomizer; @@ -224,53 +225,56 @@ public class MobSkill { if (monster.getMap().getSpawnedMonstersOnMap() < 80) { for (Integer mobId : getSummons()) { MapleMonster toSpawn = MapleLifeFactory.getMonster(mobId); - toSpawn.setPosition(monster.getPosition()); - int ypos, xpos; - xpos = (int) monster.getPosition().getX(); - ypos = (int) monster.getPosition().getY(); - switch (mobId) { - case 8500003: // Pap bomb high - toSpawn.setFh((int) Math.ceil(Math.random() * 19.0)); - ypos = -590; - break; - case 8500004: // Pap bomb - xpos = (int) (monster.getPosition().getX() + Randomizer.nextInt(1000) - 500); - if (ypos != -590) { - ypos = (int) monster.getPosition().getY(); - } - break; - case 8510100: //Pianus bomb - if (Math.ceil(Math.random() * 5) == 1) { - ypos = 78; - xpos = (int) Randomizer.nextInt(5) + (Randomizer.nextInt(2) == 1 ? 180 : 0); - } else { + if(toSpawn != null) { + if(GameConstants.isBossRush(monster.getMap().getId())) toSpawn.disableDrops(); // no littering on BRPQ pls + + toSpawn.setPosition(monster.getPosition()); + int ypos, xpos; + xpos = (int) monster.getPosition().getX(); + ypos = (int) monster.getPosition().getY(); + switch (mobId) { + case 8500003: // Pap bomb high + toSpawn.setFh((int) Math.ceil(Math.random() * 19.0)); + ypos = -590; + break; + case 8500004: // Pap bomb xpos = (int) (monster.getPosition().getX() + Randomizer.nextInt(1000) - 500); - } - break; + if (ypos != -590) { + ypos = (int) monster.getPosition().getY(); + } + break; + case 8510100: //Pianus bomb + if (Math.ceil(Math.random() * 5) == 1) { + ypos = 78; + xpos = (int) Randomizer.nextInt(5) + (Randomizer.nextInt(2) == 1 ? 180 : 0); + } else { + xpos = (int) (monster.getPosition().getX() + Randomizer.nextInt(1000) - 500); + } + break; + } + switch (monster.getMap().getId()) { + case 220080001: //Pap map + if (xpos < -890) { + xpos = (int) (Math.ceil(Math.random() * 150) - 890); + } else if (xpos > 230) { + xpos = (int) (230 - Math.ceil(Math.random() * 150)); + } + break; + case 230040420: // Pianus map + if (xpos < -239) { + xpos = (int) (Math.ceil(Math.random() * 150) - 239); + } else if (xpos > 371) { + xpos = (int) (371 - Math.ceil(Math.random() * 150)); + } + break; + } + toSpawn.setPosition(new Point(xpos, ypos)); + if (toSpawn.getId() == 8500004) { + monster.getMap().spawnFakeMonster(toSpawn); + } else { + monster.getMap().spawnMonsterWithEffect(toSpawn, getSpawnEffect(), toSpawn.getPosition()); + } } - switch (monster.getMap().getId()) { - case 220080001: //Pap map - if (xpos < -890) { - xpos = (int) (Math.ceil(Math.random() * 150) - 890); - } else if (xpos > 230) { - xpos = (int) (230 - Math.ceil(Math.random() * 150)); - } - break; - case 230040420: // Pianus map - if (xpos < -239) { - xpos = (int) (Math.ceil(Math.random() * 150) - 239); - } else if (xpos > 371) { - xpos = (int) (371 - Math.ceil(Math.random() * 150)); - } - break; - } - toSpawn.setPosition(new Point(xpos, ypos)); - if (toSpawn.getId() == 8500004) { - monster.getMap().spawnFakeMonster(toSpawn); - } else { - monster.getMap().spawnMonsterWithEffect(toSpawn, getSpawnEffect(), toSpawn.getPosition()); - } - } } break; diff --git a/src/tools/DatabaseConnection.java b/src/tools/DatabaseConnection.java index 3e3194dc6d..9161e301d2 100644 --- a/src/tools/DatabaseConnection.java +++ b/src/tools/DatabaseConnection.java @@ -3,12 +3,8 @@ package tools; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; -import java.util.Properties; -import org.apache.commons.dbcp2.ConnectionFactory; -import org.apache.commons.dbcp2.DriverManagerConnectionFactory; -import org.apache.commons.dbcp2.PoolableConnectionFactory; -import org.apache.commons.dbcp2.PoolingDriver; -import org.apache.commons.pool2.impl.GenericObjectPool; +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; import constants.ServerConstants; @@ -18,74 +14,43 @@ import constants.ServerConstants; * @author Ronan (some connection pool to this beautiful code) */ public class DatabaseConnection { - private static Properties prop; + private static HikariDataSource ds; public static Connection getConnection() throws SQLException { - if(prop != null) { - Connection con = null; - while(con == null) { //oh yes, this will loop until success! - try { - con = DriverManager.getConnection(ServerConstants.DB_URL, prop); - } catch (SQLException sqle) {} - } - - return con; + if(ds != null) { + return ds.getConnection(); } else { return DriverManager.getConnection(ServerConstants.DB_URL, ServerConstants.DB_USER, ServerConstants.DB_PASS); } } - private static Properties getProperties() { - Properties connectionProperties = new Properties(); - connectionProperties.put("user", ServerConstants.DB_USER); - connectionProperties.put("password", ServerConstants.DB_PASS); - - connectionProperties.put("minIdle", "-1"); - connectionProperties.put("maxIdle", "-1"); - - connectionProperties.put("testOnBorrow", "true"); - connectionProperties.put("lifo", "false"); - - connectionProperties.put("maxTotal", "42"); //max allotted connections - connectionProperties.put("maxConnLifetimeMillis", "60000"); //connection remains valid for 1 min - connectionProperties.put("maxWaitMillis", "777"); //there are more pools, if this one is unavailable then pass to another already - connectionProperties.put("poolPreparedStatements", "true"); - connectionProperties.put("maxOpenPreparedStatements", "100"); //max allotted PS - - return connectionProperties; - } - - private PoolingDriver installDriver(short id) { - GenericObjectPool connectionPool = new GenericObjectPool(null); - ConnectionFactory connectionFactory = new DriverManagerConnectionFactory(ServerConstants.DB_URL, prop); - PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory,connectionPool.getJmxName()); - PoolingDriver driver = new PoolingDriver(); - driver.registerPool("maplesolaxiapool" + id, connectionPool); - - return driver; - } - public DatabaseConnection() { - prop = null; + ds = null; - try { - Class.forName("com.mysql.jdbc.Driver"); // touch the mysql driver - } catch (ClassNotFoundException e) { - System.out.println("[SEVERE] SQL Driver Not Found. Consider death by clams."); - e.printStackTrace(); - return; - } - - if(ServerConstants.DB_EXPERIMENTAL_POOLS > 0) { + if(ServerConstants.DB_EXPERIMENTAL_POOL) { // Connection Pool on database ftw! - prop = getProperties(); + HikariConfig config = new HikariConfig(); + config.setJdbcUrl(ServerConstants.DB_URL); + + config.setUsername(ServerConstants.DB_USER); + config.setPassword(ServerConstants.DB_PASS); + + config.addDataSourceProperty("connectionTimeout", "30000"); + config.addDataSourceProperty("maximumPoolSize", "100"); + + config.addDataSourceProperty("cachePrepStmts", "true"); + config.addDataSourceProperty("prepStmtCacheSize", "250"); + config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); + + ds = new HikariDataSource(config); + } else { try { - for(short i = 0; i < ServerConstants.DB_EXPERIMENTAL_POOLS; i++) { - DriverManager.registerDriver(installDriver(i)); - } - } catch(SQLException sqle) { - sqle.printStackTrace(); + Class.forName("com.mysql.jdbc.Driver"); // touch the mysql driver + } catch (ClassNotFoundException e) { + System.out.println("[SEVERE] SQL Driver Not Found. Consider death by clams."); + e.printStackTrace(); + return; } } } diff --git a/tools/MobBookUpdate/build/classes/mobbookupdate/MobBookUpdate.class b/tools/MobBookUpdate/build/classes/mobbookupdate/MobBookUpdate.class index 838ae80ead..45dc15e916 100644 Binary files a/tools/MobBookUpdate/build/classes/mobbookupdate/MobBookUpdate.class and b/tools/MobBookUpdate/build/classes/mobbookupdate/MobBookUpdate.class differ diff --git a/tools/MobBookUpdate/lib/MonsterBook.img.xml b/tools/MobBookUpdate/lib/MonsterBook.img.xml index 173d4e6180..3fabc2df24 100644 --- a/tools/MobBookUpdate/lib/MonsterBook.img.xml +++ b/tools/MobBookUpdate/lib/MonsterBook.img.xml @@ -3191,7 +3191,49 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4309,7 +4351,37 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -5867,7 +5939,41 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -6378,7 +6484,39 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -7417,36 +7555,34 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -8375,35 +8511,34 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -8673,7 +8808,17 @@ - + + + + + + + + + + + @@ -9120,8 +9265,27 @@ - - + + + + + + + + + + + + + + + + + + + + + @@ -9982,21 +10146,20 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + @@ -10458,8 +10621,27 @@ - - + + + + + + + + + + + + + + + + + + + + + @@ -11896,7 +12078,47 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -11909,7 +12131,42 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -11922,7 +12179,53 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -13438,44 +13741,43 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -13752,8 +14054,7 @@ - - + @@ -13909,26 +14210,10 @@ - - - - - - - - - - - - - - - - - - - - + + + + @@ -14265,16 +14550,15 @@ - - - - - - - - - - + + + + + + + + + diff --git a/tools/MobBookUpdate/lib/MonsterBook_updated.img.xml b/tools/MobBookUpdate/lib/MonsterBook_updated.img.xml index 3fabc2df24..57705c5804 100644 --- a/tools/MobBookUpdate/lib/MonsterBook_updated.img.xml +++ b/tools/MobBookUpdate/lib/MonsterBook_updated.img.xml @@ -3191,49 +3191,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -4351,37 +4309,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -5939,41 +5867,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -6484,39 +6378,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -7555,34 +7417,36 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -8511,34 +8375,35 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -8808,17 +8673,7 @@ - - - - - - - - - - - + @@ -9284,8 +9139,9 @@ - - + + + @@ -10146,20 +10002,21 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + + @@ -10640,8 +10497,9 @@ - - + + + @@ -12078,47 +11936,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -12131,42 +11949,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -12179,53 +11962,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -12263,22 +12000,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + @@ -12317,23 +12056,25 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + @@ -12628,28 +12369,29 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + @@ -13030,16 +12772,17 @@ - - - - - - - - - - + + + + + + + + + + + @@ -13343,14 +13086,15 @@ - - - - - - - - + + + + + + + + + @@ -13605,7 +13349,8 @@ - + + @@ -13741,43 +13486,44 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -14054,7 +13800,8 @@ - + + @@ -14210,10 +13957,26 @@ - - - - + + + + + + + + + + + + + + + + + + + + @@ -14550,15 +14313,16 @@ - - - - - - - - - + + + + + + + + + + diff --git a/tools/MobBookUpdate/nbproject/private/private.xml b/tools/MobBookUpdate/nbproject/private/private.xml index 6807a2ba19..6be0bf5534 100644 --- a/tools/MobBookUpdate/nbproject/private/private.xml +++ b/tools/MobBookUpdate/nbproject/private/private.xml @@ -2,6 +2,8 @@ - + + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/tools/MobBookUpdate/src/mobbookupdate/MobBookUpdate.java + diff --git a/wz/Skill.wz/000.img.xml b/wz/Skill.wz/000.img.xml index f66ab8d508..cad3b05d19 100644 --- a/wz/Skill.wz/000.img.xml +++ b/wz/Skill.wz/000.img.xml @@ -1380,7 +1380,7 @@ - + diff --git a/wz/Skill.wz/1000.img.xml b/wz/Skill.wz/1000.img.xml index b232b433fa..0bcd88049c 100644 --- a/wz/Skill.wz/1000.img.xml +++ b/wz/Skill.wz/1000.img.xml @@ -1361,7 +1361,7 @@ - + diff --git a/wz/Skill.wz/2000.img.xml b/wz/Skill.wz/2000.img.xml index 6f29272f13..5b3c0a95ab 100644 --- a/wz/Skill.wz/2000.img.xml +++ b/wz/Skill.wz/2000.img.xml @@ -1361,7 +1361,7 @@ - + diff --git a/wz/String.wz/MonsterBook.img.xml b/wz/String.wz/MonsterBook.img.xml index 3fabc2df24..57705c5804 100644 --- a/wz/String.wz/MonsterBook.img.xml +++ b/wz/String.wz/MonsterBook.img.xml @@ -3191,49 +3191,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -4351,37 +4309,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -5939,41 +5867,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -6484,39 +6378,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -7555,34 +7417,36 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -8511,34 +8375,35 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -8808,17 +8673,7 @@ - - - - - - - - - - - + @@ -9284,8 +9139,9 @@ - - + + + @@ -10146,20 +10002,21 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + + @@ -10640,8 +10497,9 @@ - - + + + @@ -12078,47 +11936,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -12131,42 +11949,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -12179,53 +11962,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -12263,22 +12000,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + @@ -12317,23 +12056,25 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + @@ -12628,28 +12369,29 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + @@ -13030,16 +12772,17 @@ - - - - - - - - - - + + + + + + + + + + + @@ -13343,14 +13086,15 @@ - - - - - - - - + + + + + + + + + @@ -13605,7 +13349,8 @@ - + + @@ -13741,43 +13486,44 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -14054,7 +13800,8 @@ - + + @@ -14210,10 +13957,26 @@ - - - - + + + + + + + + + + + + + + + + + + + + @@ -14550,15 +14313,16 @@ - - - - - - - - - + + + + + + + + + + diff --git a/wz/String.wz/Npc.img.xml b/wz/String.wz/Npc.img.xml index 2bc83b385f..7f642e37a9 100644 --- a/wz/String.wz/Npc.img.xml +++ b/wz/String.wz/Npc.img.xml @@ -4628,10 +4628,11 @@ - - - - + + + + +