diff --git a/build/built-jar.properties b/build/built-jar.properties
index 72aaf90820..eb2bbb7156 100644
--- a/build/built-jar.properties
+++ b/build/built-jar.properties
@@ -1,4 +1,4 @@
-#Thu, 31 Aug 2017 23:23:01 -0300
+#Thu, 07 Sep 2017 21:09:39 -0300
C\:\\Nexon\\MapleSolaxia\\MapleSolaxiaV2=
diff --git a/build/classes/client/MapleCharacter$1.class b/build/classes/client/MapleCharacter$1.class
index cb815d9caf..ef96d5661d 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 1f72045106..e4d584badb 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 f7db7fd1f9..aff0cca38c 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 6da39fc720..b55d35b3eb 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 8dcdd3e354..4e1bf41c99 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 3b9fb71763..1e7494e849 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 8e27113940..2c32f8e7ff 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 30f08d6431..63ce711b6e 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 113e5b63ca..6225754c96 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 1f459ab0dd..ad6887ed88 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 7172ee0179..7fa78d4ccf 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 0b61d2af12..66cd277fe5 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
deleted file mode 100644
index efe7c95afe..0000000000
Binary files a/build/classes/client/MapleCharacter$20.class and /dev/null differ
diff --git a/build/classes/client/MapleCharacter$3.class b/build/classes/client/MapleCharacter$3.class
index c33ce7dd9c..86075c4776 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 5874ea4bf0..4a1afde118 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 44d59f7a6b..0910f6940b 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 3a6b0f060c..e5234eb4e9 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 e499dda24a..6deccc85bf 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 65bcf75823..07743d9365 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 27e0887bc9..5cebe3e1f2 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 8d7099fe0c..3e992e1cdb 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 b855e8c20e..c31637e0ad 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 28f5277d18..86bbd5007c 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 84d493934e..f3130fe2f6 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 bc54efe368..449e60db5b 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 2f156e061e..2dbc6654bb 100644
Binary files a/build/classes/client/MapleCharacter.class and b/build/classes/client/MapleCharacter.class differ
diff --git a/build/classes/client/MapleClient.class b/build/classes/client/MapleClient.class
index 10c630b0b3..f3c0c83ce6 100644
Binary files a/build/classes/client/MapleClient.class and b/build/classes/client/MapleClient.class differ
diff --git a/build/classes/client/MapleMount$1.class b/build/classes/client/MapleMount$1.class
deleted file mode 100644
index 105dc0c068..0000000000
Binary files a/build/classes/client/MapleMount$1.class and /dev/null differ
diff --git a/build/classes/client/MapleMount.class b/build/classes/client/MapleMount.class
index f67559e2ec..5e8d56dd50 100644
Binary files a/build/classes/client/MapleMount.class and b/build/classes/client/MapleMount.class differ
diff --git a/build/classes/client/command/Commands$1.class b/build/classes/client/command/Commands$1.class
index 46f609a1d2..972361df76 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 8645f9e894..bea4deb7b7 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/Equip.class b/build/classes/client/inventory/Equip.class
index 3ae9caefc8..671a28b245 100644
Binary files a/build/classes/client/inventory/Equip.class and b/build/classes/client/inventory/Equip.class differ
diff --git a/build/classes/constants/ServerConstants.class b/build/classes/constants/ServerConstants.class
index 36592436d6..76d60f2dfc 100644
Binary files a/build/classes/constants/ServerConstants.class and b/build/classes/constants/ServerConstants.class differ
diff --git a/build/classes/net/SendOpcode.class b/build/classes/net/SendOpcode.class
index fab48e0294..34a3bd3ff0 100644
Binary files a/build/classes/net/SendOpcode.class and b/build/classes/net/SendOpcode.class differ
diff --git a/build/classes/net/server/channel/handlers/AutoAssignHandler$1.class b/build/classes/net/server/channel/handlers/AutoAssignHandler$1.class
index bbfc3e7a76..c3f948772d 100644
Binary files a/build/classes/net/server/channel/handlers/AutoAssignHandler$1.class and b/build/classes/net/server/channel/handlers/AutoAssignHandler$1.class differ
diff --git a/build/classes/net/server/channel/handlers/AutoAssignHandler.class b/build/classes/net/server/channel/handlers/AutoAssignHandler.class
index 817b6673c6..de775a1a6f 100644
Binary files a/build/classes/net/server/channel/handlers/AutoAssignHandler.class and b/build/classes/net/server/channel/handlers/AutoAssignHandler.class differ
diff --git a/build/classes/net/server/channel/handlers/ChangeMapHandler.class b/build/classes/net/server/channel/handlers/ChangeMapHandler.class
index eca25ae2b8..6504079bfc 100644
Binary files a/build/classes/net/server/channel/handlers/ChangeMapHandler.class and b/build/classes/net/server/channel/handlers/ChangeMapHandler.class differ
diff --git a/build/classes/net/server/channel/handlers/CharInfoRequestHandler.class b/build/classes/net/server/channel/handlers/CharInfoRequestHandler.class
index 9cec7b3b1a..b06d7f522a 100644
Binary files a/build/classes/net/server/channel/handlers/CharInfoRequestHandler.class and b/build/classes/net/server/channel/handlers/CharInfoRequestHandler.class differ
diff --git a/build/classes/net/server/channel/handlers/EnterCashShopHandler.class b/build/classes/net/server/channel/handlers/EnterCashShopHandler.class
index c096c4905e..068b348631 100644
Binary files a/build/classes/net/server/channel/handlers/EnterCashShopHandler.class and b/build/classes/net/server/channel/handlers/EnterCashShopHandler.class differ
diff --git a/build/classes/net/server/channel/handlers/PetExcludeItemsHandler.class b/build/classes/net/server/channel/handlers/PetExcludeItemsHandler.class
index bfdb4cabfa..dbb5ecc3c8 100644
Binary files a/build/classes/net/server/channel/handlers/PetExcludeItemsHandler.class and b/build/classes/net/server/channel/handlers/PetExcludeItemsHandler.class differ
diff --git a/build/classes/net/server/channel/handlers/PetFoodHandler.class b/build/classes/net/server/channel/handlers/PetFoodHandler.class
index 354d3d90d0..3e7c673605 100644
Binary files a/build/classes/net/server/channel/handlers/PetFoodHandler.class and b/build/classes/net/server/channel/handlers/PetFoodHandler.class differ
diff --git a/build/classes/net/server/channel/handlers/PetLootHandler.class b/build/classes/net/server/channel/handlers/PetLootHandler.class
index e14d0665d2..b5116879db 100644
Binary files a/build/classes/net/server/channel/handlers/PetLootHandler.class and b/build/classes/net/server/channel/handlers/PetLootHandler.class differ
diff --git a/build/classes/net/server/channel/handlers/PlayerLoggedinHandler.class b/build/classes/net/server/channel/handlers/PlayerLoggedinHandler.class
index f4e25d5593..dcf31ec9db 100644
Binary files a/build/classes/net/server/channel/handlers/PlayerLoggedinHandler.class and b/build/classes/net/server/channel/handlers/PlayerLoggedinHandler.class differ
diff --git a/build/classes/net/server/channel/handlers/ScrollHandler.class b/build/classes/net/server/channel/handlers/ScrollHandler.class
index 1da72f6522..bcf5cc02de 100644
Binary files a/build/classes/net/server/channel/handlers/ScrollHandler.class and b/build/classes/net/server/channel/handlers/ScrollHandler.class differ
diff --git a/build/classes/net/server/channel/handlers/SpawnPetHandler.class b/build/classes/net/server/channel/handlers/SpawnPetHandler.class
index 18763cb400..92d19be4db 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 f8706d30df..8a34216533 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 fd41b4180f..204bf8b9cd 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/net/server/channel/handlers/UseCashItemHandler$1.class b/build/classes/net/server/channel/handlers/UseCashItemHandler$1.class
index 3141274444..e9bb1ecd5a 100644
Binary files a/build/classes/net/server/channel/handlers/UseCashItemHandler$1.class and b/build/classes/net/server/channel/handlers/UseCashItemHandler$1.class differ
diff --git a/build/classes/net/server/channel/handlers/UseCashItemHandler.class b/build/classes/net/server/channel/handlers/UseCashItemHandler.class
index 71b020eb3b..a491e54cb8 100644
Binary files a/build/classes/net/server/channel/handlers/UseCashItemHandler.class and b/build/classes/net/server/channel/handlers/UseCashItemHandler.class differ
diff --git a/build/classes/net/server/world/World$1.class b/build/classes/net/server/world/World$1.class
index 26812bbc32..2604d45938 100644
Binary files a/build/classes/net/server/world/World$1.class and b/build/classes/net/server/world/World$1.class differ
diff --git a/build/classes/net/server/world/World.class b/build/classes/net/server/world/World.class
index 7c1bd5d4fd..a08e8623d0 100644
Binary files a/build/classes/net/server/world/World.class and b/build/classes/net/server/world/World.class differ
diff --git a/build/classes/scripting/AbstractPlayerInteraction.class b/build/classes/scripting/AbstractPlayerInteraction.class
index 4d8d8d1ff9..1ddd19f93d 100644
Binary files a/build/classes/scripting/AbstractPlayerInteraction.class and b/build/classes/scripting/AbstractPlayerInteraction.class differ
diff --git a/build/classes/scripting/npc/NPCConversationManager.class b/build/classes/scripting/npc/NPCConversationManager.class
index 7884f38938..890f98269e 100644
Binary files a/build/classes/scripting/npc/NPCConversationManager.class and b/build/classes/scripting/npc/NPCConversationManager.class differ
diff --git a/build/classes/server/MapleInventoryManipulator.class b/build/classes/server/MapleInventoryManipulator.class
index 2c31ffc838..6fb50376e4 100644
Binary files a/build/classes/server/MapleInventoryManipulator.class and b/build/classes/server/MapleInventoryManipulator.class differ
diff --git a/build/classes/server/MapleItemInformationProvider$1.class b/build/classes/server/MapleItemInformationProvider$1.class
index cb45b48a6d..1538b58897 100644
Binary files a/build/classes/server/MapleItemInformationProvider$1.class and b/build/classes/server/MapleItemInformationProvider$1.class differ
diff --git a/build/classes/server/MapleItemInformationProvider$RewardItem.class b/build/classes/server/MapleItemInformationProvider$RewardItem.class
index e98508805f..dac248257f 100644
Binary files a/build/classes/server/MapleItemInformationProvider$RewardItem.class and b/build/classes/server/MapleItemInformationProvider$RewardItem.class differ
diff --git a/build/classes/server/MapleItemInformationProvider$scriptedItem.class b/build/classes/server/MapleItemInformationProvider$scriptedItem.class
index 5dafa5ea13..7943cda884 100644
Binary files a/build/classes/server/MapleItemInformationProvider$scriptedItem.class and b/build/classes/server/MapleItemInformationProvider$scriptedItem.class differ
diff --git a/build/classes/server/MapleItemInformationProvider.class b/build/classes/server/MapleItemInformationProvider.class
index c746ba12f4..72c2974172 100644
Binary files a/build/classes/server/MapleItemInformationProvider.class and b/build/classes/server/MapleItemInformationProvider.class differ
diff --git a/build/classes/server/MapleStatEffect$CancelEffectAction.class b/build/classes/server/MapleStatEffect$CancelEffectAction.class
index 88f23b4acb..c2ddbee840 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 34f6ab4552..508578713e 100644
Binary files a/build/classes/server/MapleStatEffect.class and b/build/classes/server/MapleStatEffect.class differ
diff --git a/build/classes/server/life/MapleMonster.class b/build/classes/server/life/MapleMonster.class
index 0ce0088246..90784264d8 100644
Binary files a/build/classes/server/life/MapleMonster.class and b/build/classes/server/life/MapleMonster.class differ
diff --git a/build/classes/server/maps/MapleMap$1.class b/build/classes/server/maps/MapleMap$1.class
index f744ca4848..40a1810dc0 100644
Binary files a/build/classes/server/maps/MapleMap$1.class and b/build/classes/server/maps/MapleMap$1.class differ
diff --git a/build/classes/server/maps/MapleMap$10.class b/build/classes/server/maps/MapleMap$10.class
index fa0dc0b39b..978c142bf6 100644
Binary files a/build/classes/server/maps/MapleMap$10.class and b/build/classes/server/maps/MapleMap$10.class differ
diff --git a/build/classes/server/maps/MapleMap$11.class b/build/classes/server/maps/MapleMap$11.class
index 52f3cc4d87..334fe659da 100644
Binary files a/build/classes/server/maps/MapleMap$11.class and b/build/classes/server/maps/MapleMap$11.class differ
diff --git a/build/classes/server/maps/MapleMap$12.class b/build/classes/server/maps/MapleMap$12.class
index 34c84139a7..75ab674d8e 100644
Binary files a/build/classes/server/maps/MapleMap$12.class and b/build/classes/server/maps/MapleMap$12.class differ
diff --git a/build/classes/server/maps/MapleMap$13.class b/build/classes/server/maps/MapleMap$13.class
index 31a626b3a1..4633113cec 100644
Binary files a/build/classes/server/maps/MapleMap$13.class and b/build/classes/server/maps/MapleMap$13.class differ
diff --git a/build/classes/server/maps/MapleMap$14.class b/build/classes/server/maps/MapleMap$14.class
index 2a4e93ce66..e82823231e 100644
Binary files a/build/classes/server/maps/MapleMap$14.class and b/build/classes/server/maps/MapleMap$14.class differ
diff --git a/build/classes/server/maps/MapleMap$15.class b/build/classes/server/maps/MapleMap$15.class
index c0b42b4513..1273909d55 100644
Binary files a/build/classes/server/maps/MapleMap$15.class and b/build/classes/server/maps/MapleMap$15.class differ
diff --git a/build/classes/server/maps/MapleMap$16.class b/build/classes/server/maps/MapleMap$16.class
index 95ffa66d21..0fb35420f3 100644
Binary files a/build/classes/server/maps/MapleMap$16.class and b/build/classes/server/maps/MapleMap$16.class differ
diff --git a/build/classes/server/maps/MapleMap$17.class b/build/classes/server/maps/MapleMap$17.class
index 89303edbef..66922f4f7b 100644
Binary files a/build/classes/server/maps/MapleMap$17.class and b/build/classes/server/maps/MapleMap$17.class differ
diff --git a/build/classes/server/maps/MapleMap$18.class b/build/classes/server/maps/MapleMap$18.class
index 24e7f16bdf..df7e9c0c33 100644
Binary files a/build/classes/server/maps/MapleMap$18.class and b/build/classes/server/maps/MapleMap$18.class differ
diff --git a/build/classes/server/maps/MapleMap$19.class b/build/classes/server/maps/MapleMap$19.class
index f9087b066d..b47e254fe6 100644
Binary files a/build/classes/server/maps/MapleMap$19.class and b/build/classes/server/maps/MapleMap$19.class differ
diff --git a/build/classes/server/maps/MapleMap$2.class b/build/classes/server/maps/MapleMap$2.class
index 8b6cb5c237..ee1593f851 100644
Binary files a/build/classes/server/maps/MapleMap$2.class and b/build/classes/server/maps/MapleMap$2.class differ
diff --git a/build/classes/server/maps/MapleMap$20.class b/build/classes/server/maps/MapleMap$20.class
index 399551d681..de685fc2ee 100644
Binary files a/build/classes/server/maps/MapleMap$20.class and b/build/classes/server/maps/MapleMap$20.class differ
diff --git a/build/classes/server/maps/MapleMap$21.class b/build/classes/server/maps/MapleMap$21.class
index f686530a0e..933606c589 100644
Binary files a/build/classes/server/maps/MapleMap$21.class and b/build/classes/server/maps/MapleMap$21.class differ
diff --git a/build/classes/server/maps/MapleMap$22.class b/build/classes/server/maps/MapleMap$22.class
index 8b57ee06eb..03b1c3a871 100644
Binary files a/build/classes/server/maps/MapleMap$22.class and b/build/classes/server/maps/MapleMap$22.class differ
diff --git a/build/classes/server/maps/MapleMap$23.class b/build/classes/server/maps/MapleMap$23.class
index 7581f2cb27..7aeddfc257 100644
Binary files a/build/classes/server/maps/MapleMap$23.class and b/build/classes/server/maps/MapleMap$23.class differ
diff --git a/build/classes/server/maps/MapleMap$24.class b/build/classes/server/maps/MapleMap$24.class
index 990ee14b71..01f91ea1cc 100644
Binary files a/build/classes/server/maps/MapleMap$24.class and b/build/classes/server/maps/MapleMap$24.class differ
diff --git a/build/classes/server/maps/MapleMap$25.class b/build/classes/server/maps/MapleMap$25.class
index 2a7e051ea2..f4f278057a 100644
Binary files a/build/classes/server/maps/MapleMap$25.class and b/build/classes/server/maps/MapleMap$25.class differ
diff --git a/build/classes/server/maps/MapleMap$26.class b/build/classes/server/maps/MapleMap$26.class
index e10462b544..c15d6b8442 100644
Binary files a/build/classes/server/maps/MapleMap$26.class and b/build/classes/server/maps/MapleMap$26.class differ
diff --git a/build/classes/server/maps/MapleMap$27.class b/build/classes/server/maps/MapleMap$27.class
index 7b4f02a22e..9db8188fdb 100644
Binary files a/build/classes/server/maps/MapleMap$27.class and b/build/classes/server/maps/MapleMap$27.class differ
diff --git a/build/classes/server/maps/MapleMap$28.class b/build/classes/server/maps/MapleMap$28.class
index cfc9174bb9..b86cca5db7 100644
Binary files a/build/classes/server/maps/MapleMap$28.class and b/build/classes/server/maps/MapleMap$28.class differ
diff --git a/build/classes/server/maps/MapleMap$29$1.class b/build/classes/server/maps/MapleMap$29$1.class
index edb56f40c9..a14b598c54 100644
Binary files a/build/classes/server/maps/MapleMap$29$1.class and b/build/classes/server/maps/MapleMap$29$1.class differ
diff --git a/build/classes/server/maps/MapleMap$29.class b/build/classes/server/maps/MapleMap$29.class
index 44aece4c53..eadd6bfb55 100644
Binary files a/build/classes/server/maps/MapleMap$29.class and b/build/classes/server/maps/MapleMap$29.class differ
diff --git a/build/classes/server/maps/MapleMap$3.class b/build/classes/server/maps/MapleMap$3.class
index ea2e01dab3..4d1c84a4c6 100644
Binary files a/build/classes/server/maps/MapleMap$3.class and b/build/classes/server/maps/MapleMap$3.class differ
diff --git a/build/classes/server/maps/MapleMap$30.class b/build/classes/server/maps/MapleMap$30.class
index 031346f6ad..87862d5d50 100644
Binary files a/build/classes/server/maps/MapleMap$30.class and b/build/classes/server/maps/MapleMap$30.class differ
diff --git a/build/classes/server/maps/MapleMap$4.class b/build/classes/server/maps/MapleMap$4.class
index 506e2d5dc3..4aa29578c9 100644
Binary files a/build/classes/server/maps/MapleMap$4.class and b/build/classes/server/maps/MapleMap$4.class differ
diff --git a/build/classes/server/maps/MapleMap$5.class b/build/classes/server/maps/MapleMap$5.class
index 54d63c2453..8fb5ce7170 100644
Binary files a/build/classes/server/maps/MapleMap$5.class and b/build/classes/server/maps/MapleMap$5.class differ
diff --git a/build/classes/server/maps/MapleMap$6.class b/build/classes/server/maps/MapleMap$6.class
index ce8de6daab..006c02fdd8 100644
Binary files a/build/classes/server/maps/MapleMap$6.class and b/build/classes/server/maps/MapleMap$6.class differ
diff --git a/build/classes/server/maps/MapleMap$7.class b/build/classes/server/maps/MapleMap$7.class
index 4d01d4f772..fcadc5aa3d 100644
Binary files a/build/classes/server/maps/MapleMap$7.class and b/build/classes/server/maps/MapleMap$7.class differ
diff --git a/build/classes/server/maps/MapleMap$8.class b/build/classes/server/maps/MapleMap$8.class
index 2db7bbba6a..13a1508217 100644
Binary files a/build/classes/server/maps/MapleMap$8.class and b/build/classes/server/maps/MapleMap$8.class differ
diff --git a/build/classes/server/maps/MapleMap$9.class b/build/classes/server/maps/MapleMap$9.class
index a94955b547..e5c60041c1 100644
Binary files a/build/classes/server/maps/MapleMap$9.class and b/build/classes/server/maps/MapleMap$9.class differ
diff --git a/build/classes/server/maps/MapleMap$ActivateItemReactor$1.class b/build/classes/server/maps/MapleMap$ActivateItemReactor$1.class
index c2b4f5b053..efba39b13e 100644
Binary files a/build/classes/server/maps/MapleMap$ActivateItemReactor$1.class and b/build/classes/server/maps/MapleMap$ActivateItemReactor$1.class differ
diff --git a/build/classes/server/maps/MapleMap$ActivateItemReactor.class b/build/classes/server/maps/MapleMap$ActivateItemReactor.class
index 18bb7c5ed0..0bece63c9f 100644
Binary files a/build/classes/server/maps/MapleMap$ActivateItemReactor.class and b/build/classes/server/maps/MapleMap$ActivateItemReactor.class differ
diff --git a/build/classes/server/maps/MapleMap$ExpireMapItemJob.class b/build/classes/server/maps/MapleMap$ExpireMapItemJob.class
index 3e9a9b8c8e..63445a468d 100644
Binary files a/build/classes/server/maps/MapleMap$ExpireMapItemJob.class and b/build/classes/server/maps/MapleMap$ExpireMapItemJob.class differ
diff --git a/build/classes/server/maps/MapleMap.class b/build/classes/server/maps/MapleMap.class
index 0cc25f24d6..e464772d79 100644
Binary files a/build/classes/server/maps/MapleMap.class and b/build/classes/server/maps/MapleMap.class differ
diff --git a/build/classes/server/maps/MapleMapFactory.class b/build/classes/server/maps/MapleMapFactory.class
index fef6d11f63..2ecbd3099f 100644
Binary files a/build/classes/server/maps/MapleMapFactory.class and b/build/classes/server/maps/MapleMapFactory.class differ
diff --git a/build/classes/tools/MaplePacketCreator$1.class b/build/classes/tools/MaplePacketCreator$1.class
index bf10881eaf..a421a4f622 100644
Binary files a/build/classes/tools/MaplePacketCreator$1.class and b/build/classes/tools/MaplePacketCreator$1.class differ
diff --git a/build/classes/tools/MaplePacketCreator$2.class b/build/classes/tools/MaplePacketCreator$2.class
index 1d30e30bd9..aae1b45fd4 100644
Binary files a/build/classes/tools/MaplePacketCreator$2.class and b/build/classes/tools/MaplePacketCreator$2.class differ
diff --git a/build/classes/tools/MaplePacketCreator.class b/build/classes/tools/MaplePacketCreator.class
index dece253035..6cb01864a4 100644
Binary files a/build/classes/tools/MaplePacketCreator.class and b/build/classes/tools/MaplePacketCreator.class differ
diff --git a/dist/MapleSolaxia.jar b/dist/MapleSolaxia.jar
index d4a0fed51c..161edee9cd 100644
Binary files a/dist/MapleSolaxia.jar and b/dist/MapleSolaxia.jar differ
diff --git a/docs/areabosses/BossEvent.js b/docs/areabosses/BossEvent.js
new file mode 100644
index 0000000000..5cd1eb0047
--- /dev/null
+++ b/docs/areabosses/BossEvent.js
@@ -0,0 +1,33 @@
+// @Author: Resinate
+
+var towns = new Array(800020120, 251010102, 260010201, 107000300, 200010300, 100040105, 100040106, 261030000, 110040000, 250010504, 240040401, 104000400, 222010310, 230040420, 230040420, 230020100, 105090310, 101030404, 250010304, 220050100, 220050000, 220050200, 221040301);
+var spawns = new Array(6090002, 5220004, 3220001, 6220000, 8220000, 5220002, 5220002, 8220002, 5220001, 7220002, 8220003, 2220000, 7220001, 8510000, 8520000, 4220001, 8220008, 3220000, 7220000, 5220003, 5220003, 5220003, 6220001);
+var x = new Array(560, 560, 645, 90, 208, 456, 474, -300, 200, 400, 0, 400, 0, 527, 138, 0, -626, 800, -300, -300, 0, 0, -4224);
+var y = new Array(50, 50, 275, 119, 83, 278, 278, 180, 140, 540, 1125, 455, 33, -437, 138, 520, -604, 1280, 390, 1030, 1030, 1030, 776);
+var mapObj;
+var mobObj;
+
+function init() {
+ scheduleNew();
+}
+
+function scheduleNew() {
+ setupTask = em.schedule("start", 0);
+}
+
+function cancelSchedule() {
+ if (setupTask != null)
+ setupTask.cancel(true);
+}
+
+function start() {
+ var time = (Math.floor(Math.random() * 10) + 10) * (60 * 1000);
+ for(var i = 0; i < towns.length; i++) {
+ mapObj = em.getChannelServer().getMapFactory().getMap(towns[i]);
+ mobObj = Packages.server.life.MapleLifeFactory.getMonster(spawns[i]);
+ if(mapObj.getMonsterById(spawns[i]) == null) {
+ mapObj.spawnMonsterOnGroundBelow(mobObj, new Packages.java.awt.Point(x[i],y[i]));
+ }
+ }
+ em.schedule("start", time);
+}
\ No newline at end of file
diff --git a/docs/mychanges_ptbr.txt b/docs/mychanges_ptbr.txt
index 79df8aa1cd..81bb263610 100644
--- a/docs/mychanges_ptbr.txt
+++ b/docs/mychanges_ptbr.txt
@@ -500,4 +500,24 @@ Pets em outros slots agora equipam devidamente.
31 Agosto 2017,
Refatorado autoassigner para focar nos stats primários a partir da avaliação do valor base do stat secundário com o 1º e 2º equips mais forte, ao invés de somente o 1º.
-Corrigido bug de acesso concorrente no sistema de rate cupons.
\ No newline at end of file
+Corrigido bug de acesso concorrente no sistema de rate cupons.
+
+01 Setembro 2017,
+Comando rates e equiplv agora usam visual ao invés de escrever no chat.
+Corrigido NPC crafters crashando o cliente no caso onde o player não tem slot disponível para o novo item.
+
+02 Setembro 2017,
+Refatorado sistema de schedules para mounts e pets. Agora o server passa a instanciar as chamadas às funções que definem "cansaço" nos animais, ao invés de instanciar uma task para cada.
+
+04 Setembro 2017,
+Adicionado sistema de exclusão de itens (pet feature) no server.
+Party recebe update de HP de jogadores ao ressucitarem na city.
+Flash Jump's levam o update necessário ao trocar de job. 3a pessoa agora pode ver a animação do FJ.
+
+05 Setembro 2017,
+Corrigido mais alguns aspectos do autoassigner.
+Corrigido itens saindo para fora do mapa. Nova posição do drop leva em conta as bordas da camera do jogador.
+
+07 Setembro 2017,
+Adicionado Vega's Spell.
+3rd job event agora possui tempo-limite e verifica se há jogadores já enfrentando o desafio.
\ No newline at end of file
diff --git a/handbook/Skill.txt b/handbook/Skill.txt
index 18ad04b301..2ceb2360d3 100644
--- a/handbook/Skill.txt
+++ b/handbook/Skill.txt
@@ -392,7 +392,7 @@
14100001 - Critical Throw - [Master Level : 30]\nEnables Critical Attack with Throwing Stars at a pre-established success rate.\nRequired Skill: #c At least Level 3 on Claw Mastery #
14101002 - Claw Booster - [Master Level : 20]\nUse HP and MP to temporarily boost up the attack speed of the claw. It only applies when the character is equipped with a claw Throwing Stars.\nRequired Skill : \n#cAt least Level 5 on Claw Mastery#
14101003 - Haste - [Master Level : 20]\nTemporarily enhances Speed and Jump stats of every member in the party.
-14101004 - Flash Jump - [Master Level : 20]\n[Master Level : 20]\nAllows a second Jump toward the direction which the character was headed when used while the character is in the air. The distance of the Jump increases in accordance with the advancement of the character’s skill level.
+14101004 - Flash Jump - [Master Level : 20]\nAllows a second Jump toward the direction which the character was headed when used while the character is in the air. The distance of the Jump increases in accordance with the advancement of the character’s skill level.
14100005 - Vanish - [Master Level : 10]\nInflicts additional damage on monsters when used while Dark Sight is activated. Dark Sight deactivates as soon as this skill is applied. \nRequired skill : #cDark Sight over level 10#
14101006 - Vampire - [Master Level : 20]\nCan attack multiple monsters 4 times and partially consumes the damage to recover HP. No more than ½ of the character’s max HP and the Monster’s max HP can be consumed.
14111000 - Shadow Partner - [Master Level : 30]\nSummons a shadow, which repeats the character’s every move, for a given duration. It has no special strength.
diff --git a/nbproject/private/private.xml b/nbproject/private/private.xml
index 3b088cb429..5af0ed1acc 100644
--- a/nbproject/private/private.xml
+++ b/nbproject/private/private.xml
@@ -2,8 +2,6 @@
-
- file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/wz/Etc.wz/Commodity.img.xml
-
+
diff --git a/scripts/event/3rdJob_bowman.js b/scripts/event/3rdJob_bowman.js
new file mode 100644
index 0000000000..a6ed002981
--- /dev/null
+++ b/scripts/event/3rdJob_bowman.js
@@ -0,0 +1,92 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 Patrick Huy
+ Matthias Butz
+ Jan Christian Meyer
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation version 3 as published by
+ the Free Software Foundation. You may not use, modify or distribute
+ this program under any other version of the GNU Affero General Public
+ License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+/**
+ *3rd Job Event - Bowman
+**/
+importPackage(Packages.tools);
+
+var entryMap = 108010100;
+var exitMap = 105040305;
+
+var minMapId = 108010100;
+var maxMapId = 108010101;
+
+var eventTime = 20; //20 minutes
+
+var lobbyRange = [0, 0];
+
+function setLobbyRange() {
+ return lobbyRange;
+}
+
+function init() {
+ em.setProperty("noEntry","false");
+}
+
+function playerEntry(eim, player) {
+ eim.getInstanceMap(maxMapId).resetPQ(1);
+
+ player.changeMap(entryMap, 0);
+ em.setProperty("noEntry","true");
+
+ player.getClient().getSession().write(MaplePacketCreator.getClock(eventTime * 60));
+ eim.startEventTimer(eventTime * 60000);
+}
+
+function playerUnregistered(eim, player) {}
+
+function playerExit(eim, player) {
+ eim.unregisterPlayer(player);
+ eim.dispose();
+ em.setProperty("noEntry","false");
+}
+
+function scheduledTimeout(eim) {
+ var player = eim.getPlayers().get(0);
+ playerExit(eim, eim.getPlayers().get(0));
+ player.changeMap(exitMap);
+}
+
+function playerDisconnected(eim, player) {
+ playerExit(eim, player);
+}
+
+function clear(eim) {
+ var player = eim.getPlayers().get(0);
+ eim.unregisterPlayer(player);
+ player.changeMap(exitMap);
+
+ eim.dispose();
+ em.setProperty("noEntry","false");
+}
+
+function changedMap(eim, chr, mapid) {
+ if(mapid < minMapId || mapid > maxMapId) playerExit(eim, chr);
+}
+
+function monsterKilled(mob, eim) {}
+
+function allMonstersDead(eim) {}
+
+function cancelSchedule() {}
+
+function dispose() {}
diff --git a/scripts/event/3rdJob_magician.js b/scripts/event/3rdJob_magician.js
new file mode 100644
index 0000000000..7bd6063cbc
--- /dev/null
+++ b/scripts/event/3rdJob_magician.js
@@ -0,0 +1,92 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 Patrick Huy
+ Matthias Butz
+ Jan Christian Meyer
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation version 3 as published by
+ the Free Software Foundation. You may not use, modify or distribute
+ this program under any other version of the GNU Affero General Public
+ License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+/**
+ *3rd Job Event - Magician
+**/
+importPackage(Packages.tools);
+
+var entryMap = 108010200;
+var exitMap = 100040106;
+
+var minMapId = 108010200;
+var maxMapId = 108010201;
+
+var eventTime = 20; //20 minutes
+
+var lobbyRange = [0, 0];
+
+function setLobbyRange() {
+ return lobbyRange;
+}
+
+function init() {
+ em.setProperty("noEntry","false");
+}
+
+function playerEntry(eim, player) {
+ eim.getInstanceMap(maxMapId).resetPQ(1);
+
+ player.changeMap(entryMap, 0);
+ em.setProperty("noEntry","true");
+
+ player.getClient().getSession().write(MaplePacketCreator.getClock(eventTime * 60));
+ eim.startEventTimer(eventTime * 60000);
+}
+
+function playerUnregistered(eim, player) {}
+
+function playerExit(eim, player) {
+ eim.unregisterPlayer(player);
+ eim.dispose();
+ em.setProperty("noEntry","false");
+}
+
+function scheduledTimeout(eim) {
+ var player = eim.getPlayers().get(0);
+ playerExit(eim, eim.getPlayers().get(0));
+ player.changeMap(exitMap);
+}
+
+function playerDisconnected(eim, player) {
+ playerExit(eim, player);
+}
+
+function clear(eim) {
+ var player = eim.getPlayers().get(0);
+ eim.unregisterPlayer(player);
+ player.changeMap(exitMap);
+
+ eim.dispose();
+ em.setProperty("noEntry","false");
+}
+
+function changedMap(eim, chr, mapid) {
+ if(mapid < minMapId || mapid > maxMapId) playerExit(eim, chr);
+}
+
+function monsterKilled(mob, eim) {}
+
+function allMonstersDead(eim) {}
+
+function cancelSchedule() {}
+
+function dispose() {}
diff --git a/scripts/event/3rdJob_pirate.js b/scripts/event/3rdJob_pirate.js
new file mode 100644
index 0000000000..bce92210d0
--- /dev/null
+++ b/scripts/event/3rdJob_pirate.js
@@ -0,0 +1,92 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 Patrick Huy
+ Matthias Butz
+ Jan Christian Meyer
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation version 3 as published by
+ the Free Software Foundation. You may not use, modify or distribute
+ this program under any other version of the GNU Affero General Public
+ License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+/**
+ *3rd Job Event - Pirate
+**/
+importPackage(Packages.tools);
+
+var entryMap = 108010500;
+var exitMap = 105070200;
+
+var minMapId = 108010500;
+var maxMapId = 108010501;
+
+var eventTime = 20; //20 minutes
+
+var lobbyRange = [0, 0];
+
+function setLobbyRange() {
+ return lobbyRange;
+}
+
+function init() {
+ em.setProperty("noEntry","false");
+}
+
+function playerEntry(eim, player) {
+ eim.getInstanceMap(maxMapId).resetPQ(1);
+
+ player.changeMap(entryMap, 0);
+ em.setProperty("noEntry","true");
+
+ player.getClient().getSession().write(MaplePacketCreator.getClock(eventTime * 60));
+ eim.startEventTimer(eventTime * 60000);
+}
+
+function playerUnregistered(eim, player) {}
+
+function playerExit(eim, player) {
+ eim.unregisterPlayer(player);
+ eim.dispose();
+ em.setProperty("noEntry","false");
+}
+
+function scheduledTimeout(eim) {
+ var player = eim.getPlayers().get(0);
+ playerExit(eim, eim.getPlayers().get(0));
+ player.changeMap(exitMap);
+}
+
+function playerDisconnected(eim, player) {
+ playerExit(eim, player);
+}
+
+function clear(eim) {
+ var player = eim.getPlayers().get(0);
+ eim.unregisterPlayer(player);
+ player.changeMap(exitMap);
+
+ eim.dispose();
+ em.setProperty("noEntry","false");
+}
+
+function changedMap(eim, chr, mapid) {
+ if(mapid < minMapId || mapid > maxMapId) playerExit(eim, chr);
+}
+
+function monsterKilled(mob, eim) {}
+
+function allMonstersDead(eim) {}
+
+function cancelSchedule() {}
+
+function dispose() {}
diff --git a/scripts/event/3rdJob_thief.js b/scripts/event/3rdJob_thief.js
new file mode 100644
index 0000000000..3bbe3cabc7
--- /dev/null
+++ b/scripts/event/3rdJob_thief.js
@@ -0,0 +1,92 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 Patrick Huy
+ Matthias Butz
+ Jan Christian Meyer
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation version 3 as published by
+ the Free Software Foundation. You may not use, modify or distribute
+ this program under any other version of the GNU Affero General Public
+ License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+/**
+ *3rd Job Event - Thief
+**/
+importPackage(Packages.tools);
+
+var entryMap = 108010400;
+var exitMap = 107000402;
+
+var minMapId = 108010400;
+var maxMapId = 108010401;
+
+var eventTime = 20; //20 minutes
+
+var lobbyRange = [0, 0];
+
+function setLobbyRange() {
+ return lobbyRange;
+}
+
+function init() {
+ em.setProperty("noEntry","false");
+}
+
+function playerEntry(eim, player) {
+ eim.getInstanceMap(maxMapId).resetPQ(1);
+
+ player.changeMap(entryMap, 0);
+ em.setProperty("noEntry","true");
+
+ player.getClient().getSession().write(MaplePacketCreator.getClock(eventTime * 60));
+ eim.startEventTimer(eventTime * 60000);
+}
+
+function playerUnregistered(eim, player) {}
+
+function playerExit(eim, player) {
+ eim.unregisterPlayer(player);
+ eim.dispose();
+ em.setProperty("noEntry","false");
+}
+
+function scheduledTimeout(eim) {
+ var player = eim.getPlayers().get(0);
+ playerExit(eim, eim.getPlayers().get(0));
+ player.changeMap(exitMap);
+}
+
+function playerDisconnected(eim, player) {
+ playerExit(eim, player);
+}
+
+function clear(eim) {
+ var player = eim.getPlayers().get(0);
+ eim.unregisterPlayer(player);
+ player.changeMap(exitMap);
+
+ eim.dispose();
+ em.setProperty("noEntry","false");
+}
+
+function changedMap(eim, chr, mapid) {
+ if(mapid < minMapId || mapid > maxMapId) playerExit(eim, chr);
+}
+
+function monsterKilled(mob, eim) {}
+
+function allMonstersDead(eim) {}
+
+function cancelSchedule() {}
+
+function dispose() {}
diff --git a/scripts/event/3rdJob_warrior.js b/scripts/event/3rdJob_warrior.js
new file mode 100644
index 0000000000..cc1e8c8ffc
--- /dev/null
+++ b/scripts/event/3rdJob_warrior.js
@@ -0,0 +1,92 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 Patrick Huy
+ Matthias Butz
+ Jan Christian Meyer
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation version 3 as published by
+ the Free Software Foundation. You may not use, modify or distribute
+ this program under any other version of the GNU Affero General Public
+ License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+/**
+ *3rd Job Event - Warrior
+**/
+importPackage(Packages.tools);
+
+var entryMap = 108010300;
+var exitMap = 105070001;
+
+var minMapId = 108010300;
+var maxMapId = 108010301;
+
+var eventTime = 20; //20 minutes
+
+var lobbyRange = [0, 0];
+
+function setLobbyRange() {
+ return lobbyRange;
+}
+
+function init() {
+ em.setProperty("noEntry","false");
+}
+
+function playerEntry(eim, player) {
+ eim.getInstanceMap(maxMapId).resetPQ(1);
+
+ player.changeMap(entryMap, 0);
+ em.setProperty("noEntry","true");
+
+ player.getClient().getSession().write(MaplePacketCreator.getClock(eventTime * 60));
+ eim.startEventTimer(eventTime * 60000);
+}
+
+function playerUnregistered(eim, player) {}
+
+function playerExit(eim, player) {
+ eim.unregisterPlayer(player);
+ eim.dispose();
+ em.setProperty("noEntry","false");
+}
+
+function scheduledTimeout(eim) {
+ var player = eim.getPlayers().get(0);
+ playerExit(eim, eim.getPlayers().get(0));
+ player.changeMap(exitMap);
+}
+
+function playerDisconnected(eim, player) {
+ playerExit(eim, player);
+}
+
+function clear(eim) {
+ var player = eim.getPlayers().get(0);
+ eim.unregisterPlayer(player);
+ player.changeMap(exitMap);
+
+ eim.dispose();
+ em.setProperty("noEntry","false");
+}
+
+function changedMap(eim, chr, mapid) {
+ if(mapid < minMapId || mapid > maxMapId) playerExit(eim, chr);
+}
+
+function monsterKilled(mob, eim) {}
+
+function allMonstersDead(eim) {}
+
+function cancelSchedule() {}
+
+function dispose() {}
diff --git a/scripts/event/3rdjob.js b/scripts/event/3rdjob.js
deleted file mode 100644
index e3d0d53c98..0000000000
--- a/scripts/event/3rdjob.js
+++ /dev/null
@@ -1,144 +0,0 @@
-importPackage(Packages.client);
-importPackage(Packages.server.life);
-importPackage(Packages.tools);
-importPackage(Packages.client.inventory);
-
-function init() {
-}
-
-
-function monsterValue(eim, mobId) {
- return 1;
-}
-
-
-function setClassVars(player) {
- var returnMapId;
- var monsterId;
- var mapId;
- if (player.getJob().equals(MapleJob.FP_WIZARD) ||
- player.getJob().equals(MapleJob.IL_WIZARD) ||
- player.getJob().equals(MapleJob.CLERIC)) {
- mapId = 108010201;
- returnMapId = 100040106;
- monsterId = 9001001;
- } else if (player.getJob().equals(MapleJob.FIGHTER) ||
- player.getJob().equals(MapleJob.PAGE) ||
- player.getJob().equals(MapleJob.SPEARMAN)) {
- mapId = 108010301;
- returnMapId = 105070001;
- monsterId = 9001000;
- } else if (player.getJob().equals(MapleJob.ASSASSIN) ||
- player.getJob().equals(MapleJob.BANDIT)) {
- mapId = 108010401;
- returnMapId = 107000402;
- monsterId = 9001003;
- } else if (player.getJob().equals(MapleJob.HUNTER) ||
- player.getJob().equals(MapleJob.CROSSBOWMAN)) {
- mapId = 108010101;
- returnMapId = 105040305;
- monsterId = 9001002;
- } else if (player.getJob().equals(MapleJob.BRAWLER) ||
- player.getJob().equals(MapleJob.GUNSLINGER)) {
- mapId = 108010501;
- returnMapId = 105040305;
- monsterId = 9001008;
- }
- return new Array(mapId, returnMapId, monsterId);
-}
-
-
-function playerEntry(eim, player) {
- var info = setClassVars(player);
- var mapId = info[0];
- var returnMapId = info[1];
- var monsterId = info[2];
- var map = eim.getMapInstance(mapId);
- map.toggleDrops();
-
- player.changeMap(map, map.getPortal(0));
- var mob = map.getMonsterById(monsterId);
- eim.registerMonster(mob);
- eim.schedule("warpOut", 20 * 60 * 1000);
- map.addMapTimer(20 * 60);
-}
-
-
-function playerDead(eim, player) {
- var info = setClassVars(player);
- var mapId = info[0];
- var returnMapId = info[1];
- var monsterId = info[2];
- player.setHp(1);
- var returnMap = em.getChannelServer().getMapFactory().getMap(returnMapId);
- player.changeMap(returnMap, returnMap.getPortal(0));
- eim.unregisterPlayer(player);
- eim.dispose();
-}
-
-
-function playerDisconnected(eim, player) {
- var info = setClassVars(player);
- var mapId = info[0];
- var returnMapId = info[1];
- var monsterId = info[2];
- eim.unregisterPlayer(player);
- player.getMap().removePlayer(player);
- var returnMap = em.getChannelServer().getMapFactory().getMap(returnMapId);
- player.setMap(returnMap);
- eim.dispose();
-}
-
-function monsterKilled(mob, eim) {}
-
-function allMonstersDead(eim) {
- var winner = eim.getPlayers().get(0);
- var info = setClassVars(winner);
- var mapId = info[0];
- var returnMapId = info[1];
- var monsterId = info[2];
- var map = eim.getMapFactory().getMap(mapId);
- map.spawnItemDrop(winner, winner, new Item(4031059, 0, 1), winner.getPosition(), true, false);
- eim.schedule("warpOut", 12 * 60 * 1000);
- map.addMapTimer(12 * 60);
-}
-
-function cancelSchedule(eim) {
-
-}
-
-
-function warpOut(eim) {
- var iter = eim.getPlayers().iterator();
- while (iter.hasNext()) {
- var player = iter.next();
- var info = setClassVars(player);
- var mapId = info[0];
- var returnMapId = info[1];
- var monsterId = info[2];
- var returnMap = em.getChannelServer().getMapFactory().getMap(returnMapId);
- player.changeMap(returnMap, returnMap.getPortal(0));
- eim.unregisterPlayer(player);
- }
- eim.dispose();
-}
-
-
-function leftParty(eim, player) {
-
-}
-
-
-function disbandParty(eim, player) {
-
-
-}
-
-
-function dispose() {
-
-
-}
-
-function cancelSchedule(eim) {
-}
\ No newline at end of file
diff --git a/scripts/event/BossRushPQ.js b/scripts/event/BossRushPQ.js
index 39bdf6cf5f..07caed1e74 100644
--- a/scripts/event/BossRushPQ.js
+++ b/scripts/event/BossRushPQ.js
@@ -49,13 +49,13 @@ function setEventRewards(eim) {
var itemSet, itemQty, evLevel;
evLevel = 6; //Rewards at event completion
- itemSet = [1122018, 1122005, 1022088, 1402013, 1032030, 1032070, 1102046, 2330004, 2041013, 2041016, 2041019, 2041022, 2049100, 2049003, 2020012, 2020013, 2020014, 2020015, 2022029, 2022045, 2022068, 2022069, 2022180, 2022179, 4004000, 4004001, 4004002, 4004003, 4004004, 4003000];
- itemQty = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 25, 25, 25, 25, 25, 25, 25, 25, 4, 4, 12, 12, 12, 12, 12, 25];
+ itemSet = [3010061, 1122018, 1122005, 1022088, 1402013, 1032030, 1032070, 1102046, 2330004, 2041013, 2041016, 2041019, 2041022, 2049100, 2049003, 2020012, 2020013, 2020014, 2020015, 2022029, 2022045, 2022068, 2022069, 2022180, 2022179, 4004000, 4004001, 4004002, 4004003, 4004004, 4003000];
+ itemQty = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 25, 25, 25, 25, 25, 25, 25, 25, 4, 4, 12, 12, 12, 12, 12, 25];
eim.setEventRewards(evLevel, itemSet, itemQty);
evLevel = 5; //Rewards at Rest Spot V
- itemSet = [1122018, 1122005, 1022088, 1402013, 1032030, 1032070, 1102046, 2330004, 2041013, 2041016, 2041019, 2041022, 2049100, 2049003, 2020012, 2020013, 2020014, 2020015, 2022029, 2022045, 2022068, 2022069, 2022180, 2022179, 4004000, 4004001, 4004002, 4004003, 4004004, 4003000];
- itemQty = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 8, 8, 8, 8, 8, 12];
+ itemSet = [3010063, 1122018, 1122005, 1022088, 1402013, 1032030, 1032070, 1102046, 2330004, 2041013, 2041016, 2041019, 2041022, 2049100, 2049003, 2020012, 2020013, 2020014, 2020015, 2022029, 2022045, 2022068, 2022069, 2022180, 2022179, 4004000, 4004001, 4004002, 4004003, 4004004, 4003000];
+ itemQty = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 8, 8, 8, 8, 8, 12];
eim.setEventRewards(evLevel, itemSet, itemQty);
evLevel = 4; //Rewards at Rest Spot IV
diff --git a/scripts/event/CafePQ_1.js b/scripts/event/CafePQ_1.js
new file mode 100644
index 0000000000..283ef1d5cc
--- /dev/null
+++ b/scripts/event/CafePQ_1.js
@@ -0,0 +1,243 @@
+/**
+ * @author: Ronan
+ * @event: Cafe PQ 1
+*/
+
+importPackage(Packages.client.inventory);
+
+var isPq = true;
+var minPlayers = 3, maxPlayers = 6;
+var minLevel = 21, maxLevel = 120;
+var entryMap = 190000000;
+var exitMap = 193000000;
+var recruitMap = 193000000;
+
+var minMapId = 190000000;
+var maxMapId = 190000002;
+
+var eventMaps = [190000000, 190000001, 190000002];
+
+var eventTime = 45; // 45 minutes
+var couponsNeeded = 400; // total of coupons to complete the event
+
+var lobbyRange = [0, 0];
+
+function init() {
+ setEventRequirements();
+}
+
+function setLobbyRange() {
+ return lobbyRange;
+}
+
+function setEventRequirements() {
+ var reqStr = "";
+
+ reqStr += "\r\n Number of players: ";
+ if(maxPlayers - minPlayers >= 1) reqStr += minPlayers + " ~ " + maxPlayers;
+ else reqStr += minPlayers;
+
+ reqStr += "\r\n Level range: ";
+ if(maxLevel - minLevel >= 1) reqStr += minLevel + " ~ " + maxLevel;
+ else reqStr += minLevel;
+
+ reqStr += "\r\n Time limit: ";
+ reqStr += eventTime + " minutes";
+
+ em.setProperty("party", reqStr);
+}
+
+function setEventExclusives(eim) {
+ var itemSet = [4001007];
+ eim.setExclusiveItems(itemSet);
+}
+
+function setEventRewards(eim) {
+ var itemSet, itemQty, evLevel, expStages;
+
+ evLevel = 1; //Rewards at clear PQ
+ itemSet = [4001014];
+ itemQty = [1];
+ eim.setEventRewards(evLevel, itemSet, itemQty);
+
+ expStages = [20000]; //bonus exp given on CLEAR stage signal
+ eim.setEventClearStageExp(expStages);
+}
+
+function getEligibleParty(party) { //selects, from the given party, the team that is allowed to attempt this event
+ var eligible = [];
+ var hasLeader = false;
+
+ if(party.size() > 0) {
+ var partyList = party.toArray();
+
+ for(var i = 0; i < party.size(); i++) {
+ var ch = partyList[i];
+
+ if(ch.getMapId() == recruitMap && ch.getLevel() >= minLevel && ch.getLevel() <= maxLevel) {
+ if(ch.isLeader()) hasLeader = true;
+ eligible.push(ch);
+ }
+ }
+ }
+
+ if(!(hasLeader && eligible.length >= minPlayers && eligible.length <= maxPlayers)) eligible = [];
+ return eligible;
+}
+
+function setup(level, lobbyid) {
+ var eim = em.newInstance("Lan1_" + lobbyid);
+ eim.setProperty("level", level);
+ eim.setProperty("stage", "0");
+
+ eim.setIntProperty("couponsNeeded", couponsNeeded);
+
+ var i;
+ for (i = 0; i < eventMaps.length; i++) {
+ var mapObj = eim.getInstanceMap(eventMaps[i]);
+ mapObj.resetPQ(level);
+ mapObj.toggleDrops();
+ mapObj.instanceMapForceRespawn();
+ }
+
+ respawnStages(eim);
+ eim.startEventTimer(eventTime * 60000);
+ setEventRewards(eim);
+ setEventExclusives(eim);
+ return eim;
+}
+
+function afterSetup(eim) {}
+
+function respawnStages(eim) {
+ var i;
+ for (i = 0; i < eventMaps.length; i++) {
+ eim.getInstanceMap(eventMaps[i]).instanceMapRespawn();
+ }
+
+ eim.schedule("respawnStages", 15 * 1000);
+}
+
+function playerEntry(eim, player) {
+ var map = eim.getMapInstance(entryMap);
+ player.changeMap(map, map.getPortal(0));
+}
+
+function scheduledTimeout(eim) {
+ end(eim);
+}
+
+function playerUnregistered(eim, player) {}
+
+function playerExit(eim, player) {
+ eim.unregisterPlayer(player);
+ player.changeMap(exitMap, 0);
+}
+
+function changedMap(eim, player, mapid) {
+ if (mapid < minMapId || mapid > maxMapId) {
+ if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+ }
+}
+
+function changedLeader(eim, leader) {
+ var mapid = leader.getMapId();
+ if (!eim.isEventCleared() && (mapid < minMapId || mapid > maxMapId)) {
+ end(eim);
+ }
+}
+
+function playerDead(eim, player) {}
+
+function playerRevive(eim, player) { // player presses ok on the death pop up.
+ if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+}
+
+function playerDisconnected(eim, player) {
+ if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+}
+
+function leftParty(eim, player) {
+ if (eim.isEventTeamLackingNow(false, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+}
+
+function disbandParty(eim) {
+ end(eim);
+}
+
+function monsterValue(eim, mobId) {
+ return 1;
+}
+
+function end(eim) {
+ var party = eim.getPlayers();
+ for (var i = 0; i < party.size(); i++) {
+ playerExit(eim, party.get(i));
+ }
+ eim.dispose();
+}
+
+function giveRandomEventReward(eim, player) {
+ eim.giveEventReward(player);
+}
+
+function clearPQ(eim) {
+ eim.stopEventTimer();
+ eim.setEventCleared();
+ eim.giveEventPlayersStageReward(1);
+
+ var i;
+ for (i = 0; i < eventMaps.length; i++) {
+ eim.getInstanceMap(eventMaps[i]).killAllMonstersNotFriendly();
+ eim.showClearEffect(eventMaps[i]);
+ }
+}
+
+function getDroppedQuantity(mob) {
+ if(mob.getLevel() > 65) {
+ return 5;
+ } else if(mob.getLevel() > 40) {
+ return 2;
+ } else {
+ return 1;
+ }
+}
+
+function monsterKilled(mob, eim) {
+ try {
+ if(eim.isEventCleared()) return;
+
+ var mapObj = mob.getMap();
+ var itemObj = new Item(4001007, 0, getDroppedQuantity(mob));
+ var dropper = eim.getPlayers().get(0);
+
+ mapObj.spawnItemDrop(mob, dropper, itemObj, mob.getPosition(), true, false);
+
+ } catch(err) {} // PQ not started yet
+}
+
+function allMonstersDead(eim) {}
+
+function cancelSchedule() {}
+
+function dispose(eim) {}
diff --git a/scripts/event/CafePQ_2.js b/scripts/event/CafePQ_2.js
new file mode 100644
index 0000000000..ca8be2219c
--- /dev/null
+++ b/scripts/event/CafePQ_2.js
@@ -0,0 +1,243 @@
+/**
+ * @author: Ronan
+ * @event: Cafe PQ 2
+*/
+
+importPackage(Packages.client.inventory);
+
+var isPq = true;
+var minPlayers = 3, maxPlayers = 6;
+var minLevel = 21, maxLevel = 120;
+var entryMap = 191000000;
+var exitMap = 193000000;
+var recruitMap = 193000000;
+
+var minMapId = 191000000;
+var maxMapId = 191000001;
+
+var eventMaps = [191000000, 191000001];
+
+var eventTime = 45; // 45 minutes
+var couponsNeeded = 350; // total of coupons to complete the event
+
+var lobbyRange = [0, 0];
+
+function init() {
+ setEventRequirements();
+}
+
+function setLobbyRange() {
+ return lobbyRange;
+}
+
+function setEventRequirements() {
+ var reqStr = "";
+
+ reqStr += "\r\n Number of players: ";
+ if(maxPlayers - minPlayers >= 1) reqStr += minPlayers + " ~ " + maxPlayers;
+ else reqStr += minPlayers;
+
+ reqStr += "\r\n Level range: ";
+ if(maxLevel - minLevel >= 1) reqStr += minLevel + " ~ " + maxLevel;
+ else reqStr += minLevel;
+
+ reqStr += "\r\n Time limit: ";
+ reqStr += eventTime + " minutes";
+
+ em.setProperty("party", reqStr);
+}
+
+function setEventExclusives(eim) {
+ var itemSet = [4001007];
+ eim.setExclusiveItems(itemSet);
+}
+
+function setEventRewards(eim) {
+ var itemSet, itemQty, evLevel, expStages;
+
+ evLevel = 1; //Rewards at clear PQ
+ itemSet = [4001009];
+ itemQty = [1];
+ eim.setEventRewards(evLevel, itemSet, itemQty);
+
+ expStages = [15000]; //bonus exp given on CLEAR stage signal
+ eim.setEventClearStageExp(expStages);
+}
+
+function getEligibleParty(party) { //selects, from the given party, the team that is allowed to attempt this event
+ var eligible = [];
+ var hasLeader = false;
+
+ if(party.size() > 0) {
+ var partyList = party.toArray();
+
+ for(var i = 0; i < party.size(); i++) {
+ var ch = partyList[i];
+
+ if(ch.getMapId() == recruitMap && ch.getLevel() >= minLevel && ch.getLevel() <= maxLevel) {
+ if(ch.isLeader()) hasLeader = true;
+ eligible.push(ch);
+ }
+ }
+ }
+
+ if(!(hasLeader && eligible.length >= minPlayers && eligible.length <= maxPlayers)) eligible = [];
+ return eligible;
+}
+
+function setup(level, lobbyid) {
+ var eim = em.newInstance("Lan2_" + lobbyid);
+ eim.setProperty("level", level);
+ eim.setProperty("stage", "0");
+
+ eim.setIntProperty("couponsNeeded", couponsNeeded);
+
+ var i;
+ for (i = 0; i < eventMaps.length; i++) {
+ var mapObj = eim.getInstanceMap(eventMaps[i]);
+ mapObj.resetPQ(level);
+ mapObj.toggleDrops();
+ mapObj.instanceMapForceRespawn();
+ }
+
+ respawnStages(eim);
+ eim.startEventTimer(eventTime * 60000);
+ setEventRewards(eim);
+ setEventExclusives(eim);
+ return eim;
+}
+
+function afterSetup(eim) {}
+
+function respawnStages(eim) {
+ var i;
+ for (i = 0; i < eventMaps.length; i++) {
+ eim.getInstanceMap(eventMaps[i]).instanceMapRespawn();
+ }
+
+ eim.schedule("respawnStages", 15 * 1000);
+}
+
+function playerEntry(eim, player) {
+ var map = eim.getMapInstance(entryMap);
+ player.changeMap(map, map.getPortal(0));
+}
+
+function scheduledTimeout(eim) {
+ end(eim);
+}
+
+function playerUnregistered(eim, player) {}
+
+function playerExit(eim, player) {
+ eim.unregisterPlayer(player);
+ player.changeMap(exitMap, 0);
+}
+
+function changedMap(eim, player, mapid) {
+ if (mapid < minMapId || mapid > maxMapId) {
+ if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+ }
+}
+
+function changedLeader(eim, leader) {
+ var mapid = leader.getMapId();
+ if (!eim.isEventCleared() && (mapid < minMapId || mapid > maxMapId)) {
+ end(eim);
+ }
+}
+
+function playerDead(eim, player) {}
+
+function playerRevive(eim, player) { // player presses ok on the death pop up.
+ if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+}
+
+function playerDisconnected(eim, player) {
+ if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+}
+
+function leftParty(eim, player) {
+ if (eim.isEventTeamLackingNow(false, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+}
+
+function disbandParty(eim) {
+ end(eim);
+}
+
+function monsterValue(eim, mobId) {
+ return 1;
+}
+
+function end(eim) {
+ var party = eim.getPlayers();
+ for (var i = 0; i < party.size(); i++) {
+ playerExit(eim, party.get(i));
+ }
+ eim.dispose();
+}
+
+function giveRandomEventReward(eim, player) {
+ eim.giveEventReward(player);
+}
+
+function clearPQ(eim) {
+ eim.stopEventTimer();
+ eim.setEventCleared();
+ eim.giveEventPlayersStageReward(1);
+
+ var i;
+ for (i = 0; i < eventMaps.length; i++) {
+ eim.getInstanceMap(eventMaps[i]).killAllMonstersNotFriendly();
+ eim.showClearEffect(eventMaps[i]);
+ }
+}
+
+function getDroppedQuantity(mob) {
+ if(mob.getLevel() > 65) {
+ return 5;
+ } else if(mob.getLevel() > 40) {
+ return 2;
+ } else {
+ return 1;
+ }
+}
+
+function monsterKilled(mob, eim) {
+ try {
+ if(eim.isEventCleared()) return;
+
+ var mapObj = mob.getMap();
+ var itemObj = new Item(4001007, 0, getDroppedQuantity(mob));
+ var dropper = eim.getPlayers().get(0);
+
+ mapObj.spawnItemDrop(mob, dropper, itemObj, mob.getPosition(), true, false);
+
+ } catch(err) {} // PQ not started yet
+}
+
+function allMonstersDead(eim) {}
+
+function cancelSchedule() {}
+
+function dispose(eim) {}
diff --git a/scripts/event/CafePQ_3.js b/scripts/event/CafePQ_3.js
new file mode 100644
index 0000000000..00e088cfd1
--- /dev/null
+++ b/scripts/event/CafePQ_3.js
@@ -0,0 +1,243 @@
+/**
+ * @author: Ronan
+ * @event: Cafe PQ 3
+*/
+
+importPackage(Packages.client.inventory);
+
+var isPq = true;
+var minPlayers = 3, maxPlayers = 6;
+var minLevel = 21, maxLevel = 120;
+var entryMap = 192000000;
+var exitMap = 193000000;
+var recruitMap = 193000000;
+
+var minMapId = 192000000;
+var maxMapId = 192000001;
+
+var eventMaps = [192000000, 192000001];
+
+var eventTime = 45; // 45 minutes
+var couponsNeeded = 350; // total of coupons to complete the event
+
+var lobbyRange = [0, 0];
+
+function init() {
+ setEventRequirements();
+}
+
+function setLobbyRange() {
+ return lobbyRange;
+}
+
+function setEventRequirements() {
+ var reqStr = "";
+
+ reqStr += "\r\n Number of players: ";
+ if(maxPlayers - minPlayers >= 1) reqStr += minPlayers + " ~ " + maxPlayers;
+ else reqStr += minPlayers;
+
+ reqStr += "\r\n Level range: ";
+ if(maxLevel - minLevel >= 1) reqStr += minLevel + " ~ " + maxLevel;
+ else reqStr += minLevel;
+
+ reqStr += "\r\n Time limit: ";
+ reqStr += eventTime + " minutes";
+
+ em.setProperty("party", reqStr);
+}
+
+function setEventExclusives(eim) {
+ var itemSet = [4001007];
+ eim.setExclusiveItems(itemSet);
+}
+
+function setEventRewards(eim) {
+ var itemSet, itemQty, evLevel, expStages;
+
+ evLevel = 1; //Rewards at clear PQ
+ itemSet = [4001013];
+ itemQty = [1];
+ eim.setEventRewards(evLevel, itemSet, itemQty);
+
+ expStages = [12000]; //bonus exp given on CLEAR stage signal
+ eim.setEventClearStageExp(expStages);
+}
+
+function getEligibleParty(party) { //selects, from the given party, the team that is allowed to attempt this event
+ var eligible = [];
+ var hasLeader = false;
+
+ if(party.size() > 0) {
+ var partyList = party.toArray();
+
+ for(var i = 0; i < party.size(); i++) {
+ var ch = partyList[i];
+
+ if(ch.getMapId() == recruitMap && ch.getLevel() >= minLevel && ch.getLevel() <= maxLevel) {
+ if(ch.isLeader()) hasLeader = true;
+ eligible.push(ch);
+ }
+ }
+ }
+
+ if(!(hasLeader && eligible.length >= minPlayers && eligible.length <= maxPlayers)) eligible = [];
+ return eligible;
+}
+
+function setup(level, lobbyid) {
+ var eim = em.newInstance("Lan3_" + lobbyid);
+ eim.setProperty("level", level);
+ eim.setProperty("stage", "0");
+
+ eim.setIntProperty("couponsNeeded", couponsNeeded);
+
+ var i;
+ for (i = 0; i < eventMaps.length; i++) {
+ var mapObj = eim.getInstanceMap(eventMaps[i]);
+ mapObj.resetPQ(level);
+ mapObj.toggleDrops();
+ mapObj.instanceMapForceRespawn();
+ }
+
+ respawnStages(eim);
+ eim.startEventTimer(eventTime * 60000);
+ setEventRewards(eim);
+ setEventExclusives(eim);
+ return eim;
+}
+
+function afterSetup(eim) {}
+
+function respawnStages(eim) {
+ var i;
+ for (i = 0; i < eventMaps.length; i++) {
+ eim.getInstanceMap(eventMaps[i]).instanceMapRespawn();
+ }
+
+ eim.schedule("respawnStages", 15 * 1000);
+}
+
+function playerEntry(eim, player) {
+ var map = eim.getMapInstance(entryMap);
+ player.changeMap(map, map.getPortal(0));
+}
+
+function scheduledTimeout(eim) {
+ end(eim);
+}
+
+function playerUnregistered(eim, player) {}
+
+function playerExit(eim, player) {
+ eim.unregisterPlayer(player);
+ player.changeMap(exitMap, 0);
+}
+
+function changedMap(eim, player, mapid) {
+ if (mapid < minMapId || mapid > maxMapId) {
+ if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+ }
+}
+
+function changedLeader(eim, leader) {
+ var mapid = leader.getMapId();
+ if (!eim.isEventCleared() && (mapid < minMapId || mapid > maxMapId)) {
+ end(eim);
+ }
+}
+
+function playerDead(eim, player) {}
+
+function playerRevive(eim, player) { // player presses ok on the death pop up.
+ if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+}
+
+function playerDisconnected(eim, player) {
+ if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+}
+
+function leftParty(eim, player) {
+ if (eim.isEventTeamLackingNow(false, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+}
+
+function disbandParty(eim) {
+ end(eim);
+}
+
+function monsterValue(eim, mobId) {
+ return 1;
+}
+
+function end(eim) {
+ var party = eim.getPlayers();
+ for (var i = 0; i < party.size(); i++) {
+ playerExit(eim, party.get(i));
+ }
+ eim.dispose();
+}
+
+function giveRandomEventReward(eim, player) {
+ eim.giveEventReward(player);
+}
+
+function clearPQ(eim) {
+ eim.stopEventTimer();
+ eim.setEventCleared();
+ eim.giveEventPlayersStageReward(1);
+
+ var i;
+ for (i = 0; i < eventMaps.length; i++) {
+ eim.getInstanceMap(eventMaps[i]).killAllMonstersNotFriendly();
+ eim.showClearEffect(eventMaps[i]);
+ }
+}
+
+function getDroppedQuantity(mob) {
+ if(mob.getLevel() > 65) {
+ return 3;
+ } else if(mob.getLevel() > 40) {
+ return 2;
+ } else {
+ return 1;
+ }
+}
+
+function monsterKilled(mob, eim) {
+ try {
+ if(eim.isEventCleared()) return;
+
+ var mapObj = mob.getMap();
+ var itemObj = new Item(4001007, 0, getDroppedQuantity(mob));
+ var dropper = eim.getPlayers().get(0);
+
+ mapObj.spawnItemDrop(mob, dropper, itemObj, mob.getPosition(), true, false);
+
+ } catch(err) {} // PQ not started yet
+}
+
+function allMonstersDead(eim) {}
+
+function cancelSchedule() {}
+
+function dispose(eim) {}
diff --git a/scripts/event/CafePQ_4.js b/scripts/event/CafePQ_4.js
new file mode 100644
index 0000000000..c3bb0fe527
--- /dev/null
+++ b/scripts/event/CafePQ_4.js
@@ -0,0 +1,243 @@
+/**
+ * @author: Ronan
+ * @event: Cafe PQ 4
+*/
+
+importPackage(Packages.client.inventory);
+
+var isPq = true;
+var minPlayers = 3, maxPlayers = 6;
+var minLevel = 21, maxLevel = 120;
+var entryMap = 195000000;
+var exitMap = 193000000;
+var recruitMap = 193000000;
+
+var minMapId = 195000000;
+var maxMapId = 195030000;
+
+var eventMaps = [195000000, 195010000, 195020000, 195030000];
+
+var eventTime = 45; // 45 minutes
+var couponsNeeded = 450; // total of coupons to complete the event
+
+var lobbyRange = [0, 0];
+
+function init() {
+ setEventRequirements();
+}
+
+function setLobbyRange() {
+ return lobbyRange;
+}
+
+function setEventRequirements() {
+ var reqStr = "";
+
+ reqStr += "\r\n Number of players: ";
+ if(maxPlayers - minPlayers >= 1) reqStr += minPlayers + " ~ " + maxPlayers;
+ else reqStr += minPlayers;
+
+ reqStr += "\r\n Level range: ";
+ if(maxLevel - minLevel >= 1) reqStr += minLevel + " ~ " + maxLevel;
+ else reqStr += minLevel;
+
+ reqStr += "\r\n Time limit: ";
+ reqStr += eventTime + " minutes";
+
+ em.setProperty("party", reqStr);
+}
+
+function setEventExclusives(eim) {
+ var itemSet = [4001007];
+ eim.setExclusiveItems(itemSet);
+}
+
+function setEventRewards(eim) {
+ var itemSet, itemQty, evLevel, expStages;
+
+ evLevel = 1; //Rewards at clear PQ
+ itemSet = [4001011];
+ itemQty = [1];
+ eim.setEventRewards(evLevel, itemSet, itemQty);
+
+ expStages = [21000]; //bonus exp given on CLEAR stage signal
+ eim.setEventClearStageExp(expStages);
+}
+
+function getEligibleParty(party) { //selects, from the given party, the team that is allowed to attempt this event
+ var eligible = [];
+ var hasLeader = false;
+
+ if(party.size() > 0) {
+ var partyList = party.toArray();
+
+ for(var i = 0; i < party.size(); i++) {
+ var ch = partyList[i];
+
+ if(ch.getMapId() == recruitMap && ch.getLevel() >= minLevel && ch.getLevel() <= maxLevel) {
+ if(ch.isLeader()) hasLeader = true;
+ eligible.push(ch);
+ }
+ }
+ }
+
+ if(!(hasLeader && eligible.length >= minPlayers && eligible.length <= maxPlayers)) eligible = [];
+ return eligible;
+}
+
+function setup(level, lobbyid) {
+ var eim = em.newInstance("Lan4_" + lobbyid);
+ eim.setProperty("level", level);
+ eim.setProperty("stage", "0");
+
+ eim.setIntProperty("couponsNeeded", couponsNeeded);
+
+ var i;
+ for (i = 0; i < eventMaps.length; i++) {
+ var mapObj = eim.getInstanceMap(eventMaps[i]);
+ mapObj.resetPQ(level);
+ mapObj.toggleDrops();
+ mapObj.instanceMapForceRespawn();
+ }
+
+ respawnStages(eim);
+ eim.startEventTimer(eventTime * 60000);
+ setEventRewards(eim);
+ setEventExclusives(eim);
+ return eim;
+}
+
+function afterSetup(eim) {}
+
+function respawnStages(eim) {
+ var i;
+ for (i = 0; i < eventMaps.length; i++) {
+ eim.getInstanceMap(eventMaps[i]).instanceMapRespawn();
+ }
+
+ eim.schedule("respawnStages", 15 * 1000);
+}
+
+function playerEntry(eim, player) {
+ var map = eim.getMapInstance(entryMap);
+ player.changeMap(map, map.getPortal(0));
+}
+
+function scheduledTimeout(eim) {
+ end(eim);
+}
+
+function playerUnregistered(eim, player) {}
+
+function playerExit(eim, player) {
+ eim.unregisterPlayer(player);
+ player.changeMap(exitMap, 0);
+}
+
+function changedMap(eim, player, mapid) {
+ if (mapid < minMapId || mapid > maxMapId) {
+ if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+ }
+}
+
+function changedLeader(eim, leader) {
+ var mapid = leader.getMapId();
+ if (!eim.isEventCleared() && (mapid < minMapId || mapid > maxMapId)) {
+ end(eim);
+ }
+}
+
+function playerDead(eim, player) {}
+
+function playerRevive(eim, player) { // player presses ok on the death pop up.
+ if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+}
+
+function playerDisconnected(eim, player) {
+ if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+}
+
+function leftParty(eim, player) {
+ if (eim.isEventTeamLackingNow(false, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+}
+
+function disbandParty(eim) {
+ end(eim);
+}
+
+function monsterValue(eim, mobId) {
+ return 1;
+}
+
+function end(eim) {
+ var party = eim.getPlayers();
+ for (var i = 0; i < party.size(); i++) {
+ playerExit(eim, party.get(i));
+ }
+ eim.dispose();
+}
+
+function giveRandomEventReward(eim, player) {
+ eim.giveEventReward(player);
+}
+
+function clearPQ(eim) {
+ eim.stopEventTimer();
+ eim.setEventCleared();
+ eim.giveEventPlayersStageReward(1);
+
+ var i;
+ for (i = 0; i < eventMaps.length; i++) {
+ eim.getInstanceMap(eventMaps[i]).killAllMonstersNotFriendly();
+ eim.showClearEffect(eventMaps[i]);
+ }
+}
+
+function getDroppedQuantity(mob) {
+ if(mob.getLevel() > 65) {
+ return 5;
+ } else if(mob.getLevel() > 40) {
+ return 2;
+ } else {
+ return 1;
+ }
+}
+
+function monsterKilled(mob, eim) {
+ try {
+ if(eim.isEventCleared()) return;
+
+ var mapObj = mob.getMap();
+ var itemObj = new Item(4001007, 0, getDroppedQuantity(mob));
+ var dropper = eim.getPlayers().get(0);
+
+ mapObj.spawnItemDrop(mob, dropper, itemObj, mob.getPosition(), true, false);
+
+ } catch(err) {} // PQ not started yet
+}
+
+function allMonstersDead(eim) {}
+
+function cancelSchedule() {}
+
+function dispose(eim) {}
diff --git a/scripts/event/CafePQ_5.js b/scripts/event/CafePQ_5.js
new file mode 100644
index 0000000000..38ac2922d8
--- /dev/null
+++ b/scripts/event/CafePQ_5.js
@@ -0,0 +1,243 @@
+/**
+ * @author: Ronan
+ * @event: Cafe PQ 5
+*/
+
+importPackage(Packages.client.inventory);
+
+var isPq = true;
+var minPlayers = 3, maxPlayers = 6;
+var minLevel = 21, maxLevel = 120;
+var entryMap = 196000000;
+var exitMap = 193000000;
+var recruitMap = 193000000;
+
+var minMapId = 196000000;
+var maxMapId = 196010000;
+
+var eventMaps = [196000000, 196010000];
+
+var eventTime = 45; // 45 minutes
+var couponsNeeded = 500; // total of coupons to complete the event
+
+var lobbyRange = [0, 0];
+
+function init() {
+ setEventRequirements();
+}
+
+function setLobbyRange() {
+ return lobbyRange;
+}
+
+function setEventRequirements() {
+ var reqStr = "";
+
+ reqStr += "\r\n Number of players: ";
+ if(maxPlayers - minPlayers >= 1) reqStr += minPlayers + " ~ " + maxPlayers;
+ else reqStr += minPlayers;
+
+ reqStr += "\r\n Level range: ";
+ if(maxLevel - minLevel >= 1) reqStr += minLevel + " ~ " + maxLevel;
+ else reqStr += minLevel;
+
+ reqStr += "\r\n Time limit: ";
+ reqStr += eventTime + " minutes";
+
+ em.setProperty("party", reqStr);
+}
+
+function setEventExclusives(eim) {
+ var itemSet = [4001007];
+ eim.setExclusiveItems(itemSet);
+}
+
+function setEventRewards(eim) {
+ var itemSet, itemQty, evLevel, expStages;
+
+ evLevel = 1; //Rewards at clear PQ
+ itemSet = [4001012];
+ itemQty = [1];
+ eim.setEventRewards(evLevel, itemSet, itemQty);
+
+ expStages = [25000]; //bonus exp given on CLEAR stage signal
+ eim.setEventClearStageExp(expStages);
+}
+
+function getEligibleParty(party) { //selects, from the given party, the team that is allowed to attempt this event
+ var eligible = [];
+ var hasLeader = false;
+
+ if(party.size() > 0) {
+ var partyList = party.toArray();
+
+ for(var i = 0; i < party.size(); i++) {
+ var ch = partyList[i];
+
+ if(ch.getMapId() == recruitMap && ch.getLevel() >= minLevel && ch.getLevel() <= maxLevel) {
+ if(ch.isLeader()) hasLeader = true;
+ eligible.push(ch);
+ }
+ }
+ }
+
+ if(!(hasLeader && eligible.length >= minPlayers && eligible.length <= maxPlayers)) eligible = [];
+ return eligible;
+}
+
+function setup(level, lobbyid) {
+ var eim = em.newInstance("Lan5_" + lobbyid);
+ eim.setProperty("level", level);
+ eim.setProperty("stage", "0");
+
+ eim.setIntProperty("couponsNeeded", couponsNeeded);
+
+ var i;
+ for (i = 0; i < eventMaps.length; i++) {
+ var mapObj = eim.getInstanceMap(eventMaps[i]);
+ mapObj.resetPQ(level);
+ mapObj.toggleDrops();
+ mapObj.instanceMapForceRespawn();
+ }
+
+ respawnStages(eim);
+ eim.startEventTimer(eventTime * 60000);
+ setEventRewards(eim);
+ setEventExclusives(eim);
+ return eim;
+}
+
+function afterSetup(eim) {}
+
+function respawnStages(eim) {
+ var i;
+ for (i = 0; i < eventMaps.length; i++) {
+ eim.getInstanceMap(eventMaps[i]).instanceMapRespawn();
+ }
+
+ eim.schedule("respawnStages", 15 * 1000);
+}
+
+function playerEntry(eim, player) {
+ var map = eim.getMapInstance(entryMap);
+ player.changeMap(map, map.getPortal(0));
+}
+
+function scheduledTimeout(eim) {
+ end(eim);
+}
+
+function playerUnregistered(eim, player) {}
+
+function playerExit(eim, player) {
+ eim.unregisterPlayer(player);
+ player.changeMap(exitMap, 0);
+}
+
+function changedMap(eim, player, mapid) {
+ if (mapid < minMapId || mapid > maxMapId) {
+ if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+ }
+}
+
+function changedLeader(eim, leader) {
+ var mapid = leader.getMapId();
+ if (!eim.isEventCleared() && (mapid < minMapId || mapid > maxMapId)) {
+ end(eim);
+ }
+}
+
+function playerDead(eim, player) {}
+
+function playerRevive(eim, player) { // player presses ok on the death pop up.
+ if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+}
+
+function playerDisconnected(eim, player) {
+ if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+}
+
+function leftParty(eim, player) {
+ if (eim.isEventTeamLackingNow(false, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+}
+
+function disbandParty(eim) {
+ end(eim);
+}
+
+function monsterValue(eim, mobId) {
+ return 1;
+}
+
+function end(eim) {
+ var party = eim.getPlayers();
+ for (var i = 0; i < party.size(); i++) {
+ playerExit(eim, party.get(i));
+ }
+ eim.dispose();
+}
+
+function giveRandomEventReward(eim, player) {
+ eim.giveEventReward(player);
+}
+
+function clearPQ(eim) {
+ eim.stopEventTimer();
+ eim.setEventCleared();
+ eim.giveEventPlayersStageReward(1);
+
+ var i;
+ for (i = 0; i < eventMaps.length; i++) {
+ eim.getInstanceMap(eventMaps[i]).killAllMonstersNotFriendly();
+ eim.showClearEffect(eventMaps[i]);
+ }
+}
+
+function getDroppedQuantity(mob) {
+ if(mob.getLevel() > 65) {
+ return 5;
+ } else if(mob.getLevel() > 40) {
+ return 2;
+ } else {
+ return 1;
+ }
+}
+
+function monsterKilled(mob, eim) {
+ try {
+ if(eim.isEventCleared()) return;
+
+ var mapObj = mob.getMap();
+ var itemObj = new Item(4001007, 0, getDroppedQuantity(mob));
+ var dropper = eim.getPlayers().get(0);
+
+ mapObj.spawnItemDrop(mob, dropper, itemObj, mob.getPosition(), true, false);
+
+ } catch(err) {} // PQ not started yet
+}
+
+function allMonstersDead(eim) {}
+
+function cancelSchedule() {}
+
+function dispose(eim) {}
diff --git a/scripts/event/CafePQ_6.js b/scripts/event/CafePQ_6.js
new file mode 100644
index 0000000000..84089fc09a
--- /dev/null
+++ b/scripts/event/CafePQ_6.js
@@ -0,0 +1,244 @@
+/**
+ * @author: Ronan
+ * @event: Cafe PQ 6
+*/
+
+importPackage(Packages.client.inventory);
+
+var isPq = true;
+var minPlayers = 3, maxPlayers = 6;
+var minLevel = 21, maxLevel = 120;
+var entryMap = 197000000;
+var exitMap = 193000000;
+var recruitMap = 193000000;
+
+var minMapId = 197000000;
+var maxMapId = 197010000;
+
+var eventMaps = [197000000, 197010000];
+
+var eventTime = 45; // 45 minutes
+var couponsNeeded = 300; // total of coupons to complete the event
+
+var lobbyRange = [0, 0];
+
+function init() {
+ setEventRequirements();
+}
+
+function setLobbyRange() {
+ return lobbyRange;
+}
+
+function setEventRequirements() {
+ var reqStr = "";
+
+ reqStr += "\r\n Number of players: ";
+ if(maxPlayers - minPlayers >= 1) reqStr += minPlayers + " ~ " + maxPlayers;
+ else reqStr += minPlayers;
+
+ reqStr += "\r\n Level range: ";
+ if(maxLevel - minLevel >= 1) reqStr += minLevel + " ~ " + maxLevel;
+ else reqStr += minLevel;
+
+ reqStr += "\r\n Time limit: ";
+ reqStr += eventTime + " minutes";
+
+ em.setProperty("party", reqStr);
+}
+
+function setEventExclusives(eim) {
+ var itemSet = [4001007];
+ eim.setExclusiveItems(itemSet);
+}
+
+function setEventRewards(eim) {
+ var itemSet, itemQty, evLevel, expStages;
+
+ evLevel = 1; //Rewards at clear PQ
+ itemSet = [4001010];
+ itemQty = [1];
+ eim.setEventRewards(evLevel, itemSet, itemQty);
+
+ expStages = [10000]; //bonus exp given on CLEAR stage signal
+ eim.setEventClearStageExp(expStages);
+}
+
+function getEligibleParty(party) { //selects, from the given party, the team that is allowed to attempt this event
+ var eligible = [];
+ var hasLeader = false;
+
+ if(party.size() > 0) {
+ var partyList = party.toArray();
+
+ for(var i = 0; i < party.size(); i++) {
+ var ch = partyList[i];
+
+ if(ch.getMapId() == recruitMap && ch.getLevel() >= minLevel && ch.getLevel() <= maxLevel) {
+ if(ch.isLeader()) hasLeader = true;
+ eligible.push(ch);
+ }
+ }
+ }
+
+ if(!(hasLeader && eligible.length >= minPlayers && eligible.length <= maxPlayers)) eligible = [];
+ return eligible;
+}
+
+function setup(level, lobbyid) {
+ var eim = em.newInstance("Lan6_" + lobbyid);
+ eim.setProperty("level", level);
+ eim.setProperty("stage", "0");
+
+ eim.setIntProperty("couponsNeeded", couponsNeeded);
+
+ var i;
+ for (i = 0; i < eventMaps.length; i++) {
+ var mapObj = eim.getInstanceMap(eventMaps[i]);
+ mapObj.resetPQ(level);
+ mapObj.toggleDrops();
+ mapObj.instanceMapForceRespawn();
+ }
+
+ respawnStages(eim);
+ eim.startEventTimer(eventTime * 60000);
+ setEventRewards(eim);
+ setEventExclusives(eim);
+ return eim;
+}
+
+function afterSetup(eim) {}
+
+function respawnStages(eim) {
+ var i;
+ for (i = 0; i < eventMaps.length; i++) {
+ eim.getInstanceMap(eventMaps[i]).instanceMapRespawn();
+ }
+
+ eim.schedule("respawnStages", 15 * 1000);
+}
+
+function playerEntry(eim, player) {
+ var map = eim.getMapInstance(entryMap);
+ player.changeMap(map, map.getPortal(0));
+}
+
+function scheduledTimeout(eim) {
+ end(eim);
+}
+
+function playerUnregistered(eim, player) {}
+
+function playerExit(eim, player) {
+ eim.unregisterPlayer(player);
+ player.changeMap(exitMap, 0);
+}
+
+function changedMap(eim, player, mapid) {
+ if (mapid < minMapId || mapid > maxMapId) {
+ if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+ }
+}
+
+function changedLeader(eim, leader) {
+ var mapid = leader.getMapId();
+ if (!eim.isEventCleared() && (mapid < minMapId || mapid > maxMapId)) {
+ end(eim);
+ }
+}
+
+function playerDead(eim, player) {}
+
+function playerRevive(eim, player) { // player presses ok on the death pop up.
+ if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+}
+
+function playerDisconnected(eim, player) {
+ if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+}
+
+function leftParty(eim, player) {
+ if (eim.isEventTeamLackingNow(false, minPlayers, player)) {
+ eim.unregisterPlayer(player);
+ end(eim);
+ }
+ else
+ eim.unregisterPlayer(player);
+}
+
+function disbandParty(eim) {
+ end(eim);
+}
+
+function monsterValue(eim, mobId) {
+ return 1;
+}
+
+function end(eim) {
+ var party = eim.getPlayers();
+ for (var i = 0; i < party.size(); i++) {
+ playerExit(eim, party.get(i));
+ }
+ eim.dispose();
+}
+
+function giveRandomEventReward(eim, player) {
+ eim.giveEventReward(player);
+}
+
+function clearPQ(eim) {
+ eim.stopEventTimer();
+ eim.setEventCleared();
+ eim.giveEventPlayersStageReward(1);
+
+ var i;
+ for (i = 0; i < eventMaps.length; i++) {
+ eim.getInstanceMap(eventMaps[i]).killAllMonstersNotFriendly();
+ eim.showClearEffect(eventMaps[i]);
+ }
+}
+
+function getDroppedQuantity(mob) {
+ if(mob.getLevel() > 65) {
+ return 5;
+ } else if(mob.getLevel() > 40) {
+ return 2;
+ } else {
+ return 1;
+ }
+}
+
+function monsterKilled(mob, eim) {
+ try {
+ if(eim.isEventCleared()) return;
+
+ var mapObj = mob.getMap();
+ var itemObj = new Item(4001007, 0, 1);
+ var dropper = eim.getPlayers().get(0);
+
+ itemObj.setQuantity(getDroppedQuantity(mob));
+ mapObj.spawnItemDrop(mob, dropper, itemObj, mob.getPosition(), true, false);
+
+ } catch(err) {} // PQ not started yet
+}
+
+function allMonstersDead(eim) {}
+
+function cancelSchedule() {}
+
+function dispose(eim) {}
diff --git a/scripts/npc/1002002.js b/scripts/npc/1002002.js
index 098ecf5f7c..2fba5a9035 100644
--- a/scripts/npc/1002002.js
+++ b/scripts/npc/1002002.js
@@ -60,7 +60,7 @@ function action(mode, type, selection) {
if(selection == 0)
cm.gainMeso(-1500);
cm.getPlayer().saveLocation("FLORINA");
- cm.warp(110000000);
+ cm.warp(110000000, "st00");
}
cm.dispose();
}
diff --git a/scripts/npc/1052013.js b/scripts/npc/1052013.js
index a85cd12dc4..286a29d20d 100644
--- a/scripts/npc/1052013.js
+++ b/scripts/npc/1052013.js
@@ -23,10 +23,113 @@
/*
NPC ID: 1052013
NPC NAME: Computer
- @author Vcoc
+ @author Ronan
*/
+var status;
+var pqArea;
+
function start() {
- cm.sendOk("MapleStory.exe stopped working... Please, restart the game.");
- cm.dispose();
-}
\ No newline at end of file
+ status = -1;
+ action(1, 0, 0);
+}
+
+function action(mode, type, selection) {
+ if (mode == -1) {
+ cm.dispose();
+ } else {
+ if (mode == 0 && type > 0) {
+ cm.dispose();
+ return;
+ }
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if(cm.getMapId() != 193000000) {
+ var eim = cm.getEventInstance();
+
+ if(status == 0) {
+ if(!eim.isEventCleared()) {
+ var couponsNeeded = eim.getIntProperty("couponsNeeded");
+
+ if(cm.isEventLeader()) {
+ if(cm.haveItem(4001007, couponsNeeded)) {
+ cm.sendNext("Your team collected all the needed coupons, good work!");
+ cm.gainItem(4001007, couponsNeeded);
+ eim.clearPQ();
+
+ cm.dispose();
+ return;
+ } else {
+ cm.sendYesNo("Your team must collect #r" + couponsNeeded + "#k coupons to complete this event. Talk to me when you have the right amount in hands... Or you want to #bquit now#k? Note that if you quit now #ryour team will be forced to quit#k as well.");
+ }
+ } else {
+ cm.sendYesNo("Your team must collect #r" + couponsNeeded + "#k coupons to complete this event. Let your leader talk to me with the right amount in hands... Or you want to #bquit now#k? Note that if you quit now your team #rmay become undermanned#k to complete this event.");
+ }
+ } else {
+ if(!eim.giveEventReward(cm.getPlayer())) {
+ cm.sendOk("Please make a room on your ETC inventory to receive the prize.");
+ cm.dispose();
+ } else {
+ cm.warp(193000000);
+ cm.dispose();
+ }
+ }
+ } else if(status == 1) {
+ cm.warp(193000000);
+ cm.dispose();
+ }
+ } else {
+ var levels = ["#m190000000#", "#m191000000#", "#m192000000#", "#m195000000#", "#m196000000#", "#m197000000#"];
+ if (status == 0) {
+ var sendStr = "Premium Road is a place of multiple areas with monsters of most various types gathered together, an ideal place for grinding EXP and erasers for the #p1052014#. Select the area you are willing to face:\r\n\r\n#b";
+ for(var i = 0; i < 6; i++) {
+ sendStr += "#L" + i + "#" + levels[i] + "#l\r\n";
+ }
+
+ cm.sendSimple(sendStr);
+ } else if (status == 1) {
+ pqArea = selection + 1;
+
+ em = cm.getEventManager("CafePQ_" + pqArea);
+ if(em == null) {
+ cm.sendOk("The CafePQ_" + pqArea + "has encountered an error.");
+ cm.dispose();
+ return;
+ }
+
+ cm.sendSimple("#e#b\r\n#k#n" + em.getProperty("party") + "\r\n\r\nThe #p1052014# operates differently than the common ones. They do not use mesos or gachapon tickets, rather #rERASERS#k, that can be obtained by completing the missions held on the Premium Road. To go there, you must find partners and attend to a Party Quest. When teamed up and ready, have your #bparty leader#k talk to me.#b\r\n#L0#I want to participate in the party quest.\r\n#L1#I want to find party members.\r\n#L2#I would like to hear more details.");
+ } else if (status == 2) {
+ if (selection == 0) {
+ if (cm.getParty() == null) {
+ cm.sendOk("You can participate in the party quest only if you are in a party.");
+ cm.dispose();
+ } else if(!cm.isLeader()) {
+ cm.sendOk("Your party leader must talk to me to start this party quest.");
+ cm.dispose();
+ } else {
+ var eli = em.getEligibleParty(cm.getParty());
+ if(eli.size() > 0) {
+ if(!em.startInstance(cm.getParty(), cm.getPlayer().getMap(), 1)) {
+ cm.sendOk("Another party has already entered the #rParty Quest#k in this channel. Please try another channel, or wait for the current party to finish.");
+ }
+ }
+ else {
+ cm.sendOk("You cannot start this party quest yet, because either your party is not in the range size, some of your party members are not eligible to attempt it or they are not in this map. If you're having trouble finding party members, try Party Search.");
+ }
+
+ cm.dispose();
+ }
+ } else if (selection == 1) {
+ cm.sendOk("Try using a Super Megaphone or asking your buddies or guild to join!");
+ cm.dispose();
+ } else {
+ cm.sendOk("#e#b#k#n\r\nOn the maps ahead, you will face many common-leveled mobs to face on. Grind all the required coupons from them and give it to me. All members will then receive a eraser, corresponding with the level faced. Insert on the machine #bmany of the same eraser or multiple different ones#k to have a better chance on greater prizes.");
+ cm.dispose();
+ }
+ }
+ }
+ }
+}
diff --git a/scripts/npc/1052014.js b/scripts/npc/1052014.js
index 2477256bc6..eba0bd722b 100644
--- a/scripts/npc/1052014.js
+++ b/scripts/npc/1052014.js
@@ -20,13 +20,198 @@
along with this program. If not, see .
*/
-/*
- NPC ID: 1052014
- NPC NAME: Vending Machine
- @author Vcoc
+/**
+ * @author: Ronan
+ * @npc: Vending Machine
+ * @map: 193000000 - Premium Road - Kerning City Internet Cafe
+ * @func: Cafe PQ Rewarder
*/
+var status;
+
+var itemSet_lv6 = [1442046, 1432018, 1102146, 1102145, 2022094, 2022544, 2022123, 2022310, 2040727, 2041058, 2040817, 4000030, 4003005, 4003000, 4011007, 4021009, 4011008, 3010098];
+var itemQty_lv6 = [1, 1, 1, 1, 50, 20, 30, 30, 1, 1, 1, 50, 50, 50, 1, 1, 4, 1];
+
+var itemSet_lv5 = [1382015, 1382016, 1442044, 1382035, 2022310, 2022068, 2022069, 2022190, 2022047, 2040727, 2040924, 2040501, 4000030, 4003005, 4003000, 4011003, 4011006, 4021004, 3010099];
+var itemQty_lv5 = [1, 1, 1, 1, 30, 70, 70, 50, 50, 1, 1, 1, 30, 30, 40, 3, 2, 3, 1];
+
+var itemSet_lv4 = [1332029, 1472027, 1462032, 1492019, 2022045, 2022048, 2022094, 2022123, 2022058, 2041304, 2041019, 2040826, 2040758, 4000030, 4003005, 4003000, 4010007, 4011003, 4021003, 3010016, 3010017];
+var itemQty_lv4 = [1, 1, 1, 1, 70, 60, 40, 30, 100, 1, 1, 1, 1, 15, 15, 30, 8, 1, 1, 1, 1];
+
+var itemSet_lv3 = [1302058, 1372008, 1422030, 1422031, 1022082, 2022279, 2022120, 2001001, 2001002, 2022071, 2022189, 2040914, 2041001, 2041041, 2041308, 4031203, 4000030, 4003005, 4003000, 4010004, 4010006, 4020000, 4020006, 3010002, 3010003];
+var itemQty_lv3 = [1, 1, 1, 1, 1, 100, 70, 70, 70, 40, 40, 1, 1, 1, 1, 15, 10, 15, 12, 5, 5, 5, 5, 1, 1];
+
+var itemSet_lv2 = [1022073, 1012098, 1012101, 1012102, 1012103, 2022055, 2022056, 2022103, 2020029, 2020032, 2020031, 2022191, 2022016, 2043300, 2043110, 2043800, 2041001, 2040903, 4031203, 4000021, 4003005, 4003000, 4003001, 4010000, 4010001, 4010003, 4010004, 4020004, 3010004, 3010005];
+var itemQty_lv2 = [1, 1, 1, 1, 1, 70, 70, 70, 70, 100, 100, 100, 100, 1, 1, 1, 1, 1, 7, 10, 12, 10, 3, 8, 8, 5, 5, 7, 1, 1];
+
+var itemSet_lv1 = [1302021, 1302024, 1302033, 1082150, 1002419, 2022053, 2022054, 2020032, 2022057, 2022096, 2022097, 2022192, 2020030, 2010005, 2022041, 2030000, 2040100, 2040004, 2040207, 2048004, 4031203, 4000021, 4003005, 4003000, 4003001, 4010000, 4010001, 4010002, 4010005, 4020004];
+var itemQty_lv1 = [1, 1, 1, 1, 1, 30, 30, 30, 30, 30, 40, 40, 40, 80, 80, 20, 1, 1, 1, 1, 3, 5, 2, 2, 1, 3, 3, 3, 3, 3];
+
+var levels = ["Tier 1", "Tier 2", "Tier 3", "Tier 4", "Tier 5", "Tier 6"];
+
+var tickets = [0, 0, 0, 0, 0, 0];
+var currentTier;
+var curItemQty;
+var curItemSel;
+var advance = true;
+
function start() {
- cm.sendOk("At the moment, the machine is empty...");
- cm.dispose();
+ status = -1;
+ action(1, 0, 0);
+}
+
+function action(mode, type, selection) {
+ if (mode == -1) {
+ cm.dispose();
+ } else {
+ if (mode == 0 && type > 0) {
+ cm.dispose();
+ return;
+ }
+ if (mode == 1 && advance)
+ status++;
+ else
+ status--;
+
+ advance = true;
+
+ if(status == 0) {
+ cm.sendNext("This is the vending machine of the Internet Cafe. Place your erasers earned throughout the quests to redeem a prize. You can place #bany amount of erasers#k, however take note that bigger shots improves the reward possibilities!");
+ } else if(status == 1) {
+ var sendStr;
+ currentTier = getRewardTier();
+
+ if(currentTier >= 0) sendStr = "With the erasers you have currently placed, you can retrieve a #r" + levels[currentTier] + "#k prize. Place erasers:";
+ else sendStr = "You have placed no erasers yet. Place erasers:";
+
+ var listStr = "";
+ for(var i = 0; i < tickets.length; i++) {
+ listStr += "#b#L" + i + "##t" + (4001009 + i) + "##k";
+ if(tickets[i] > 0) listStr += " - " + tickets[i] + " erasers";
+ listStr += "#l\r\n";
+ }
+
+ cm.sendSimple(sendStr + "\r\n\r\n" + listStr + "#r#L6#Retrieve a prize!#l#k\r\n");
+
+ } else if(status == 2) {
+ if(selection == 6) {
+ if(currentTier < 0) {
+ cm.sendPrev("You have set no erasers. Insert at least one to claim a prize.");
+ advance = false;
+ } else {
+ givePrize();
+ cm.dispose();
+ }
+ } else {
+ var tickSel = 4001009 + selection;
+ curItemQty = cm.getItemQuantity(tickSel);
+ curItemSel = selection;
+
+ if(curItemQty > 0) {
+ cm.sendGetText("How many of #b#t" + tickSel + "##k do you want to insert on the machine? (#r" + curItemQty + "#k available)#k");
+ } else {
+ cm.sendPrev("You have got #rnone#k of #b#t" + tickSel + "##k to insert on the machine. Click '#rBack#k' to return to the main interface.");
+ advance = false;
+ }
+ }
+ } else if(status == 3) {
+ var text = cm.getText();
+
+ try {
+ var placedQty = parseInt(text);
+ if(isNaN(placedQty) || placedQty < 0) throw true;
+
+ if(placedQty > curItemQty) {
+ cm.sendPrev("You cannot insert the given amount of erasers (#r" + curItemQty + "#k available). Click '#rBack#k' to return to the main interface.");
+ advance = false;
+ } else {
+ tickets[curItemSel] = placedQty;
+
+ cm.sendPrev("Operation succeeded. Click '#rBack#k' to return to the main interface.");
+ advance = false;
+ }
+ } catch(err) {
+ cm.sendPrev("You must enter a positive number of erasers to insert. Click '#rBack#k' to return to the main interface.");
+ advance = false;
+ }
+
+ status = 2;
+ } else {
+ cm.dispose();
+ }
+ }
+}
+
+function getRewardTier() {
+ var points = getPoints();
+
+ if(points <= 6) {
+ if(points <= 0) return -1;
+ else return 0;
+ }
+ if(points >= 46) return 5;
+
+ return Math.floor((points - 6) / 8);
+}
+
+function getPoints() {
+ var points = 0;
+
+ for(var i = 0; i < tickets.length; i++) {
+ if(tickets[i] <= 0) continue;
+
+ points += (6 + ((tickets[i] - 1) * getTicketMultiplier(i))); //6 from uniques + rest from each ticket difficulty
+ }
+
+ return points;
+}
+
+function getTicketMultiplier(ticket) {
+ if(ticket == 1 || ticket == 3) return 3;
+ else return 1;
+}
+
+function givePrize() {
+ var lvTarget, lvQty;
+
+ if(currentTier == 0) {
+ lvTarget = itemSet_lv1;
+ lvQty = itemQty_lv1;
+ } else if(currentTier == 1) {
+ lvTarget = itemSet_lv2;
+ lvQty = itemQty_lv2;
+ } else if(currentTier == 2) {
+ lvTarget = itemSet_lv3;
+ lvQty = itemQty_lv3;
+ } else if(currentTier == 3) {
+ lvTarget = itemSet_lv4;
+ lvQty = itemQty_lv4;
+ } else if(currentTier == 4) {
+ lvTarget = itemSet_lv5;
+ lvQty = itemQty_lv5;
+ } else {
+ lvTarget = itemSet_lv6;
+ lvQty = itemQty_lv6;
+ }
+
+ if(!hasRewardSlot(lvTarget, lvQty)) {
+ cm.sendOk("Check for an available space on your inventory before retrieving a prize.");
+ } else {
+ var rnd = Math.floor(Math.random() * lvTarget.length);
+
+ for(var i = 0; i < tickets.length; i++) {
+ cm.gainItem(4001009 + i, -1 * tickets[i]);
+ }
+ cm.gainItem(lvTarget[rnd], lvQty[rnd]);
+ }
+}
+
+function hasRewardSlot(lvTarget, lvQty) {
+ for(var i = 0; i < lvTarget.length; i++) {
+ if(!cm.canHold(lvTarget[i], lvQty[i])) {
+ return false;
+ }
+ }
+
+ return true;
}
\ No newline at end of file
diff --git a/scripts/npc/1052015.js b/scripts/npc/1052015.js
index 97c641b192..65cf4d8c2a 100644
--- a/scripts/npc/1052015.js
+++ b/scripts/npc/1052015.js
@@ -20,13 +20,93 @@
along with this program. If not, see .
*/
-/*
- NPC ID: 1052015
- NPC NAME: Billy
- @author Vcoc
+/**
+ * @author: Ronan
+ * @npc: Billy
+ * @map: 193000000 - Premium Road - Kerning City Internet Cafe
+ * @func: Cafe PQ Reward Announcer
*/
+var status;
+
+var itemSet_lv6 = [1442046, 1432018, 1102146, 1102145, 2022094, 2022544, 2022123, 2022310, 2040727, 2041058, 2040817, 4000030, 4003005, 4003000, 4011007, 4021009, 4011008, 3010098];
+var itemQty_lv6 = [1, 1, 1, 1, 50, 20, 30, 30, 1, 1, 1, 50, 50, 50, 1, 1, 4, 1];
+
+var itemSet_lv5 = [1382015, 1382016, 1442044, 1382035, 2022310, 2022068, 2022069, 2022190, 2022047, 2040727, 2040924, 2040501, 4000030, 4003005, 4003000, 4011003, 4011006, 4021004, 3010099];
+var itemQty_lv5 = [1, 1, 1, 1, 30, 70, 70, 50, 50, 1, 1, 1, 30, 30, 40, 3, 2, 3, 1];
+
+var itemSet_lv4 = [1332029, 1472027, 1462032, 1492019, 2022045, 2022048, 2022094, 2022123, 2022058, 2041304, 2041019, 2040826, 2040758, 4000030, 4003005, 4003000, 4010007, 4011003, 4021003, 3010016, 3010017];
+var itemQty_lv4 = [1, 1, 1, 1, 70, 60, 40, 30, 100, 1, 1, 1, 1, 15, 15, 30, 8, 1, 1, 1, 1];
+
+var itemSet_lv3 = [1302058, 1372008, 1422030, 1422031, 1022082, 2022279, 2022120, 2001001, 2001002, 2022071, 2022189, 2040914, 2041001, 2041041, 2041308, 4031203, 4000030, 4003005, 4003000, 4010004, 4010006, 4020000, 4020006, 3010002, 3010003];
+var itemQty_lv3 = [1, 1, 1, 1, 1, 100, 70, 70, 70, 40, 40, 1, 1, 1, 1, 15, 10, 15, 12, 5, 5, 5, 5, 1, 1];
+
+var itemSet_lv2 = [1022073, 1012098, 1012101, 1012102, 1012103, 2022055, 2022056, 2022103, 2020029, 2020032, 2020031, 2022191, 2022016, 2043300, 2043110, 2043800, 2041001, 2040903, 4031203, 4000021, 4003005, 4003000, 4003001, 4010000, 4010001, 4010003, 4010004, 4020004, 3010004, 3010005];
+var itemQty_lv2 = [1, 1, 1, 1, 1, 70, 70, 70, 70, 100, 100, 100, 100, 1, 1, 1, 1, 1, 7, 10, 12, 10, 3, 8, 8, 5, 5, 7, 1, 1];
+
+var itemSet_lv1 = [1302021, 1302024, 1302033, 1082150, 1002419, 2022053, 2022054, 2020032, 2022057, 2022096, 2022097, 2022192, 2020030, 2010005, 2022041, 2030000, 2040100, 2040004, 2040207, 2048004, 4031203, 4000021, 4003005, 4003000, 4003001, 4010000, 4010001, 4010002, 4010005, 4020004];
+var itemQty_lv1 = [1, 1, 1, 1, 1, 30, 30, 30, 30, 30, 40, 40, 40, 80, 80, 20, 1, 1, 1, 1, 3, 5, 2, 2, 1, 3, 3, 3, 3, 3];
+
+var levels = ["Tier 1", "Tier 2", "Tier 3", "Tier 4", "Tier 5", "Tier 6"];
+
function start() {
- cm.sendOk("Do you keep seeing blue screen? Ahhh... then restart the computer.");
- cm.dispose();
-}
\ No newline at end of file
+ status = -1;
+ action(1, 0, 0);
+}
+
+function action(mode, type, selection) {
+ if (mode == -1) {
+ cm.dispose();
+ } else {
+ if (mode == 0 && status == 0) {
+ cm.dispose();
+ return;
+ }
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ var sendStr = "The #bInternet Cafe Party Quest#k rewards players with ticket-like #bfigure erasers#k, that can be used on the vending machine to retrieve prizes. By further increasing the stakes, one can get better prizes, separated by #rtiers#k.\r\n\r\nThe possible rewards for each tier are depicted here:\r\n\r\n#b";
+ for(var i = 0; i < 6; i++) {
+ sendStr += "#L" + i + "#" + levels[i] + "#l\r\n";
+ }
+
+ cm.sendSimple(sendStr);
+ } else if(status == 1) {
+ var lvTarget, lvQty;
+
+ if(selection == 0) {
+ lvTarget = itemSet_lv1;
+ lvQty = itemQty_lv1;
+ } else if(selection == 1) {
+ lvTarget = itemSet_lv2;
+ lvQty = itemQty_lv2;
+ } else if(selection == 2) {
+ lvTarget = itemSet_lv3;
+ lvQty = itemQty_lv3;
+ } else if(selection == 3) {
+ lvTarget = itemSet_lv4;
+ lvQty = itemQty_lv4;
+ } else if(selection == 4) {
+ lvTarget = itemSet_lv5;
+ lvQty = itemQty_lv5;
+ } else {
+ lvTarget = itemSet_lv6;
+ lvQty = itemQty_lv6;
+ }
+
+ var sendStr = "The following items are being awarded at #b" + levels[selection] + "#k:\r\n\r\n";
+ for(var i = 0; i < lvTarget.length; i++) {
+ sendStr += " #L" + i + "# #i" + lvTarget[i] + "# #t" + lvTarget[i] + "#";
+ if(lvQty[i] > 1) sendStr += " (" + lvQty[i] + ")";
+ sendStr += "#l\r\n";
+ }
+
+ cm.sendPrev(sendStr);
+ } else if(status == 2) {
+ cm.dispose();
+ }
+ }
+}
diff --git a/scripts/npc/1061009.js b/scripts/npc/1061009.js
index e60b962520..6083fce716 100644
--- a/scripts/npc/1061009.js
+++ b/scripts/npc/1061009.js
@@ -19,34 +19,52 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
-/* Door of Dimension
+/* 1061009 - Door of Dimension
Enter 3rd job event
*/
-function start() {
- if (cm.getPlayer().gotPartyQuestItem("JBP") && !cm.haveItem(4031059)) {
- if (cm.getPlayer().getMapId() == 105070001 && (cm.getJobId() >= 110 && cm.getJobId() <= 130))
- cm.warp(108010300);
- else if (cm.getPlayer().getMapId() == 105040305 && (cm.getJobId() >= 310 && cm.getJobId() <= 320))
- cm.warp(108010100);
- else if (cm.getPlayer().getMapId() == 100040106 && (cm.getJobId() >= 210 && cm.getJobId() <= 230))
- cm.warp(108010200);
- else if (cm.getPlayer().getMapId() == 107000402 && (cm.getJobId() >= 410 && cm.getJobId() <= 420))
- cm.warp(108010400);
- else if (cm.getPlayer().getMapId() == 105070200 && (cm.getJobId() >= 510 && cm.getJobId() <= 520))
- cm.warp(108010500);
- }
- cm.dispose();
-/*20 minutes*/
+function jobString(niche) {
+ if(niche == 1) return "warrior";
+ else if(niche == 2) return "magician";
+ else if(niche == 3) return "bowman";
+ else if(niche == 4) return "thief";
+ else if(niche == 5) return "pirate";
+
+ return "beginner";
}
-/*
+function canEnterDimensionMap(mapid, jobid) {
+ if (mapid == 105070001 && (jobid >= 110 && jobid <= 130))
+ return true;
+ else if (mapid == 105040305 && (jobid >= 310 && jobid <= 320))
+ return true;
+ else if (mapid == 100040106 && (jobid >= 210 && jobid <= 230))
+ return true;
+ else if (mapid == 107000402 && (jobid >= 410 && jobid <= 420))
+ return true;
+ else if (mapid == 105070200 && (jobid >= 510 && jobid <= 520))
+ return true;
+
+ return false;
+}
-1061010 - Crystal NPC
-*/
-/*var em = cm.getEventManager("3rdjob");
+function start() {
+ if (canEnterDimensionMap(cm.getMapId(), cm.getJob().getId()) && cm.getPlayer().gotPartyQuestItem("JBP") && !cm.haveItem(4031059)) {
+ var js = jobString(cm.getPlayer().getJob().getJobNiche());
+
+ var em = cm.getEventManager("3rdJob_" + js);
if (em == null)
- cm.sendOk("Sorry, but 3rd job advancement is closed.");
- else
- em.newInstance(cm.getPlayer().getName()).registerPlayer(cm.getPlayer());
-*/
\ No newline at end of file
+ cm.sendOk("Sorry, but 3rd job advancement (" + js + ") is closed.");
+ else {
+ if (em.getProperty("noEntry") == "false") {
+ var eim = em.newInstance("3rdjob_" + js);
+ eim.registerPlayer(cm.getPlayer());
+ }
+ else {
+ cm.sendOk("Someone else is already challenging the clone. Please wait until the area is cleared.");
+ }
+ }
+ }
+
+ cm.dispose();
+}
diff --git a/scripts/npc/2010005.js b/scripts/npc/2010005.js
index 55d534519a..a292177c9e 100644
--- a/scripts/npc/2010005.js
+++ b/scripts/npc/2010005.js
@@ -80,9 +80,10 @@ function action(mode, type, selection) {
cm.dispose();
} else
access = true;
- } if (access) {
+ }
+ if (access) {
cm.getPlayer().saveLocation("FLORINA");
- cm.warp(110000000);
+ cm.warp(110000000, "st00");
cm.dispose();
}
} else if (status == 3)
diff --git a/scripts/npc/2012006.js b/scripts/npc/2012006.js
index 7f754c7cce..3143911072 100644
--- a/scripts/npc/2012006.js
+++ b/scripts/npc/2012006.js
@@ -22,7 +22,7 @@ function action(mode, type, selection) {
sel = selection;
cm.sendNext("Ok #h #, I will send you to the platform for #m" + (200000110 + (sel * 10)) + "#");
}else if (status == 1) {
- cm.warp(200000110 + (sel * 10));
+ cm.warp(200000110 + (sel * 10), "west00");
cm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/npc/2012012.js b/scripts/npc/2012012.js
new file mode 100644
index 0000000000..7753307534
--- /dev/null
+++ b/scripts/npc/2012012.js
@@ -0,0 +1,47 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 Patrick Huy
+ Matthias Butz
+ Jan Christian Meyer
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License version 3
+ as published by the Free Software Foundation. You may not use, modify
+ or distribute this program under any other version of the
+ GNU Affero General Public License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+var status;
+
+function start() {
+ status = -1;
+ action(1, 0, 0);
+}
+
+function action(mode, type, selection) {
+ if (mode == -1) {
+ cm.dispose();
+ } else {
+ if (mode == 0 && type > 0) {
+ cm.dispose();
+ return;
+ }
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if(status == 0) {
+ cm.sendOk("Can you help me find the Ancient Book? I lost it somewhere in El Nath...");
+ cm.dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/scripts/npc/2020011.js b/scripts/npc/2020011.js
index 36a00592a1..8d5f88b33e 100644
--- a/scripts/npc/2020011.js
+++ b/scripts/npc/2020011.js
@@ -95,7 +95,7 @@ function action(mode, type, selection){
if (sel == 0){
if (cm.getPlayer().getLevel() >= 70 && cm.getJobId() % 10 == 0){
if (status == 0)
- cm.sendYesNo("Welcome. I'm #b#p2020011##k, the chief of all thieves, ready to share my street knowledge and hard knock life to those willing to listen. You seem ready to make the leap forward, the one ready to take on the challenges of the 3rd job advancement. Too many thieves have come and gone, unable to meet the standards of achieving the 3rd job advancement. What about you? Are you ready to be tested and make the 3th job advancemente?");
+ cm.sendYesNo("Welcome. I'm #b#p2020011##k, the chief of all thieves, ready to share my street knowledge and hard knock life to those willing to listen. You seem ready to make the leap forward, the one ready to take on the challenges of the 3rd job advancement. Too many thieves have come and gone, unable to meet the standards of achieving the 3rd job advancement. What about you? Are you ready to be tested and make the 3th job advancement?");
else if (status == 1){
cm.getPlayer().setPartyQuestItemObtained("JB3");
cm.sendNext("Good. You will be tested on two important aspects of the thief: strength and wisdom. I'll now explain to you the physical half of the test. Remember #b#p1052001##k from Kerning City? Go see him, and he'll give you the details on the first half of the test. Please complete the mission, and get #b#t4031057##k from #p1052001#.");
diff --git a/scripts/npc/2040016.js b/scripts/npc/2040016.js
index 86eabcb20b..2cb2bd0b3c 100644
--- a/scripts/npc/2040016.js
+++ b/scripts/npc/2040016.js
@@ -259,25 +259,26 @@ function action(mode, type, selection) {
else {
if (!cm.haveItem(mats, matQty * qty)) complete=false;
}
- }
-
- if (!complete)
- cm.sendOk("Hold it, I can't finish that without all of the proper materials. Bring them first, then we'll talk.");
- else {
- if (mats instanceof Array) {
- for (var i = 0; i < mats.length; i++){
- cm.gainItem(mats[i], -matQty[i] * qty);
+
+ if (!complete)
+ cm.sendOk("Hold it, I can't finish that without all of the proper materials. Bring them first, then we'll talk.");
+ else {
+ if (mats instanceof Array) {
+ for (var i = 0; i < mats.length; i++){
+ cm.gainItem(mats[i], -matQty[i] * qty);
+ }
}
+ else
+ cm.gainItem(mats, -matQty * qty);
+
+ if (cost > 0)
+ cm.gainMeso(-cost * qty);
+
+ cm.gainItem(recvItem, recvQty);
+ cm.sendOk("All done. If you need anything else, you know where to find me.");
}
- else
- cm.gainItem(mats, -matQty * qty);
-
- if (cost > 0)
- cm.gainMeso(-cost * qty);
-
- cm.gainItem(recvItem, recvQty);
- cm.sendOk("All done. If you need anything else, you know where to find me.");
}
+
cm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/npc/2040022.js b/scripts/npc/2040022.js
index 0ff25dfbf9..cb869209fb 100644
--- a/scripts/npc/2040022.js
+++ b/scripts/npc/2040022.js
@@ -200,10 +200,14 @@ function action(mode, type, selection) {
if(!cm.canHold(item, 1)) {
cm.sendOk("Verify for a slot in your inventory first.");
+ cm.dispose();
+ return;
}
else if (cm.getMeso() < cost)
{
cm.sendOk("I'm afraid my fees are non-negotiable.");
+ cm.dispose();
+ return;
}
else
{
diff --git a/scripts/npc/2040048.js b/scripts/npc/2040048.js
index 7304b999fa..48a3bb3804 100644
--- a/scripts/npc/2040048.js
+++ b/scripts/npc/2040048.js
@@ -75,9 +75,9 @@ function action(mode, type, selection) {
} else
access = true;
}
- if (access == true) {
+ if (access == true) {
cm.getPlayer().saveLocation("FLORINA");
- cm.warp(110000000);
+ cm.warp(110000000, "st00");
cm.dispose();
}
} else if (status == 3)
diff --git a/scripts/npc/2100001.js b/scripts/npc/2100001.js
index 740cf3ff55..312512fd6d 100644
--- a/scripts/npc/2100001.js
+++ b/scripts/npc/2100001.js
@@ -183,27 +183,27 @@ function action(mode, type, selection) {
}
else {
if (!cm.haveItem(mats, matQty * qty))complete=false;
-
}
- }
-
- if (!complete)
- cm.sendOk("Please check and see if you have all the necessary items with you. If so, then please check your etc. inventory and see if you have an empty space.");
- else {
- if (mats instanceof Array) {
- for (var i = 0; i < mats.length; i++){
- cm.gainItem(mats[i], -matQty[i] * qty);
+
+ if (!complete)
+ cm.sendOk("Please check and see if you have all the necessary items with you. If so, then please check your etc. inventory and see if you have an empty space.");
+ else {
+ if (mats instanceof Array) {
+ for (var i = 0; i < mats.length; i++){
+ cm.gainItem(mats[i], -matQty[i] * qty);
+ }
}
+ else
+ cm.gainItem(mats, -matQty * qty);
+
+ if (cost > 0)
+ cm.gainMeso(-cost * qty);
+
+ cm.gainItem(recvItem, recvQty);
+ cm.sendOk("There, finished. What do you think, a piece of art, isn't it? Well, if you need anything else, you know where to find me.");
}
- else
- cm.gainItem(mats, -matQty * qty);
-
- if (cost > 0)
- cm.gainMeso(-cost * qty);
-
- cm.gainItem(recvItem, recvQty);
- cm.sendOk("There, finished. What do you think, a piece of art, isn't it? Well, if you need anything else, you know where to find me.");
}
+
cm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/npc/2101014.js b/scripts/npc/2101014.js
index 0a3521dce3..69dcacd2b1 100644
--- a/scripts/npc/2101014.js
+++ b/scripts/npc/2101014.js
@@ -1,8 +1,8 @@
/*
- This file is part of the OdinMS Maple Story Server
+ This file is part of the OdinMS Maple Story Server
Copyright (C) 2008 Patrick Huy
- Matthias Butz
- Jan Christian Meyer
+ Matthias Butz
+ Jan Christian Meyer
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
@@ -13,13 +13,20 @@
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
+/*
+ NPC NAME: Cesar (2)
+ NPC ID: 2101014
+ Author: Vcoc
+ Function: AriantPQ
+*/
+
status = -1;
var sel;
empty = [false, false, false];
@@ -36,7 +43,7 @@ function start() {
if(cm.getPlayerCount(980010101 + (i * 100)) > 0)
continue;
else
- text += "\r\n#L" + i + "# Battle Arena " + (i + 1) + "([" + cm.getPlayerCount(980010100 + (i * 100)) + "/" + cm.getPlayer().getAriantSlotsRoom(i) + "] users" + cm.getPlayer().getAriantRoomLeaderName(i) + "/Lv 20~29 )#l";
+ text += "\r\n#L" + i + "# Battle Arena " + (i + 1) + "([" + cm.getPlayerCount(980010100 + (i * 100)) + "/" + cm.getPlayer().getAriantSlotsRoom(i) + "] users: " + cm.getPlayer().getAriantRoomLeaderName(i) + ")#l";
else{
empty[i] = true;
text += "\r\n#L" + i + "# Battle Arena " + (i + 1) + "( Empty )#l";
@@ -95,7 +102,7 @@ function action(mode, type, selection){
}else if (status == 2)
cm.sendNextPrev("It's simple. If you absorb the power of the monster #b#t2270002##k, then you'll make #b#t4031868##k, which is something Queen Areda loves. The combatant with the most jewels wins the match. It's actually a smart idea to prevent others from absorbing in order to win.");
else if (status == 3)
- cm.sendNextPrev("One thing. #rYou may not use pets for this.#k Understood?~!");
+ cm.sendNextPrev("One thing. Using #b#t2100067##k, you can steal #b#t4031868##k from your enemies. Warning: #rYou may not use pets for this.#k Understood?!");
else if (status == 4)
cm.dispose();
}
diff --git a/scripts/npc/2101017.js b/scripts/npc/2101017.js
index bb6e3013c1..51c9ad5cfb 100644
--- a/scripts/npc/2101017.js
+++ b/scripts/npc/2101017.js
@@ -1,8 +1,8 @@
/*
- This file is part of the OdinMS Maple Story Server
+ This file is part of the OdinMS Maple Story Server
Copyright (C) 2008 Patrick Huy
- Matthias Butz
- Jan Christian Meyer
+ Matthias Butz
+ Jan Christian Meyer
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
@@ -13,13 +13,20 @@
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
+/*
+ NPC NAME: Cesar (3)
+ NPC ID: 2101017
+ Author: Vcoc
+ Function: AriantPQ
+*/
+
importPackage(Packages.tools);
importPackage(Packages.client);
@@ -55,10 +62,10 @@ function action(mode, type, selection){
if(sel == 0){
if(cm.haveItem(2270002))
cm.sendNext("You already have #b#t2270002##k.");
- else if(cm.canHold(2270002) && cm.canHold(2100067)){
- if(cm.haveItem(2100067))
- cm.removeAll(2100067);
- cm.gainItem(2270002, 32);
+ else if(cm.canHold(2270002) && cm.canHold(2100067)){
+ if(cm.haveItem(2100067))
+ cm.removeAll(2100067);
+ cm.gainItem(2270002, 50);
cm.gainItem(2100067, 5);
cm.sendNext("Now lower the HP of the monsters, and use #b#t2270002##k to absorb their power!");
}else
@@ -70,6 +77,9 @@ function action(mode, type, selection){
cm.sendYesNo("Are you sure you want to leave?"); //No GMS like.
} else if (status == 1){
if(type == 1){
+ cm.removeAll(4031868);
+ cm.removeAll(2270002);
+ cm.removeAll(2100067);
cm.warp(980010020);
cm.dispose();
return;
@@ -78,7 +88,7 @@ function action(mode, type, selection){
} else if (status == 2)
cm.sendNextPrev("It's simple. If you absorb the power of the monster #b#t2270002##k, then you'll make #b#t4031868##k, which is something Queen Areda loves. The combatant with the most jewels wins the match. It's actually a smart idea to prevent others from absorbing in order to win.");
else if (status == 3)
- cm.sendNextPrev("One thing. #rYou may not use pets for this.#k Understood?~!");
+ cm.sendNextPrev("One thing. Using #b#t2100067##k, you can steal #b#t4031868##k from your enemies. Warning: #rYou may not use pets for this.#k Understood?!");
else if (status == 4)
cm.dispose();
}else{
diff --git a/scripts/npc/2101018.js b/scripts/npc/2101018.js
index 197a6269dc..51eca3877d 100644
--- a/scripts/npc/2101018.js
+++ b/scripts/npc/2101018.js
@@ -1,8 +1,8 @@
/*
- This file is part of the OdinMS Maple Story Server
+ This file is part of the OdinMS Maple Story Server
Copyright (C) 2008 Patrick Huy
- Matthias Butz
- Jan Christian Meyer
+ Matthias Butz
+ Jan Christian Meyer
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
@@ -13,13 +13,20 @@
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
+/*
+ NPC NAME: Cesar (1)
+ NPC ID: 2101018
+ Author: Vcoc
+ Function: AriantPQ
+*/
+
status = -1;
function start() {
if((cm.getPlayer().getLevel() < 19 || cm.getPlayer().getLevel() > 30) && !cm.getPlayer().isGM()){
@@ -33,7 +40,7 @@ function start() {
function action(mode, type, selection){
status++;
if (status == 4){
- cm.getPlayer().saveLocation("ARIANT");
+ cm.getPlayer().saveLocation("MIRROR");
cm.warp(980010000, 3);
cm.dispose();
}
diff --git a/scripts/npc/2112000.js b/scripts/npc/2112000.js
index 02760b8b28..9b1df35614 100644
--- a/scripts/npc/2112000.js
+++ b/scripts/npc/2112000.js
@@ -96,7 +96,8 @@ function action(mode, type, selection) {
var mapobj = eim.getMapInstance(926100401);
var bossobj = MapleLifeFactory.getMonster(9300139);
- mapobj.spawnMonsterOnGroundBelow(bossobj, new Packages.java.awt.Point(250, 100));
+
+ mapobj.spawnMonsterWithEffect(bossobj, 13, new Packages.java.awt.Point(250, 100));
eim.setIntProperty("statusStg7", 1);
eim.setIntProperty("yuletePassed", -1);
@@ -106,7 +107,8 @@ function action(mode, type, selection) {
var mapobj = eim.getMapInstance(926100401);
var bossobj = MapleLifeFactory.getMonster(9300140);
- mapobj.spawnMonsterOnGroundBelow(bossobj, new Packages.java.awt.Point(250, 100));
+
+ mapobj.spawnMonsterWithEffect(bossobj, 14, new Packages.java.awt.Point(250, 100));
eim.setIntProperty("statusStg7", 2);
eim.setIntProperty("yuletePassed", -1);
diff --git a/scripts/npc/9000038.js b/scripts/npc/9000038.js
index 1d3e62670f..ba04e6f605 100644
--- a/scripts/npc/9000038.js
+++ b/scripts/npc/9000038.js
@@ -7,11 +7,11 @@
var status;
-var itemSet_lv6 = [1122018, 1122005, 1022088, 1402013, 1032030, 1032070, 1102046, 2330004, 2041013, 2041016, 2041019, 2041022, 2049100, 2049003, 2020012, 2020013, 2020014, 2020015, 2022029, 2022045, 2022068, 2022069, 2022179, 2022180, 4004000, 4004001, 4004002, 4004003, 4004004, 4003000];
-var itemQty_lv6 = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 25, 25, 25, 25, 25, 25, 25, 25, 4, 4, 12, 12, 12, 12, 12, 25];
+var itemSet_lv6 = [3010061, 1122018, 1122005, 1022088, 1402013, 1032030, 1032070, 1102046, 2330004, 2041013, 2041016, 2041019, 2041022, 2049100, 2049003, 2020012, 2020013, 2020014, 2020015, 2022029, 2022045, 2022068, 2022069, 2022179, 2022180, 4004000, 4004001, 4004002, 4004003, 4004004, 4003000];
+var itemQty_lv6 = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 25, 25, 25, 25, 25, 25, 25, 25, 4, 4, 12, 12, 12, 12, 12, 25];
-var itemSet_lv5 = [1122018, 1122005, 1022088, 1402013, 1032030, 1032070, 1102046, 2330004, 2041013, 2041016, 2041019, 2041022, 2049100, 2049003, 2020012, 2020013, 2020014, 2020015, 2022029, 2022045, 2022068, 2022069, 2022179, 2022180, 4004000, 4004001, 4004002, 4004003, 4004004, 4003000];
-var itemQty_lv5 = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 8, 8, 8, 8, 8, 12];
+var itemSet_lv5 = [3010063, 1122018, 1122005, 1022088, 1402013, 1032030, 1032070, 1102046, 2330004, 2041013, 2041016, 2041019, 2041022, 2049100, 2049003, 2020012, 2020013, 2020014, 2020015, 2022029, 2022045, 2022068, 2022069, 2022179, 2022180, 4004000, 4004001, 4004002, 4004003, 4004004, 4003000];
+var itemQty_lv5 = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 8, 8, 8, 8, 8, 12];
var itemSet_lv4 = [1122001, 1122006, 1022103, 1442065, 1032042, 1032021, 1102168, 2070005, 2040025, 2040029, 2040301, 2040413, 2040701, 2040817, 2002028, 2020009, 2020010, 2020011, 2022004, 2022005, 2022025, 2022027, 2022048, 2022049, 4020000, 4020001, 4020002, 4020003, 4020004, 4020005, 4020006, 4020007, 4020008, 4003000];
var itemQty_lv4 = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 45, 45, 45, 45, 45, 45, 45, 45, 45, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8];
diff --git a/scripts/npc/9010022.js b/scripts/npc/9010022.js
index ea4f8fdb8b..31c1fea1ef 100644
--- a/scripts/npc/9010022.js
+++ b/scripts/npc/9010022.js
@@ -27,29 +27,31 @@ function action(mode, type, selection) {
cm.dispose();
} else {
var selStr = "";
- if (cm.getLevel() >= 20 && cm.getLevel() <= 30) {
+ /*if (cm.getLevel() >= 20 && cm.getLevel() <= 30) { NOT IMPLEMENTED
selStr += "#0# Ariant Coliseum";
- }
+ } */
if (cm.getLevel() >= 25) {
selStr += "#1# Mu Lung Dojo";
}
- if (cm.getLevel() >= 30 && cm.getLevel() <= 50) {
+ /*if (cm.getLevel() >= 30 && cm.getLevel() <= 50) { NOT IMPLEMENTED
selStr += "#2# Monster Carnival 1";
}
- if (cm.getLevel() >= 51 && cm.getLevel() <= 70) {
+ if (cm.getLevel() >= 51 && cm.getLevel() <= 70) { NOT IMPLEMENTED
selStr += "#3# Monster Carnival 2";
}
- if (cm.getLevel() >= 40) {
+ if (cm.getLevel() >= 40) { NOT IMPLEMENTED
selStr += "#5# Nett's Pyramid";
}
- if (cm.getLevel() >= 25 && cm.getLevel() <= 30) {
+ if (cm.getLevel() >= 25 && cm.getLevel() <= 30) { NOT IMPLEMENTED
selStr += "#6# Construction Site";
}
+ */
+
cm.sendDimensionalMirror(selStr);
}
} else if (status == 1) {
diff --git a/scripts/npc/9010022_old.js b/scripts/npc/9010022_old.js
new file mode 100644
index 0000000000..ea4f8fdb8b
--- /dev/null
+++ b/scripts/npc/9010022_old.js
@@ -0,0 +1,80 @@
+importPackage(Packages.client);
+importPackage(Packages.server.maps);
+
+var status;
+var sel;
+
+function start() {
+ status = -1;
+ action(1, 0, 0);
+}
+
+function action(mode, type, selection) {
+ if (mode == -1) {
+ cm.dispose();
+ } else {
+ if (mode == 0) {
+ cm.dispose();
+ return;
+ }
+ if (mode == 1)
+ status++;
+ else
+ status--;
+ if (status == 0) {
+ if (cm.getLevel() < 20) {
+ cm.sendDimensionalMirror("#-1# There is no place for you to transport to from here.");
+ cm.dispose();
+ } else {
+ var selStr = "";
+ if (cm.getLevel() >= 20 && cm.getLevel() <= 30) {
+ selStr += "#0# Ariant Coliseum";
+ }
+
+ if (cm.getLevel() >= 25) {
+ selStr += "#1# Mu Lung Dojo";
+ }
+
+ if (cm.getLevel() >= 30 && cm.getLevel() <= 50) {
+ selStr += "#2# Monster Carnival 1";
+ }
+
+ if (cm.getLevel() >= 51 && cm.getLevel() <= 70) {
+ selStr += "#3# Monster Carnival 2";
+ }
+
+ if (cm.getLevel() >= 40) {
+ selStr += "#5# Nett's Pyramid";
+ }
+
+ if (cm.getLevel() >= 25 && cm.getLevel() <= 30) {
+ selStr += "#6# Construction Site";
+ }
+ cm.sendDimensionalMirror(selStr);
+ }
+ } else if (status == 1) {
+ cm.getPlayer().saveLocation("MIRROR");
+ switch (selection) {
+ case 0:
+ cm.warp(980010000, 3);
+ break;
+ case 1:
+ cm.warp(925020000, 0);
+ break;
+ case 2:
+ cm.warp(980000000, 3);
+ break;
+ case 3:
+ cm.warp(980030000, 3);
+ break;
+ case 5:
+ cm.warp(926010000);
+ break;
+ case 6:
+ cm.warp(910320000);
+ break;
+ }
+ cm.dispose();
+ }
+ }
+}
diff --git a/scripts/npc/9209000.js b/scripts/npc/9209000.js
index 7785f506bf..bd821adde1 100644
--- a/scripts/npc/9209000.js
+++ b/scripts/npc/9209000.js
@@ -34,7 +34,7 @@ function action(mode, type, selection) {
masterybook = cm.getAvailableMasteryBooks();
if(skillbook.length == 0 && masterybook.length == 0) {
- cm.sendOk(greeting + "There are no more books available to further improve your job skills for now. Either you maxed out everything or you didn't reach the minimum requisites for some skill books yet.");
+ cm.sendOk(greeting + "There are no more books available to further improve your job skills for now. Either you #bmaxed out everything#k or #byou didn't reach the minimum requisites to use some skill books#k yet.");
cm.dispose();
} else if(skillbook.length > 0 && masterybook.length > 0) {
diff --git a/scripts/npc/9270018.js b/scripts/npc/9270018.js
index f655803d27..d21c82daeb 100644
--- a/scripts/npc/9270018.js
+++ b/scripts/npc/9270018.js
@@ -62,10 +62,12 @@ function action(mode, type, selection) {
cm.sendYesNo("The plane is taking off soon, are you sure you want to leave now? The ticket is not refundable.");
airport = 1;
} else if (cm.getMapId() == 540010002) {
- cm.sendYesNo("We're reaching Kerning City in a minute, are you sure you want to leave now? The ticket is not refundable.");
+ cm.sendOk("We're reaching Kerning City in a minute, please sit down and wait.");
+ cm.dispose();
s2k = 1;
} else if (cm.getMapId() == 540010101) {
- cm.sendYesNo("We're reaching Singapore in a minute, are you sure you want to leave now? The ticket is not refundable.");
+ cm.sendOk("We're reaching Singapore in a minute, please sit down and wait.");
+ cm.dispose();
k2s = 1;
}
} else if(status == 1) {
diff --git a/scripts/npc/commands.js b/scripts/npc/commands.js
index 94a2f8c437..270ac092a9 100644
--- a/scripts/npc/commands.js
+++ b/scripts/npc/commands.js
@@ -60,8 +60,8 @@ function writeSolaxiaCommandsLv5() { //Developer
addCommand("debugmonster", "");
addCommand("debugpacket", "");
- addCommand("debugnearestportal", "");
- addCommand("debugnearestspawnpoint", "");
+ addCommand("debugportal", "");
+ addCommand("debugspawnpoint", "");
addCommand("debugpos", "");
addCommand("debugmap", "");
addCommand("debugmobsp", "");
@@ -204,6 +204,7 @@ function writeSolaxiaCommandsLv0() { //Common
addCommand("whodrops", "");
addCommand("dispose", "");
addCommand("equiplv", "");
+ addCommand("showrates", "");
addCommand("rates", "");
addCommand("online", "");
addCommand("gm", "");
diff --git a/scripts/portal/catPriest_map.js b/scripts/portal/catPriest_map.js
new file mode 100644
index 0000000000..ae00495f3a
--- /dev/null
+++ b/scripts/portal/catPriest_map.js
@@ -0,0 +1,4 @@
+function enter(pi) {
+ pi.warp(925000000, 2);
+ return true;
+}
\ No newline at end of file
diff --git a/sql/db_database.sql b/sql/db_database.sql
index ac40336741..131bb622e5 100644
--- a/sql/db_database.sql
+++ b/sql/db_database.sql
@@ -16369,6 +16369,13 @@ CREATE TABLE IF NOT EXISTS `pets` (
PRIMARY KEY (`petid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+CREATE TABLE IF NOT EXISTS `petignores` (
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+ `petid` int(10) unsigned NOT NULL ,
+ `itemid` int(10) unsigned NOT NULL ,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
CREATE TABLE IF NOT EXISTS `playernpcs` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(13) NOT NULL,
@@ -20658,7 +20665,7 @@ INSERT INTO `shopitems` (`shopitemid`, `shopid`, `itemid`, `price`, `pitch`, `po
(6486, 1337, 5072000, 1, 0, 8),
(6487, 1337, 5390000, 1, 0, 9),
(6488, 1337, 5390001, 1, 0, 10),
-(6489, 1337, 5390001, 1, 0, 11),
+(6489, 1337, 5390002, 1, 0, 11),
(6490, 1337, 1452044, 1, 0, 12),
(6491, 1337, 1472052, 1, 0, 13),
(6492, 1337, 1462039, 1, 0, 14),
@@ -21214,7 +21221,8 @@ INSERT INTO `shopitems` ( `shopid`, `itemid`, `price`, `position`) VALUES
(1052116, 2000003, 200, 208),
(1052116, 2000002, 320, 212),
(1052116, 2000001, 160, 216),
-(1052116, 2000000, 50, 220);
+(1052116, 2000000, 50, 220),
+(9120002, 2061003, 40, 0, 100);
CREATE TABLE IF NOT EXISTS `skillmacros` (
`id` int(11) NOT NULL AUTO_INCREMENT,
diff --git a/sql/db_drops.sql b/sql/db_drops.sql
index 29e4e9e8b2..6eeb3ed445 100644
--- a/sql/db_drops.sql
+++ b/sql/db_drops.sql
@@ -19816,8 +19816,9 @@ USE `maplesolaxia`;
(9420501, 1492005, 1, 1, 0, 2000),
(8820001, 2388043, 1, 1, 0, 24000);
- # delete item drops from Seruf in inactive form
+ # delete item drops from bosses in inactive form
DELETE FROM temp_data WHERE dropperid=4220001;
+ DELETE FROM temp_data WHERE dropperid=5220001;
# delete item drops from summoned Slimes
DELETE FROM temp_data WHERE dropperid=9500100;
@@ -19917,8 +19918,8 @@ USE `maplesolaxia`;
DELETE FROM drop_data WHERE dropperid >= 9300054 AND dropperid <= 9300056;
DELETE FROM drop_data WHERE dropperid >= 9300143 AND dropperid <= 9300144;
DELETE FROM drop_data WHERE dropperid >= 8810019 AND dropperid <= 8810023;
+ DELETE FROM drop_data WHERE dropperid = 9300157;
DELETE FROM drop_data WHERE dropperid = 9500100;
-
DELETE FROM drop_data where dropperid >= 9300141 AND dropperid <= 9300154 AND (itemid < 4001130 OR itemid >= 4001136);
# remove key of dimension dropping outside PQ
@@ -19931,6 +19932,41 @@ USE `maplesolaxia`;
DELETE FROM drop_data WHERE dropperid >= 9300184 AND dropperid < 9300215 AND (itemid < 2380000 OR itemid >= 2390000);
DELETE FROM drop_data WHERE dropperid >= 9500337 AND dropperid < 9500364 AND (itemid < 2380000 OR itemid >= 2390000);
+ # reinsert loot for Dark Nependeath
+ DELETE FROM drop_data WHERE dropperid=4130104;
+ INSERT IGNORE INTO drop_data (`dropperid`, `itemid`, `minimum_quantity`, `maximum_quantity`, `questid`, `chance`) VALUES
+(4130104, 4000062, 1, 1, 0, 600000),
+(4130104, 2041014, 1, 1, 0, 300),
+(4130104, 4004004, 1, 1, 0, 10000),
+(4130104, 2000002, 1, 1, 0, 20000),
+(4130104, 2000004, 1, 1, 0, 20000),
+(4130104, 2000003, 1, 1, 0, 20000),
+(4130104, 4020006, 1, 1, 0, 9000),
+(4130104, 4010003, 1, 1, 0, 9000),
+(4130104, 4004000, 1, 1, 0, 10000),
+(4130104, 1302013, 1, 1, 0, 700),
+(4130104, 2044201, 1, 1, 0, 300),
+(4130104, 4006001, 1, 1, 0, 10000),
+(4130104, 1051027, 1, 1, 0, 700),
+(4130104, 1002092, 1, 1, 0, 1500),
+(4130104, 1040080, 1, 1, 0, 800),
+(4130104, 1060068, 1, 1, 0, 800),
+(4130104, 1072110, 1, 1, 0, 800),
+(4130104, 1082063, 1, 1, 0, 1000),
+(4130104, 1041087, 1, 1, 0, 800),
+(4130104, 1061086, 1, 1, 0, 800),
+(4130104, 1040095, 1, 1, 0, 800),
+(4130104, 1060084, 1, 1, 0, 800),
+(4130104, 1082084, 1, 1, 0, 1000),
+(4130104, 1072132, 1, 1, 0, 800),
+(4130104, 4130000, 1, 1, 0, 6000),
+(4130104, 4130003, 1, 1, 0, 6000),
+(4130104, 4130013, 1, 1, 0, 6000),
+(4130104, 2383003, 1, 1, 0, 8000),
+(4130104, 0, 172, 258, 0, 400000),
+(4130104, 1040096, 1, 1, 0, 700),
+(4130104, 1060085, 1, 1, 0, 700);
+
# reinsert dojo loot
INSERT IGNORE INTO drop_data (`dropperid`, `itemid`, `minimum_quantity`, `maximum_quantity`, `questid`, `chance`) VALUES
(9300184, 2022359, 1, 1, 0, 200000),
diff --git a/sql/db_shopupdate.sql b/sql/db_shopupdate.sql
index 56d2cf0273..06f0bfe730 100644
--- a/sql/db_shopupdate.sql
+++ b/sql/db_shopupdate.sql
@@ -90,28 +90,14 @@ INSERT IGNORE INTO `shopitems` (`shopitemid`, `shopid`, `itemid`, `price`, `pitc
UPDATE shopitems SET price = 11*price WHERE (`position` >= 27 and `position` <= 67 and `shopid` = 9201082);
INSERT IGNORE INTO `shopitems` (`shopid`, `itemid`, `price`, `pitch`, `position`) VALUES
-(9120002, 3010005, 5000, 0, 80),
-(9120002, 3010004, 5000, 0, 84),
-(9120002, 3010006, 5000, 0, 88),
-(9120002, 3010003, 5000, 0, 92),
-(9120002, 3010002, 5000, 0, 96),
-(9120002, 2061003, 40, 0, 100),
-(9201020, 3010011, 1200, 0, 92),
-(9201020, 3010009, 4200, 0, 96),
-(9201020, 3010014, 15000, 0, 100),
(1031100, 3010015, 20000, 0, 100),
-(1081000, 3010013, 100000, 0, 100),
-(9110002, 3010019, 770000, 0, 80),
-(9110002, 3010017, 1000000, 0, 84),
-(9110002, 3010016, 1000000, 0, 88),
-(9110002, 3010008, 1000000, 0, 92),
-(9110002, 3010007, 1000000, 0, 96),
-(9110002, 3011000, 4200000, 0, 100),
-(2100004, 3010064, 3000000, 0, 100),
-(1052116, 3010098, 7700000, 0, 92),
-(1052116, 3010063, 1400000, 0, 96),
-(1052116, 3010061, 250000, 0, 100),
-(2030009, 3010099, 10000000, 0, 100);
+(9110002, 3010019, 7700000, 0, 92),
+(9110002, 3010008, 10000000, 0, 96),
+(9110002, 3010007, 10000000, 0, 100),
+(9201020, 3010011, 12000000, 0, 92),
+(9201020, 3010009, 4200000, 0, 96),
+(9201020, 3010014, 7000000, 0, 100),
+(1081000, 3010013, 4000000, 0, 100);
# adding antibanish scrolls
INSERT IGNORE INTO `shopitems` (`shopid`, `itemid`, `price`, `pitch`, `position`) VALUES
diff --git a/src/client/MapleCharacter.java b/src/client/MapleCharacter.java
index 45f7505c62..7bd04b4ae9 100644
--- a/src/client/MapleCharacter.java
+++ b/src/client/MapleCharacter.java
@@ -115,6 +115,7 @@ import client.inventory.MapleInventoryType;
import client.inventory.MaplePet;
import client.inventory.MapleWeaponType;
import client.inventory.ModifyInventory;
+import client.inventory.PetDataFactory;
import constants.ExpTable;
import constants.GameConstants;
import constants.ItemConstants;
@@ -254,8 +255,10 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
private ScheduledFuture> pendantOfSpirit = null; //1122017
private List> timers = new ArrayList<>();
private Lock chrLock = new ReentrantLock();
+ private Lock petLock = new ReentrantLock();
private NumberFormat nf = new DecimalFormat("#,###,###,###");
- private ArrayList excluded = new ArrayList<>();
+ private Map> excluded = new LinkedHashMap<>();
+ private Set excludedItems = new LinkedHashSet<>();
private List crushRings = new ArrayList<>();
private List friendshipRings = new ArrayList<>();
private static String[] ariantroomleader = new String[3];
@@ -266,6 +269,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
private Map area_info = new LinkedHashMap<>();
private AutobanManager autoban;
private boolean isbanned = false;
+ private boolean blockCashShop = false;
private byte pendantExp = 0, lastmobcount = 0, doorSlot = -1;
private List trockmaps = new ArrayList<>();
private List viptrockmaps = new ArrayList<>();
@@ -479,10 +483,6 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
}
- public void addExcluded(int x) {
- excluded.add(x);
- }
-
public void addFame(int famechange) {
this.fame += famechange;
}
@@ -513,11 +513,16 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
public void addPet(MaplePet pet) {
- for (int i = 0; i < 3; i++) {
- if (pets[i] == null) {
- pets[i] = pet;
- return;
+ petLock.lock();
+ try {
+ for (int i = 0; i < 3; i++) {
+ if (pets[i] == null) {
+ pets[i] = pet;
+ return;
+ }
}
+ } finally {
+ petLock.unlock();
}
}
@@ -775,6 +780,14 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
public void setLastMobCount(byte count) {
lastmobcount = count;
}
+
+ public boolean cannotEnterCashShop() {
+ return blockCashShop;
+ }
+
+ public void toggleBlockCashShop() {
+ blockCashShop = !blockCashShop;
+ }
public void newClient(MapleClient c) {
this.loggedIn = true;
@@ -895,7 +908,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
if (effect.isMonsterRiding()) {
if (effect.getSourceId() != Corsair.BATTLE_SHIP) {
- this.getMount().cancelSchedule();
+ this.getClient().getWorldServer().unregisterMountHunger(this);
this.getMount().setActive(false);
}
}
@@ -962,12 +975,6 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
Hide(!isHidden());
}
- private void cancelFullnessSchedule(int petSlot) {
- if (fullnessSchedule[petSlot] != null) {
- fullnessSchedule[petSlot].cancel(false);
- }
- }
-
public void cancelMagicDoor() {
List mbsvhList;
@@ -1028,7 +1035,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
public void setMasteries(int jobId) {
int[] skills = new int[4];
for (int i = 0; i > skills.length; i++) {
- skills[i] = 0; //that initalization meng
+ skills[i] = 0; //that initialization meng
}
if (jobId == 112) {
skills[0] = Hero.ACHILLES;
@@ -1094,6 +1101,9 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
for (Integer skillId : skills) {
if (skillId != 0) {
Skill skill = SkillFactory.getSkill(skillId);
+ final int skilllevel = getSkillLevel(skill);
+ if(skilllevel > 0) continue;
+
changeSkillLevel(skill, (byte) 0, 10, -1);
}
}
@@ -1161,7 +1171,11 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
setMasteries(this.job.getId());
guildUpdate();
+
+ getMap().broadcastMessage(this, MaplePacketCreator.removePlayerFromMap(this.getId()), false);
+ getMap().broadcastMessage(this, MaplePacketCreator.spawnPlayerMapobject(this), false);
getMap().broadcastMessage(this, MaplePacketCreator.showForeignEffect(getId(), 8), false);
+
if (GameConstants.hasSPTable(newJob) && newJob.getId() != 2001) {
if (getBuffedValue(MapleBuffStat.MONSTER_RIDING) != null) {
cancelBuffStats(MapleBuffStat.MONSTER_RIDING);
@@ -1205,7 +1219,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
return new Pair<>(this.banishMap, this.banishSp);
}
- private void clearBanishPlayerData() {
+ public void clearBanishPlayerData() {
this.banishMap = -1;
this.banishSp = -1;
this.banishTime = 0;
@@ -1316,7 +1330,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
if(mbs.getKey() == MapleBuffStat.MAP_PROTECTION) {
byte value = (byte)mbs.getValue().value;
- if(value == 1 && thisMap.getReturnMapId() == 211000000) return true; //protection from cold
+ if(value == 1 && (thisMap.getReturnMapId() == 211000000 || thisMap.getReturnMapId() == 193000000)) return true; //protection from cold
else if(value == 2 && (thisMap.getReturnMapId() == 211000000 || thisMap.getReturnMapId() == 230000000)) return true; //breathing underwater
else return false;
}
@@ -2738,8 +2752,86 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
return eventInstance;
}
- public ArrayList getExcluded() {
- return excluded;
+ public void resetExcluded(int petId) {
+ chrLock.lock();
+ try {
+ Set petExclude = excluded.get(petId);
+
+ if(petExclude != null) petExclude.clear();
+ else excluded.put(petId, new LinkedHashSet());
+ } finally {
+ chrLock.unlock();
+ }
+ }
+
+ public void addExcluded(int petId, int x) {
+ chrLock.lock();
+ try {
+ excluded.get(petId).add(x);
+ } finally {
+ chrLock.unlock();
+ }
+ }
+
+ public void commitExcludedItems() {
+ Map> petExcluded = this.getExcluded();
+
+ chrLock.lock();
+ try {
+ excludedItems.clear();
+ } finally {
+ chrLock.unlock();
+ }
+
+ for(Map.Entry> pe : petExcluded.entrySet()) {
+ byte petIndex = this.getPetIndex(pe.getKey());
+ if(petIndex < 0) continue;
+
+ Set exclItems = pe.getValue();
+ if (!exclItems.isEmpty()) {
+ client.announce(MaplePacketCreator.loadExceptionList(this.getId(), pe.getKey(), petIndex, new ArrayList<>(exclItems)));
+
+ chrLock.lock();
+ try {
+ for(Integer itemid: exclItems) {
+ excludedItems.add(itemid);
+ }
+ } finally {
+ chrLock.unlock();
+ }
+ }
+ }
+ }
+
+ public void exportExcludedItems(MapleClient c) {
+ Map> petExcluded = this.getExcluded();
+ for(Map.Entry> pe : petExcluded.entrySet()) {
+ byte petIndex = this.getPetIndex(pe.getKey());
+ if(petIndex < 0) continue;
+
+ Set exclItems = pe.getValue();
+ if (!exclItems.isEmpty()) {
+ c.announce(MaplePacketCreator.loadExceptionList(this.getId(), pe.getKey(), petIndex, new ArrayList<>(exclItems)));
+ }
+ }
+ }
+
+ public Map> getExcluded() {
+ chrLock.lock();
+ try {
+ return Collections.unmodifiableMap(excluded);
+ } finally {
+ chrLock.unlock();
+ }
+ }
+
+ public Set getExcludedItems() {
+ chrLock.lock();
+ try {
+ return Collections.unmodifiableSet(excludedItems);
+ } finally {
+ chrLock.unlock();
+ }
}
public int getExp() {
@@ -3177,22 +3269,32 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
public int getNextEmptyPetIndex() {
- for (int i = 0; i < 3; i++) {
- if (pets[i] == null) {
- return i;
+ petLock.lock();
+ try {
+ for (int i = 0; i < 3; i++) {
+ if (pets[i] == null) {
+ return i;
+ }
}
+ return 3;
+ } finally {
+ petLock.unlock();
}
- return 3;
}
public int getNoPets() {
- int ret = 0;
- for (int i = 0; i < 3; i++) {
- if (pets[i] != null) {
- ret++;
+ petLock.lock();
+ try {
+ int ret = 0;
+ for (int i = 0; i < 3; i++) {
+ if (pets[i] != null) {
+ ret++;
+ }
}
+ return ret;
+ } finally {
+ petLock.unlock();
}
- return ret;
}
public int getNumControlledMonsters() {
@@ -3345,33 +3447,55 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
public MaplePet[] getPets() {
- return pets;
+ petLock.lock();
+ try {
+ return Arrays.copyOf(pets, pets.length);
+ } finally {
+ petLock.unlock();
+ }
}
public MaplePet getPet(int index) {
- return pets[index];
+ if(index < 0) return null;
+
+ petLock.lock();
+ try {
+ return pets[index];
+ } finally {
+ petLock.unlock();
+ }
}
public byte getPetIndex(int petId) {
- for (byte i = 0; i < 3; i++) {
- if (pets[i] != null) {
- if (pets[i].getUniqueId() == petId) {
- return i;
+ petLock.lock();
+ try {
+ for (byte i = 0; i < 3; i++) {
+ if (pets[i] != null) {
+ if (pets[i].getUniqueId() == petId) {
+ return i;
+ }
}
}
+ return -1;
+ } finally {
+ petLock.unlock();
}
- return -1;
}
public byte getPetIndex(MaplePet pet) {
- for (byte i = 0; i < 3; i++) {
- if (pets[i] != null) {
- if (pets[i].getUniqueId() == pet.getUniqueId()) {
- return i;
+ petLock.lock();
+ try {
+ for (byte i = 0; i < 3; i++) {
+ if (pets[i] != null) {
+ if (pets[i].getUniqueId() == pet.getUniqueId()) {
+ return i;
+ }
}
}
+ return -1;
+ } finally {
+ petLock.unlock();
}
- return -1;
}
public int getPossibleReports() {
@@ -4404,6 +4528,29 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
}
}
+
+ PreparedStatement ps2;
+ ResultSet rs2;
+ for(byte i = 0; i < 3; i++) {
+ MaplePet pet = ret.getPet(i);
+ if(pet == null) continue;
+
+ int petId = pet.getUniqueId();
+ ps2 = con.prepareStatement("SELECT itemid FROM petignores WHERE petid = ?"); // Get pet details..
+ ps2.setInt(1, petId);
+
+ ret.resetExcluded(petId);
+
+ rs2 = ps2.executeQuery();
+ while(rs2.next()) {
+ ret.addExcluded(petId, rs2.getInt("itemid"));
+ }
+
+ ps2.close();
+ rs2.close();
+ }
+ ret.commitExcludedItems();
+
if (channelserver) {
MapleMapFactory mapFactory = client.getChannelServer().getMapFactory();
ret.map = mapFactory.getMap(ret.mapid);
@@ -5124,26 +5271,31 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
public void removePet(MaplePet pet, boolean shift_left) {
- int slot = -1;
- for (int i = 0; i < 3; i++) {
- if (pets[i] != null) {
- if (pets[i].getUniqueId() == pet.getUniqueId()) {
- pets[i] = null;
- slot = i;
- break;
- }
- }
- }
- if (shift_left) {
- if (slot > -1) {
- for (int i = slot; i < 3; i++) {
- if (i != 2) {
- pets[i] = pets[i + 1];
- } else {
+ petLock.lock();
+ try {
+ int slot = -1;
+ for (int i = 0; i < 3; i++) {
+ if (pets[i] != null) {
+ if (pets[i].getUniqueId() == pet.getUniqueId()) {
pets[i] = null;
+ slot = i;
+ break;
}
}
}
+ if (shift_left) {
+ if (slot > -1) {
+ for (int i = slot; i < 3; i++) {
+ if (i != 2) {
+ pets[i] = pets[i + 1];
+ } else {
+ pets[i] = null;
+ }
+ }
+ }
+ }
+ } finally {
+ petLock.unlock();
}
}
@@ -5484,11 +5636,34 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
if (updateRows < 1) {
throw new RuntimeException("Character not in database (" + id + ")");
}
- for (int i = 0; i < 3; i++) {
- if (pets[i] != null) {
- pets[i].saveToDb();
+
+ petLock.lock();
+ try {
+ for (int i = 0; i < 3; i++) {
+ if (pets[i] != null) {
+ pets[i].saveToDb();
+ }
+ }
+ } finally {
+ petLock.unlock();
+ }
+
+ for(Entry> es: getExcluded().entrySet()) {
+ try (PreparedStatement ps2 = con.prepareStatement("DELETE FROM petignores WHERE petid=?")) {
+ ps2.setInt(1, es.getKey());
+ ps2.executeUpdate();
+ }
+
+ try (PreparedStatement ps2 = con.prepareStatement("INSERT INTO petignores (petid, itemid) VALUES (?, ?)")) {
+ ps2.setInt(1, es.getKey());
+ for(Integer x: es.getValue()) {
+ ps2.setInt(2, x);
+ ps2.addBatch();
+ }
+ ps2.executeBatch();
}
}
+
deleteWhereCharacterId(con, "DELETE FROM keymap WHERE characterid = ?");
ps = con.prepareStatement("INSERT INTO keymap (characterid, `key`, `type`, `action`) VALUES (?, ?, ?, ?)");
ps.setInt(1, id);
@@ -6212,10 +6387,15 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
public void shiftPetsRight() {
- if (pets[2] == null) {
- pets[2] = pets[1];
- pets[1] = pets[0];
- pets[0] = null;
+ petLock.lock();
+ try {
+ if (pets[2] == null) {
+ pets[2] = pets[1];
+ pets[1] = pets[0];
+ pets[0] = null;
+ }
+ } finally {
+ petLock.unlock();
}
}
@@ -6297,32 +6477,37 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
return coolDowns.containsKey(Integer.valueOf(skillId));
}
- public void startFullnessSchedule(final int decrease, final MaplePet pet, int petSlot) {
- if(isGM() && ServerConstants.GM_PETS_NEVER_HUNGRY || ServerConstants.PETS_NEVER_HUNGRY) {
- return;
- }
+ public void runFullnessSchedule(int petSlot) {
+ MaplePet pet = getPet(petSlot);
+ if(pet == null) return;
- ScheduledFuture> schedule;
- schedule = TimerManager.getInstance().register(new Runnable() {
- @Override
- public void run() {
- int newFullness = pet.getFullness() - decrease;
- if (newFullness <= 5) {
- pet.setFullness(15);
- pet.saveToDb();
- unequipPet(pet, true);
- } else {
- pet.setFullness(newFullness);
- pet.saveToDb();
- Item petz = getInventory(MapleInventoryType.CASH).getItem(pet.getPosition());
- if (petz != null) {
- forceUpdateItem(petz);
- }
- }
+ int newFullness = pet.getFullness() - PetDataFactory.getHunger(pet.getItemId());
+ if (newFullness <= 5) {
+ pet.setFullness(15);
+ pet.saveToDb();
+ unequipPet(pet, true);
+ dropMessage(6, "Your pet grew hungry! Treat it some pet food to keep it healthy!");
+ } else {
+ pet.setFullness(newFullness);
+ pet.saveToDb();
+ Item petz = getInventory(MapleInventoryType.CASH).getItem(pet.getPosition());
+ if (petz != null) {
+ forceUpdateItem(petz);
}
- }, 180000, 18000);
- fullnessSchedule[petSlot] = schedule;
-
+ }
+ }
+
+ public void runTirednessSchedule() {
+ if(maplemount != null) {
+ int tiredness = maplemount.incrementAndGetTiredness();
+
+ this.getMap().broadcastMessage(MaplePacketCreator.updateMount(this.getId(), maplemount, false));
+ if (tiredness > 99) {
+ maplemount.setTiredness(99);
+ this.dispelSkill(this.getJobType() * 10000000 + 1004);
+ this.dropMessage(6, "Your mount grew tired! Treat it some revitalizer before riding it again!");
+ }
+ }
}
public void startMapEffect(String msg, int itemId) {
@@ -6346,8 +6531,9 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
public void unequipAllPets() {
for (int i = 0; i < 3; i++) {
- if (pets[i] != null) {
- unequipPet(pets[i], true);
+ MaplePet pet = getPet(i);
+ if (pet != null) {
+ unequipPet(pet, true);
}
}
}
@@ -6361,11 +6547,13 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
this.getPet(this.getPetIndex(pet)).setSummoned(false);
this.getPet(this.getPetIndex(pet)).saveToDb();
}
- cancelFullnessSchedule(getPetIndex(pet));
+
+ this.getClient().getWorldServer().unregisterPetHunger(this, getPetIndex(pet));
getMap().broadcastMessage(this, MaplePacketCreator.showPet(this, pet, true, hunger), true);
+
+ removePet(pet, shift_left);
client.announce(MaplePacketCreator.petStatUpdate(this));
client.announce(MaplePacketCreator.enableActions());
- removePet(pet, shift_left);
}
public void updateMacros(int position, SkillMacro updateMacro) {
@@ -6832,6 +7020,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
public void showAllEquipFeatures() {
MapleItemInformationProvider mii = MapleItemInformationProvider.getInstance();
+ String showMsg = "";
for (Item item : getInventory(MapleInventoryType.EQUIPPED).list()) {
Equip nEquip = (Equip) item;
@@ -6840,7 +7029,11 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
continue;
}
- nEquip.showEquipFeatures(client);
+ showMsg += nEquip.showEquipFeatures(client);
+ }
+
+ if(!showMsg.isEmpty()) {
+ this.showHint("#ePLAYER EQUIPMENTS:#n\r\n\r\n" + showMsg);
}
}
diff --git a/src/client/MapleClient.java b/src/client/MapleClient.java
index 1069d5e784..1bf91fe380 100644
--- a/src/client/MapleClient.java
+++ b/src/client/MapleClient.java
@@ -154,7 +154,7 @@ public class MapleClient {
}
public void sendCharList(int server) {
- this.session.write(MaplePacketCreator.getCharList(this, server));
+ this.announce(MaplePacketCreator.getCharList(this, server));
}
public List loadCharacters(int serverId) {
@@ -1318,6 +1318,7 @@ public class MapleClient {
}
player.getInventory(MapleInventoryType.EQUIPPED).checked(false); //test
player.getMap().removePlayer(player);
+ player.clearBanishPlayerData();
player.getClient().getChannelServer().removePlayer(player);
player.getClient().updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
try {
diff --git a/src/client/MapleMount.java b/src/client/MapleMount.java
index c19e2b9d00..52f4bd1e3a 100644
--- a/src/client/MapleMount.java
+++ b/src/client/MapleMount.java
@@ -21,10 +21,6 @@
*/
package client;
-import java.util.concurrent.ScheduledFuture;
-import server.TimerManager;
-import tools.MaplePacketCreator;
-
/**
* @author PurpleMadness Patrick :O
*/
@@ -34,7 +30,6 @@ public class MapleMount {
private int tiredness;
private int exp;
private int level;
- private ScheduledFuture> tirednessSchedule;
private MapleCharacter owner;
private boolean active;
@@ -95,21 +90,10 @@ public class MapleMount {
tiredness = 0;
}
}
-
- private void increaseTiredness() {
- if(owner != null) {
- this.tiredness++;
- owner.getMap().broadcastMessage(MaplePacketCreator.updateMount(owner.getId(), this, false));
- if (tiredness > 99) {
- this.tiredness = 99;
- owner.dispelSkill(owner.getJobType() * 10000000 + 1004);
- owner.dropMessage(6, "Your mount grew tired! Treat it some revitalizer before riding it again!");
- }
- } else {
- if(this.tirednessSchedule != null) {
- this.tirednessSchedule.cancel(false);
- }
- }
+
+ public int incrementAndGetTiredness() {
+ this.tiredness++;
+ return this.tiredness;
}
public void setExp(int newexp) {
@@ -124,21 +108,6 @@ public class MapleMount {
this.itemid = newitemid;
}
- public void startSchedule() {
- this.tirednessSchedule = TimerManager.getInstance().register(new Runnable() {
- @Override
- public void run() {
- increaseTiredness();
- }
- }, 60000, 60000);
- }
-
- public void cancelSchedule() {
- if (this.tirednessSchedule != null) {
- this.tirednessSchedule.cancel(false);
- }
- }
-
public void setActive(boolean set) {
this.active = set;
}
@@ -148,8 +117,7 @@ public class MapleMount {
}
public void empty() {
- cancelSchedule();
- this.tirednessSchedule = null;
+ if(owner != null) owner.getClient().getWorldServer().unregisterMountHunger(owner);
this.owner = null;
}
}
diff --git a/src/client/command/Commands.java b/src/client/command/Commands.java
index b9bd487993..8b4d46a8a4 100644
--- a/src/client/command/Commands.java
+++ b/src/client/command/Commands.java
@@ -489,42 +489,41 @@ public class Commands {
case "equiplv":
player.showAllEquipFeatures();
break;
-
- case "rates":
- //c.resetVoteTime();
- player.yellowMessage("BOSSDROP RATE");
- player.message(">>Total BOSSDROP Rate: " + c.getWorldServer().getBossDropRate() + "x");
- player.message(">>------------------------------------------------");
+
+ case "showrates":
+ String showMsg = "#eEXP RATE#n" + "\r\n";
+ showMsg += "Server EXP Rate: #k" + c.getWorldServer().getExpRate() + "x#k" + "\r\n";
+ showMsg += "Player EXP Rate: #k" + player.getRawExpRate() + "x#k" + "\r\n";
+ if(player.getCouponExpRate() != 1) showMsg += "Coupon EXP Rate: #k" + player.getCouponExpRate() + "x#k" + "\r\n";
+ showMsg += "EXP Rate: #e#b" + player.getExpRate() + "x#k#n" + "\r\n";
- player.yellowMessage("DROP RATE");
- player.message(">>Base DROP Rate: " + c.getWorldServer().getDropRate() + "x");
- player.message(">>Your DROP Rate: " + player.getRawDropRate() + "x");
- if(player.getCouponDropRate() != 1) player.message(">>Your Coupon DROP Rate: " + player.getCouponDropRate() + "x");
- player.message(">>------------------------------------------------");
- player.message(">>Total DROP Rate: " + player.getDropRate() + "x");
-
- player.yellowMessage("MESO RATE");
- player.message(">>Base MESO Rate: " + c.getWorldServer().getMesoRate() + "x");
- player.message(">>Your MESO Rate: " + player.getRawMesoRate() + "x");
- if(player.getCouponMesoRate() != 1) player.message(">>Your Coupon MESO Rate: " + player.getCouponMesoRate() + "x");
- player.message(">>------------------------------------------------");
- player.message(">>Total MESO Rate: " + player.getMesoRate() + "x");
-
- player.yellowMessage("EXP RATE");
- player.message(">>Base EXP Rate: " + c.getWorldServer().getExpRate() + "x");
- player.message(">>Your EXP Rate: " + player.getRawExpRate() + "x");
- if(player.getCouponExpRate() != 1) player.message(">>Your Coupon EXP Rate: " + player.getCouponExpRate() + "x");
- player.message(">>------------------------------------------------");
- player.message(">>Total EXP Rate: " + player.getExpRate() + "x");
- /*if(c.getWorldServer().getExpRate() > ServerConstants.EXP_RATE) {
- player.message(">>Event EXP bonus: " + (c.getWorldServer().getExpRate() - ServerConstants.EXP_RATE) + "x");
- }
- player.message(">>Voted EXP bonus: " + (c.hasVotedAlready() ? "1x" : "0x (If you vote now, you will earn an additional 1x EXP!)"));
-
- if (player.getLevel() < 10) {
- player.message("Players under level 10 always have 1x exp.");
- }*/
- break;
+ showMsg += "\r\n" + "#eMESO RATE#n" + "\r\n";
+ showMsg += "Server MESO Rate: #k" + c.getWorldServer().getMesoRate() + "x#k" + "\r\n";
+ showMsg += "Player MESO Rate: #k" + player.getRawMesoRate() + "x#k" + "\r\n";
+ if(player.getCouponMesoRate() != 1) showMsg += "Coupon MESO Rate: #k" + player.getCouponMesoRate() + "x#k" + "\r\n";
+ showMsg += "MESO Rate: #e#b" + player.getMesoRate() + "x#k#n" + "\r\n";
+
+ showMsg += "\r\n" + "#eDROP RATE#n" + "\r\n";
+ showMsg += "Server DROP Rate: #k" + c.getWorldServer().getDropRate() + "x#k" + "\r\n";
+ showMsg += "Player DROP Rate: #k" + player.getRawDropRate() + "x#k" + "\r\n";
+ if(player.getCouponDropRate() != 1) showMsg += "Coupon DROP Rate: #k" + player.getCouponDropRate() + "x#k" + "\r\n";
+ showMsg += "DROP Rate: #e#b" + player.getDropRate() + "x#k#n" + "\r\n";
+
+ showMsg += "\r\n" + "#eBOSSDROP RATE#n" + "\r\n";
+ showMsg += "Server BOSSDROP Rate: #e#b" + c.getWorldServer().getBossDropRate() + "x#k#n" + "\r\n";
+
+ player.showHint(showMsg);
+ break;
+
+ case "rates":
+ String showMsg_ = "#eCHARACTER RATES#n" + "\r\n\r\n";
+ showMsg_ += "EXP Rate: #e#b" + player.getExpRate() + "x#k#n" + "\r\n";
+ showMsg_ += "MESO Rate: #e#b" + player.getMesoRate() + "x#k#n" + "\r\n";
+ showMsg_ += "DROP Rate: #e#b" + player.getDropRate() + "x#k#n" + "\r\n";
+ showMsg_ += "BOSSDROP Rate: #e#b" + c.getWorldServer().getBossDropRate() + "x#k#n" + "\r\n";
+
+ player.showHint(showMsg_);
+ break;
case "online":
for (Channel ch : Server.getInstance().getChannelsFromWorld(player.getWorld())) {
@@ -788,13 +787,21 @@ public class Commands {
}
if (sub.length == 2) {
- player.setRemainingSp(Integer.parseInt(sub[1]));
+ int newSp = Integer.parseInt(sub[1]);
+ if(newSp < 0) newSp = 0;
+ else if(newSp > ServerConstants.MAX_AP) newSp = ServerConstants.MAX_AP;
+
+ player.setRemainingSp(newSp);
player.updateSingleStat(MapleStat.AVAILABLESP, player.getRemainingSp());
} else {
victim = c.getChannelServer().getPlayerStorage().getCharacterByName(sub[1]);
if(victim != null) {
- victim.setRemainingSp(Integer.parseInt(sub[2]));
+ int newSp = Integer.parseInt(sub[2]);
+ if(newSp < 0) newSp = 0;
+ else if(newSp > ServerConstants.MAX_AP) newSp = ServerConstants.MAX_AP;
+
+ victim.setRemainingSp(newSp);
victim.updateSingleStat(MapleStat.AVAILABLESP, player.getRemainingSp());
player.dropMessage(5, "SP given.");
@@ -809,15 +816,23 @@ public class Commands {
player.yellowMessage("Syntax: !ap [] ");
break;
}
-
+
if (sub.length < 3) {
- player.setRemainingAp(Integer.parseInt(sub[1]));
+ int newAp = Integer.parseInt(sub[1]);
+ if(newAp < 0) newAp = 0;
+ else if(newAp > ServerConstants.MAX_AP) newAp = ServerConstants.MAX_AP;
+
+ player.setRemainingAp(newAp);
player.updateSingleStat(MapleStat.AVAILABLEAP, player.getRemainingAp());
} else {
victim = c.getChannelServer().getPlayerStorage().getCharacterByName(sub[1]);
if(victim != null) {
- victim.setRemainingAp(Integer.parseInt(sub[2]));
+ int newAp = Integer.parseInt(sub[2]);
+ if(newAp < 0) newAp = 0;
+ else if(newAp > ServerConstants.MAX_AP) newAp = ServerConstants.MAX_AP;
+
+ victim.setRemainingAp(newAp);
victim.updateSingleStat(MapleStat.AVAILABLEAP, victim.getRemainingAp());
} else {
player.message("Player '" + sub[1] + "' could not be found on this channel.");
@@ -1181,15 +1196,28 @@ public class Commands {
break;
case "setstat":
- final int x = Short.parseShort(sub[1]);
- player.setStr(x);
- player.setDex(x);
- player.setInt(x);
- player.setLuk(x);
- player.updateSingleStat(MapleStat.STR, x);
- player.updateSingleStat(MapleStat.DEX, x);
- player.updateSingleStat(MapleStat.INT, x);
- player.updateSingleStat(MapleStat.LUK, x);
+ if (sub.length < 2){
+ player.yellowMessage("Syntax: !setstat ");
+ break;
+ }
+
+ int x;
+ try {
+ x = Integer.parseInt(sub[1]);
+
+ if(x > Short.MAX_VALUE) x = Short.MAX_VALUE;
+ else if(x < 0) x = 0;
+
+ player.setStr(x);
+ player.setDex(x);
+ player.setInt(x);
+ player.setLuk(x);
+ player.updateSingleStat(MapleStat.STR, x);
+ player.updateSingleStat(MapleStat.DEX, x);
+ player.updateSingleStat(MapleStat.INT, x);
+ player.updateSingleStat(MapleStat.LUK, x);
+
+ } catch(NumberFormatException nfe) {}
break;
case "maxstat":
@@ -2278,14 +2306,14 @@ public class Commands {
player.getMap().broadcastMessage(MaplePacketCreator.customPacket(joinStringFrom(sub, 1)));
break;
- case "debugnearestportal":
+ case "debugportal":
MaplePortal portal = player.getMap().findClosestPortal(player.getPosition());
if(portal != null) player.dropMessage(6, "Closest portal: " + portal.getId() + " '" + portal.getName() + "' Type: " + portal.getType() + " --> toMap: " + portal.getTargetMapId() + " scriptname: '" + portal.getScriptName() + "' state: " + portal.getPortalState() + ".");
else player.dropMessage(6, "There is no portal on this map.");
break;
- case "debugnearestspawnpoint":
+ case "debugspawnpoint":
SpawnPoint sp = player.getMap().findClosestSpawnpoint(player.getPosition());
if(sp != null) player.dropMessage(6, "Closest mob spawn point: " + " Position: x " + sp.getPosition().getX() + " y " + sp.getPosition().getY() + " Spawns mobid: '" + sp.getMonsterId() + "' --> canSpawn: " + !sp.getDenySpawn() + " canSpawnRightNow: " + sp.shouldSpawn() + ".");
else player.dropMessage(6, "There is no mob spawn point on this map.");
@@ -2381,8 +2409,8 @@ public class Commands {
target.setGMLevel(newLevel);
target.getClient().setGMLevel(newLevel);
- target.dropMessage("You are now a level " + newLevel + " GM");
- player.dropMessage(target + " is now a level " + newLevel + " GM");
+ target.dropMessage("You are now a level " + newLevel + " GM. See @commands for a list of available commands.");
+ player.dropMessage(target + " is now a level " + newLevel + " GM.");
} else {
player.dropMessage("Player '"+ sub[1] +"' was not found on this channel.");
}
diff --git a/src/client/inventory/Equip.java b/src/client/inventory/Equip.java
index 77a66f08cc..8cfbcb24e5 100644
--- a/src/client/inventory/Equip.java
+++ b/src/client/inventory/Equip.java
@@ -542,14 +542,14 @@ public class Equip extends Item {
return true;
}
- public void showEquipFeatures(MapleClient c) {
+ public String showEquipFeatures(MapleClient c) {
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
- if(!ii.isUpgradeable(this.getItemId())) return;
+ if(!ii.isUpgradeable(this.getItemId())) return "";
String eqpName = ii.getName(getItemId());
- String eqpInfo = reachedMaxLevel(eqpName) ? " - MAX LEVEL" : (" EXP: " + itemExp + " / " + ExpTable.getEquipExpNeededForLevel(itemLevel));
+ String eqpInfo = reachedMaxLevel(eqpName) ? " #e#rMAX LEVEL#k#n" : (" EXP: #e#b" + (int)itemExp + "#k#n / " + ExpTable.getEquipExpNeededForLevel(itemLevel));
- c.getPlayer().dropMessage(5, "'" + eqpName + "' -> Level: " + itemLevel + eqpInfo);
+ return "'" + eqpName + "' -> LV: #e#b" + itemLevel + "#k#n " + eqpInfo + "\r\n";
}
public final void showLevelupMessage(String msg, MapleClient c) {
diff --git a/src/constants/ServerConstants.java b/src/constants/ServerConstants.java
index e673d72621..bcadd516a4 100644
--- a/src/constants/ServerConstants.java
+++ b/src/constants/ServerConstants.java
@@ -44,9 +44,9 @@ public class ServerConstants {
public static final boolean USE_ITEM_SORT_BY_NAME = false; //Item sorting based on name rather than id.
public static final boolean USE_PARTY_SEARCH = false;
public static final boolean USE_AUTOBAN = false; //Commands the server to detect infractors automatically.
- public static final boolean USE_ANOTHER_AUTOASSIGNER = true; //Based on distributing AP accordingly to required secondary stat on equipments.
+ public static final boolean USE_SERVER_AUTOASSIGNER = true; //Server-builtin autoassigner, uses algorithm 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_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_ENFORCE_MDOOR_POSITION = true; //Forces mystic door to be spawned near spawnpoints. (since things bugs out other way, and this helps players to 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
@@ -58,7 +58,7 @@ public class ServerConstants {
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_AP = 32767; //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.
public static final long PET_LOOT_UPON_ATTACK = (long)(0.7 * 1000); //Time the pet must wait before trying to pick items up.
@@ -66,7 +66,7 @@ public class ServerConstants {
//Dangling Items Configuration
public static final int ITEM_EXPIRE_TIME = 3 * 60 * 1000; //Time before items start disappearing. Recommended to be set up to 3 minutes.
public static final int ITEM_MONITOR_TIME = 5 * 60 * 1000; //Interval between item monitoring tasks 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.
+ public static final int ITEM_LIMIT_ON_MAP = 200; //Max number of items allowed on a map.
//Some Gameplay Enhancing Configurations
//Scroll Configuration
@@ -102,6 +102,10 @@ public class ServerConstants {
public static final double PET_AUTOHP_RATIO = 0.99; //Will automatically consume potions until given ratio of the MaxHP/MaxMP is reached.
public static final double PET_AUTOMP_RATIO = 0.99;
+ //Pet & Mount Configuration
+ public static final byte PET_EXHAUST_COUNT = 3; //Number of proc counts (1 per minute) on the exhaust schedule for fullness.
+ public static final byte MOUNT_EXHAUST_COUNT = 1; //Number of proc counts (1 per minute) on the exhaust schedule for tiredness.
+
//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
diff --git a/src/net/SendOpcode.java b/src/net/SendOpcode.java
index fc3c99f823..3ef6bbc6ff 100644
--- a/src/net/SendOpcode.java
+++ b/src/net/SendOpcode.java
@@ -201,7 +201,7 @@ public enum SendOpcode {
MOVE_PET(0xAA),
PET_CHAT(0xAB),
PET_NAMECHANGE(0xAC),
- PET_SHOW(0xAD),
+ PET_EXCEPTION_LIST(0xAD),
PET_COMMAND(0xAE),
SPAWN_SPECIAL_MAPOBJECT(0xAF),
REMOVE_SPECIAL_MAPOBJECT(0xB0),
@@ -334,7 +334,8 @@ public enum SendOpcode {
ENABLE_TV(0x157),
MTS_OPERATION2(0x15B),
MTS_OPERATION(0x15C),
- VICIOUS_HAMMER(0x162);
+ VICIOUS_HAMMER(0x162),
+ VEGA_SCROLL(0x166);
private int code = -2;
private SendOpcode(int code) {
diff --git a/src/net/server/MountTirednessWorker.java b/src/net/server/MountTirednessWorker.java
new file mode 100644
index 0000000000..b204c4c6a1
--- /dev/null
+++ b/src/net/server/MountTirednessWorker.java
@@ -0,0 +1,41 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 Patrick Huy
+ Matthias Butz
+ Jan Christian Meyer
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation version 3 as published by
+ the Free Software Foundation. You may not use, modify or distribute
+ this program under any other version of the GNU Affero General Public
+ License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+package net.server;
+
+import net.server.world.World;
+
+/**
+ * @author Ronan
+ */
+public class MountTirednessWorker implements Runnable {
+ private World wserv;
+
+ @Override
+ public void run() {
+ wserv.runMountSchedule();
+ }
+
+ public MountTirednessWorker(World world) {
+ wserv = world;
+ }
+}
diff --git a/src/net/server/PetFullnessWorker.java b/src/net/server/PetFullnessWorker.java
new file mode 100644
index 0000000000..bb60f2325a
--- /dev/null
+++ b/src/net/server/PetFullnessWorker.java
@@ -0,0 +1,41 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 Patrick Huy
+ Matthias Butz
+ Jan Christian Meyer
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation version 3 as published by
+ the Free Software Foundation. You may not use, modify or distribute
+ this program under any other version of the GNU Affero General Public
+ License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+package net.server;
+
+import net.server.world.World;
+
+/**
+ * @author Ronan
+ */
+public class PetFullnessWorker implements Runnable {
+ private World wserv;
+
+ @Override
+ public void run() {
+ wserv.runPetSchedule();
+ }
+
+ public PetFullnessWorker(World world) {
+ wserv = world;
+ }
+}
diff --git a/src/net/server/channel/handlers/AutoAssignHandler.java b/src/net/server/channel/handlers/AutoAssignHandler.java
index f16b328376..990257d06e 100644
--- a/src/net/server/channel/handlers/AutoAssignHandler.java
+++ b/src/net/server/channel/handlers/AutoAssignHandler.java
@@ -52,12 +52,16 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
@Override
public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
+ int[] statGain = new int[4];
+ int[] statEqpd = new int[4];
+
+ statGain[0] = 0; statGain[1] = 0; statGain[2] = 0; statGain[3] = 0;
slea.skip(8);
if (chr.getRemainingAp() < 1) return;
- if(ServerConstants.USE_ANOTHER_AUTOASSIGNER == true) {
- // ---------- Ronan Lana's AUTOASSIGNER -------------
+ if(ServerConstants.USE_SERVER_AUTOASSIGNER) {
+ // --------- Ronan Lana's AUTOASSIGNER ---------
// This method excels for assigning APs in such a way to cover all equipments AP requirements.
int str = 0, dex = 0, luk = 0, int_ = 0;
@@ -84,6 +88,11 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
int_ += nEquip.getInt();
}
+ statEqpd[0] = str;
+ statEqpd[1] = dex;
+ statEqpd[2] = luk;
+ statEqpd[3] = int_;
+
Collections.sort(eqpStrList, Collections.reverseOrder());
Collections.sort(eqpDexList, Collections.reverseOrder());
Collections.sort(eqpLukList, Collections.reverseOrder());
@@ -100,7 +109,7 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
MapleJob stance = c.getPlayer().getJobStyle();
int prStat = 0, scStat = 0, trStat = 0, temp, tempAp = chr.getRemainingAp(), CAP;
- MapleStat primary, secondary, tertiary = MapleStat.INT;
+ MapleStat primary, secondary, tertiary = MapleStat.LUK;
switch(stance) {
case MAGICIAN:
CAP = 165;
@@ -124,6 +133,7 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
primary = MapleStat.INT;
secondary = MapleStat.LUK;
+ tertiary = MapleStat.DEX;
break;
@@ -197,6 +207,7 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
scStat += temp;
tempAp -= temp;
+ // thieves will upgrade STR as well only if a level-based threshold is reached.
if(chr.getStr() >= Math.max(13, (int)(0.4 * chr.getLevel()))) {
if(chr.getStr() < 50) {
trStat = (chr.getLevel() - 10) - (chr.getStr() + str - eqpStr);
@@ -205,7 +216,6 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
trStat = Math.min(50 - chr.getStr(), trStat);
trStat = Math.min(tempAp, trStat);
tempAp -= trStat;
- tertiary = MapleStat.STR;
}
temp = (20 + (chr.getLevel() / 2)) - Math.max(50, trStat + chr.getStr() + str - eqpStr);
@@ -234,6 +244,7 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
primary = MapleStat.LUK;
secondary = MapleStat.DEX;
+ tertiary = MapleStat.STR;
break;
@@ -289,25 +300,28 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
}
//-------------------------------------------------------------------------------------
- int total = 0;
+
int extras = 0;
- total += trStat;
- extras += gainStatByType(chr, tertiary, trStat);
+ extras = gainStatByType(chr, primary, statGain, statEqpd, prStat + extras);
+ extras = gainStatByType(chr, secondary, statGain, statEqpd, scStat + extras);
+ extras = gainStatByType(chr, tertiary, statGain, statEqpd, trStat + extras);
+
+ if(extras > 0) { //redistribute surplus in priority order
+ extras = gainStatByType(chr, primary, statGain, statEqpd, extras);
+ extras = gainStatByType(chr, secondary, statGain, statEqpd, extras);
+ extras = gainStatByType(chr, tertiary, statGain, statEqpd, extras);
+ gainStatByType(chr, getQuaternaryStat(stance), statGain, statEqpd, extras);
+ }
- total += scStat;
- extras += gainStatByType(chr, secondary, scStat);
-
- total += prStat;
- extras += gainStatByType(chr, primary, prStat);
-
- int remainingAp = (chr.getRemainingAp() - total) + extras;
+ int remainingAp = (chr.getRemainingAp() - getAccumulatedStatGain(statGain));
chr.setRemainingAp(remainingAp);
chr.updateSingleStat(MapleStat.AVAILABLEAP, remainingAp);
c.announce(MaplePacketCreator.enableActions());
+
//----------------------------------------------------------------------------------------
- c.announce(MaplePacketCreator.serverNotice(1, "Better AP applications detected:\r\nSTR: +" + str + "\r\nDEX: +" + dex + "\r\nINT: +" + int_ + "\r\nLUK: +" + luk));
+ c.announce(MaplePacketCreator.serverNotice(1, "Better AP applications detected:\r\nSTR: +" + statGain[0] + "\r\nDEX: +" + statGain[1] + "\r\nINT: +" + statGain[3] + "\r\nLUK: +" + statGain[2]));
}
else {
int total = 0;
@@ -317,6 +331,18 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
c.disconnect(false, false);
return;
}
+
+ MapleInventory iv = chr.getInventory(MapleInventoryType.EQUIPPED);
+ Collection- equippedC = iv.list();
+ for (Item item : equippedC) { //selecting the biggest AP value of each stat from each equipped item.
+ Equip nEquip = (Equip)item;
+
+ statEqpd[0] += nEquip.getStr();
+ statEqpd[1] += nEquip.getDex();
+ statEqpd[2] += nEquip.getLuk();
+ statEqpd[3] += nEquip.getInt();
+ }
+
for (int i = 0; i < 2; i++) {
int type = slea.readInt();
int tempVal = slea.readInt();
@@ -324,8 +350,7 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
return;
}
total += tempVal;
- System.out.println(tempVal);
- extras += gainStatByType(chr, MapleStat.getBy5ByteEncoding(type), tempVal);
+ extras += gainStatByType(chr, MapleStat.getBy5ByteEncoding(type), statGain, statEqpd, tempVal);
}
int remainingAp = (chr.getRemainingAp() - total) + extras;
chr.setRemainingAp(remainingAp);
@@ -334,37 +359,48 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
}
}
- private int gainStatByType(MapleCharacter chr, MapleStat type, int gain) {
+ private int gainStatByType(MapleCharacter chr, MapleStat type, int[] statGain, int[] statEqpd, int gain) {
+ if(gain <= 0) return 0;
+
int newVal = 0;
if (type.equals(MapleStat.STR)) {
- newVal = chr.getStr() + gain;
+ newVal = chr.getStr() + statEqpd[0] + gain;
if (newVal > ServerConstants.MAX_AP) {
- chr.setStr(ServerConstants.MAX_AP);
+ statGain[0] += gain - (newVal - ServerConstants.MAX_AP);
+ chr.setStr(ServerConstants.MAX_AP - statEqpd[0]);
} else {
+ statGain[0] += gain;
chr.setStr(newVal);
}
} else if (type.equals(MapleStat.INT)) {
- newVal = chr.getInt() + gain;
+ newVal = chr.getInt() + statEqpd[3] + gain;
if (newVal > ServerConstants.MAX_AP) {
- chr.setInt(ServerConstants.MAX_AP);
+ statGain[3] += gain - (newVal - ServerConstants.MAX_AP);
+ chr.setInt(ServerConstants.MAX_AP - statEqpd[3]);
} else {
+ statGain[3] += gain;
chr.setInt(newVal);
}
} else if (type.equals(MapleStat.LUK)) {
- newVal = chr.getLuk() + gain;
+ newVal = chr.getLuk() + statEqpd[2] + gain;
if (newVal > ServerConstants.MAX_AP) {
- chr.setLuk(ServerConstants.MAX_AP);
+ statGain[2] += gain - (newVal - ServerConstants.MAX_AP);
+ chr.setLuk(ServerConstants.MAX_AP - statEqpd[2]);
} else {
+ statGain[2] += gain;
chr.setLuk(newVal);
}
} else if (type.equals(MapleStat.DEX)) {
- newVal = chr.getDex() + gain;
+ newVal = chr.getDex() + statEqpd[1] + gain;
if (newVal > ServerConstants.MAX_AP) {
- chr.setDex(ServerConstants.MAX_AP);
+ statGain[1] += gain - (newVal - ServerConstants.MAX_AP);
+ chr.setDex(ServerConstants.MAX_AP - statEqpd[1]);
} else {
+ statGain[1] += gain;
chr.setDex(newVal);
}
}
+
if (newVal > ServerConstants.MAX_AP) {
chr.updateSingleStat(type, ServerConstants.MAX_AP);
return newVal - ServerConstants.MAX_AP;
@@ -372,4 +408,19 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
chr.updateSingleStat(type, newVal);
return 0;
}
+
+ private MapleStat getQuaternaryStat(MapleJob stance) {
+ if(stance != MapleJob.MAGICIAN) return MapleStat.INT;
+ return MapleStat.STR;
+ }
+
+ private int getAccumulatedStatGain(int[] statGain) {
+ int acc = 0;
+
+ for(byte i = 0; i < statGain.length; i++) {
+ acc += statGain[i];
+ }
+
+ return acc;
+ }
}
diff --git a/src/net/server/channel/handlers/ChangeMapHandler.java b/src/net/server/channel/handlers/ChangeMapHandler.java
index f6bc30116d..fd6ad8df39 100644
--- a/src/net/server/channel/handlers/ChangeMapHandler.java
+++ b/src/net/server/channel/handlers/ChangeMapHandler.java
@@ -88,6 +88,7 @@ public final class ChangeMapHandler extends AbstractMaplePacketHandler {
chr.setStance(0);
}
chr.setHp(50);
+ chr.updatePartyMemberHP();
chr.changeMap(to, to.getRandomPlayerSpawnpoint());
}
} else if (targetid != -1) {
diff --git a/src/net/server/channel/handlers/CharInfoRequestHandler.java b/src/net/server/channel/handlers/CharInfoRequestHandler.java
index 6f14c11f02..f97ec9408b 100644
--- a/src/net/server/channel/handlers/CharInfoRequestHandler.java
+++ b/src/net/server/channel/handlers/CharInfoRequestHandler.java
@@ -30,12 +30,17 @@ import tools.data.input.SeekableLittleEndianAccessor;
public final class CharInfoRequestHandler extends AbstractMaplePacketHandler {
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
- slea.readInt();
+ slea.skip(4);
int cid = slea.readInt();
MapleMapObject target = c.getPlayer().getMap().getMapObject(cid);
if (target != null) {
if (target instanceof MapleCharacter) {
- c.announce(MaplePacketCreator.charInfo((MapleCharacter) target));
+ MapleCharacter player = (MapleCharacter) target;
+
+ if(c.getPlayer().getId() != player.getId()) {
+ player.exportExcludedItems(c);
+ }
+ c.announce(MaplePacketCreator.charInfo(player));
}
}
}
diff --git a/src/net/server/channel/handlers/EnterCashShopHandler.java b/src/net/server/channel/handlers/EnterCashShopHandler.java
index e512544776..d2d6ecd63e 100644
--- a/src/net/server/channel/handlers/EnterCashShopHandler.java
+++ b/src/net/server/channel/handlers/EnterCashShopHandler.java
@@ -38,6 +38,11 @@ public class EnterCashShopHandler extends AbstractMaplePacketHandler {
try {
MapleCharacter mc = c.getPlayer();
+ if (mc.cannotEnterCashShop()) {
+ c.announce(MaplePacketCreator.enableActions());
+ return;
+ }
+
if (mc.getCashShop().isOpened()) {
return;
}
diff --git a/src/net/server/channel/handlers/PetExcludeItemsHandler.java b/src/net/server/channel/handlers/PetExcludeItemsHandler.java
index 6b73c87461..4b1842c51a 100644
--- a/src/net/server/channel/handlers/PetExcludeItemsHandler.java
+++ b/src/net/server/channel/handlers/PetExcludeItemsHandler.java
@@ -22,18 +22,35 @@
package net.server.channel.handlers;
import client.MapleClient;
+import client.MapleCharacter;
+import client.inventory.MaplePet;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
+//import tools.MaplePacketCreator;
/**
* @author BubblesDev
+ * @author Ronan
*/
public final class PetExcludeItemsHandler extends AbstractMaplePacketHandler {
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
- slea.readLong();
+ final int petId = slea.readInt();
+ slea.skip(4);
+
+ MapleCharacter chr = c.getPlayer();
+ byte petIndex = (byte)chr.getPetIndex(petId);
+ if (petIndex < 0) return;
+
+ final MaplePet pet = chr.getPet(petIndex);
+ if (pet == null) {
+ return;
+ }
+
+ chr.resetExcluded(petId);
byte amount = slea.readByte();
for (int i = 0; i < amount; i++) {
- c.getPlayer().addExcluded(slea.readInt());
+ chr.addExcluded(petId, slea.readInt());
}
+ chr.commitExcludedItems();
}
}
diff --git a/src/net/server/channel/handlers/PetFoodHandler.java b/src/net/server/channel/handlers/PetFoodHandler.java
index 3174385a20..694752c6b9 100644
--- a/src/net/server/channel/handlers/PetFoodHandler.java
+++ b/src/net/server/channel/handlers/PetFoodHandler.java
@@ -22,7 +22,6 @@
package net.server.channel.handlers;
import client.MapleCharacter;
-import constants.ExpTable;
import client.MapleClient;
import client.inventory.MapleInventoryType;
import client.inventory.MaplePet;
@@ -61,7 +60,10 @@ public final class PetFoodHandler extends AbstractMaplePacketHandler {
}
}
}
+
MaplePet pet = chr.getPet(slot);
+ if(pet == null) return;
+
short pos = slea.readShort();
int itemId = slea.readInt();
Item use = chr.getInventory(MapleInventoryType.USE).getItem(pos);
diff --git a/src/net/server/channel/handlers/PetLootHandler.java b/src/net/server/channel/handlers/PetLootHandler.java
index 40a4697404..604464ef74 100644
--- a/src/net/server/channel/handlers/PetLootHandler.java
+++ b/src/net/server/channel/handlers/PetLootHandler.java
@@ -21,10 +21,14 @@
*/
package net.server.channel.handlers;
+import java.util.Set;
+
import client.MapleCharacter;
import client.MapleClient;
+import client.inventory.MapleInventoryType;
import client.inventory.MaplePet;
import net.AbstractMaplePacketHandler;
+import server.maps.MapleMapItem;
import server.maps.MapleMapObject;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
@@ -52,6 +56,30 @@ public final class PetLootHandler extends AbstractMaplePacketHandler {
slea.skip(13);
int oid = slea.readInt();
MapleMapObject ob = chr.getMap().getMapObject(oid);
+ if(ob == null) {
+ c.getSession().write(MaplePacketCreator.enableActions());
+ return;
+ }
+
+ if (chr.getInventory(MapleInventoryType.EQUIPPED).findById(1812007) != null) {
+ final Set petIgnore = chr.getExcludedItems();
+ MapleMapItem mapitem = (MapleMapItem) ob;
+
+ if(!petIgnore.isEmpty()) {
+ if (chr.getInventory(MapleInventoryType.EQUIPPED).findById(1812000) != null) { // Meso magnet
+ if (mapitem.getMeso() > 0 && petIgnore.contains(Integer.MAX_VALUE)) {
+ c.getSession().write(MaplePacketCreator.enableActions());
+ return;
+ }
+ } else if (chr.getInventory(MapleInventoryType.EQUIPPED).findById(1812001) != null) { // Item Pouch
+ if (petIgnore.contains(mapitem.getItem().getItemId())) {
+ c.getSession().write(MaplePacketCreator.enableActions());
+ return;
+ }
+ }
+ }
+ }
+
chr.pickupItem(ob, petIndex);
}
}
diff --git a/src/net/server/channel/handlers/PlayerLoggedinHandler.java b/src/net/server/channel/handlers/PlayerLoggedinHandler.java
index fed813dc9e..5a90e0efd7 100644
--- a/src/net/server/channel/handlers/PlayerLoggedinHandler.java
+++ b/src/net/server/channel/handlers/PlayerLoggedinHandler.java
@@ -48,7 +48,6 @@ import client.MapleFamily;
import client.SkillFactory;
import client.inventory.MapleInventoryType;
import client.inventory.MaplePet;
-import client.inventory.PetDataFactory;
import constants.GameConstants;
import constants.ServerConstants;
@@ -246,7 +245,7 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
if(newcomer) {
for(MaplePet pet : player.getPets()) {
if(pet != null)
- player.startFullnessSchedule(PetDataFactory.getHunger(pet.getItemId()), pet, player.getPetIndex(pet));
+ world.registerPetHunger(player, player.getPetIndex(pet));
}
player.reloadQuestExpirations();
@@ -261,6 +260,9 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
if (GameConstants.hasSPTable(player.getJob()) && player.getJob().getId() != 2001) {
player.createDragon();
}
+
+ player.commitExcludedItems();
+
if (newcomer){
/*
if (!c.hasVotedAlready()){
@@ -279,5 +281,7 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
if(ServerConstants.USE_ADD_RATES_BY_LEVEL == true) player.setPlayerRates();
player.setWorldRates();
player.updateCouponRates();
+
+ player.receivePartyMemberHP();
}
}
diff --git a/src/net/server/channel/handlers/ScrollHandler.java b/src/net/server/channel/handlers/ScrollHandler.java
index 3c21aa62a3..029368bcbd 100644
--- a/src/net/server/channel/handlers/ScrollHandler.java
+++ b/src/net/server/channel/handlers/ScrollHandler.java
@@ -94,7 +94,7 @@ public final class ScrollHandler extends AbstractMaplePacketHandler {
if (ItemConstants.isCleanSlate(scroll.getItemId()) && !(toScroll.getLevel() + toScroll.getUpgradeSlots() < ii.getEquipStats(toScroll.getItemId()).get("tuc"))) { //upgrade slots can be over because of hammers
return;
}
- Equip scrolled = (Equip) ii.scrollEquipWithId(toScroll, scroll.getItemId(), whiteScroll, c.getPlayer().isGM());
+ Equip scrolled = (Equip) ii.scrollEquipWithId(toScroll, scroll.getItemId(), whiteScroll, 0, c.getPlayer().isGM());
ScrollResult scrollSuccess = Equip.ScrollResult.FAIL; // fail
if (scrolled == null) {
scrollSuccess = Equip.ScrollResult.CURSE;
diff --git a/src/net/server/channel/handlers/SpawnPetHandler.java b/src/net/server/channel/handlers/SpawnPetHandler.java
index 021746f168..8ca43b91e0 100644
--- a/src/net/server/channel/handlers/SpawnPetHandler.java
+++ b/src/net/server/channel/handlers/SpawnPetHandler.java
@@ -24,15 +24,10 @@ package net.server.channel.handlers;
import client.MapleCharacter;
import java.awt.Point;
import java.io.File;
-import java.sql.PreparedStatement;
import client.MapleClient;
import client.inventory.MapleInventoryType;
import client.inventory.MaplePet;
-import client.inventory.PetDataFactory;
import client.SkillFactory;
-import java.sql.Connection;
-import java.sql.SQLException;
-import tools.DatabaseConnection;
import net.AbstractMaplePacketHandler;
import provider.MapleDataProvider;
import provider.MapleDataProviderFactory;
@@ -95,7 +90,8 @@ public final class SpawnPetHandler extends AbstractMaplePacketHandler {
chr.getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showPet(c.getPlayer(), pet, false, false), true);
c.announce(MaplePacketCreator.petStatUpdate(c.getPlayer()));
c.announce(MaplePacketCreator.enableActions());
- chr.startFullnessSchedule(PetDataFactory.getHunger(pet.getItemId()), pet, chr.getPetIndex(pet));
+
+ chr.getClient().getWorldServer().registerPetHunger(chr, chr.getPetIndex(pet));
}
}
}
diff --git a/src/net/server/channel/handlers/SpecialMoveHandler.java b/src/net/server/channel/handlers/SpecialMoveHandler.java
index 35a560e3d0..6481185e76 100644
--- a/src/net/server/channel/handlers/SpecialMoveHandler.java
+++ b/src/net/server/channel/handlers/SpecialMoveHandler.java
@@ -117,9 +117,6 @@ public final class SpecialMoveHandler extends AbstractMaplePacketHandler {
int gain = lose * (ef.getY() / 100);
chr.setMp(chr.getMp() + gain);
chr.updateSingleStat(MapleStat.MP, chr.getMp());
- } else if (skillid == Hermit.FLASH_JUMP) {
- slea.skip(2); // always 0? Also 3rd party FJ effect doesn't seem to work, agh!
- //chr.getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showBuffeffect(chr.getId(), skillid, chr.getSkillLevel(skillid), (byte)0), false);
} else if (skillid == Priest.DISPEL || skillid == SuperGM.HEAL_PLUS_DISPEL) {
slea.skip((skillid == Priest.DISPEL) ? 10 : 11);
chr.getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showBuffeffect(chr.getId(), skillid, chr.getSkillLevel(skillid)), false);
diff --git a/src/net/server/channel/handlers/TakeDamageHandler.java b/src/net/server/channel/handlers/TakeDamageHandler.java
index ab45b0b313..a9c082233c 100644
--- a/src/net/server/channel/handlers/TakeDamageHandler.java
+++ b/src/net/server/channel/handlers/TakeDamageHandler.java
@@ -85,28 +85,32 @@ public final class TakeDamageHandler extends AbstractMaplePacketHandler {
return;
}
if (damage > 0) {
- loseItems = map.getMonsterById(monsteridfrom).getStats().loseItem();
- if (loseItems != null) {
- MapleInventoryType type;
- final int playerpos = player.getPosition().x;
- byte d = 1;
- Point pos = new Point(0, player.getPosition().y);
- for (loseItem loseItem : loseItems) {
- type = MapleItemInformationProvider.getInstance().getInventoryType(loseItem.getId());
- for (byte b = 0; b < loseItem.getX(); b++) {//LOL?
- if (Randomizer.nextInt(101) >= loseItem.getChance()) {
- if (player.haveItem(loseItem.getId())) {
- pos.x = (int) (playerpos + ((d % 2 == 0) ? (25 * (d + 1) / 2) : -(25 * (d / 2))));
- MapleInventoryManipulator.removeById(c, type, loseItem.getId(), 1, false, false);
- map.spawnItemDrop(c.getPlayer(), c.getPlayer(), new Item(loseItem.getId(), (short) 0, (short) 1), map.calcDropPos(pos, player.getPosition()), true, true);
- d++;
- } else {
- break;
+ MapleMonster assaulter = map.getMonsterById(monsteridfrom);
+
+ if(assaulter != null) {
+ loseItems = assaulter.getStats().loseItem();
+ if (loseItems != null) {
+ MapleInventoryType type;
+ final int playerpos = player.getPosition().x;
+ byte d = 1;
+ Point pos = new Point(0, player.getPosition().y);
+ for (loseItem loseItem : loseItems) {
+ type = MapleItemInformationProvider.getInstance().getInventoryType(loseItem.getId());
+ for (byte b = 0; b < loseItem.getX(); b++) {//LOL?
+ if (Randomizer.nextInt(101) >= loseItem.getChance()) {
+ if (player.haveItem(loseItem.getId())) {
+ pos.x = (int) (playerpos + ((d % 2 == 0) ? (25 * (d + 1) / 2) : -(25 * (d / 2))));
+ MapleInventoryManipulator.removeById(c, type, loseItem.getId(), 1, false, false);
+ map.spawnItemDrop(c.getPlayer(), c.getPlayer(), new Item(loseItem.getId(), (short) 0, (short) 1), map.calcDropPos(pos, player.getPosition()), true, true);
+ d++;
+ } else {
+ break;
+ }
}
}
}
+ map.removeMapObject(attacker);
}
- map.removeMapObject(attacker);
}
}
} else {
diff --git a/src/net/server/channel/handlers/UseCashItemHandler.java b/src/net/server/channel/handlers/UseCashItemHandler.java
index 4c250bc870..f14cf9f789 100644
--- a/src/net/server/channel/handlers/UseCashItemHandler.java
+++ b/src/net/server/channel/handlers/UseCashItemHandler.java
@@ -28,9 +28,11 @@ import client.MapleStat;
import client.Skill;
import client.SkillFactory;
import client.inventory.Equip;
+import client.inventory.Equip.ScrollResult;
import client.inventory.Item;
import client.inventory.MapleInventoryType;
import client.inventory.MaplePet;
+import client.inventory.ModifyInventory;
import constants.ItemConstants;
import java.sql.SQLException;
@@ -56,7 +58,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
- MapleCharacter player = c.getPlayer();
+ final MapleCharacter player = c.getPlayer();
if (System.currentTimeMillis() - player.getLastUsedCashItem() < 3000) {
player.dropMessage(1, "You have used a cash item recently. Wait a moment and try again.");
c.announce(MaplePacketCreator.enableActions());
@@ -514,7 +516,65 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
c.announce(MaplePacketCreator.sendHammerData(equip.getVicious()));
player.forceUpdateItem(equip);
} else if (itemType == 561) { //VEGA'S SPELL
- c.announce(MaplePacketCreator.enableActions());
+ if (slea.readInt() != 1) {
+ return;
+ }
+
+ final byte eSlot = (byte) slea.readInt();
+ final Item eitem = c.getPlayer().getInventory(MapleInventoryType.EQUIP).getItem(eSlot);
+
+ if (slea.readInt() != 2) {
+ return;
+ }
+
+ final byte uSlot = (byte) slea.readInt();
+ final Item uitem = c.getPlayer().getInventory(MapleInventoryType.USE).getItem(uSlot);
+ if (eitem == null || uitem == null) {
+ return;
+ }
+
+ //should have a check here against PE hacks
+
+ Equip toScroll = (Equip) eitem;
+ if (toScroll.getUpgradeSlots() < 1) {
+ c.getSession().write(MaplePacketCreator.getInventoryFull());
+ return;
+ }
+
+ c.getPlayer().toggleBlockCashShop();
+
+ final int curlevel = toScroll.getLevel();
+ c.getSession().write(MaplePacketCreator.sendVegaScroll(0x40));
+
+ final Equip scrolled = (Equip) ii.scrollEquipWithId(toScroll, uitem.getItemId(), false, itemId, c.getPlayer().isGM());
+ c.getSession().write(MaplePacketCreator.sendVegaScroll(scrolled.getLevel() > curlevel ? 0x41 : 0x43));
+ //opcodes 0x42, 0x44: "this item cannot be used"; 0x39, 0x45: crashes
+
+ MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.USE, uSlot, (short) 1, false);
+ remove(c, itemId);
+
+ final MapleClient client = c;
+ TimerManager.getInstance().schedule(new Runnable() {
+ @Override
+ public void run() {
+ if(!player.isLoggedin()) return;
+
+ player.toggleBlockCashShop();
+
+ final List mods = new ArrayList<>();
+ mods.add(new ModifyInventory(3, scrolled));
+ mods.add(new ModifyInventory(0, scrolled));
+ client.announce(MaplePacketCreator.modifyInventory(true, mods));
+
+ ScrollResult scrollResult = scrolled.getLevel() > curlevel ? ScrollResult.SUCCESS : ScrollResult.FAIL;
+ player.getMap().broadcastMessage(MaplePacketCreator.getScrollEffect(player.getId(), scrollResult, false));
+ if (eSlot < 0 && (scrollResult == ScrollResult.SUCCESS)) {
+ player.equipChanged();
+ }
+
+ client.getSession().write(MaplePacketCreator.enableActions());
+ }
+ }, 1000 * 3);
} else {
System.out.println("NEW CASH ITEM: " + itemType + "\n" + slea.toString());
c.announce(MaplePacketCreator.enableActions());
diff --git a/src/net/server/world/World.java b/src/net/server/world/World.java
index 81e7fef757..7f1ca4507d 100644
--- a/src/net/server/world/World.java
+++ b/src/net/server/world/World.java
@@ -33,6 +33,7 @@ import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.HashMap;
@@ -41,7 +42,11 @@ import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.Set;
import java.util.HashSet;
+import java.util.concurrent.ScheduledFuture;
+import server.TimerManager;
+import net.server.PetFullnessWorker;
+import net.server.MountTirednessWorker;
import net.server.PlayerStorage;
import net.server.Server;
import net.server.channel.Channel;
@@ -49,7 +54,6 @@ import net.server.channel.CharacterIdChannelPair;
import net.server.guild.MapleGuild;
import net.server.guild.MapleGuildCharacter;
import net.server.guild.MapleGuildSummary;
-import tools.LogHelper;
import tools.DatabaseConnection;
import tools.MaplePacketCreator;
@@ -70,6 +74,14 @@ public class World {
private Map gsStore = new HashMap<>();
private PlayerStorage players = new PlayerStorage();
private Set queuedGuilds = new HashSet<>();
+
+ private Map activePets = new LinkedHashMap<>();
+ private ScheduledFuture> petsSchedule;
+ private long petUpdate;
+
+ private Map activeMounts = new LinkedHashMap<>();
+ private ScheduledFuture> mountsSchedule;
+ private long mountUpdate;
public World(int world, int flag, String eventmsg, int exprate, int droprate, int mesorate, int bossdroprate) {
this.id = world;
@@ -81,6 +93,12 @@ public class World {
this.bossdroprate = bossdroprate;
runningPartyId.set(1);
runningMessengerId.set(1);
+
+ petUpdate = System.currentTimeMillis();
+ mountUpdate = petUpdate;
+
+ petsSchedule = TimerManager.getInstance().register(new PetFullnessWorker(this), 60 * 1000, 60 * 1000);
+ mountsSchedule = TimerManager.getInstance().register(new MountTirednessWorker(this), 60 * 1000, 60 * 1000);
}
public List getChannels() {
@@ -181,7 +199,7 @@ public class World {
channels.get(chr.getClient().getChannel() - 1).removePlayer(chr);
players.removePlayer(chr.getId());
}
-
+
public int getId() {
return id;
}
@@ -657,6 +675,100 @@ public class World {
}
}
}
+
+ private static Integer getPetKey(MapleCharacter chr, byte petSlot) { // assuming max 3 pets
+ return (chr.getId() << 2) + petSlot;
+ }
+
+ public void registerPetHunger(MapleCharacter chr, byte petSlot) {
+ if(chr.isGM() && ServerConstants.GM_PETS_NEVER_HUNGRY || ServerConstants.PETS_NEVER_HUNGRY) {
+ return;
+ }
+
+ Integer key = getPetKey(chr, petSlot);
+ synchronized(activePets) {
+ byte initProc;
+ if(System.currentTimeMillis() - petUpdate > 55000) initProc = ServerConstants.PET_EXHAUST_COUNT - 2;
+ else initProc = ServerConstants.PET_EXHAUST_COUNT - 1;
+
+ activePets.put(key, initProc);
+ }
+ }
+
+ public void unregisterPetHunger(MapleCharacter chr, byte petSlot) {
+ Integer key = getPetKey(chr, petSlot);
+ synchronized(activePets) {
+ activePets.remove(key);
+ }
+ }
+
+ public void runPetSchedule() {
+ Map deployedPets;
+ synchronized(activePets) {
+ petUpdate = System.currentTimeMillis();
+ deployedPets = Collections.unmodifiableMap(activePets);
+ }
+
+ for(Map.Entry dp: deployedPets.entrySet()) {
+ MapleCharacter chr = this.getPlayerStorage().getCharacterById(dp.getKey() / 4);
+ if(chr == null || !chr.isLoggedin()) continue;
+
+ Byte dpVal = (byte)(dp.getValue() + 1);
+ if(dpVal == ServerConstants.PET_EXHAUST_COUNT) {
+ chr.runFullnessSchedule(dp.getKey() % 4);
+ dpVal = 0;
+ }
+
+ synchronized(activePets) {
+ activePets.put(dp.getKey(), dpVal);
+ }
+ }
+ }
+
+ public void registerMountHunger(MapleCharacter chr) {
+ if(chr.isGM() && ServerConstants.GM_PETS_NEVER_HUNGRY || ServerConstants.PETS_NEVER_HUNGRY) {
+ return;
+ }
+
+ Integer key = chr.getId();
+ synchronized(activeMounts) {
+ byte initProc;
+ if(System.currentTimeMillis() - mountUpdate > 45000) initProc = ServerConstants.MOUNT_EXHAUST_COUNT - 2;
+ else initProc = ServerConstants.MOUNT_EXHAUST_COUNT - 1;
+
+ activeMounts.put(key, initProc);
+ }
+ }
+
+ public void unregisterMountHunger(MapleCharacter chr) {
+ Integer key = chr.getId();
+ synchronized(activeMounts) {
+ activeMounts.remove(key);
+ }
+ }
+
+ public void runMountSchedule() {
+ Map deployedMounts;
+ synchronized(activeMounts) {
+ mountUpdate = System.currentTimeMillis();
+ deployedMounts = Collections.unmodifiableMap(activeMounts);
+ }
+
+ for(Map.Entry dp: deployedMounts.entrySet()) {
+ MapleCharacter chr = this.getPlayerStorage().getCharacterById(dp.getKey());
+ if(chr == null || !chr.isLoggedin()) continue;
+
+ Byte dpVal = (byte)(dp.getValue() + 1);
+ if(dpVal == ServerConstants.MOUNT_EXHAUST_COUNT) {
+ chr.runTirednessSchedule();
+ dpVal = 0;
+ }
+
+ synchronized(activeMounts) {
+ activeMounts.put(dp.getKey(), dpVal);
+ }
+ }
+ }
public void setServerMessage(String msg) {
for (Channel ch : channels) {
@@ -674,6 +786,17 @@ public class World {
for (Channel ch : getChannels()) {
ch.shutdown();
}
+
+ if(petsSchedule != null) {
+ petsSchedule.cancel(false);
+ petsSchedule = null;
+ }
+
+ if(mountsSchedule != null) {
+ mountsSchedule.cancel(false);
+ mountsSchedule = null;
+ }
+
players.disconnectAll();
}
}
diff --git a/src/scripting/AbstractPlayerInteraction.java b/src/scripting/AbstractPlayerInteraction.java
index 6289b1d82d..753faa3d76 100644
--- a/src/scripting/AbstractPlayerInteraction.java
+++ b/src/scripting/AbstractPlayerInteraction.java
@@ -375,7 +375,7 @@ public class AbstractPlayerInteraction {
getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showPet(c.getPlayer(), evolved, false, false), true);
c.announce(MaplePacketCreator.petStatUpdate(c.getPlayer()));
c.announce(MaplePacketCreator.enableActions());
- getPlayer().startFullnessSchedule(PetDataFactory.getHunger(evolved.getItemId()), evolved, getPlayer().getPetIndex(evolved));
+ chr.getClient().getWorldServer().registerPetHunger(chr, chr.getPetIndex(evolved));
*/
MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.CASH, target.getPosition(), (short) 1, false);
@@ -452,7 +452,7 @@ public class AbstractPlayerInteraction {
}
if(ServerConstants.USE_ENHANCED_CRAFTING == true && c.getPlayer().getCS() == true)
- item = MapleItemInformationProvider.getInstance().scrollEquipWithId(item, 2049100, true, c.getPlayer().isGM());
+ item = MapleItemInformationProvider.getInstance().scrollEquipWithId(item, 2049100, true, 0, c.getPlayer().isGM());
} else {
item = new Item(id, (short) 0, quantity, petId);
}
diff --git a/src/scripting/npc/NPCConversationManager.java b/src/scripting/npc/NPCConversationManager.java
index 09b8407d98..9646b6b841 100644
--- a/src/scripting/npc/NPCConversationManager.java
+++ b/src/scripting/npc/NPCConversationManager.java
@@ -280,7 +280,7 @@ public class NPCConversationManager extends AbstractPlayerInteraction {
public void gainCloseness(int closeness) {
for (MaplePet pet : getPlayer().getPets()) {
- pet.gainClosenessFullness(getPlayer(), closeness, 0, 0);
+ if(pet != null) pet.gainClosenessFullness(getPlayer(), closeness, 0, 0);
}
}
diff --git a/src/server/MapleInventoryManipulator.java b/src/server/MapleInventoryManipulator.java
index c5ac8c65a4..b240e4d3a8 100644
--- a/src/server/MapleInventoryManipulator.java
+++ b/src/server/MapleInventoryManipulator.java
@@ -537,7 +537,7 @@ public class MapleInventoryManipulator {
c.getPlayer().setChalkboard(null);
}
}
- if ((!ItemConstants.isRechargable(itemId) && c.getPlayer().getItemQuantity(itemId, true) < quantity) || quantity < 0 || source == null) {
+ if (source == null || (!ItemConstants.isRechargable(itemId) && source.getQuantity() < quantity) || quantity < 0) {
return;
}
Point dropPos = new Point(c.getPlayer().getPosition());
diff --git a/src/server/MapleItemInformationProvider.java b/src/server/MapleItemInformationProvider.java
index aba5e64875..9c83843c96 100644
--- a/src/server/MapleItemInformationProvider.java
+++ b/src/server/MapleItemInformationProvider.java
@@ -559,7 +559,7 @@ public class MapleItemInformationProvider {
return (short)Math.min(Short.MAX_VALUE, value);
}
- public Item scrollEquipWithId(Item equip, int scrollId, boolean usingWhiteScroll, boolean isGM) {
+ public Item scrollEquipWithId(Item equip, int scrollId, boolean usingWhiteScroll, int vegaItemId, boolean isGM) {
if (equip instanceof Equip) {
Equip nEquip = (Equip) equip;
@@ -567,7 +567,14 @@ public class MapleItemInformationProvider {
Map eqstats = this.getEquipStats(equip.getItemId());
if (((nEquip.getUpgradeSlots() > 0 || ItemConstants.isCleanSlate(scrollId))) || isGM) {
- if(isGM || rollSuccessChance((double)stats.get("success"))) {
+ double prop = (double)stats.get("success");
+ if (vegaItemId == 5610000) {
+ prop = 30.0;
+ } else if (vegaItemId == 5610001) {
+ prop = 90.0;
+ }
+
+ if(isGM || rollSuccessChance(prop)) {
short flag = nEquip.getFlag();
switch (scrollId) {
case 2040727:
diff --git a/src/server/MapleStatEffect.java b/src/server/MapleStatEffect.java
index 415aa5f76e..87be07ae6a 100644
--- a/src/server/MapleStatEffect.java
+++ b/src/server/MapleStatEffect.java
@@ -752,7 +752,7 @@ public class MapleStatEffect {
}
if (isDispel() && makeChanceResult()) {
applyto.dispelDebuffs();
- } else if (isHeroWill()) {
+ } else if (isCureAllAbnormalStatus()) {
applyto.dispelDebuff(MapleDisease.SEDUCE);
applyto.dispelDebuff(MapleDisease.ZOMBIFY);
applyto.dispelDebuffs();
@@ -1042,9 +1042,7 @@ public class MapleStatEffect {
applyto.mount(ridingLevel, sourceid);
}
- if(!(ServerConstants.PETS_NEVER_HUNGRY || applyto.isGM() && ServerConstants.GM_PETS_NEVER_HUNGRY)) {
- applyto.getMount().startSchedule();
- }
+ applyto.getClient().getWorldServer().registerMountHunger(applyto);
}
if (sourceid == Corsair.BATTLE_SHIP) {
givemount = new MapleMount(applyto, 1932000, sourceid);
@@ -1399,7 +1397,7 @@ public class MapleStatEffect {
return skill && (sourceid == Priest.DISPEL || sourceid == SuperGM.HEAL_PLUS_DISPEL);
}
- private boolean isHeroWill() {
+ private boolean isCureAllAbnormalStatus() {
if (skill) {
switch (sourceid) {
case Hero.HEROS_WILL:
@@ -1418,7 +1416,8 @@ public class MapleStatEffect {
default:
return false;
}
- }
+ } else if (sourceid == 2022544) return true;
+
return false;
}
diff --git a/src/server/life/MapleMonster.java b/src/server/life/MapleMonster.java
index fe860389a0..990c59fcd3 100644
--- a/src/server/life/MapleMonster.java
+++ b/src/server/life/MapleMonster.java
@@ -150,7 +150,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
return stats.getExp();
}
- int getLevel() {
+ public int getLevel() {
return stats.getLevel();
}
diff --git a/src/server/maps/MapleMap.java b/src/server/maps/MapleMap.java
index 88d3c42a4e..8e50c0163d 100644
--- a/src/server/maps/MapleMap.java
+++ b/src/server/maps/MapleMap.java
@@ -99,6 +99,7 @@ public class MapleMap {
private LinkedList> registeredDrops = new LinkedList<>();
private List areas = new ArrayList<>();
private MapleFootholdTree footholds = null;
+ private Rectangle mapArea = new Rectangle();
private int mapid;
private AtomicInteger runningOid = new AtomicInteger(100);
private int returnMapId;
@@ -433,7 +434,15 @@ public class MapleMap {
Point ret = calcPointBelow(new Point(initial.x, initial.y - 85));
if (ret == null) {
return fallback;
+ } else if(!mapArea.contains(ret)) {
+ if(initial.y > mapArea.y + mapArea.height) return fallback; // found drop pos underneath the map :O
+
+ int borderX = (initial.x < mapArea.x) ? mapArea.x : mapArea.x + mapArea.width;
+ ret = calcPointBelow(new Point(borderX, initial.y - 85));
+
+ if(ret == null) return fallback;
}
+
return ret;
}
@@ -1886,7 +1895,7 @@ public class MapleMap {
}, 30 * 60 * 1000);
}
MaplePet[] pets = chr.getPets();
- for (int i = 0; i < chr.getPets().length; i++) {
+ for (int i = 0; i < pets.length; i++) {
if (pets[i] != null) {
pets[i].setPos(getGroundBelow(chr.getPosition()));
chr.announce(MaplePacketCreator.showPet(chr, pets[i], false, false));
@@ -2314,7 +2323,15 @@ public class MapleMap {
public MapleFootholdTree getFootholds() {
return footholds;
}
-
+
+ public void setMapPointBoundings(int px, int py, int h, int w) {
+ mapArea.setBounds(px, py, w, h);
+ }
+
+ public void setMapLineBoundings(int vrTop, int vrBottom, int vrLeft, int vrRight) {
+ mapArea.setBounds(vrLeft, vrTop, vrRight - vrLeft, vrBottom - vrTop);
+ }
+
/**
* it's threadsafe, gtfo :D
*
@@ -2667,6 +2684,26 @@ public class MapleMap {
}
}
+ public void instanceMapForceRespawn() {
+ if(!allowSummons) return;
+
+ final int numShouldSpawn = (short) ((monsterSpawn.size() - spawnedMonstersOnMap.get()));//Fking lol'd
+ if (numShouldSpawn > 0) {
+ List randomSpawn = new ArrayList<>(monsterSpawn);
+ Collections.shuffle(randomSpawn);
+ int spawned = 0;
+ for (SpawnPoint spawnPoint : randomSpawn) {
+ if(spawnPoint.shouldForceSpawn()) {
+ spawnMonster(spawnPoint.getMonster());
+ spawned++;
+ if (spawned >= numShouldSpawn) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
public void restoreMapSpawnPoints() {
for (SpawnPoint spawnPoint : monsterSpawn) {
spawnPoint.setDenySpawn(false);
diff --git a/src/server/maps/MapleMapFactory.java b/src/server/maps/MapleMapFactory.java
index 1e7de3181a..ce700d55ae 100644
--- a/src/server/maps/MapleMapFactory.java
+++ b/src/server/maps/MapleMapFactory.java
@@ -127,6 +127,27 @@ public class MapleMapFactory {
MapleDataTool.getString(timeMob.getChildByPath("message")));
}
+ int bounds[] = new int[4];
+ bounds[0] = MapleDataTool.getInt(infoData.getChildByPath("VRTop"));
+ bounds[1] = MapleDataTool.getInt(infoData.getChildByPath("VRBottom"));
+
+ if(bounds[0] == bounds[1]) { // old-style baked map
+ MapleData minimapData = mapData.getChildByPath("miniMap");
+ if(minimapData != null) {
+ bounds[0] = MapleDataTool.getInt(minimapData.getChildByPath("centerX")) * -1;
+ bounds[1] = MapleDataTool.getInt(minimapData.getChildByPath("centerY")) * -1;
+ bounds[2] = MapleDataTool.getInt(minimapData.getChildByPath("height"));
+ bounds[3] = MapleDataTool.getInt(minimapData.getChildByPath("width"));
+
+ map.setMapPointBoundings(bounds[0], bounds[1], bounds[2], bounds[3]);
+ }
+ } else {
+ bounds[2] = MapleDataTool.getInt(infoData.getChildByPath("VRLeft"));
+ bounds[3] = MapleDataTool.getInt(infoData.getChildByPath("VRRight"));
+
+ map.setMapLineBoundings(bounds[0], bounds[1], bounds[2], bounds[3]);
+ }
+
List allFootholds = new LinkedList<>();
Point lBound = new Point();
Point uBound = new Point();
diff --git a/src/server/quest/requirements/MinTamenessRequirement.java b/src/server/quest/requirements/MinTamenessRequirement.java
index 8da0c7141a..8d0c3a8676 100644
--- a/src/server/quest/requirements/MinTamenessRequirement.java
+++ b/src/server/quest/requirements/MinTamenessRequirement.java
@@ -58,8 +58,8 @@ public class MinTamenessRequirement extends MapleQuestRequirement {
for(MaplePet pet : chr.getPets()) {
if(pet == null) continue;
- if(pet.getCloseness() > curCloseness)
- curCloseness = pet.getCloseness();
+ if(pet.getCloseness() > curCloseness)
+ curCloseness = pet.getCloseness();
}
return curCloseness >= minTameness;
diff --git a/src/tools/MaplePacketCreator.java b/src/tools/MaplePacketCreator.java
index 90eed55360..0d2c533a8a 100644
--- a/src/tools/MaplePacketCreator.java
+++ b/src/tools/MaplePacketCreator.java
@@ -83,6 +83,7 @@ import client.MapleCharacter.SkillEntry;
import client.MapleClient;
import client.MapleDisease;
import client.MapleFamilyEntry;
+import client.MapleJob;
import client.MapleKeyBinding;
import client.MapleMount;
import client.MapleQuestStatus;
@@ -1823,7 +1824,16 @@ public class MaplePacketCreator {
mplew.writeInt(CHAR_MAGIC_SPAWN);
mplew.writeShort(0);
mplew.write(0);
+
mplew.writeShort(chr.getJob().getId());
+
+ /* replace "mplew.writeShort(chr.getJob().getId())" with this snippet for 3rd party FJ animation on all classes
+ if (chr.getJob().isA(MapleJob.HERMIT) || chr.getJob().isA(MapleJob.DAWNWARRIOR2) || chr.getJob().isA(MapleJob.NIGHTWALKER2)) {
+ mplew.writeShort(chr.getJob().getId());
+ } else {
+ mplew.writeShort(412);
+ }*/
+
addCharLook(mplew, chr, false);
mplew.writeInt(chr.getInventory(MapleInventoryType.CASH).countById(5110000));
mplew.writeInt(chr.getItemEffect());
@@ -2000,7 +2010,7 @@ public class MaplePacketCreator {
mplew.writeShort(SendOpcode.SUMMON_ATTACK.getValue());
mplew.writeInt(cid);
mplew.writeInt(summonOid);
- mplew.write(direction);
+ mplew.write(0); // char level
mplew.write(direction);
mplew.write(allDamage.size());
for (SummonAttackEntry attackEntry : allDamage) {
@@ -4329,6 +4339,19 @@ public class MaplePacketCreator {
mplew.write(0);
return mplew.getPacket();
}
+
+ public static final byte[] loadExceptionList(final int cid, final int petId, final byte petIdx, final List data) {
+ final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
+ mplew.writeShort(SendOpcode.PET_EXCEPTION_LIST.getValue());
+ mplew.writeInt(cid);
+ mplew.write(petIdx);
+ mplew.writeLong(petId);
+ mplew.write(data.size());
+ for (final Integer ids : data) {
+ mplew.writeInt(ids);
+ }
+ return mplew.getPacket();
+ }
public static byte[] petStatUpdate(MapleCharacter chr) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
@@ -6884,6 +6907,13 @@ public class MaplePacketCreator {
return mplew.getPacket();
}
+ public static byte[] sendVegaScroll(int op) {
+ MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
+ mplew.writeShort(SendOpcode.VEGA_SCROLL.getValue());
+ mplew.write(op);
+ return mplew.getPacket();
+ }
+
public static byte[] resetForcedStats() {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(2);
mplew.writeShort(SendOpcode.FORCED_STAT_RESET.getValue());
diff --git a/tools/MobBookUpdate/lib/MonsterBookOrig.img.xml b/tools/MobBookUpdate/lib/MonsterBookOrig.img.xml
deleted file mode 100644
index 4275039b99..0000000000
--- a/tools/MobBookUpdate/lib/MonsterBookOrig.img.xml
+++ /dev/null
@@ -1,14866 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tools/MobBookUpdate/lib/MonsterBook_updated.img.xml b/tools/MobBookUpdate/lib/MonsterBook_updated.img.xml
index 57705c5804..c265b4afa6 100644
--- a/tools/MobBookUpdate/lib/MonsterBook_updated.img.xml
+++ b/tools/MobBookUpdate/lib/MonsterBook_updated.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 @@
-
+
+
+
+
+
+
+
+
+
+
+
@@ -10002,21 +10147,20 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -11936,7 +12080,47 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -11949,7 +12133,42 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -11962,7 +12181,53 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -13486,44 +13751,43 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -13800,8 +14064,7 @@
-
-
+
@@ -13957,26 +14220,10 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
@@ -14313,16 +14560,15 @@
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/tools/MobBookUpdate/nbproject/private/private.xml b/tools/MobBookUpdate/nbproject/private/private.xml
index 6be0bf5534..6807a2ba19 100644
--- a/tools/MobBookUpdate/nbproject/private/private.xml
+++ b/tools/MobBookUpdate/nbproject/private/private.xml
@@ -2,8 +2,6 @@
-
- file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/tools/MobBookUpdate/src/mobbookupdate/MobBookUpdate.java
-
+
diff --git a/wz/Character.wz/Cap/01002419.img.xml b/wz/Character.wz/Cap/01002419.img.xml
index 97b4946453..7de5db0643 100644
--- a/wz/Character.wz/Cap/01002419.img.xml
+++ b/wz/Character.wz/Cap/01002419.img.xml
@@ -23,7 +23,6 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -6378,7 +6484,39 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -7417,36 +7555,34 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -8375,35 +8511,34 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -8673,7 +8808,17 @@
-
+
+
+
+
+
+
+
+
+
+
+
@@ -10002,21 +10147,20 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -11936,7 +12080,47 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -11949,7 +12133,42 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -11962,7 +12181,53 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -13486,44 +13751,43 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -13800,8 +14064,7 @@
-
-
+
@@ -13957,26 +14220,10 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
@@ -14313,16 +14560,15 @@
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/wz/String.wz/Skill.img.xml b/wz/String.wz/Skill.img.xml
index 002319a275..fd5959db40 100644
--- a/wz/String.wz/Skill.img.xml
+++ b/wz/String.wz/Skill.img.xml
@@ -10401,7 +10401,7 @@
-
+
diff --git a/wz/UI.wz/UIWindow.img.xml b/wz/UI.wz/UIWindow.img.xml
index 61e2b100df..f33be14513 100644
--- a/wz/UI.wz/UIWindow.img.xml
+++ b/wz/UI.wz/UIWindow.img.xml
@@ -10194,10 +10194,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+