diff --git a/.gitignore b/.gitignore
index 505c52f286..58dfab0bd4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -71,10 +71,18 @@
/tools/MapleInvalidItemWithNoNameFetcher/dist/
/tools/MapleInvalidItemWithNoNameFetcher/nbproject/
+/tools/MapleMapFieldLimitChecker/build/
+/tools/MapleMapFieldLimitChecker/dist/
+/tools/MapleMapFieldLimitChecker/nbproject/
+
/tools/MapleMapInfoRetriever/build/
/tools/MapleMapInfoRetriever/dist/
/tools/MapleMapInfoRetriever/nbproject/
+/tools/MapleMapLootLimitChecker/build/
+/tools/MapleMapLootLimitChecker/dist/
+/tools/MapleMapLootLimitChecker/nbproject/
+
/tools/MapleMesoFetcher/build/
/tools/MapleMesoFetcher/dist/
/tools/MapleMesoFetcher/nbproject/
diff --git a/Dockerfile b/Dockerfile
index 70178f3236..070ffa17cb 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -6,4 +6,4 @@ WORKDIR /mnt
COPY ./ ./
RUN sh ./posix-compile.sh
EXPOSE 8484 7575 7576 7577
-CMD exec tini -- sh ./docker-launch.sh
\ No newline at end of file
+CMD exec tini -- sh ./posix-launch.sh
\ No newline at end of file
diff --git a/README.md b/README.md
index e3411185f3..7ba64be0d3 100644
--- a/README.md
+++ b/README.md
@@ -6,10 +6,14 @@ Besides myself for maintaining this repository, credits are to be given to Wizet
Regarding distributability and usage of the code presented here: like it was before, this MapleStory server is open-source. By that, it is meant that anyone is **free to install, use, modify and redistribute the contents**, as long as there is **no kind of commercial trading involved** and the **credits to the original creators are maintained** within the codes.
-This is a NetBeans 8.0.2 Project, that MUST be built and run on Java 7 (JDK/JRE 1.7.0_79+) in order to run properly. This means that it's easier to install the project via opening the server project folder inside NetBeans' IDE. Once installed, build this project on your machine and run the server using the "launch.bat" application.
+This is a NetBeans 8.2 Project, that should be built and run on Java 8 in order to run properly (used to be ran in Java 7, thanks @kolakcc for the Java 8 support!).
+
+Being a NetBeans 8.2 Project, this means that it's easier to install the project via opening the server project folder inside NetBeans' IDE. Once installed, build this project on your machine and run the server using the "launch.bat" application.
In this project, many gameplay-wise issues generated from either the original WZ files and the server source have been partially or completely solved. Considering the use of the provided edited WZ's and server-side wz.xml files should be of the greatest importance when dealing with this instance of server source, in order to perceive it at it's full potential. My opinion, though!
+- In other case, as fallback from the provided ones, consider using **whole clean set**. Selecting part of the provided ones to play pretty much *may eventually* lead to unexpected issues.
+
The main objective of this project is to try as best as possible to recreate what once was the original MapleStory v83, while adding up some flavors that spices up the gameplay. In other words, aim to get the best of the MapleStory of that era.
---
@@ -19,17 +23,21 @@ Server files: https://github.com/ronancpl/HeavenMS
Client files & general tools: https://drive.google.com/drive/folders/0BzDsHSr-0V4MYVJ0TWIxd05hYUk
-Java7 SDK: https://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase7-521261.html
+Java 8 SDK & NetBeans bundle: https://www.oracle.com/technetwork/pt/java/javase/downloads/jdk-netbeans-jsp-3413153-ptb.html
**Important note about localhosts**: these executables are red-flagged by antivirus tools as __potentially malicious softwares__, this happens due to the reverse engineering methods that were applied onto these software artifacts. Those depicted here have been put to use for years already and posed no harm so far, so they are soundly assumed to be safe.
- Latest localhost: https://hostr.co/itrvrHapvtEg
+ Latest localhost: https://hostr.co/amuX5SLeeVZx
The following list, in bottom-up chronological order, holds information regarding all changes that were applied from the starting localhost used in this development. Some lines have a link attached, that will lead you to a snapshot of the localhost at that version of the artifact. Naturally, later versions holds all previous changes along with the proposed changes.
**Change log:**
- * Fixed Monster Magnet crashing the caster when trying to pull-in bosses.
+ * Cleared need for administrator privileges (OS) to play the game, credits to Ubaware.
+
+ * Set a higher cap for AP assigning with AP Reset, credits to Ubaware.
+
+ * Fixed Monster Magnet crashing the caster when trying to pull bosses. Drawback: Dojo HPBar becomes unavailable. https://hostr.co/SvnSKrGzXhG0
* Fixed some 'rn' problems with quest icons & removed "tab" from party leader changed message. https://hostr.co/tsYsQzzV6xT0
@@ -131,18 +139,14 @@ Firstly, install all the general tools required to run the server:
* mysql-query-browser.msi -> MySQL client component, visually shows the DB data and hubs queries.
* hamachi.msi -> used for establishing a tunnelling route for the server/client communication.
-
-Now install the Java 7 Development Kit:
-
-* jdk-7u79-windows-x64.exe
-* netbeans-8.0.2-javase-windows.exe -> It's a NetBeans project, use other IDE at your own risk.
+Now install the Java 8 SDK & NetBeans bundle:
+* jdk-8u111-nb-8_2-windows-x64.exe -> It's a NetBeans project, use other IDE at your own risk.
Now that the tools have been installed, test if they are working.
For WampServer:
-* Once you're done installing it, run it and you will see the Wamp icon on the bottom right corner.
-Left click it and click 'Put Online'.
+* Once you're done installing it, run it and you will see the Wamp icon on the bottom right corner. Left click it and click 'Put Online'.
* In case of ORANGE ICON, change port 80 at "httpd.conf" to another, as it clashes with a Windows default port. Then Left click it again and click 'Start All Services'.
* The Wamp icon must look completely green (if its orange or red, you have a problem).
@@ -161,7 +165,9 @@ For expediency, "HeavenMS-master" folder on this guide will be referred just as
Setting up the SQL: open MySQL Query Browser, then create a new session with the parameters below, then click OK.
-Server Host: localhost Port: 3306 Username: root
+* Server Host: localhost
+* Port: 3306
+* Username: root
Now it must be done CAREFULLY:
@@ -183,9 +189,7 @@ Now open NetBeans, and click "Open a project..." . Select then the "HeavenMS" fo
Inside the project, you may encounter some code errors.
-Firstly, a **new Java7 platform** must be defined to run the server. Click "Manage Platforms...", then "Add platform", browse through "C:\Program Files\Java" for the JDK 1.7 folder. Then, name this new platform "JDK 1.7".
-
-In case errors still show up, these errors probably occurs because you have yet to set the core JARs of the project. From the project hierarchy, right-click the project and select "Resolve Project Problems".
+If that's the case, you have yet to set the core JARs of the project. From the project hierarchy, right-click the project and select "Resolve Project Problems".
Locate the folder "cores" inside the root directory of this project and manually configure the missing files on NetBeans (mina-core, slf4j-api, ...).
@@ -247,7 +251,7 @@ To change a character's GM level, make sure that character is not logged in, the
---
### Some notes about WZ/WZ.XML EDITING
-NOTE: Be extremely wary when using server-side's XMLs data being reimporting into the client's WZ, as some means of synchronization between the server and client modules, this action COULD generate some kind of bugs afterwards. Client-to-server data reimporting seems to be fine, though.
+NOTE: Be extremely wary when using server-side's XMLs data being reimported into the client's WZ, as some means of synchronization between the server and client modules, this action COULD generate some kind of bugs afterwards. Client-to-server data reimporting seems to be fine, though.
#### Editing the v83 WZ's:
diff --git a/config.yaml b/config.yaml
new file mode 100644
index 0000000000..35125c96f4
--- /dev/null
+++ b/config.yaml
@@ -0,0 +1,459 @@
+#World Name: (0 "Scania", 1 "Bera", 2 "Broa", 3 "Windia", 4 "Khaini", 5 "Bellocan", 6 "Mardia", 7 "Kradia", 8 "Yellonde", 9 "Demethos", 10 "Galicia", 11 "El Nido", 12 "Zenith", 13 "Arcenia", 14 "Kastia", 15 "Judis", 16 "Plana", 17 "Kalluna", 18 "Stius", 19 "Croa", 20 "Medere")
+#Flag types: (0 = nothing, 1 = event, 2 = new, 3 = hot)
+#Recommended to use only up to 15 worlds
+worlds:
+ #Properties for Scania 0
+ - flag: 0
+ server_message: Welcome to Scania!
+ event_message: Scania!
+ why_am_i_recommended: Welcome to Scania!
+ channels: 3
+ exp_rate: 10
+ meso_rate: 10
+ drop_rate: 10
+ boss_drop_rate: 10 #NOTE: Boss drop rate OVERRIDES common drop rate, for bosses-only.
+ quest_rate: 5 #Multiplier for Exp & Meso gains when completing a quest. Only available when USE_QUEST_RATE is true. Stacks with server Exp & Meso rates.
+ fishing_rate: 10 #Multiplier for success likelihood on meso thrown during fishing.
+ travel_rate: 10 #Means of transportation rides/departs using 1/N of the default time.
+
+ #Properties for Bera 1
+ - flag: 0
+ server_message: Welcome to Bera!
+ event_message: Bera!
+ why_am_i_recommended: Welcome to Bera!
+ channels: 3
+
+ #Properties for Broa 2
+ - flag: 0
+ server_message: Welcome to Broa!
+ event_message: Broa!
+ why_am_i_recommended: Welcome to Broa!
+ channels: 3
+
+ #Properties for Windia 3
+ - flag: 0
+ server_message: Welcome to Windia!
+ event_message: Windia!
+ why_am_i_recommended: Welcome to Windia!
+ channels: 3
+
+ #Properties for Khaini 4
+ - flag: 0
+ server_message: Welcome to Khaini!
+ event_message: Khaini!
+ why_am_i_recommended: Welcome to Khaini!
+ channels: 3
+
+ #Properties for Bellocan 5
+ - flag: 0
+ server_message: Welcome to Bellocan!
+ event_message: Bellocan!
+ why_am_i_recommended: Welcome to Bellocan!
+ channels: 3
+
+ #Properties for Mardia 6
+ - flag: 0
+ server_message: Welcome to Mardia!
+ event_message: Mardia!
+ why_am_i_recommended: Welcome to Mardia!
+ channels: 3
+
+ #Properties for Kradia 7
+ - flag: 0
+ server_message: Welcome to Kradia!
+ event_message: Kradia!
+ why_am_i_recommended: Welcome to Kradia!
+ channels: 3
+
+ #Properties for Yellonde 8
+ - flag: 0
+ server_message: Welcome to Yellonde!
+ event_message: Yellonde!
+ why_am_i_recommended: Welcome to Yellonde!
+ channels: 3
+
+ #Properties for Demethos 9
+ - flag: 0
+ server_message: Welcome to Demethos!
+ event_message: Demethos!
+ why_am_i_recommended: Welcome to Demethos!
+ channels: 3
+
+ #Properties for Galicia 10
+ - flag: 0
+ server_message: Welcome to Galicia!
+ event_message: Galicia!
+ why_am_i_recommended: Welcome to Galicia!
+ channels: 3
+
+ #Properties for El Nido 11
+ - flag: 0
+ server_message: Welcome to El Nido!
+ event_message: El Nido!
+ why_am_i_recommended: Welcome to El Nido!
+ channels: 3
+
+ #Properties for Zenith 12
+ - flag: 0
+ server_message: Welcome to Zenith!
+ event_message: Zenith!
+ why_am_i_recommended: Welcome to Zenith!
+ channels: 3
+
+ #Properties for Arcenia 13
+ - flag: 0
+ server_message: Welcome to Arcenia!
+ event_message: Arcenia!
+ why_am_i_recommended: Welcome to Arcenia!
+ channels: 3
+
+ #Properties for Kastia 14
+ - flag: 0
+ server_message: Welcome to Kastia!
+ event_message: Kastia!
+ why_am_i_recommended: Welcome to Kastia!
+ channels: 3
+
+ #Properties for Judis 15
+ - flag: 0
+ server_message: Welcome to Judis!
+ event_message: Judis!
+ why_am_i_recommended: Welcome to Judis!
+ channels: 3
+
+ #Properties for Plana 16
+ - flag: 0
+ server_message: Welcome to Plana!
+ event_message: Plana!
+ why_am_i_recommended: Welcome to Plana!
+ channels: 3
+
+ #Properties for Kalluna 17
+ - flag: 0
+ server_message: Welcome to Kalluna!
+ event_message: Kalluna!
+ why_am_i_recommended: Welcome to Kalluna!
+ channels: 3
+
+ #Properties for Stius 18
+ - flag: 0
+ server_message: Welcome to Stius!
+ event_message: Stius!
+ why_am_i_recommended: Welcome to Stius!
+ channels: 3
+
+ #Properties for Croa 19
+ - flag: 0
+ server_message: Welcome to Croa!
+ event_message: Croa!
+ why_am_i_recommended: Welcome to Croa!
+ channels: 3
+
+ #Properties for Medere 20
+ - flag: 0
+ server_message: Welcome to Medere!
+ event_message: Medere!
+ why_am_i_recommended: Welcome to Medere!
+ channels: 3
+
+
+server:
+ #Thread Tracker Configuration
+ USE_THREAD_TRACKER: true #[SEVERE] This deadlock auditing thing will bloat the memory as fast as the time frame one takes to lose track of a raindrop on a tempesting day. Only for debugging purposes.
+
+ #Database Configuration
+ DB_URL: "jdbc:mysql://localhost:3306/heavenms"
+ DB_USER: "root"
+ DB_PASS: ""
+ DB_CONNECTION_POOL: true #Installs a connection pool to hub DB connections. Set false to default.
+
+ #Login Configuration
+ WORLDS: 1 #Initial number of worlds on the server.
+ WLDLIST_SIZE: 21 #Max possible worlds on the server.
+ CHANNEL_SIZE: 20 #Max possible channels per world (which is 20, based on the channel list on login phase).
+ CHANNEL_LOAD: 100 #Max players per channel (limit actually used to calculate the World server capacity).
+ CHANNEL_LOCKS: 20 #Total number of structure management locks each channel has.
+
+ RESPAWN_INTERVAL: 10000 #10 seconds, 10000.
+ PURGING_INTERVAL: 300000 #5 minutes, 300000.
+ RANKING_INTERVAL: 3600000 #60 minutes, 3600000.
+ COUPON_INTERVAL: 3600000 #60 minutes, 3600000.
+ UPDATE_INTERVAL: 777 #Dictates the frequency on which the "centralized server time" is updated.
+
+ ENABLE_PIC: false #Pick true/false to enable or disable Pic. Delete character requires PIC available.
+ ENABLE_PIN: false #Pick true/false to enable or disable Pin.
+
+ BYPASS_PIC_EXPIRATION: 20 #Enables PIC bypass, which will remain active for that account by that client machine for N minutes. Set 0 to disable.
+ BYPASS_PIN_EXPIRATION: 15 #Enables PIN bypass, which will remain active for that account by that client machine for N minutes. Set 0 to disable.
+
+ AUTOMATIC_REGISTER: true #Automatically register players when they login with a nonexistent username.
+ BCRYPT_MIGRATION: true #Performs a migration from old SHA-1 and SHA-512 password to bcrypt.
+ COLLECTIVE_CHARSLOT: false #Available character slots are contabilized globally rather than per world server.
+ DETERRED_MULTICLIENT: false #Enables detection of multi-client and suspicious remote IP on the login system.
+ #Besides blocking logging in with several client sessions on the same machine, this also blocks suspicious login attempts for players that tries to login on an account using several diferent remote addresses.
+
+ #Multiclient Coordinator Configuration
+ MAX_ALLOWED_ACCOUNT_HWID: 4 #Allows up to N concurrent HWID's for an account. HWID's remains linked to an account longer the more times it's used to login.
+ MAX_ACCOUNT_LOGIN_ATTEMPT: 15 #After N tries on an account, login on that account gets disabled for a short period.
+ LOGIN_ATTEMPT_DURATION: 120 #Period in seconds the login attempt remains registered on the system.
+
+ #Ip Configuration
+ HOST: 127.0.0.1
+ LOCALSERVER: true
+ GMSERVER: false
+
+ #Other configuration
+ SHUTDOWNHOOK: true
+
+ #Server Flags
+ USE_CUSTOM_KEYSET: true #Enables auto-setup of the HeavenMS's custom keybindings when creating characters.
+ USE_DEBUG: false #Will enable some text prints on the client, oriented for debugging purposes.
+ USE_DEBUG_SHOW_INFO_EQPEXP: false #Prints on the cmd all equip exp gain info.
+ USE_DEBUG_SHOW_RCVD_PACKET: false #Prints on the cmd all received packet ids.
+ USE_DEBUG_SHOW_RCVD_MVLIFE: false #Prints on the cmd all received move life content.
+ USE_DEBUG_SHOW_PACKET: false
+ USE_SUPPLY_RATE_COUPONS: true #Allows rate coupons to be sold through the Cash Shop.
+ USE_IP_VALIDATION: true #Enables IP checking when logging in.
+ USE_CHARACTER_ACCOUNT_CHECK: false #Enables one-character-per-account check when logging in. This might be resource intensive.
+
+ USE_MAXRANGE: true #Will send and receive packets from all events on a map, rather than those of only view range.
+ USE_MAXRANGE_ECHO_OF_HERO: true
+ USE_MTS: false
+ USE_CPQ: true #Renders the CPQ available or not.
+ USE_AUTOHIDE_GM: false #When enabled, GMs are automatically hidden when joining. Thanks to Steven Deblois (steven1152).
+ USE_BUYBACK_SYSTEM: true #Enables the HeavenMS-builtin buyback system, to be used by dead players when clicking the MTS button.
+ USE_FIXED_RATIO_HPMP_UPDATE: true #Enables the HeavenMS-builtin HPMP update based on the current pool to max pool ratio.
+ USE_FAMILY_SYSTEM: true
+ USE_DUEY: true
+ USE_RANDOMIZE_HPMP_GAIN: true #Enables randomizing on MaxHP/MaxMP gains and INT accounting for the MaxMP gain on level up.
+ USE_STORAGE_ITEM_SORT: true #Enables storage "Arrange Items" feature.
+ USE_ITEM_SORT: true #Enables inventory "Item Sort/Merge" feature.
+ USE_ITEM_SORT_BY_NAME: false #Item sorting based on name rather than id.
+ USE_PARTY_FOR_STARTERS: true #Players level 10 or below can create/invite other players on the given level range.
+ USE_AUTOASSIGN_STARTERS_AP: false #Beginners level 10 or below have their AP autoassigned (they can't choose to levelup a stat). Set true ONLY if the localhost doesn't support AP assigning for beginners level 10 or below.
+ USE_AUTOASSIGN_SECONDARY_CAP: true #Prevents AP autoassign from spending on secondary stats after the player class' cap (defined on the autoassign handler) has been reached.
+ USE_STARTING_AP_4: true #Use early-GMS 4/4/4/4 starting stats. To overcome AP shortage, this gives 4AP/5AP at 1st/2nd job advancements.
+ USE_AUTOBAN: false #Commands the server to detect infractors automatically.
+ USE_AUTOBAN_LOG: true #Log autoban related messages. Still logs even with USE_AUTOBAN disabled.
+ USE_AUTOSAVE: true #Enables server autosaving feature (saves characters to DB each 1 hour).
+ USE_SERVER_AUTOASSIGNER: true #HeavenMS-builtin autoassigner, uses algorithm based on distributing AP accordingly with required secondary stat on equipments.
+ USE_REFRESH_RANK_MOVE: true
+ USE_ENFORCE_ADMIN_ACCOUNT: false #Forces accounts having GM characters to be treated as a "GM account" by the client (localhost). Some of the GM account perks is the ability to FLY, but unable to TRADE.
+ USE_ENFORCE_NOVICE_EXPRATE: true #Hardsets experience rate 1x for beginners level 10 or under. Ideal for roaming on novice areas without caring too much about losing some stats.
+ USE_ENFORCE_HPMP_SWAP: false #Forces players to reuse stats (via AP Resetting) located on HP/MP pool only inside the HP/MP stats.
+ USE_ENFORCE_MOB_LEVEL_RANGE: true #Players N levels below the killed mob will gain no experience from defeating it.
+ USE_ENFORCE_JOB_LEVEL_RANGE: false #Caps the player level on the minimum required to advance their current jobs.
+ USE_ENFORCE_JOB_SP_RANGE: false #Caps the player SP level on the total obtainable by their current jobs. After changing jobs, missing SP will be retrieved.
+ USE_ENFORCE_ITEM_SUGGESTION: false #Forces the Owl of Minerva and the Cash Shop to always display the defined item array instead of those featured by the players.
+ USE_ENFORCE_UNMERCHABLE_CASH: true #Forces players to not sell CASH items via merchants, drops of it disappears.
+ USE_ENFORCE_UNMERCHABLE_PET: true #Forces players to not sell pets via merchants, drops of it disappears. (since non-named pets gets dirty name and other possible DB-related issues)
+ USE_ENFORCE_MERCHANT_SAVE: true #Forces automatic DB save on merchant owners, at every item movement on shop.
+ USE_ENFORCE_MDOOR_POSITION: false #Forces mystic door to be spawned near spawnpoints.
+ USE_SPAWN_CLEAN_MDOOR: false #Makes mystic doors to be spawned without deploy animation. This clears disconnecting issues that may happen when trying to cancel doors a couple seconds after deployment.
+ USE_SPAWN_LOOT_ON_ANIMATION: false #Makes loot appear some time after the mob has been killed (following the mob death animation, instead of instantly).
+ USE_SPAWN_RELEVANT_LOOT: true #Forces to only spawn loots that are collectable by the player or any of their party members.
+ USE_ERASE_PERMIT_ON_OPENSHOP: true #Forces "shop permit" item to be consumed when player deploy his/her player shop.
+ USE_ERASE_UNTRADEABLE_DROP: true #Forces flagged untradeable items to disappear when dropped.
+ USE_ERASE_PET_ON_EXPIRATION: false #Forces pets to be removed from inventory when expire time comes, rather than converting it to a doll.
+ USE_BUFF_MOST_SIGNIFICANT: true #When applying buffs, the player will stick with the highest stat boost among the listed, rather than overwriting stats.
+ USE_BUFF_EVERLASTING: false #Every applied buff on players holds expiration time so high it'd be considered permanent. Suggestion thanks to Vcoc.
+ USE_MULTIPLE_SAME_EQUIP_DROP: true #Enables multiple drops by mobs of the same equipment, number of possible drops based on the quantities provided at the drop data.
+ USE_BANISHABLE_TOWN_SCROLL: true #Enables town scrolls to act as if it's a "player banish", rendering the antibanish scroll effect available.
+ USE_ENABLE_FULL_RESPAWN: true #At respawn task, always respawn missing mobs when they're available. Spawn count doesn't depend on how many players are currently there.
+ USE_ENABLE_CHAT_LOG: false #Write in-game chat to log
+ USE_REBIRTH_SYSTEM: false #Flag to enable/disable rebirth system
+ USE_MAP_OWNERSHIP_SYSTEM: true #Flag to enable/disable map ownership system
+ USE_FISHING_SYSTEM: true #Flag to enable/disable custom fishing system
+ USE_NPCS_SCRIPTABLE: true #Flag to enable/disable serverside predefined script NPCs.
+
+ #Events/PQs Configuration
+ USE_OLD_GMS_STYLED_PQ_NPCS: true #Enables PQ NPCs with similar behaviour to old GMS style, that skips info about the PQs and immediately tries to register the party in.
+ USE_ENABLE_SOLO_EXPEDITIONS: true #Enables start expeditions with any number of players. This will also bypass all the Zakum prequest.
+ USE_ENABLE_DAILY_EXPEDITIONS: false #Enables daily entry limitations in expeditions.
+ USE_ENABLE_RECALL_EVENT: false #Enables a disconnected player to reaccess the last event instance they were in before logging out. Recall only works if the event isn't cleared or disposed yet. Suggestion thanks to Alisson (Goukken).
+
+ #Announcement Configuration
+ USE_ANNOUNCE_SHOPITEMSOLD: false #Automatic message sent to owner when an item from the Player Shop or Hired Merchant is sold.
+ USE_ANNOUNCE_CHANGEJOB: false #Automatic message sent to acquantainces when changing jobs.
+
+ #Cash Shop Configuration
+ USE_JOINT_CASHSHOP_INVENTORY: true #Enables usage of a same cash shop inventory for explorers, cygnus and legends. Items from exclusive cash shop inventories won't show up on the shared inventory, though.
+ USE_CLEAR_OUTDATED_COUPONS: true #Enables deletion of older code coupon registry from the DB, freeing so-long irrelevant data.
+ ALLOW_CASHSHOP_NAME_CHANGE: true #Allows players to buy name changes in the cash shop.
+ ALLOW_CASHSHOP_WORLD_TRANSFER: true #Allows players to buy world transfers in the cash shop.
+
+ #Maker Configuration
+ USE_MAKER_PERMISSIVE_ATKUP: true #Allows players to use attack-based strengthening gems on non-weapon items.
+ USE_MAKER_FEE_HEURISTICS: true #Apply compiled values for stimulants and reagents into the Maker fee calculations (max error revolves around 50k mesos). Set false to use basic constant values instead (results are never higher than requested by the client-side).
+
+ #Custom Configuration
+ USE_ENABLE_CUSTOM_NPC_SCRIPT: true #Enables usage of custom HeavenMS NPC scripts (Agent E, Coco, etc). Will not disable Abdula (it's actually useful for the gameplay) or quests.
+ USE_STARTER_MERGE: false #Allows any players to use the Equipment Merge custom mechanic (as opposed to the high-level, Maker lv3 requisites).
+
+ #Commands Configuration
+ BLOCK_GENERATE_CASH_ITEM: false #Prevents creation of cash items with the item/drop command.
+ USE_WHOLE_SERVER_RANKING: false #Enables a ranking pool made from every character registered on the server for the "ranks" command, instead of separated by worlds.
+
+ EQUIP_EXP_RATE: 1.0 #Rate for equipment exp gain, grows linearly. Set 1.0 for default (about 100~200 same-level range mobs killed to pass equip from level 1 to 2).
+ PQ_BONUS_EXP_RATE: 0.5 #Rate for the PQ exp reward.
+
+ EXP_SPLIT_LEVEL_INTERVAL: 5 #Non-contributing players must be within N level between the mob to receive EXP.
+ EXP_SPLIT_LEECH_INTERVAL: 5 #Non-contributing players must be within N level between any contributing party member to receive EXP.
+ EXP_SPLIT_MVP_MOD: 0.2
+ EXP_SPLIT_COMMON_MOD: 0.8
+ PARTY_BONUS_EXP_RATE: 1.0 #Rate for the party exp bonus reward.
+
+ #Miscellaneous Configuration
+ TIMEZONE: GMT-3
+ USE_DISPLAY_NUMBERS_WITH_COMMA: true #Enforce comma on displayed strings (use this when USE_UNITPRICE_WITH_COMMA is active and you still want to display comma-separated values).
+ USE_UNITPRICE_WITH_COMMA: true #Set this accordingly with the layout of the unitPrices on Item.wz XML's, whether it's using commas or dots to represent fractions.
+ MAX_MONITORED_BUFFSTATS: 5 #Limits accounting for "dormant" buff effects, that should take place when stronger stat buffs expires.
+ MAX_AP: 32767 #Max AP allotted on the auto-assigner.
+ MAX_EVENT_LEVELS: 8 #Event has different levels of rewarding system.
+ BLOCK_NPC_RACE_CONDT: 500 # (0.5 * 1000) Time the player client must wait before reopening a conversation with an NPC.
+ TOT_MOB_QUEST_REQUIREMENT: 77 #Overwrites old 999-mobs requirement for the ToT questline with new requirement value, set 0 for default.
+ MOB_REACTOR_REFRESH_TIME: 30000 # (30 * 1000) Overwrites refresh time for those reactors oriented to inflict damage to bosses (Ice Queen, Riche), set 0 for default.
+ PARTY_SEARCH_REENTRY_LIMIT: 10 #Max amount of times a party leader is allowed to persist on the Party Search before entry expiration (thus needing to manually restart the Party Search to be able to search for members).
+ NAME_CHANGE_COOLDOWN: 2592000000 # (30*24*60*60*1000) Cooldown for name changes, default (GMS) is 30 days.
+ WORLD_TRANSFER_COOLDOWN: 2592000000 # (30*24*60*60*1000) Cooldown for world tranfers, default is same as name change (30 days).
+ INSTANT_NAME_CHANGE: false #Whether or not to wait for server restart to apply name changes. Does on reconnect otherwise (requires queries on every login).
+
+ #Dangling Items/Locks Configuration
+ ITEM_EXPIRE_TIME: 180000 # (3 * 60 * 1000) Time before items start disappearing. Recommended to be set up to 3 minutes.
+ KITE_EXPIRE_TIME: 3600000 # (60 * 60 * 1000) Time before kites (cash item) disappears.
+ ITEM_MONITOR_TIME: 300000 # (5 * 60 * 1000) Interval between item monitoring tasks on maps, which checks for dangling (null) item objects on the map item history.
+ LOCK_MONITOR_TIME: 30000 # (30 * 1000) Waiting time for a lock to be released. If it reaches timeout, a critical server deadlock has made present.
+
+ #Map Monitor Configuration
+ ITEM_EXPIRE_CHECK: 10000 # (10 * 10000) Interval between item expiring tasks on maps, which checks and makes disappear expired items.
+ ITEM_LIMIT_ON_MAP: 200 #Max number of items allowed on a map.
+ MAP_VISITED_SIZE: 5 #Max length for last mapids visited by a player. This is used to recover and update drops on these maps accordingly with player actions.
+ MAP_DAMAGE_OVERTIME_INTERVAL: 5000 #Interval in milliseconds between map environment damage (e.g. El Nath and Aqua Road surrondings).
+
+ #Channel Mob Disease Monitor Configuration
+ MOB_STATUS_MONITOR_PROC: 200 #Frequency in milliseconds between each proc on the mob disease monitor schedule.
+ MOB_STATUS_MONITOR_LIFE: 84 #Idle proc count the mob disease monitor is allowed to be there before closing it due to inactivity.
+ MOB_STATUS_AGGRO_PERSISTENCE: 2 #Idle proc count on aggro update for a mob to keep following the current controller, given him/her is the leading damage dealer.
+ MOB_STATUS_AGGRO_INTERVAL: 5000 #Interval in milliseconds between aggro logistics update.
+
+ #Some Gameplay Enhancing Configurations
+ #Scroll Configuration
+ USE_PERFECT_GM_SCROLL: true #Scrolls from GMs never uses up slots nor fails.
+ USE_PERFECT_SCROLLING: true #Scrolls doesn't use slots upon failure.
+ USE_ENHANCED_CHSCROLL: true #Equips even more powerful with chaos upgrade.
+ USE_ENHANCED_CRAFTING: true #Apply chaos scroll on every equip crafted.
+ USE_ENHANCED_CLNSLATE: true #Clean slates can be applied to recover successfully used slots as well.
+ SCROLL_CHANCE_ROLLS: 10 #Number of rolls for success on a scroll, set 1 for default.
+ CHSCROLL_STAT_RATE: 3 #Number of rolls of stat upgrade on a successfully applied chaos scroll, set 1 for default.
+ CHSCROLL_STAT_RANGE: 6 #Stat upgrade range (-N, N) on chaos scrolls.
+
+ #Beginner Skills Configuration
+ USE_ULTRA_NIMBLE_FEET: true #Massive speed & jump upgrade.
+ USE_ULTRA_RECOVERY: true #Massive recovery amounts overtime.
+ USE_ULTRA_THREE_SNAILS: true #Massive damage on shell toss.
+
+ #Other Skills Configuration
+ USE_FULL_ARAN_SKILLSET: false #Enables starter availability to all Aran job skills. Suggestion thanks to Masterrulax.
+ USE_FAST_REUSE_HERO_WILL: true #Greatly reduce cooldown on Hero's Will.
+ USE_ANTI_IMMUNITY_CRASH: true #Crash skills additionally removes the mob's invincibility buffs. Suggestion thanks to Celestial.
+ USE_UNDISPEL_HOLY_SHIELD: true #Holy shield buff also prevents players from suffering dispel from mobs.
+ USE_FULL_HOLY_SYMBOL: true #Holy symbol doesn't require EXP sharers to work in full.
+
+ #Character Configuration
+ USE_ADD_SLOTS_BY_LEVEL: true #Slots are added each 20 levels.
+ USE_ADD_RATES_BY_LEVEL: true #Rates are added each 20 levels.
+ USE_STACK_COUPON_RATES: false #Multiple coupons effects builds up together.
+ USE_PERFECT_PITCH: true #For lvl 30 or above, each lvlup grants player 1 perfect pitch.
+
+ #Quest Configuration
+ USE_QUEST_RATE: false #Exp/Meso gained by quests uses fixed server exp/meso rate times quest rate as multiplier, instead of player rates.
+
+ #Quest Points Configuration
+ QUEST_POINT_REPEATABLE_INTERVAL: 24 #Minimum interval between repeatable quest completions for quest points to be awarded.
+ QUEST_POINT_REQUIREMENT: 16 #Exchange factor between N quest points to +1 fame, set 0 to disable the entire quest point mechanism.
+ QUEST_POINT_PER_QUEST_COMPLETE: 4 #Each completed quest awards N quest points, set 0 to disable.
+ QUEST_POINT_PER_EVENT_CLEAR: 1 #Each completed event instance awards N quest points, set 0 to disable.
+
+ #Guild Configuration
+ CREATE_GUILD_MIN_PARTNERS: 6 #Minimum number of members on Guild Headquarters to establish a new guild.
+ CREATE_GUILD_COST: 1500000
+ CHANGE_EMBLEM_COST: 5000000
+ EXPAND_GUILD_BASE_COST: 500000
+ EXPAND_GUILD_TIER_COST: 1000000
+ EXPAND_GUILD_MAX_COST: 5000000
+
+ #Family Configuration
+ FAMILY_REP_PER_KILL: 4 #Amount of rep gained per monster kill.
+ FAMILY_REP_PER_BOSS_KILL: 20 #Amount of rep gained per boss kill.
+ FAMILY_REP_PER_LEVELUP: 200 #Amount of rep gained upon leveling up.
+ FAMILY_MAX_GENERATIONS: 1000 #Maximum depth of family tree. (Distance from leader to farthest junior)
+
+ #Equipment Configuration
+ USE_EQUIPMNT_LVLUP_SLOTS: true #Equips can upgrade slots at level up.
+ USE_EQUIPMNT_LVLUP_POWER: true #Enable more powerful stat upgrades at equip level up.
+ USE_EQUIPMNT_LVLUP_CASH: true #Enable equip leveling up on cash equipments as well.
+ USE_SPIKES_AVOID_BANISH: true #Shoes equipped with spikes prevents mobs from banishing wearer.
+ MAX_EQUIPMNT_LVLUP_STAT_UP: 10000 #Max stat upgrade an equipment can have on a levelup.
+ MAX_EQUIPMNT_STAT: 32767 #Max stat on an equipment by leveling up.
+ USE_EQUIPMNT_LVLUP: 7 #All equips lvlup at max level of N, set 1 to disable.
+
+ #Map-Chair Configuration
+ USE_CHAIR_EXTRAHEAL: true #Enable map chairs to further recover player's HP and MP (player must have the Chair Mastery skill).
+ CHAIR_EXTRA_HEAL_MULTIPLIER: 10 #Due to only being able to be send up-to-255 heal values, values being actually updated is the one displayed times this.
+ CHAIR_EXTRA_HEAL_MAX_DELAY: 21 #Players are expected to recover fully after using this skill for N seconds.
+
+ #Player NPC Configuration
+ PLAYERNPC_INITIAL_X: 262 #Map frame width for putting PlayerNPCs.
+ PLAYERNPC_INITIAL_Y: 262 #Map frame height for putting PlayerNPCs.
+ PLAYERNPC_AREA_X: 320 #Initial width gap between PlayerNPCs.
+ PLAYERNPC_AREA_Y: 160 #Initial height gap between PlayerNPCs.
+ PLAYERNPC_AREA_STEPS: 4 #Max number of times gap is shortened to comport PlayerNPCs.
+ PLAYERNPC_ORGANIZE_AREA: true #Automatically rearranges PlayerNPCs on the map if there is no space set the new NPC. Current distance gap between NPCs is decreased to solve this issue.
+ PLAYERNPC_AUTODEPLOY: true #Makes PlayerNPC automatically deployed on the Hall of Fame at the instant one reaches max level. If false, eligible players must talk to 1st job instructor to deploy a NPC.
+
+ #Pet Auto-Pot Configuration
+ USE_COMPULSORY_AUTOPOT: true #Pets will consume as many potions as needed to fulfill the AUTOHP/MP ratio threshold.
+ USE_EQUIPS_ON_AUTOPOT: true #Player MaxHP and MaxMP check values on autopot handler will be updated by the HP/MP bonuses on equipped items.
+ PET_AUTOHP_RATIO: 0.99 #Will automatically consume potions until given ratio of the MaxHP/MaxMP is reached.
+ PET_AUTOMP_RATIO: 0.99
+
+ #Pet & Mount Configuration
+ PET_EXHAUST_COUNT: 3 #Number of proc counts (1 per minute) on the exhaust schedule for fullness.
+ MOUNT_EXHAUST_COUNT: 1 #Number of proc counts (1 per minute) on the exhaust schedule for tiredness.
+
+ #Pet Hunger Configuration
+ PETS_NEVER_HUNGRY: false #If true, pets and mounts will never grow hungry.
+ GM_PETS_NEVER_HUNGRY: true #If true, pets and mounts owned by GMs will never grow hungry.
+
+ #Event Configuration
+ EVENT_MAX_GUILD_QUEUE: 10 #Max number of guilds in queue for GPQ.
+ EVENT_LOBBY_DELAY: 10 #Cooldown duration in seconds before reopening an event lobby.
+
+ #Dojo Configuration
+ USE_FAST_DOJO_UPGRADE: true #Reduced Dojo training points amount required for a belt upgrade.
+ USE_DEADLY_DOJO: false #Should bosses really use 1HP,1MP attacks in dojo?
+ DOJO_ENERGY_ATK: 100 #Dojo energy gain when deal attack
+ DOJO_ENERGY_DMG: 20 #Dojo energy gain when recv attack
+
+ #Wedding Configuration
+ WEDDING_RESERVATION_DELAY: 3 #Minimum idle slots before processing a wedding reservation.
+ WEDDING_RESERVATION_TIMEOUT: 10 #Limit time in minutes for the couple to show up before cancelling the wedding reservation.
+ WEDDING_RESERVATION_INTERVAL: 60 #Time between wedding starts in minutes.
+ WEDDING_BLESS_EXP: 30000 #Exp gained per bless count.
+ WEDDING_GIFT_LIMIT: 1 #Max number of gifts per person to same wishlist on marriage instances.
+ WEDDING_BLESSER_SHOWFX: true #Pops bubble sprite effect on players blessing the couple. Setting this false shows the blessing effect on the couple instead.
+
+ #Buyback Configuration
+ USE_BUYBACK_WITH_MESOS: true #Enables usage of either mesos or NX for the buyback fee.
+ BUYBACK_FEE: 77.70 #Sets the base amount needed to buyback (level 30 or under will use the base value).
+ BUYBACK_LEVEL_STACK_FEE: 85.47 #Sets the level-stacking portion of the amount needed to buyback (fee will sum up linearly until level 120, when it reaches the peak).
+ BUYBACK_MESO_MULTIPLIER: 1000 #Sets a multiplier for the fee when using meso as the charge unit.
+ BUYBACK_RETURN_MINUTES: 1 #Sets the maximum amount of time the player can wait before decide to buyback.
+ BUYBACK_COOLDOWN_MINUTES: 7 #Sets the time the player must wait before using buyback again.
+
+ # Login timeout by shavit
+ TIMEOUT_DURATION: 3600000 # Kicks clients who don't send any packet to the game server in due time (in millisseconds).
+
+ #Event End Timestamp
+ EVENT_END_TIMESTAMP: 1428897600000
+
diff --git a/configuration.ini b/configuration.ini
deleted file mode 100644
index 01a874e45d..0000000000
--- a/configuration.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-HOST=127.0.0.1
-URL=jdbc:mysql://localhost:3306/heavenms
-DB_USER=root
-DB_PASS=
-JAVA8=FALSE
-SHUTDOWNHOOK=true
\ No newline at end of file
diff --git a/cores/yamlbeans-1.13.jar b/cores/yamlbeans-1.13.jar
new file mode 100644
index 0000000000..45cac40fe9
Binary files /dev/null and b/cores/yamlbeans-1.13.jar differ
diff --git a/docker-launch.sh b/docker-launch.sh
deleted file mode 100644
index 654a2c088c..0000000000
--- a/docker-launch.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/bash
-
-sed -i "s/HOST=.*/HOST=${HOST}/" configuration.ini
-sed -i "s|URL=.*|URL=${URL}|" configuration.ini
-sed -i "s/DB_USER=.*/DB_USER=${DB_USER}/" configuration.ini
-sed -i "s/DB_PASS=.*/DB_PASS=${DB_PASS}/" configuration.ini
-
-exec sh ./posix-launch.sh
\ No newline at end of file
diff --git a/docs/area_bosses/AreaBoss.js b/docs/area_bosses/AreaBoss.js
new file mode 100644
index 0000000000..834b6a68ea
--- /dev/null
+++ b/docs/area_bosses/AreaBoss.js
@@ -0,0 +1,35 @@
+// @Author: Resinate
+
+importPackage(Packages.server.life);
+importPackage(Packages.tools);
+
+var towns = new Array(800020120, 251010102, 260010201, 107000300, 200010300, 100040105, 100040106, 261030000, 110040000, 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, 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, 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, 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() {
+ for(var i = 0; i < towns.length; i++) {
+ mapObj = em.getChannelServer().getMapFactory().getMap(towns[i]);
+ mobObj = MapleLifeFactory.getMonster(spawns[i]);
+ if(mapObj.getMonsterById(spawns[i]) == null) {
+ mapObj.spawnMonsterOnGroundBelow(mobObj, new Packages.java.awt.Point(x[i],y[i]));
+ }
+ }
+ setupTask = em.schedule("start", 30 * 60 * 1000);
+}
diff --git a/docs/area_bosses/BossEvent.js b/docs/area_bosses/BossEvent.js
deleted file mode 100644
index 5cd1eb0047..0000000000
--- a/docs/area_bosses/BossEvent.js
+++ /dev/null
@@ -1,33 +0,0 @@
-// @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/issues.txt b/docs/issues.txt
index bfd66cbfb2..4cb1acf797 100644
--- a/docs/issues.txt
+++ b/docs/issues.txt
@@ -10,12 +10,15 @@ Known issues:
- If there are multiple bosses that shows HPBar on the map, if a player hits more than one the HPBar may start flickering on the screen.
- Sometimes battleship may behave oddly with the enhanced buff system, making the character d/c in certain scenarios.
- Dragon Roar doesn't show the stun effect to players.
+- Cygnus job 'Final Attack' skills not functional.
+- Steal skill doesn't deduct the loot from the drop pool from a mob.
- Snipe will show much higher damage value than actually applicable to the attacker.
-- Some monster status such as freeze and weapon/magic reflect doesn't behave properly in certain scenarios. Freeze seems to not work on mobs with low OID or are starters from server boot time.
+- Some monster status such as weapon/magic reflect doesn't behave properly in certain scenarios.
- On low-end connections, things such as command summoning a player that is currently logging in (already visible to other players) may cause the player to freeze, consequently freezing the account as well since the server-side disconnection doesn't happen.
- Reportedly, there are cases where mob positions fail to sync between player's client-view.
- Visual equip EXP watch value will present stuttering for early levels requirement (EXP needed less than 100), and requirement at level 200 will not progress at all due to the level cap in client.
- Monster Magnet will crash the player when trying to pull fixed monsters.
+- Some magic skills such as "Energy Bolt" or "Holy Arrow" doesn't display damage to other players when the attacks come from close range to the targeted mob. Oddly enough, using "closeRangeAttack" packet seems to clear the issue on most skills, however in others "Error 5" crash renders this unusable.
---------------------------
---------------------------
@@ -29,15 +32,13 @@ Missing features list:
---------------------------
** Others **
-- GM Events (Snowball, OX, Fitness)
-- Family system
- MTS
---------------------------
---------------------------
** Quest **
-- Family & Medal quests.
+- Medal quests.
---------------------------
@@ -48,7 +49,7 @@ Missing features list:
---------------------------
** Packet issues & advanced PQs **
-- Mystic Doors (won't deploy players properly is some situations, only destination map matches).
+- Mystic Doors (won't deploy players properly in some situations, only destination map matches).
- Nett's Pyramid Party Quest
---------------------------
diff --git a/docs/leftover.txt b/docs/leftover.txt
index 38d0fbcee6..2001688854 100644
--- a/docs/leftover.txt
+++ b/docs/leftover.txt
@@ -2,10 +2,7 @@
Uncoded features:
NX Format
-Name Change
-World transfer
MTS (v53)
-Family system (v67)
Family and Medal Quests(?)
Uncoded Party Quests:
diff --git a/docs/mychanges_ptbr.txt b/docs/mychanges_ptbr.txt
index 97c3bc975e..bfd4c72496 100644
--- a/docs/mychanges_ptbr.txt
+++ b/docs/mychanges_ptbr.txt
@@ -1950,3 +1950,327 @@ Normalizado uso de lobbyids em início de eventos nos scripts.
15 Junho 2019,
Corrigido limites de requisitos de nível para acessar expedições nos scripts de NPCs que as gerenciam.
+
+19 Junho 2019,
+Corrigido janela congelada de Legendary Spirit ao tentar aplicar scrolls em equipamentos sem slots.
+Ajustado chance de drops de skillbooks.
+Revisado funcionalidade de arrendamento de mapas. Jogadores não mais perdem posse ao trocar de mapas, somente ao expirar devido à falta de atividades ou ao tentar arrendar outro mapa.
+Revisado expedições retirando jogadores assim que o líder sai de mapa ou não há mais em campo a quantidade mínima de jogadores requisitada para começar o evento.
+Corrigido gerenciador de mapas finalizando antes dos eventos, potencialmente levando a quebra de scripts de evento durante a fase de shutdown do servidor.
+Corrigido comandos de começar/completar quests não atuando para quests não previstas pelos XMLs.
+Revisado sistema de quests desnecessariamente inicializando estruturas de leitura de XMLs.
+Corrigido sistema de quests no objeto do jogador não acessando corretamente certas quests devido a uso indevido de inteiros de tamanho short e int.
+
+20 Junho 2019,
+Implementado sistema de contabilização de entradas em bosses.
+Corrigido potencial exploit com expressão facial podendo crashar jogadores ao receber expressão inválida.
+
+21 - 22 Junho 2019,
+Ajustado data no Duey, que estava atuando de forma inesperada anteriormente.
+Adicionado checagem contra potenciais exploits de dano dado em mobs por mobs ou summons em seus respectivos handlers.
+Adicionado checagem contra potenciais exploits por itens nos handlers de cadeira e expressão facial.
+Ajustado checagem contra potenciais exploits de distância/inexistência de NPC na área onde o jogador se encontra, ao se realizar operações sobre quests.
+Refatorado função que modifica estado de mob aliado no mapa (no lado servidor) sendo executada dentro de definição de pacote.
+Implementado suporte para entrega rápida pelo Duey.
+
+24 - 25 Junho 2019,
+Corrigido Horntail não dropando itens após mudança recente na lógica de drops.
+Revisado sistema de comandos. Cada comando no sistema é inicializado somente uma vez, ao iniciar o servidor.
+Ajustado Maker skill, agora utilizando pacotes de resultados ao realizar suas operações.
+Corrigido Mini Dungeons utilizando tempo limite pré-determinado no código-fonte.
+Revisado utilização de "timeLimit" em objeto MapleMap. Valor supostamente pré-determinado pela receita XML poderia ser sobrescrito por outros métodos da classe.
+Ajustado evento de Gaga no espaço, evento agora funcional.
+Adicionado minigame RPS de NPC, recursos implementados pelo Arnah.
+
+27 Junho 2019,
+Corrigido contabilização de dano de auto-destruição de mobs não sendo aplicado corretamente.
+
+01 Julho 2019,
+Corrigido contabilização de entrada em bosses não checando criação de expedições.
+Corrigido caso de overflow em valor máximo calculado de dano em skills.
+Implementado retirada de itens mantidos pelo Duey na DB, após dado a data de expirar.
+
+02 Julho 2019,
+Refatorado flags de itens utilizando tamanho menor que o esperado.
+Adicionado checagem por FieldLimit ao lançar itens em mapas dados como "untradeable".
+Adicionado funcionalidade "Quest Item Restore".
+
+11 Julho 2019,
+Implementado instanciação de flag "somente compartilhável dentro de mesma conta" em itens recém-gerados que possuem essa funcionalidade.
+Implementado atualização de estados no portão de entrada do Papulatus.
+Corrigido deslize apontado pelo Conrad, na aplicação de caixas de limites usados pelos buffs em área.
+Implementado finalização de instância de minidungeon assim que o líder de party sai da área ou há troca de líderes com alguém fora da área.
+
+14 Julho 2019,
+Refatorado atributos de HenesysPQ sendo utilizados em objetos de áreas do jogo.
+Corrigido mobs aliados não realizando item drops devidamente após atualização recente no sistema de loot.
+Corrigido quest de proteger hog (explorers) "completando" mesmo embora o jogador tenha tentado sair da instância ao conversar com o NPC.
+Corrigido possível exploit com quest de proteger hog (explorers), onde o jogador poderia vir a tentar novamente a instância após completá-la (resultando em recompensas rápidas).
+Corrigido script de Papulatus não levando os métodos de checagem de requisitos atualizados para expedições.
+Corrigido diversos scripts de expedições finalizando expedições indevidamente ao realizar operações de party.
+Implementado checagem por flag de FieldLimit que evita penalidade de perda de EXP em certas áreas do jogo.
+Revisado limite de dano aplicável por alguns summons, cujo valor limite estava muito abaixo do esperado, levando a problemas com aplicação de ataques dos mesmos.
+
+15 Julho 2019,
+Implementado normalização de fuso horário em pacotes enviados ao cliente. Agora o sistema utiliza mesmo fuso horário definido nas flags do servidor.
+Corrigido certos casos onde grupos dentro de lobby de CPQ não conseguiam ser desafiados, geralmente ocorrendo ao se desconectar após o desafio ter sido aceito e antes de começar a instância.
+Revisado script de créditos.
+Adicionado checagem por GM's no método de autoban de jogador.
+
+17 Julho 2019,
+Corrigido drops de reatores não utilizando o sistema de drops sequenciais.
+Revisado uso de sincronizações em vários métodos do sistema, tais como nos métodos de colocação de novos itens no mapa, detecção de toque em reatores, tabela de convidados em casamento, aplicação de dano de jogadores em mobs, recepção de pacotes.
+
+18 Julho 2019,
+Corrigido aplicação indevida de requisição de palavra-chave que prosseguia quest em uma das quests na questline de Aran.
+Corrigido nome errado em coluna da tabela "reports".
+Corrigido uso de NPC default na conversa padrão que ocorre ao se utilizar o comando "startquest" e "completequest".
+
+19 Julho 2019,
+Corrigido quest onde mobs podem aparecer na área do NPC Grendel permitindo repetir os ganhos de quest tanto quanto respawn de mobs à vontade.
+Corrigido robes de sauna e outros, que permitem ganhos bônus de HP, gerando ganhos 10x maiores que o esperado.
+Ajustado limites para recuperação de HP de forma a permitir ganhos em vários casos onde há a aplicação de bônus, tais como usando sauna robe, Endure skill.
+
+22 Julho 2019,
+Corrigido atributo de contagem de dano em mob aliado da HenesysPQ não instanciado.
+Corrigido skill "Combat Step" sendo considerado um "buff" pelo sistema do servidor. Isso implicava em duplicação de efeito visual para outros jogadores.
+
+26 - 27 Julho 2019,
+Corrigido problemas de cast de tipos que passou a ocorrer após trocar para Java 8.
+Ajustado flag que permite jogadores a ganhar EXP de mob independente de diferenças de nível.
+Corrigido Gaviota não sumindo após lançar ataque.
+Corrigido funcionalidade de ignorar items de pets não se mantendo após trocar de mapas.
+Corrigido CPQ1 campo 3 e 4 não permitindo jogadores a usar summons/protectors em campo.
+Corrigido líderes de expedição recebendo pacote de timer para fase de registro em casos onde a expedição falhou em ser iniciada.
+Corrigido problema de locking ocorrendo recentemente ao tentar rodar limpeza de itens no mapa (ocorre ao realizar drops de vários itens, mais antigos imediatamente sumindo), problema ocorrendo devido a um caso de loop infinito.
+Corrigido várias skills de summons não utilizando o ícone de buff no canto superior direito da tela.
+Corrigido alguns danos de summons sendo calculados extremamente baixos quando o jogador não equipa uma arma ou o mesmo não possui pelo menos uma dezena em ataque.
+
+28 Julho 2019,
+Corrigido funcionalidade de loot explosivo de mobs não aplicando devidamente.
+Corrigido linguagens, bastante usado na MCPQ, não utilizando o valor requisitado pelo jogador ao logar/trocar de canais.
+Corrigido casos de NPE ao tentar realizar updates de posição lado-servidor em alguns summons de jogador.
+Revisado reset de reatores em reatores que estão desaparecidos por um tempo, para retornar de imediato.
+
+31 Julho 2019,
+Revisado AP inicial de jogadores, agora mantendo dois sistemas para suprir a falta de 9 AP's. Ambos com AP's começando em 4/4/4/4: 0AP inicialmente, com ganhos de 4AP na primeira mudança de classe e 5AP na segunda mudança. Se não estiver usando esse método, jogadores possuem de início 9 AP's à disposição.
+
+02 Agosto 2019,
+Refatorado vários scripts de quests, não mais realizando disposes e envio de caixas de texto no mesmo status.
+
+05 Agosto 2019,
+Revisado casos onde o sistema de recompensas de quests avisa "inventário cheio" mesmo embora novos espaços pudessem ser encontrados na retirada de itens.
+Corrigido posicionamento não-verificado de lojas criadas por jogadores.
+Corrigido ganho reduzido de EXP ao utilizar skill Mortal Blow.
+Corrigido clique em "O" na UI de recepção de itens pelo Duey não realizando ação alguma.
+Corrigido representação de "quick" na lista de pacotes recebidos pelo Duey não constando os pacotes enviados sem mensagem escrita.
+Revisado certos casos onde itens enviados com "quick delivery" não conseguiam ser recebidos imediatamente.
+
+06 Agosto 2019,
+Corrigido certas montarias não-ligadas a itens de inventário não atuando devidamente ao transicionar mapas (terceiros não conseguiam visualizar a montaria).
+Revisado os vários scripts de quests anteriormente refatorado. Adição: último if status sinalizando disposes de caixas de texto nos penúltimos status.
+
+08 - 10 Agosto 2019,
+Adicionado handler para aplicação de dano em mobs por objetos de ambiente.
+Revisado uso de Steal ao aplicar dano, preenchendo lista (e buscando evitar novas aplicações) assim que utilizado.
+Setado checagem para limites de lobbyid ao se iniciar uma instância de evento.
+Revisado boss logs somente removendo os itens da tabela a partir de um dia antes, não todas as entradas, assim que a tarefa de reset é iniciada.
+Refatorado elementos não-condizentes com o padrão de design Factory na classe geradora de mapas.
+Revisado possível cenário de vazamento de memória ocorrido devido a exceção lançada em algum trecho entre removeKilledMonsterObject e dispatchMonsterKilled.
+Aprimorado loots de reatores, agora colocando loots visíveis ao jogador no centro, similarmente a como loots de mobs ocorrem.
+Ajustado frequência de loots de reatores para 200ms.
+
+12 - 14 Agosto 2019,
+Refatorado vários casos de erros em acessos a funções estáticas a partir de scripts, que passou a ocorrer após trocar de versão Java.
+Corrigido listas que mantém conteúdo dos mundos e canais esvaziando antes que os processos em execução do TimerManager terminem de executar, no momento do sinal de shutdown do servidor.
+Revisado update de quests para o jogador durante script de quests, problema permite movimento enquanto o mesmo ainda está falando com o NPC.
+Revisado novamente os scripts de quest! Problema detectado envolvia incidências de iniciar e completar de quests com disposes na mesma estrutura status.
+
+19 - 20 Agosto 2019,
+Revisado autocommit antes da hora e falta de chamada a rollbacks quando ocorre exceção no método de salvar jogador na DB.
+Corrigido quest scripts recém-formatados pelo caso dos updates de quest durante conversação com NPCs.
+Revisado cálculo de perda de EXP em nocaute.
+Corrigido caso de deadlock relacionado a party HP e manutenção de doors, ocorrendo devido a uso indevido de statLock antes de prtLock.
+
+22 - 23 Agosto 2019,
+Revisado envio sequencial de pacotes pelo IoSession acoplado à conexão com o cliente.
+Corrigido possibilidade de uso de SP Reset para aumentar skills imprevistas.
+Adicionado permissão de drops de NX utilizando a mesma flag dos shops.
+Adicionado comando para setar quantidade de slots em todos os inventários.
+
+24 Agosto 2019,
+Refatorado objeto de MapleStorage, agora sendo gerado um objeto por conta, acoplado ao mundo que jogador pertence (não mais acoplado diretamente com objeto do jogador, jogador agora recebe uma visão deste objeto).
+
+26 - 27 Agosto 2019,
+Revisado uso de objeto de jogador pelo MaplePartyCharacter, retirando acesso ao mesmo quando o jogador está desconectado (assim limpando retenção de múltiplos objetos de jogador offline, quando os mesmos se encontram em party).
+Corrigido casos inesperados como Nimble Feet seguido de Morph fazendo o segundo atuar inesperadamente, aplicando outras imagens de morphs.
+Corrigido buffs importantes para mecânicas do jogo sendo sobrescritas por possuir menores ganhos que outros.
+Revisado diversos casos no código-fonte onde havia possibilidade de acesso ao objeto de jogador nulo a partir do MaplePartyCharacter (quando o jogador se encontra offline e está na party).
+Corrigido caso de EXP ganho ocorrendo menor que o esperado, ao se usar diversos modificadores de ganhos.
+Corrigido bug crítico na atualização recente relacionado a skill mounts, onde na inicialização dos mounts informações estariam sendo perdidas inesperadamente...
+Corrigido informações de mount não sendo atualizado para o jogador assim que o mesmo loga, levando a certas quests com requerimento de mount não permitindo inicialização pelo lado-cliente.
+Revisado sistema criado para manutenção de pacotes enviados através do IoSession, tal sistema agora atuando como uma "pool" ao invés de uma "factory".
+
+29 Agosto 2019,
+Revisado uso de loop em espera ocupada no sistema de manutenção de pacotes enviados. Em geral, threads que solicitam anúncio de pacotes não necessitam evitar esperar até que cada pacote seja enviado.
+
+30 Agosto 2019,
+Corrigido skill Seal não atuando devidamente para Blaze Wizard.
+Corrigido skill Seal atuando em bosses.
+Refatorado funções ainda utilizando invocável desabstraindo o mesmo, assim evitando múltiplos casts de tipo ao decorrer da busca pelo motor de scripts.
+
+02 - 03 Setembro 2019,
+Revisado pontos de spawn usados em warps em vários scripts do servidor.
+Refatorado métodos da CPQ buscando jogadores pelo storage de canais. Não deveria mais haver necessidade já que a partir de uma atualização recente membros offline contém objeto de jogador nulo, e ao reentrar o MPC já assume o novo objeto de jogador.
+
+05 - 06 Setembro 2019,
+Adicionado doors em mapas de cidade como objetos visíveis em campo.
+Corrigido aplicação de status de mobs, onde em várias ocasiões os mobs poderiam parecer inafetáveis aos mesmos.
+
+07 Setembro 2019,
+Corrigido jogador não recebendo informações de debuffs em outros jogadores ao trocar de mapas.
+
+10 - 12 Setembro 2019,
+Corrigido algumas skills de tipo "mágico", que não usam cargas, não mostrando dano para outros jogadores quando golpe ocorre suficientemente perto.
+Adicionado checagem por evidência de disponibilidade de scripts em quests.
+Corrigido inscrição de itens no MTS levando a certos atributos de itens sendo perdidos no processo.
+Adicionado ganho de MaxHP extra da skill para Thunderbreakers, em ambos casos de aumento de nível e de MaxHP usando AP.
+Refatorado ação de autopots, permitindo o mesmo a agir imediatamente após detecção de perda suficiente de HP/MP ao usar itens ou skills.
+Adicionado efeito sonoro de portal ao atravessar Mystic Door.
+
+16 Setembro 2019,
+Adicionado checagem no uso de autopots ao usar HP/MP, limites são calculados baseado em estimativa detectada de uso dos autopots pelo lado cliente.
+
+20 Setembro 2019,
+Adicionado update de macros ao usar SP reset.
+Refatorado vários pacotes Java contendo classes diversificadas.
+Corrigido nomenclatura errônea de "worker" introduzida, querendo significar "task".
+
+21 - 24 Setembro 2019,
+Corrigido ferramenta detectora de métodos estáticos não realizando varredura completa em arquivos, parando em casos onde um método estático é encontrado em cada.
+Implementado ferramenta detectora de scripts de quest que estiveram sendo usados como paliativo.
+Refatorado amplamente métodos que lidam com atribuição de progresso de quests.
+Revisado uso de vários scripts de quest que estiveram sendo usados como paliativo.
+Alterado declaração de "MapleCharacter c", considerado ambíguo à de MapleClient.
+Revisado uso de progresso de quests feito pelos scripts, de forma a parear com o novo modelo.
+
+26 - 28 Setembro 2019,
+Corrigido casos no novo modelo onde algumas quests utilizando informações de progresso não conseguiriam ser completadas.
+Corrigido uso envio desnecessário de pacote ao atualizar progresso de quest causando popup inesperado de mensagens de quests para jogadores.
+Corrigido alguns scripts não levando a atualização dos endereços dos pacotes alterados na última refatoração.
+Corrigido script de quest de Magatia checando errado quantidade de livros adquiridos pelo jogador no progresso de quest.
+
+29 Setembro 2019,
+Revisado Raise UI, agora utilizando o novo sistema de progressão.
+Corrigido checagem por espaço no inventário, ao tentar ganhar itens via quest, não informando o jogador adequadamente sobre itens one-of-a-kind.
+Corrigido uso de itens na Raise UI, quando não atualizando progresso algum (nenhum pacote enviado ao jogador), não permitindo jogador acesso a certos recursos (como Cash Shop/MTS).
+Revisado aplicação geral do novo modelo de progressão de quests implementado.
+
+01 - 02 Outubro 2019,
+Corrigido caso de exceção de modificação concorrente dentro de módulo de incremento de progresso de mob em quests.
+Corrigido caixa de diálogo com conteúdo extra, ao terminar uma quest, não sendo enviada ao jogador.
+Corrigido retransmissão de pacotes de movimentos com sequência vazia crashando outros jogadores.
+Refatorado checagem por pacotes de movimentos com sequência vazia, agora atuando no módulo abstrato.
+Corrigido progresso de mobs em quests não atualizando o infoex devidamente ao jogador, levando à falta do balão de "quest completa".
+Corrigido quest de 1o job de Cygnus permitindo retornar para estado que tenta concluir quest, permitindo assim múltiplas instâncias de conclusão da mesma.
+Adicionado scripting atuante ao abrir Raise UI, permitindo assim utilizar ações elaboradas, tais como EXP de combate para Mimiana.
+Corrigido pets não sendo despawnados assim que se dá o tempo de expiração.
+Corrigido jogadores com "hide" controlando mobs em certas situações.
+Corrigido análise de alerta de HP/MP lado-servidor não contando com os atributos de HP/MP de equipamentos e buffs.
+
+03 Outubro 2019,
+Corrigido skill "Energy Charge" levando atualização de buff ao tocar em mobs, levando a casos onde o buff nos stats poderia inesperadamente ficar retido além do tempo de atuação previsto.
+Substituído utilização de "Jackson annotations + SnakeYaml" por "YamlBeans", utilizando-se assim menos artefatos JARs no processo (anteriormente 5, agora somente 1). Nota: na transição, fora constatado que a utilização da tecnologia anterior era mais permissiva perante o arquivo de configurações, porém estrutura do novo arquivo foi normalizado e está agora funcional.
+Refatorado inicialização de eventos ao iniciar o servidor, em busca de melhorar o tempo de startup.
+
+05 - 08 Outubro 2019,
+Refatorado os diversos schedulers que estavam presentes na classe de canais, agora abstraídas e atuando dentro de serviços.
+Corrigido circunstância onde movimentos de mobs poderiam estar sendo processados enquanto jogador está transitando mapas, levando a possível inconsistência na aplicação de movimento do mob na área acessada.
+
+10 - 12 Outubro 2019,
+Modificado uso de "default" de petid nos itens de inventário armazenados na DB (de -1 para nulo), assim permitindo criar chaves únicas.
+Adicionado uso de chaves estrangeiras para o petid.
+Implementado código de suporte para cupons de "associação" de cosméticos de cabelo.
+Corrigido bug recente em bosses com atributo "link" sem HPbar sendo detectados como possuindo HPbar, se o mob base possui.
+Corrigido bug recente na skill "Body Pressure" não aplicando a sua passiva com chance de neutralizar ao tocar mobs.
+Corrigido quest com NPC "Shaman Rock" aplicando progresso que não corresponde com o esperado (progresso extra agora movido para um novo questid).
+Adicionado método que permite executar scripts de mapa no sistema de scripts de portal.
+Corrigido problema recente ao referenciar script com progresso "Touch the Sky" (script de portal utilizando métodos de scripts de mapa).
+Adicionado fallback para scripts de NPC MapleTV.
+Revisado aplicação e abordagem deste código-base nos arquivos XML legado.
+
+15 - 16 Outubro 2019,
+Corrigido caso inconsistente onde objeto de jogador seria mantido no storage de jogadores caso o jogador tentasse se deregistrar de um canal (sem desconectar) e não mais retornando na mesma sessão.
+Adicionado código para funcionalidade de "Safety Charm", que permite jogadores curar 30% MaxHP/MaxMP ao retornar em campo.
+Implementado extensão das facilidades de serviços, agora atuando desjuntamente de canais.
+Implementado serviço de mundo para salvar jogadores, assim evitando geração de novas threads para cada jogador que está sendo persistido na DB.
+
+18 Outubro 2019,
+Revisado abordagem de inicialização de scripts de eventos em canais. Usuários não são mais bloqueados ao tentar logar devido ao canal não ter todos os eventos carregados.
+
+19 Outubro 2019,
+Corrigido certos itens de quest não aparecendo de mobs em casos onde o mesmo não é requisito para iniciar/completar.
+Corrigido NPC Pi crashando jogadores ao tentar criar flechas.
+Corrigido script de reevolução de pets não atuando em pet Robos, além de agora evitar repetir pets na conversão.
+
+21 - 22 Outubro 2019,
+Corrigido boss HPbar não desaparecendo em certos cenários. O mesmo deveria ocorrer assim que mob é retirado do mapa.
+Revisado informações de mob, que não são propagáveis, sendo repassados à definição do novo mob.
+Revisado carregamento de storages ao inicializar informações de conta podendo retornar nulo indevidamente em caso de exceção lançada.
+Corrigido dois casos de deadlock ocorrendo ao tentar cancelar efeito de stat de jogador.
+Adicionado auditoria de locks para os componentes que travam para leitura e escrita.
+Adicionado clip de introdução de Cygnus.
+Revisado updateBuffEffect, agora checando por determinados buffs de pirata e usando pacotes específicos para os mesmos.
+Revisado geração desnecessária de objetos de mapa ao carregar nomes para comando "goto".
+Corrigido buffs de mob em fakes desaparecendo assim que o mesmo muda de estado para real.
+
+24 Outubro 2019,
+Revisado uso de scriptids na geração de PlayerNPCs. Agora somente ids existentes na base especificada vai adiante.
+
+27 Outubro 2019,
+Revisado lógica booleana na detecção de foothold abaixo, não realizando múltiplas checagens sobre um mesmo atributo.
+
+28 Outubro 2019,
+Revisado lógica recente de uso de petid único levando a lançamento de exceção (transações de DB implica retirada de item de pet do CS storage na DB antes de colocar o mesmo no inventário).
+Corrigido portal relacionado a quest em Ariant inesperadamente levando jogadores à passagem secreta de Sleepywood, em caso de conclusão de questline da mesma.
+Corrigido loop em scripts de quest de associação a Alcadno/Zenumist em Magatia.
+Adicionado utilização de dispose em quest scripts para o comando homônimo.
+
+30 Outubro 2019,
+Corrigido bug em scripts (que possivelmente passou a ocorrer ao utilizar Java8) relacionado ao tentar utilizar métodos da biblioteca Math sem corresponder parâmetros com a assinatura adequada.
+Corrigido entrega de itemid inesperado em script relacionado a EllinPQ.
+
+01 - 03 Novembro 2019,
+Corrigido deslize recente em na funcionalidade de recuperação de itens de quest.
+Adicionado custom npc para MapleTVs: geradora de scrolls, provê os mesmos após trocar diversos itens ganhos durante jogo.
+
+04 Novembro 2019,
+Revisado diversos fluxos de aquisição de locks ao longo das classes mais relevantes do código-fonte.
+Corrigido problema inesperado com funcionalidade restoreLostItem.
+Inserido remoção de cash item para dentro da cláusula que checa item no inventário.
+Corrigido bug em pet autopot retirando quantidades negativas do inventário.
+Corrigido caso de deadlock em tentativa de aquisição de lock inesperada após adquirir os de mapas, que deveriam ter prioridade baixa.
+
+07 Novembro 2019,
+Adicionado cura de debuffs zumbificação e confusão na lista de debuffs a serem curados pela poção "cura-tudo".
+Corrigido duplicação em mensagem de pós-quest enviada, em casos onde há a presença de ação que automatiza mensagem guiando jogador para a próxima quest.
+
+09 - 10 Novembro 2019,
+Refatorado certos usos de finalização não-sucedida de quests, que poderiam compartilhar das mecânicas de desistência de quest.
+Revisado aquisição de endereço remoto para checagem de transição de jogadores e multi-cliente, agora também avaliando distinção de HWID passado.
+Corrigido pós-quests ainda permitindo jogadores a movimentarem enquanto a mensagem está na tela, devido a certo conflito com envio de recompensas permitindo movimentação do jogador.
+Corrigido informação de skillbooks por quests não-funcional após refatoração recente.
+Corrigido chance de drop de item de quest em El Nath extremamente baixa.
+
+11 - 12 Novembro 2019,
+Corrigido algumas skills de ataque de Aran (double, triple swing) não aplicando consumo de MP devidamente.
+Revisado caso com doors levando jogadores a solo abaixo inesperadamente.
+Corrigido pots em MCPQ não atuando devidamente para outros jogadores no grupo ou somente para si.
+Corrigido buffs random em MCPQ acertando sempre múltiplos jogadores.
+Corrigido poção "cura-tudo" em MCPQ: pots pequenos curando todos os jogadores de party, pots grandes não curando slow.
+Corrigido caso inesperado em 2nd job de pirata bloqueando saída de jogadores do mapa enquanto não lidarem com todos os mobs.
+
+13 Novembro 2019,
+Corrigido problema no sistema de matching ao tentar rodar ações externas enquanto travando os recursos do sistema, ao criar match.
+Corrigido caso onde novos jogadores poderiam ser agregados à party e entrar em campo na MCPQ assim que confirmação de partida e contagem de início fossem efetivados.
+Adicionado cache para requerimento de scrolls, assim melhorando tempo de resposta para o novo custom NPC de geração de scrolls.
diff --git a/launch.bat b/launch.bat
index 076a28d634..52b0eafefa 100644
--- a/launch.bat
+++ b/launch.bat
@@ -1,6 +1,6 @@
@echo off
@title HeavenMS
-set PATH=C:\Program Files\Java\jdk1.7.0_79\bin;%PATH%
+set PATH=C:\Program Files\Java\jdk1.8.0_211\bin;%PATH%
set CLASSPATH=.;dist\*
java -Xmx2048m -Dwzpath=wz\ net.server.Server
pause
\ No newline at end of file
diff --git a/launch_server_linux.sh b/launch_server_linux.sh
deleted file mode 100644
index 57d9b2d6ec..0000000000
--- a/launch_server_linux.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-export CLASSPATH=".:dist/*"
-java -Xmx2048m -Dwzpath=wz/ net.server.Server
\ No newline at end of file
diff --git a/linux-compile.sh b/linux-compile.sh
new file mode 100755
index 0000000000..9cfec04218
--- /dev/null
+++ b/linux-compile.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+# thanks to lkxyyjx
+sudo ant -Dplatforms.JDK_1.7.home=/opt/jdk1.7.0_80 compile
+sudo ant -Dplatforms.JDK_1.7.home=/opt/jdk1.7.0_80 jar
\ No newline at end of file
diff --git a/linux-launch.sh b/linux-launch.sh
new file mode 100644
index 0000000000..40557cec8e
--- /dev/null
+++ b/linux-launch.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+# cores in classpath, thanks to lkxyyjx
+export CLASSPATH=".:dist/*:cores/*"
+java -Xmx2048m -Dwzpath=wz/ net.server.Server
\ No newline at end of file
diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml
index 6fd0f0e472..d08448f6c7 100644
--- a/nbproject/build-impl.xml
+++ b/nbproject/build-impl.xml
@@ -46,51 +46,15 @@ is divided into following sections:
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Must set platform.home
- Must set platform.bootcp
- Must set platform.java
- Must set platform.javac
-
- The J2SE Platform is not correctly set up.
- Your active platform is: ${platform.active}, but the corresponding property "platforms.${platform.active}.home" is not found in the project's properties files.
- Either open the project in the IDE and setup the Platform with the same name or add it manually.
- For example like this:
- ant -Duser.properties.file=<path_to_property_file> jar (where you put the property "platforms.${platform.active}.home" in a .properties file)
- or ant -Dplatforms.${platform.active}.home=<path_to_JDK_home> jar (where no properties file is used)
-
+
@@ -112,7 +76,7 @@ is divided into following sections:
-
+
@@ -190,6 +154,7 @@ is divided into following sections:
+
@@ -217,6 +182,20 @@ is divided into following sections:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -242,6 +221,7 @@ is divided into following sections:
+
@@ -284,7 +264,7 @@ is divided into following sections:
-
+
@@ -324,7 +304,7 @@ is divided into following sections:
-
+
@@ -405,7 +385,7 @@ is divided into following sections:
-
+
@@ -428,7 +408,7 @@ is divided into following sections:
-
+
@@ -460,7 +440,7 @@ is divided into following sections:
-
+
@@ -540,7 +520,7 @@ is divided into following sections:
-
+
@@ -565,7 +545,7 @@ is divided into following sections:
-
+
@@ -707,7 +687,7 @@ is divided into following sections:
-
+
@@ -742,9 +722,6 @@ is divided into following sections:
-
-
-
@@ -760,9 +737,7 @@ is divided into following sections:
-
-
-
+
@@ -787,7 +762,7 @@ is divided into following sections:
-
+
@@ -814,7 +789,7 @@ is divided into following sections:
-
+
@@ -853,7 +828,7 @@ is divided into following sections:
-
+
@@ -865,7 +840,7 @@ is divided into following sections:
-
+
@@ -988,15 +963,15 @@ is divided into following sections:
-
+
-
+
-
+
@@ -1004,7 +979,7 @@ is divided into following sections:
-
+
@@ -1012,7 +987,7 @@ is divided into following sections:
To run this application from the command line without Ant, try:
- ${platform.java} -jar "${dist.jar.resolved}"
+ java -jar "${dist.jar.resolved}"
@@ -1199,7 +1174,7 @@ is divided into following sections:
Must select one file in the IDE or set run.class
-
+
Must select one file in the IDE or set applet.url
@@ -1221,13 +1196,10 @@ is divided into following sections:
-
-
-
-
+
-
+
diff --git a/nbproject/genfiles.properties b/nbproject/genfiles.properties
index 4d5b6615f0..6db8caa016 100644
--- a/nbproject/genfiles.properties
+++ b/nbproject/genfiles.properties
@@ -1,8 +1,8 @@
-build.xml.data.CRC32=92113194
+build.xml.data.CRC32=92efccf9
build.xml.script.CRC32=ff13faf5
-build.xml.stylesheet.CRC32=8064a381@1.75.2.48
+build.xml.stylesheet.CRC32=8064a381@1.80.1.48
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
-nbproject/build-impl.xml.data.CRC32=92113194
-nbproject/build-impl.xml.script.CRC32=cef58264
-nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.75.2.48
+nbproject/build-impl.xml.data.CRC32=92efccf9
+nbproject/build-impl.xml.script.CRC32=8cda444e
+nbproject/build-impl.xml.stylesheet.CRC32=830a3534@1.80.1.48
diff --git a/nbproject/private/private.properties b/nbproject/private/private.properties
index 67c9c27960..c1164614bd 100644
--- a/nbproject/private/private.properties
+++ b/nbproject/private/private.properties
@@ -3,4 +3,4 @@ do.depend=false
do.jar=true
javac.debug=true
javadoc.preview=true
-user.properties.file=C:\\Users\\RonanLana\\AppData\\Roaming\\NetBeans\\8.0.2\\build.properties
+user.properties.file=C:\\Users\\RonanLana\\AppData\\Roaming\\NetBeans\\8.2\\build.properties
diff --git a/nbproject/project.properties b/nbproject/project.properties
index 861f8eb51c..4188fc88d4 100644
--- a/nbproject/project.properties
+++ b/nbproject/project.properties
@@ -34,6 +34,7 @@ file.reference.mina-core-2.0.19.jar=cores/mina-core-2.0.19.jar
file.reference.mysql-connector-java-bin.jar=cores/mysql-connector-java-bin.jar
file.reference.slf4j-api-1.7.21.jar=cores/slf4j-api-1.7.21.jar
file.reference.slf4j-jdk14-1.7.5.jar=cores/slf4j-jdk14-1.7.5.jar
+file.reference.yamlbeans-1.13.jar=cores/yamlbeans-1.13.jar
includes=**
jar.archive.disabled=${jnlp.enabled}
jar.compress=true
@@ -43,14 +44,16 @@ javac.classpath=\
${file.reference.slf4j-api-1.7.21.jar}:\
${file.reference.HikariCP-java7-2.4.13.jar}:\
${file.reference.mysql-connector-java-bin.jar}:\
- ${file.reference.slf4j-jdk14-1.7.5.jar}
+ ${file.reference.slf4j-jdk14-1.7.5.jar}:\
+ ${file.reference.yamlbeans-1.13.jar}
# Space-separated list of extra javac options
javac.compilerargs=
javac.deprecation=false
+javac.external.vm=false
javac.processorpath=\
${javac.classpath}
-javac.source=1.7
-javac.target=1.7
+javac.source=1.8
+javac.target=1.8
javac.test.classpath=\
${javac.classpath}:\
${build.classes.dir}
@@ -84,7 +87,7 @@ manifest.custom.permissions=
manifest.file=manifest.mf
meta.inf.dir=${src.dir}/META-INF
mkdist.disabled=false
-platform.active=JDK_1.7
+platform.active=default_platform
project.license=gpl30_msv2
project.licensePath=./nbproject/licenseheader.txt
run.classpath=\
diff --git a/nbproject/project.xml b/nbproject/project.xml
index aed1c56350..980f89761c 100644
--- a/nbproject/project.xml
+++ b/nbproject/project.xml
@@ -4,7 +4,6 @@
HeavenMS
-
diff --git a/scripts/event/3rdJob_bowman.js b/scripts/event/3rdJob_bowman.js
index 583e4db8a9..4388b7a27a 100644
--- a/scripts/event/3rdJob_bowman.js
+++ b/scripts/event/3rdJob_bowman.js
@@ -31,7 +31,7 @@ var maxMapId = 108010101;
var eventTime = 20; //20 minutes
-var lobbyRange = [0, 0];
+var lobbyRange = [0, 7];
function setLobbyRange() {
return lobbyRange;
diff --git a/scripts/event/3rdJob_magician.js b/scripts/event/3rdJob_magician.js
index cd11b6d427..e7875bcea2 100644
--- a/scripts/event/3rdJob_magician.js
+++ b/scripts/event/3rdJob_magician.js
@@ -31,7 +31,7 @@ var maxMapId = 108010201;
var eventTime = 20; //20 minutes
-var lobbyRange = [0, 0];
+var lobbyRange = [0, 7];
function setLobbyRange() {
return lobbyRange;
diff --git a/scripts/event/3rdJob_mount.js b/scripts/event/3rdJob_mount.js
index bc9bd937b1..094086c8ce 100644
--- a/scripts/event/3rdJob_mount.js
+++ b/scripts/event/3rdJob_mount.js
@@ -33,7 +33,7 @@ var eventMaps = [923010000];
var eventTime = 5; //5 minutes
-var lobbyRange = [0, 0];
+var lobbyRange = [0, 7];
function setLobbyRange() {
return lobbyRange;
diff --git a/scripts/event/3rdJob_pirate.js b/scripts/event/3rdJob_pirate.js
index e79e1e2551..2b0164ba8e 100644
--- a/scripts/event/3rdJob_pirate.js
+++ b/scripts/event/3rdJob_pirate.js
@@ -31,7 +31,7 @@ var maxMapId = 108010501;
var eventTime = 20; //20 minutes
-var lobbyRange = [0, 0];
+var lobbyRange = [0, 7];
function setLobbyRange() {
return lobbyRange;
diff --git a/scripts/event/3rdJob_thief.js b/scripts/event/3rdJob_thief.js
index 9ed7e979fc..3da091fa42 100644
--- a/scripts/event/3rdJob_thief.js
+++ b/scripts/event/3rdJob_thief.js
@@ -31,7 +31,7 @@ var maxMapId = 108010401;
var eventTime = 20; //20 minutes
-var lobbyRange = [0, 0];
+var lobbyRange = [0, 7];
function setLobbyRange() {
return lobbyRange;
diff --git a/scripts/event/3rdJob_warrior.js b/scripts/event/3rdJob_warrior.js
index 86cd6b9e5b..f8c938d075 100644
--- a/scripts/event/3rdJob_warrior.js
+++ b/scripts/event/3rdJob_warrior.js
@@ -31,7 +31,7 @@ var maxMapId = 108010301;
var eventTime = 20; //20 minutes
-var lobbyRange = [0, 0];
+var lobbyRange = [0, 7];
function setLobbyRange() {
return lobbyRange;
diff --git a/scripts/event/4jaerial.js b/scripts/event/4jaerial.js
index 43a0149526..d026a0fb09 100644
--- a/scripts/event/4jaerial.js
+++ b/scripts/event/4jaerial.js
@@ -30,7 +30,7 @@ var maxMapId = 912020000;
var eventTime = 2; //2 minutes
-var lobbyRange = [0, 0];
+var lobbyRange = [0, 7];
function setLobbyRange() {
return lobbyRange;
diff --git a/scripts/event/4jberserk.js b/scripts/event/4jberserk.js
deleted file mode 100644
index d3fd4fa747..0000000000
--- a/scripts/event/4jberserk.js
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- 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 .
-*/
-var exitMap;
-var minPlayers = 3;
-
-function init() {}
-
-function monsterValue(eim, mobId) {
- return 1;
-}
-
-function setup(level, lobbyid) {
- exitMap = em.getChannelServer().getMapFactory().getMap(105090800); //
-
- var eim = em.newInstance("4jberserk_" + lobbyid);
- eim.setProperty("level", level);
-
- var mf = eim.getMapFactory();
-
- var map = mf.getMap(910500200);
- map.addMapTimer(3*60);
- em.schedule("timeOut", 20 * 60000);
-
- //you can't warp up to the rocks until all rogs are dead, I think?
- eim.setProperty("canWarp","false");
-
- return eim;
-}
-
-function afterSetup(eim) {}
-
-function playerEntry(eim, player) {
- var map = eim.getMapInstance(910500200);
- player.changeMap(map, map.getPortal(0));
-
-//TODO: hold time across map changes
-//player.getClient().announce(tools.MaplePacketCreator.getClock(1800));
-}
-
-function playerDead(eim, player) {
-}
-
-function playerRevive(eim, player) {
- //if (eim.isLeader(player)) { //check for party leader
- //boot whole party and end
- var party = eim.getPlayers();
- for (var i = 0; i < party.size(); i++) {
- playerExit(eim, party.get(i));
- }
- eim.dispose();
-/*/}
- else { //boot dead player
- // If only 2 players are left, uncompletable:
- var party = eim.getPlayers();
- if (party.size() <= minPlayers) {
- for (var i = 0; i < party.size(); i++) {
- playerExit(eim,party.get(i));
- }
- eim.dispose();
- }
- else
- playerExit(eim, player);
- }*/
-}
-
-function playerDisconnected(eim, player) {
- //if (eim.isLeader(player)) { //check for party leader
- //boot whole party and end
- var party = eim.getPlayers();
- for (var i = 0; i < party.size(); i++) {
- if (party.get(i).equals(player)) {
- removePlayer(eim, player);
- }
- else {
- playerExit(eim, party.get(i));
- }
- }
- eim.dispose();
-/*/}
- else { //boot d/ced player
- // If only 2 players are left, uncompletable:
- var party = eim.getPlayers();
- if (party.size() < minPlayers) {
- for (var i = 0; i < party.size(); i++) {
- playerExit(eim,party.get(i));
- }
- eim.dispose();
- }
- else
- playerExit(eim, player);
- }*/
-}
-
-function leftParty(eim, player) {
- // If only 2 players are left, uncompletable:
- var party = eim.getPlayers();
- if (true) {
- for (var i = 0; i < party.size(); i++) {
- playerExit(eim,party.get(i));
- }
- eim.dispose();
- }
- else
- playerExit(eim, player);
-}
-
-function disbandParty(eim) {
- //boot whole party and end
- var party = eim.getPlayers();
- for (var i = 0; i < party.size(); i++) {
- playerExit(eim, party.get(i));
- }
- eim.dispose();
-}
-
-function playerUnregistered(eim, player) {}
-
-function playerExit(eim, player) {
- eim.unregisterPlayer(player);
- player.changeMap(exitMap, exitMap.getPortal(0));
-}
-
-//for offline players
-function removePlayer(eim, player) {
- eim.unregisterPlayer(player);
- player.getMap().removePlayer(player);
- player.setMap(exitMap);
-}
-
-function clearPQ(eim) {
- var party = eim.getPlayers();
- for (var i = 0; i < party.size(); i++)
- playerExit(eim, party.get(i));
- eim.dispose();
-}
-
-function monsterKilled(mob, eim) {}
-
-function allMonstersDead(eim) {
- eim.setProperty("canWarp","true");
-}
-
-function cancelSchedule() {}
-
-function timeOut() {
- var iter = em.getInstances().iterator();
- while (iter.hasNext()) {
- var eim = iter.next();
- if (eim.getPlayerCount() > 0) {
- var pIter = eim.getPlayers().iterator();
- while (pIter.hasNext())
- playerExit(eim, pIter.next());
- }
- eim.dispose();
- }
-}
-
-
-// ---------- FILLER FUNCTIONS ----------
-
-function dispose() {}
-
-function scheduledTimeout(eim) {}
-
-function changedLeader(eim, leader) {}
-
diff --git a/scripts/event/4jrush.js b/scripts/event/4jrush.js
deleted file mode 100644
index a1258d0ec6..0000000000
--- a/scripts/event/4jrush.js
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- 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 .
-*/
-/*
- * @author AngelSL
- *
- * 4th Job Rush Quest.
- * Based on Kerning City PQ script by Stereo
- */
-
-var exitMap;
-var minPlayers = 3;
-
-function init() {}
-
-function monsterValue(eim, mobId) {
- return 1;
-}
-
-function setup(level, lobbyid) {
- exitMap = em.getChannelServer().getMapFactory().getMap(105090700); //
-
- var eim = em.newInstance("4jrush_" + lobbyid);
- eim.setProperty("level", level);
-
- var mf = eim.getMapFactory();
- var map = mf.getMap(910500100);
- map.addMapTimer(20*60);
- em.schedule("timeOut", 20 * 60000);
- return eim;
-}
-
-function afterSetup(eim) {}
-
-function playerEntry(eim, player) {
- var map = eim.getMapInstance(910500100);
- player.changeMap(map, map.getPortal(0));
-}
-
-function playerDead(eim, player) {
-}
-
-function playerRevive(eim, player) {
- var party = eim.getPlayers();
- for (var i = 0; i < party.size(); i++) {
- playerExit(eim, party.get(i));
- }
- eim.dispose();
-}
-
-function playerDisconnected(eim, player) {
- var party = eim.getPlayers();
- for (var i = 0; i < party.size(); i++) {
- if (party.get(i).equals(player)) {
- removePlayer(eim, player);
- }
- else {
- playerExit(eim, party.get(i));
- }
- }
- eim.dispose();
-}
-
-function leftParty(eim, player) {
- // If only 2 players are left, uncompletable:
- var party = eim.getPlayers();
- if (true) {
- for (var i = 0; i < party.size(); i++) {
- playerExit(eim,party.get(i));
- }
- eim.dispose();
- }
- else
- playerExit(eim, player);
-}
-
-function disbandParty(eim) {
- //boot whole party and end
- var party = eim.getPlayers();
- for (var i = 0; i < party.size(); i++) {
- playerExit(eim, party.get(i));
- }
- eim.dispose();
-}
-
-function playerUnregistered(eim, player) {}
-
-function playerExit(eim, player) {
- eim.unregisterPlayer(player);
- player.changeMap(exitMap, exitMap.getPortal(0));
-}
-
-//for offline players
-function removePlayer(eim, player) {
- eim.unregisterPlayer(player);
- player.getMap().removePlayer(player);
- player.setMap(exitMap);
-}
-
-function clearPQ(eim) {
- //KPQ does nothing special with winners
- var party = eim.getPlayers();
- for (var i = 0; i < party.size(); i++) {
- playerExit(eim, party.get(i));
- }
- eim.dispose();
-}
-
-function monsterKilled(mob, eim) {}
-
-function allMonstersDead(eim) {}
-
-function cancelSchedule() {}
-
-function timeOut() {
- var iter = em.getInstances().iterator();
- while (iter.hasNext()) {
- var eim = iter.next();
- if (eim.getPlayerCount() > 0) {
- var pIter = eim.getPlayers().iterator();
- while (pIter.hasNext()) {
- playerExit(eim, pIter.next());
- }
- }
- eim.dispose();
- }
-}
-
-
-// ---------- FILLER FUNCTIONS ----------
-
-function dispose() {}
-
-function scheduledTimeout(eim) {}
-
-function changedLeader(eim, leader) {}
-
diff --git a/scripts/event/4jship.js b/scripts/event/4jship.js
index bd7d4370dd..ba58956743 100644
--- a/scripts/event/4jship.js
+++ b/scripts/event/4jship.js
@@ -30,7 +30,7 @@ var maxMapId = 912010200;
var eventTime = 4; //4 minutes
-var lobbyRange = [0, 0];
+var lobbyRange = [0, 7];
function setLobbyRange() {
return lobbyRange;
diff --git a/scripts/event/4jsuper.js b/scripts/event/4jsuper.js
index 835a79db80..322beef6d7 100644
--- a/scripts/event/4jsuper.js
+++ b/scripts/event/4jsuper.js
@@ -30,7 +30,7 @@ var maxMapId = 912010200;
var eventTime = 4; //4 minutes
-var lobbyRange = [0, 0];
+var lobbyRange = [0, 7];
function setLobbyRange() {
return lobbyRange;
diff --git a/scripts/event/Aran_2ndmount.js b/scripts/event/Aran_2ndmount.js
index 81cb47b67b..d9d064cc7f 100644
--- a/scripts/event/Aran_2ndmount.js
+++ b/scripts/event/Aran_2ndmount.js
@@ -31,7 +31,7 @@ var maxMapId = 921110000;
var eventTime = 3; //3 minutes
-var lobbyRange = [0, 0];
+var lobbyRange = [0, 7];
function setLobbyRange() {
return lobbyRange;
diff --git a/scripts/event/Aran_3rdmount.js b/scripts/event/Aran_3rdmount.js
index aab415b92d..9c2a023622 100644
--- a/scripts/event/Aran_3rdmount.js
+++ b/scripts/event/Aran_3rdmount.js
@@ -31,7 +31,7 @@ var maxMapId = 914030000;
var eventTime = 3; //3 minutes
-var lobbyRange = [0, 0];
+var lobbyRange = [0, 7];
function setLobbyRange() {
return lobbyRange;
diff --git a/scripts/event/BalrogBattle.js b/scripts/event/BalrogBattle.js
index 35f4af113b..0517777dda 100644
--- a/scripts/event/BalrogBattle.js
+++ b/scripts/event/BalrogBattle.js
@@ -170,7 +170,7 @@ function playerLeft(eim, player) {
function changedMap(eim, player, mapid) {
if (mapid < minMapId || mapid > maxMapId) {
- if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ if (eim.isExpeditionTeamLackingNow(true, minPlayers, player)) {
eim.unregisterPlayer(player);
end(eim);
}
@@ -179,17 +179,12 @@ function changedMap(eim, player, mapid) {
}
}
-function changedLeader(eim, leader) {
- var mapid = leader.getMapId();
- if (!eim.isEventCleared() && (mapid < minMapId || mapid > maxMapId)) {
- end(eim);
- }
-}
+function changedLeader(eim, leader) {}
function playerDead(eim, player) {}
function playerRevive(eim, player) { // player presses ok on the death pop up.
- if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ if (eim.isExpeditionTeamLackingNow(true, minPlayers, player)) {
eim.unregisterPlayer(player);
end(eim);
}
@@ -198,7 +193,7 @@ function playerRevive(eim, player) { // player presses ok on the death pop up.
}
function playerDisconnected(eim, player) {
- if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ if (eim.isExpeditionTeamLackingNow(true, minPlayers, player)) {
eim.unregisterPlayer(player);
end(eim);
}
@@ -206,19 +201,9 @@ function playerDisconnected(eim, player) {
eim.unregisterPlayer(player);
}
-function leftParty(eim, player) {
- if (eim.isEventTeamLackingNow(false, minPlayers, player)) {
- end(eim);
- }
- else
- playerLeft(eim, player);
-}
+function leftParty(eim, player) {}
-function disbandParty(eim) {
- if (!eim.isEventCleared()) {
- end(eim);
- }
-}
+function disbandParty(eim) {}
function monsterValue(eim, mobId) {
return 1;
@@ -259,7 +244,8 @@ function monsterKilled(mob, eim) {
eim.showClearEffect();
eim.clearPQ();
- eim.dispatchUpdateQuestMobCount(bossMobId, entryMap);
+ eim.dispatchRaiseQuestMobCount(bossMobId, entryMap);
+ eim.dispatchRaiseQuestMobCount(9101003, entryMap); // thanks Atoot for noticing quest not getting updated after boss kill
mob.getMap().broadcastBalrogVictory(eim.getLeader().getName());
} else {
if(count == 1) {
diff --git a/scripts/event/BalrogBattle_Easy.js b/scripts/event/BalrogBattle_Easy.js
index e345319546..1fa9b7da5f 100644
--- a/scripts/event/BalrogBattle_Easy.js
+++ b/scripts/event/BalrogBattle_Easy.js
@@ -170,7 +170,7 @@ function playerLeft(eim, player) {
function changedMap(eim, player, mapid) {
if (mapid < minMapId || mapid > maxMapId) {
- if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ if (eim.isExpeditionTeamLackingNow(true, minPlayers, player)) {
eim.unregisterPlayer(player);
end(eim);
}
@@ -179,17 +179,12 @@ function changedMap(eim, player, mapid) {
}
}
-function changedLeader(eim, leader) {
- var mapid = leader.getMapId();
- if (!eim.isEventCleared() && (mapid < minMapId || mapid > maxMapId)) {
- end(eim);
- }
-}
+function changedLeader(eim, leader) {}
function playerDead(eim, player) {}
function playerRevive(eim, player) { // player presses ok on the death pop up.
- if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ if (eim.isExpeditionTeamLackingNow(true, minPlayers, player)) {
eim.unregisterPlayer(player);
end(eim);
}
@@ -198,7 +193,7 @@ function playerRevive(eim, player) { // player presses ok on the death pop up.
}
function playerDisconnected(eim, player) {
- if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ if (eim.isExpeditionTeamLackingNow(true, minPlayers, player)) {
eim.unregisterPlayer(player);
end(eim);
}
@@ -206,19 +201,9 @@ function playerDisconnected(eim, player) {
eim.unregisterPlayer(player);
}
-function leftParty(eim, player) {
- if (eim.isEventTeamLackingNow(false, minPlayers, player)) {
- end(eim);
- }
- else
- playerLeft(eim, player);
-}
+function leftParty(eim, player) {}
-function disbandParty(eim) {
- if (!eim.isEventCleared()) {
- end(eim);
- }
-}
+function disbandParty(eim) {}
function monsterValue(eim, mobId) {
return 1;
@@ -259,7 +244,7 @@ function monsterKilled(mob, eim) {
eim.showClearEffect();
eim.clearPQ();
- eim.dispatchUpdateQuestMobCount(bossMobId, entryMap);
+ eim.dispatchRaiseQuestMobCount(bossMobId, entryMap);
mob.getMap().broadcastBalrogVictory(eim.getLeader().getName());
} else {
if(count == 1) {
diff --git a/scripts/event/BalrogQuest.js b/scripts/event/BalrogQuest.js
index 161aeb9d26..c25725fc24 100644
--- a/scripts/event/BalrogQuest.js
+++ b/scripts/event/BalrogQuest.js
@@ -31,7 +31,7 @@ var maxMapId = 910520000;
var eventTime = 10; //10 minutes
-var lobbyRange = [0, 0];
+var lobbyRange = [0, 7];
function setLobbyRange() {
return lobbyRange;
diff --git a/scripts/event/CWKPQ.js b/scripts/event/CWKPQ.js
index c10d12ada7..ab0f49b709 100644
--- a/scripts/event/CWKPQ.js
+++ b/scripts/event/CWKPQ.js
@@ -241,7 +241,7 @@ function scheduledTimeout(eim) {
function changedMap(eim, player, mapid) {
if (mapid < minMapId || mapid > maxMapId) {
- if (eim.isExpeditionTeamLackingNow(true, minPlayers, player)) {
+ if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
eim.dropMessage(5, "[Expedition] Either the leader has quit the expedition or there is no longer the minimum number of members required to continue it.");
eim.unregisterPlayer(player);
end(eim);
@@ -297,7 +297,7 @@ function changedLeader(eim, leader) {}
function playerDead(eim, player) {}
function playerRevive(eim, player) {
- if (eim.isExpeditionTeamLackingNow(true, minPlayers, player)) {
+ if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
eim.unregisterPlayer(player);
eim.dropMessage(5, "[Expedition] Either the leader has quit the expedition or there is no longer the minimum number of members required to continue it.");
end(eim);
@@ -309,7 +309,7 @@ function playerRevive(eim, player) {
}
function playerDisconnected(eim, player) {
- if (eim.isExpeditionTeamLackingNow(true, minPlayers, player)) {
+ if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
eim.dropMessage(5, "[Expedition] Either the leader has quit the expedition or there is no longer the minimum number of members required to continue it.");
eim.unregisterPlayer(player);
end(eim);
diff --git a/scripts/event/DelliBattle.js b/scripts/event/DelliBattle.js
index 241ebc7970..327ab2778c 100644
--- a/scripts/event/DelliBattle.js
+++ b/scripts/event/DelliBattle.js
@@ -35,7 +35,7 @@ var maxMapId = 925010300;
var eventTime = 6; // 6 minutes
-var lobbyRange = [0, 0];
+var lobbyRange = [0, 7];
function init() {
setEventRequirements();
diff --git a/scripts/event/ElementalBattle.js b/scripts/event/ElementalBattle.js
index 3052293046..17ee7b3a59 100644
--- a/scripts/event/ElementalBattle.js
+++ b/scripts/event/ElementalBattle.js
@@ -36,7 +36,7 @@ var maxMapId = 922020100;
var eventTime = 20; // 20 minutes
-var lobbyRange = [0, 0];
+var lobbyRange = [0, 7];
function init() {
setEventRequirements();
diff --git a/scripts/event/GuardianNex.js b/scripts/event/GuardianNex.js
index 982ee33b59..360e414543 100644
--- a/scripts/event/GuardianNex.js
+++ b/scripts/event/GuardianNex.js
@@ -24,7 +24,7 @@ function respawn(eim){}
function playerEntry(eim, player){
var cave = eim.getMapInstance(eventMap + 10 * eim.getIntProperty("nex"));
- player.changeMap(cave);
+ player.changeMap(cave, 1);
}
function scheduledTimeout(eim){
diff --git a/scripts/event/HenesysPQ.js b/scripts/event/HenesysPQ.js
index e9ae26ac9f..2b44f2a4a5 100644
--- a/scripts/event/HenesysPQ.js
+++ b/scripts/event/HenesysPQ.js
@@ -105,6 +105,8 @@ function setup(level, lobbyid) {
var eim = em.newInstance("Henesys" + lobbyid);
eim.setProperty("level", level);
eim.setProperty("stage", "0");
+ eim.setProperty("bunnyCake", "0");
+ eim.setProperty("bunnyDamaged", "0");
eim.getInstanceMap(910010000).resetPQ(level);
eim.getInstanceMap(910010000).allowSummonState(false);
@@ -243,6 +245,25 @@ function friendlyKilled(mob, eim) {
}
}
+function friendlyItemDrop(eim, mob) {
+ if (mob.getId() == 9300061) {
+ var cakes = eim.getIntProperty("bunnyCake") + 1;
+ eim.setIntProperty("bunnyCake", cakes);
+
+ mob.getMap().broadcastMessage(Packages.tools.MaplePacketCreator.serverNotice(6, "The Moon Bunny made rice cake number " + cakes + "."));
+ }
+}
+
+function friendlyDamaged(eim, mob) {
+ if (mob.getId() == 9300061) {
+ var bunnyDamage = eim.getIntProperty("bunnyDamaged") + 1;
+ if (bunnyDamage > 5) {
+ broadcastMessage(Packages.tools.MaplePacketCreator.serverNotice(6, "The Moon Bunny is feeling sick. Please protect it so it can make delicious rice cakes."));
+ eim.setIntProperty("bunnyDamaged", 0);
+ }
+ }
+}
+
function allMonstersDead(eim) {}
function cancelSchedule() {}
diff --git a/scripts/event/HorntailBattle.js b/scripts/event/HorntailBattle.js
index 3aced02c62..401014f6df 100644
--- a/scripts/event/HorntailBattle.js
+++ b/scripts/event/HorntailBattle.js
@@ -214,7 +214,7 @@ function monsterKilled(mob, eim) {
eim.showClearEffect(mob.getMap().getId());
eim.clearPQ();
- eim.dispatchUpdateQuestMobCount(8810018, 240060200);
+ eim.dispatchRaiseQuestMobCount(8810018, 240060200);
mob.getMap().broadcastHorntailVictory();
} else if(isHorntailHead(mob)) {
var killed = eim.getIntProperty("defeatedHead");
diff --git a/scripts/event/MK_PrimeMinister.js b/scripts/event/MK_PrimeMinister.js
index d29be7e5ed..0ef72ad21d 100644
--- a/scripts/event/MK_PrimeMinister.js
+++ b/scripts/event/MK_PrimeMinister.js
@@ -52,7 +52,7 @@ function primeMinisterCheck(eim) {
var pIter = map.getAllPlayers().iterator();
while (pIter.hasNext()) {
var player = pIter.next();
- if (player.getQuestStatus(2333) == 1 && player.getAbstractPlayerInteraction().getQuestProgress(2333, mobId) == 0) {
+ if (player.getQuestStatus(2333) == 1 && player.getAbstractPlayerInteraction().getQuestProgressInt(2333, mobId) == 0) {
return true;
}
}
diff --git a/scripts/event/MahaBattle.js b/scripts/event/MahaBattle.js
index 40f731315f..6791f678ad 100644
--- a/scripts/event/MahaBattle.js
+++ b/scripts/event/MahaBattle.js
@@ -33,7 +33,7 @@ var maxMapId = 914020000;
var eventTime = 10; // 10 minutes
-var lobbyRange = [0, 0];
+var lobbyRange = [0, 7];
function init() {}
diff --git a/scripts/event/PapulatusBattle.js b/scripts/event/PapulatusBattle.js
index 39f1b253d3..6ff9c0dfd6 100644
--- a/scripts/event/PapulatusBattle.js
+++ b/scripts/event/PapulatusBattle.js
@@ -115,7 +115,9 @@ function setup(level, lobbyid) {
return eim;
}
-function afterSetup(eim) {}
+function afterSetup(eim) {
+ updateGateState(1);
+}
function respawnStages(eim) {}
@@ -143,7 +145,7 @@ function playerLeft(eim, player) {
function changedMap(eim, player, mapid) {
if (mapid < minMapId || mapid > maxMapId) {
- if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ if (eim.isExpeditionTeamLackingNow(true, minPlayers, player)) {
eim.unregisterPlayer(player);
end(eim);
}
@@ -152,17 +154,12 @@ function changedMap(eim, player, mapid) {
}
}
-function changedLeader(eim, leader) {
- var mapid = leader.getMapId();
- if (!eim.isEventCleared() && (mapid < minMapId || mapid > maxMapId)) {
- end(eim);
- }
-}
+function changedLeader(eim, leader) {}
function playerDead(eim, player) {}
function playerRevive(eim, player) { // player presses ok on the death pop up.
- if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ if (eim.isExpeditionTeamLackingNow(true, minPlayers, player)) {
eim.unregisterPlayer(player);
end(eim);
}
@@ -171,7 +168,7 @@ function playerRevive(eim, player) { // player presses ok on the death pop up.
}
function playerDisconnected(eim, player) {
- if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
+ if (eim.isExpeditionTeamLackingNow(true, minPlayers, player)) {
eim.unregisterPlayer(player);
end(eim);
}
@@ -179,19 +176,9 @@ function playerDisconnected(eim, player) {
eim.unregisterPlayer(player);
}
-function leftParty(eim, player) {
- if (eim.isEventTeamLackingNow(false, minPlayers, player)) {
- end(eim);
- }
- else
- playerLeft(eim, player);
-}
+function leftParty(eim, player) {}
-function disbandParty(eim) {
- if (!eim.isEventCleared()) {
- end(eim);
- }
-}
+function disbandParty(eim) {}
function monsterValue(eim, mobId) {
return 1;
@@ -213,6 +200,7 @@ function giveRandomEventReward(eim, player) {
function clearPQ(eim) {
eim.stopEventTimer();
eim.setEventCleared();
+ updateGateState(0);
}
function isPapulatus(mob) {
@@ -231,5 +219,14 @@ function allMonstersDead(eim) {}
function cancelSchedule() {}
-function dispose(eim) {}
+function updateGateState(newState) { // thanks Conrad for noticing missing gate update
+ em.getChannelServer().getMapFactory().getMap(220080000).getReactorById(2208001).forceHitReactor(newState);
+ em.getChannelServer().getMapFactory().getMap(220080000).getReactorById(2208002).forceHitReactor(newState);
+ em.getChannelServer().getMapFactory().getMap(220080000).getReactorById(2208003).forceHitReactor(newState);
+}
+function dispose(eim) {
+ if (!eim.isEventCleared()) {
+ updateGateState(0);
+ }
+}
diff --git a/scripts/event/Puppeteer.js b/scripts/event/Puppeteer.js
index 35baa8c0dc..0fd8898cb6 100644
--- a/scripts/event/Puppeteer.js
+++ b/scripts/event/Puppeteer.js
@@ -24,7 +24,7 @@ function respawn(eim){}
function playerEntry(eim, player){
var cave = eim.getMapInstance(eventMap);
- player.changeMap(cave);
+ player.changeMap(cave, 1);
}
function scheduledTimeout(eim){
diff --git a/scripts/event/RescueGaga.js b/scripts/event/RescueGaga.js
new file mode 100644
index 0000000000..dc9dd6b7c7
--- /dev/null
+++ b/scripts/event/RescueGaga.js
@@ -0,0 +1,211 @@
+/**
+ * @author: kevintjuh93
+ * @author: Ronan
+*/
+
+importPackage(Packages.tools);
+
+var isPq = true;
+var minPlayers = 1, maxPlayers = 1;
+var minLevel = 12, maxLevel = 255;
+var entryMap = 922240000;
+var exitMap = 922240200;
+var recruitMap = 922240200;
+
+var minMapId = 922240000;
+var maxMapId = 922240100;
+
+var eventTime = 3; // 3 minutes
+
+var lobbyRange = [0, 19];
+
+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 = [];
+ eim.setExclusiveItems(itemSet);
+}
+
+function setEventRewards(eim) {
+ var itemSet, itemQty, evLevel, expStages;
+
+ evLevel = 1; //Rewards at clear PQ
+ itemSet = [];
+ itemQty = [];
+ eim.setEventRewards(evLevel, itemSet, itemQty);
+
+ expStages = []; //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("RescueGaga_" + lobbyid);
+ eim.setProperty("level", level);
+ eim.setProperty("stage", "0");
+ eim.setProperty("falls", "0");
+
+ respawnStages(eim);
+ eim.startEventTimer(eventTime * 60000);
+ setEventRewards(eim);
+ setEventExclusives(eim);
+ return eim;
+}
+
+function afterSetup(eim) {}
+
+function respawnStages(eim) {}
+
+function playerEntry(eim, player) {
+ var map = eim.getMapInstance(entryMap);
+ player.changeMap(map, map.getPortal(0));
+
+ player.announce(MaplePacketCreator.showEffect("event/space/start"));
+ player.startMapEffect("Please rescue Gaga within the time limit.", 5120027);
+}
+
+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);
+
+ player.changeMap(mapid, 0);
+ player.cancelEffect(2360002);
+
+ end(eim);
+ } else {
+ eim.unregisterPlayer(player);
+
+ player.changeMap(mapid, 0);
+ player.cancelEffect(2360002);
+ }
+ } else if (mapid == maxMapId) {
+ eim.clearPQ();
+
+ var rgaga = player.getEvents().get("rescueGaga");
+ rgaga.complete();
+ }
+}
+
+function afterChangedMap(eim, player, mapid) {
+ if (mapid == minMapId) {
+ player.getAbstractPlayerInteraction().useItem(2360002);//HOORAY <3
+ } else {
+ player.cancelEffect(2360002);
+ }
+}
+
+function changedLeader(eim, leader) {}
+
+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) {}
+
+function disbandParty(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.schedule("spawnGrandpaBunny", 10 * 1000);
+}
+
+function spawnGrandpaBunny(eim) {
+ eim.spawnNpc(9001105, new java.awt.Point(175, -20), eim.getInstanceMap(maxMapId));
+}
+
+function monsterKilled(mob, eim) {}
+
+function allMonstersDead(eim) {}
+
+function cancelSchedule() {}
+
+function dispose(eim) {}
diff --git a/scripts/event/RockSpirit.js b/scripts/event/RockSpirit.js
index 149ced9bd1..9bd0726582 100644
--- a/scripts/event/RockSpirit.js
+++ b/scripts/event/RockSpirit.js
@@ -63,7 +63,7 @@ function respawn(eim) {
function playerEntry(eim, player) {
var amplifierMap = eim.getMapInstance(entryMap.getId());
- player.changeMap(amplifierMap);
+ player.changeMap(amplifierMap, 1);
eim.schedule("timeOut", timer);
}
diff --git a/scripts/event/RockSpiritVIP.js b/scripts/event/RockSpiritVIP.js
index 0d2ecba425..60085fb57d 100644
--- a/scripts/event/RockSpiritVIP.js
+++ b/scripts/event/RockSpiritVIP.js
@@ -63,7 +63,7 @@ function respawn(eim) {
function playerEntry(eim, player) {
var amplifierMap = eim.getMapInstance(entryMap.getId());
- player.changeMap(amplifierMap);
+ player.changeMap(amplifierMap, 1);
eim.schedule("timeOut", timer);
}
diff --git a/scripts/event/ZakumBattle.js b/scripts/event/ZakumBattle.js
index c52de1b557..3145e5044c 100644
--- a/scripts/event/ZakumBattle.js
+++ b/scripts/event/ZakumBattle.js
@@ -85,7 +85,9 @@ function setEventRewards(eim) {
eim.setEventClearStageMeso(mesoStages);
}
-function afterSetup(eim) {}
+function afterSetup(eim) {
+ updateGateState(1);
+}
function setup(channel) {
var eim = em.newInstance("Zakum" + channel);
@@ -188,6 +190,7 @@ function giveRandomEventReward(eim, player) {
function clearPQ(eim) {
eim.stopEventTimer();
eim.setEventCleared();
+ updateGateState(0);
}
function isZakum(mob) {
@@ -209,4 +212,12 @@ function allMonstersDead(eim) {}
function cancelSchedule() {}
-function dispose(eim) {}
+function updateGateState(newState) { // thanks Conrad for noticing missing gate update
+ em.getChannelServer().getMapFactory().getMap(211042300).getReactorById(2118002).forceHitReactor(newState);
+}
+
+function dispose(eim) {
+ if (!eim.isEventCleared()) {
+ updateGateState(0);
+ }
+}
diff --git a/scripts/map/onFirstUserEnter/spaceGaGa_sMap.js b/scripts/map/onFirstUserEnter/spaceGaGa_sMap.js
index 842f00ed6d..3ec7de09a7 100644
--- a/scripts/map/onFirstUserEnter/spaceGaGa_sMap.js
+++ b/scripts/map/onFirstUserEnter/spaceGaGa_sMap.js
@@ -1,5 +1,4 @@
function start(ms) {
- ms.getPlayer().resetEnteredScript();
- ms.getPlayer().getMap().addMapTimer(180);
+ ms.getPlayer().resetEnteredScript();
ms.spawnMonster(9300331, -28, 0);
}
\ No newline at end of file
diff --git a/scripts/map/onFirstUserEnter/spaceGaGa_start.js b/scripts/map/onFirstUserEnter/spaceGaGa_start.js
deleted file mode 100644
index 57d476e830..0000000000
--- a/scripts/map/onFirstUserEnter/spaceGaGa_start.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- 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 .
-*/
-/*
- *@Author: kevintjuh93
-*/
-
-importPackage(Packages.tools);
-var player;
-
-function start(ms) {
- player = ms.getPlayer();
- player.resetEnteredScript();
- ms.getClient().announce(MaplePacketCreator.showEffect("event/space/start"));
- player.startMapEffect("Please rescue Gaga within the time limit.", 5120027);
- var map = player.getMap();
- if (map.getTimeLeft() > 0) {
- ms.getClient().announce(MaplePacketCreator.getClock(map.getTimeLeft()));
- } else {
- map.addMapTimer(180);
- }
- ms.useItem(2360002);//HOORAY <3
-}
\ No newline at end of file
diff --git a/scripts/map/onUserEnter/130030000.js b/scripts/map/onUserEnter/130030000.js
index 1d94337e2e..f789e5ab3b 100644
--- a/scripts/map/onUserEnter/130030000.js
+++ b/scripts/map/onUserEnter/130030000.js
@@ -21,5 +21,5 @@
*/
function start(ms) {
- ms.getPlayer().updateQuestInfo(20010, "1");
+ ms.setQuestProgress(20010, 20022, 1);
}
\ No newline at end of file
diff --git a/scripts/map/onUserEnter/130030001.js b/scripts/map/onUserEnter/130030001.js
index 1d94337e2e..f789e5ab3b 100644
--- a/scripts/map/onUserEnter/130030001.js
+++ b/scripts/map/onUserEnter/130030001.js
@@ -21,5 +21,5 @@
*/
function start(ms) {
- ms.getPlayer().updateQuestInfo(20010, "1");
+ ms.setQuestProgress(20010, 20022, 1);
}
\ No newline at end of file
diff --git a/scripts/map/onUserEnter/910510000.js b/scripts/map/onUserEnter/910510000.js
index c489ca085b..51e18daa4b 100644
--- a/scripts/map/onUserEnter/910510000.js
+++ b/scripts/map/onUserEnter/910510000.js
@@ -5,11 +5,11 @@ function start(ms){
var map = player.getMap();
if(player.isCygnus()) {
- if(ms.isQuestStarted(20730) && ms.getQuestProgress(20730, 9300285) == 0) {
+ if(ms.isQuestStarted(20730) && ms.getQuestProgressInt(20730, 9300285) == 0) {
map.spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(9300285), new java.awt.Point(680, 258));
}
} else {
- if(ms.isQuestStarted(21731) && ms.getQuestProgress(21731, 9300344) == 0) {
+ if(ms.isQuestStarted(21731) && ms.getQuestProgressInt(21731, 9300344) == 0) {
map.spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(9300344), new java.awt.Point(680, 258));
}
}
diff --git a/scripts/map/onUserEnter/914000100.js b/scripts/map/onUserEnter/914000100.js
index 6ec1755650..108f8c451c 100644
--- a/scripts/map/onUserEnter/914000100.js
+++ b/scripts/map/onUserEnter/914000100.js
@@ -21,5 +21,5 @@
*/
function start(ms) {
- ms.getPlayer().updateQuestInfo(21000, "1");
+ ms.setQuestProgress(21000, 21002, 1);
}
\ No newline at end of file
diff --git a/scripts/map/onUserEnter/925040100.js b/scripts/map/onUserEnter/925040100.js
index 14f9c3dce8..738b9c75ac 100644
--- a/scripts/map/onUserEnter/925040100.js
+++ b/scripts/map/onUserEnter/925040100.js
@@ -4,7 +4,7 @@ function start(ms){
var player = ms.getPlayer();
var map = player.getMap();
- if(ms.isQuestStarted(21747) && ms.getQuestProgress(21747, 9300351) == 0) {
+ if(ms.isQuestStarted(21747) && ms.getQuestProgressInt(21747, 9300351) == 0) {
map.spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(9300351), new java.awt.Point(897, 51));
}
}
\ No newline at end of file
diff --git a/scripts/map/onUserEnter/cygnusJobTutorial.js b/scripts/map/onUserEnter/cygnusJobTutorial.js
new file mode 100644
index 0000000000..f7eb69877d
--- /dev/null
+++ b/scripts/map/onUserEnter/cygnusJobTutorial.js
@@ -0,0 +1,25 @@
+/*
+ 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 .
+*/
+
+function start(ms) {
+ ms.displayCygnusIntro();
+}
\ No newline at end of file
diff --git a/src/constants/skills/Swordsman.java b/scripts/map/onUserEnter/highposition.js
similarity index 83%
rename from src/constants/skills/Swordsman.java
rename to scripts/map/onUserEnter/highposition.js
index 979a87696d..815a15c05c 100644
--- a/src/constants/skills/Swordsman.java
+++ b/scripts/map/onUserEnter/highposition.js
@@ -19,13 +19,11 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
-package constants.skills;
-/**
+/*
+ * Author: kevintjuh93
*
- * @author BubblesDev
- */
-public class Swordsman {
- public static final int IMPROVED_MAX_HP_INCREASE = 1000001;
- public static final int IRON_BODY = 1000003;
-}
\ No newline at end of file
+*/
+function start(ms) {
+ ms.touchTheSky();
+}
diff --git a/scripts/map/onUserEnter/startEreb.js b/scripts/map/onUserEnter/startEreb.js
new file mode 100644
index 0000000000..7351fdf8dc
--- /dev/null
+++ b/scripts/map/onUserEnter/startEreb.js
@@ -0,0 +1,5 @@
+function start(ms) {
+ if (ms.getJobId() == 1000 && ms.getLevel() >= 10) {
+ ms.unlockUI();
+ }
+}
\ No newline at end of file
diff --git a/scripts/npc/1012100.js b/scripts/npc/1012100.js
index abebcb671a..5d44d1e5f1 100644
--- a/scripts/npc/1012100.js
+++ b/scripts/npc/1012100.js
@@ -34,7 +34,7 @@ spawnPnpcFee = 7000000;
jobType = 3;
function start() {
- if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()))) {
+ if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()))) {
spawnPnpc = true;
var sendStr = "You have walked a long way to reach the power, wisdom and courage you hold today, haven't you? What do you say about having right now #ra NPC on the Hall of Fame holding the current image of your character#k? Do you like it?";
@@ -93,7 +93,7 @@ function action(mode, type, selection) {
return;
}
- if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
+ if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
cm.sendOk("There you go! Hope you will like it.");
cm.gainMeso(-spawnPnpcFee);
} else {
diff --git a/scripts/npc/1012103.js b/scripts/npc/1012103.js
index aef9f6426b..f3508b0bdb 100644
--- a/scripts/npc/1012103.js
+++ b/scripts/npc/1012103.js
@@ -72,7 +72,10 @@ function action(mode, type, selection) {
} else if (status == 2){
cm.dispose();
if (beauty == 1){
- if (cm.haveItem(5150001)){
+ if (cm.haveItem(5420002)){ // thanks MedicOP for noticing uncoded functionality for Hair Membership coupons
+ cm.setHair(hairnew[selection]);
+ cm.sendOk("Enjoy your new and improved hairstyle!");
+ } else if (cm.haveItem(5150001)){
cm.gainItem(5150001, -1);
cm.setHair(hairnew[selection]);
cm.sendOk("Enjoy your new and improved hairstyle!");
diff --git a/scripts/npc/1022000.js b/scripts/npc/1022000.js
index 4d4aaeae59..ccea9025d8 100644
--- a/scripts/npc/1022000.js
+++ b/scripts/npc/1022000.js
@@ -35,7 +35,7 @@ spawnPnpcFee = 7000000;
jobType = 1;
function start() {
- if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()))) {
+ if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()))) {
spawnPnpc = true;
var sendStr = "You have walked a long way to reach the power, wisdom and courage you hold today, haven't you? What do you say about having right now #ra NPC on the Hall of Fame holding the current image of your character#k? Do you like it?";
@@ -94,7 +94,7 @@ function action(mode, type, selection) {
return;
}
- if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
+ if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
cm.sendOk("There you go! Hope you will like it.");
cm.gainMeso(-spawnPnpcFee);
} else {
diff --git a/scripts/npc/1032001.js b/scripts/npc/1032001.js
index 98bb35d84a..c10656286c 100644
--- a/scripts/npc/1032001.js
+++ b/scripts/npc/1032001.js
@@ -35,7 +35,7 @@ spawnPnpcFee = 7000000;
jobType = 2;
function start() {
- if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()))) {
+ if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()))) {
spawnPnpc = true;
var sendStr = "You have walked a long way to reach the power, wisdom and courage you hold today, haven't you? What do you say about having right now #ra NPC on the Hall of Fame holding the current image of your character#k? Do you like it?";
@@ -94,7 +94,7 @@ function action(mode, type, selection) {
return;
}
- if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
+ if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
cm.sendOk("There you go! Hope you will like it.");
cm.gainMeso(-spawnPnpcFee);
} else {
diff --git a/scripts/npc/1032109.js b/scripts/npc/1032109.js
index 80c74e25b2..a21274ad52 100644
--- a/scripts/npc/1032109.js
+++ b/scripts/npc/1032109.js
@@ -9,6 +9,11 @@ var status;
var mobId = 2220100; //Blue Mushroom
function start(){
+ if (!cm.isQuestStarted(20718)) { // thanks Stray, Ari
+ cm.dispose();
+ return;
+ }
+
status = -1;
action(1, 0, 0);
}
diff --git a/scripts/npc/1052001.js b/scripts/npc/1052001.js
index a9ae74c161..9ab5b9f37d 100644
--- a/scripts/npc/1052001.js
+++ b/scripts/npc/1052001.js
@@ -34,7 +34,7 @@ spawnPnpcFee = 7000000;
jobType = 4;
function start() {
- if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()))) {
+ if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()))) {
spawnPnpc = true;
var sendStr = "You have walked a long way to reach the power, wisdom and courage you hold today, haven't you? What do you say about having right now #ra NPC on the Hall of Fame holding the current image of your character#k? Do you like it?";
@@ -95,7 +95,7 @@ function action(mode, type, selection) {
return;
}
- if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
+ if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
cm.sendOk("There you go! Hope you will like it.");
cm.gainMeso(-spawnPnpcFee);
} else {
diff --git a/scripts/npc/1052007.js b/scripts/npc/1052007.js
index 8636978a81..27a0f1a4d6 100644
--- a/scripts/npc/1052007.js
+++ b/scripts/npc/1052007.js
@@ -66,7 +66,7 @@ function action(mode, type, selection) {
ticketSelection = selection;
if (ticketSelection > -1) {
cm.gainItem(4031035 + ticketSelection, -1);
- cm.warp(103000897 + (ticketSelection * 3));
+ cm.warp(103000897 + (ticketSelection * 3), "st00"); // thanks IxianMace for noticing a few scripts having misplaced warp SP's
hasTicket = false;
cm.dispose();
return;
diff --git a/scripts/npc/1052008.js b/scripts/npc/1052008.js
index 33176a4bf1..095fd671cf 100644
--- a/scripts/npc/1052008.js
+++ b/scripts/npc/1052008.js
@@ -28,6 +28,6 @@ function start() {
cm.gainItem(4031039,1);
else
cm.gainItem(4020000 + ((Math.random()*5)|0), 1);
- cm.warp(103000100);
+ cm.warp(103000100, 0);
cm.dispose();
}
\ No newline at end of file
diff --git a/scripts/npc/1052009.js b/scripts/npc/1052009.js
index 6a83c44ff1..f1de2aab88 100644
--- a/scripts/npc/1052009.js
+++ b/scripts/npc/1052009.js
@@ -28,6 +28,6 @@ function start() {
cm.gainItem(4031040,1);
else
cm.gainItem(prizes[parseInt(Math.random() * prizes.length)],1);
- cm.warp(103000100);
+ cm.warp(103000100, 0);
cm.dispose();
}
\ No newline at end of file
diff --git a/scripts/npc/1052010.js b/scripts/npc/1052010.js
index 4e072e4822..7f75e4c2ad 100644
--- a/scripts/npc/1052010.js
+++ b/scripts/npc/1052010.js
@@ -28,6 +28,6 @@ function start() {
cm.gainItem(4031041,1);
else
cm.gainItem(prizes[parseInt(Math.random() * prizes.length)],1);
- cm.warp(103000100);
+ cm.warp(103000100, 0);
cm.dispose();
}
\ No newline at end of file
diff --git a/scripts/npc/1052012.js b/scripts/npc/1052012.js
index 8c03fb6da3..bb683cac66 100644
--- a/scripts/npc/1052012.js
+++ b/scripts/npc/1052012.js
@@ -53,7 +53,7 @@ function action(mode, type, selection) {
cm.sendOk("Oh, you don't have the money, right? Sorry, I can't let you in.");
} else {
cm.gainMeso(-5000);
- cm.warp(193000000);
+ cm.warp(193000000, "out00");
}
cm.dispose();
diff --git a/scripts/npc/1052100.js b/scripts/npc/1052100.js
index 826885bc6d..127be5cc40 100644
--- a/scripts/npc/1052100.js
+++ b/scripts/npc/1052100.js
@@ -78,7 +78,10 @@ function action(mode, type, selection) {
else if (status == 2){
cm.dispose();
if (beauty == 1){
- if (cm.haveItem(5150003)){
+ if (cm.haveItem(5420003)){
+ cm.setHair(hairnew[selection]);
+ cm.sendOk("Enjoy your new and improved hairstyle!");
+ } else if (cm.haveItem(5150003)){
cm.gainItem(5150003, -1);
cm.setHair(hairnew[selection]);
cm.sendOk("Enjoy your new and improved hairstyle!");
diff --git a/scripts/npc/1061014.js b/scripts/npc/1061014.js
index 545218e1e1..d5fb6da0f1 100644
--- a/scripts/npc/1061014.js
+++ b/scripts/npc/1061014.js
@@ -65,8 +65,13 @@ function action(mode, type, selection) {
cm.sendSimple("#e#b\r\n#k#n" + em.getProperty("party") + "\r\n\r\nWould you like to assemble a team to take on #r" + expedBoss + "#k?\r\n#b#L1#Lets get this going!#l\r\n\#L2#No, I think I'll wait a bit...#l\r\n\#L3#I would like to see info about this expedition...#l");
status = 1;
} else if (expedition.isLeader(player)) { //If you're the leader, manage the exped
- cm.sendSimple(list);
- status = 2;
+ if (expedition.isInProgress()) {
+ cm.sendOk("Your expedition is already in progress, for those who remain battling lets pray for those brave souls.");
+ cm.dispose();
+ } else {
+ cm.sendSimple(list);
+ status = 2;
+ }
} else if (expedition.isRegistering()) { //If the expedition is registering
if (expedition.contains(player)) { //If you're in it but it hasn't started, be patient
cm.sendOk("You have already registered for the expedition. Please wait for #r" + expedition.getLeader().getName() + "#k to begin it.");
@@ -99,8 +104,11 @@ function action(mode, type, selection) {
return;
}
- if (cm.createExpedition(exped)) {
+ var res = cm.createExpedition(exped);
+ if (res == 0) {
cm.sendOk("The #r" + expedBoss + " Expedition#k has been created.\r\n\r\nTalk to me again to view the current team, or start the fight!");
+ } else if (res > 0) {
+ cm.sendOk("Sorry, you've already reached the quota of attempts for this expedition! Try again another day...");
} else {
cm.sendOk("An unexpected error has occurred when starting the expedition, please try again later.");
}
diff --git a/scripts/npc/1061018.js b/scripts/npc/1061018.js
index 1fd6b88c23..a603b7044b 100644
--- a/scripts/npc/1061018.js
+++ b/scripts/npc/1061018.js
@@ -28,7 +28,7 @@ function action(mode, type, selection) {
}
} else if(status == 1){
if(cm.getEventInstance().isEventCleared()) {
- cm.warp(cm.getMapId() == 105100300 ? 105100301 : 105100401);
+ cm.warp(cm.getMapId() == 105100300 ? 105100301 : 105100401, 0);
} else {
cm.warp(105100100);
}
diff --git a/scripts/npc/1063012.js b/scripts/npc/1063012.js
index 54b0167de3..c5d98a2b9f 100644
--- a/scripts/npc/1063012.js
+++ b/scripts/npc/1063012.js
@@ -21,12 +21,15 @@
*/
var status = -1;
+/*
+Custom Quest 100300
+*/
function activateShamanRock(slot,progress) {
- var active = (progress >> slot) % 2;
- if(!active) {
- progress |= (1 << slot);
+ var ch = progress[slot];
+ if(ch == '0') {
+ var nextProgress = progress.substr(0, slot) + '1' + progress.substr(slot + 1);
- cm.updateQuest(2236, progress);
+ cm.setQuestProgress(2236, nextProgress);
cm.gainItem(4032263, -1);
cm.sendOk("The seal took it's place, repelling the evil in the area.");
return 1;
@@ -45,7 +48,11 @@ function start() {
else if(map == 105070000) activateShamanRock(2,progress);
else if(map == 105090000) { // workaround... TWO SAME NPC ID ON SAME MAP
- if(!activateShamanRock(3,progress)) {
+ var npcOid = cm.getQuestProgressInt(100300, 1);
+ if (npcOid == 0) {
+ activateShamanRock(3,progress);
+ cm.setQuestProgress(100300, 1, cm.getNpcObjectId());
+ } else if (cm.getNpcObjectId() != npcOid) {
activateShamanRock(4,progress);
}
}
diff --git a/scripts/npc/1063013.js b/scripts/npc/1063013.js
index 54b0167de3..c5d98a2b9f 100644
--- a/scripts/npc/1063013.js
+++ b/scripts/npc/1063013.js
@@ -21,12 +21,15 @@
*/
var status = -1;
+/*
+Custom Quest 100300
+*/
function activateShamanRock(slot,progress) {
- var active = (progress >> slot) % 2;
- if(!active) {
- progress |= (1 << slot);
+ var ch = progress[slot];
+ if(ch == '0') {
+ var nextProgress = progress.substr(0, slot) + '1' + progress.substr(slot + 1);
- cm.updateQuest(2236, progress);
+ cm.setQuestProgress(2236, nextProgress);
cm.gainItem(4032263, -1);
cm.sendOk("The seal took it's place, repelling the evil in the area.");
return 1;
@@ -45,7 +48,11 @@ function start() {
else if(map == 105070000) activateShamanRock(2,progress);
else if(map == 105090000) { // workaround... TWO SAME NPC ID ON SAME MAP
- if(!activateShamanRock(3,progress)) {
+ var npcOid = cm.getQuestProgressInt(100300, 1);
+ if (npcOid == 0) {
+ activateShamanRock(3,progress);
+ cm.setQuestProgress(100300, 1, cm.getNpcObjectId());
+ } else if (cm.getNpcObjectId() != npcOid) {
activateShamanRock(4,progress);
}
}
diff --git a/scripts/npc/1072002.js b/scripts/npc/1072002.js
index dad871dbfa..3f2ed5c98e 100644
--- a/scripts/npc/1072002.js
+++ b/scripts/npc/1072002.js
@@ -69,7 +69,7 @@ function action(mode, type, selection) {
cm.gainItem(4031010, -1);
cm.sendOk("You will have to collect me #b30 #t4031013##k. Good luck.")
} else if (status == 4) {
- cm.warp(108000100);
+ cm.warp(108000100, 0);
cm.dispose();
}
else {
diff --git a/scripts/npc/1072008.js b/scripts/npc/1072008.js
index 78226f09d1..03a5973b8a 100644
--- a/scripts/npc/1072008.js
+++ b/scripts/npc/1072008.js
@@ -5,36 +5,52 @@
**/
var status;
-
+
function start() {
status = -1;
- action(1,0,0);
+ action(1, 0, 0);
}
-function action(mode,type,selection) {
- if (status == -1) {
- if (cm.getMapId() == 108000502) {
- if (!(cm.haveItem(4031856,15))) {
- cm.sendNext("Go, and get me 15 #b#t4031856##k.");
- cm.dispose();
- } else {
- status = 2;
- cm.sendNext("Wow, you have brought me 15 #b#t4031856##k! Congratulations. Let me warp you out now.");
- }
- } else if (cm.getMapId() == 108000501) {
- if (!(cm.haveItem(4031857,15))) {
- cm.sendNext("Go, and get me 15 #b#t4031857##k.");
- cm.dispose();
- } else {
- status = 2;
- cm.sendNext("Wow, you have brought me 15 #b#t4031857##k! Congratulations. Let me warp you out now.");
- }
- } else {
- cm.sendNext("Error. Please report this.");
- cm.dispose();
- }
- } else if (status == 2) {
- cm.warp(120000101,0);
- cm.dispose();
+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) {
+ if (cm.getMapId() == 108000502) {
+ if (!(cm.haveItem(4031856,15))) {
+ cm.sendSimple("You haven't brought me all the crystals yet. I'm looking forward for your progress, mate! \r\n#b#L1#I would like to leave#l");
+ } else {
+ status++;
+ cm.sendNext("Wow, you have brought me 15 #b#t4031856##k! Congratulations. Let me warp you out now.");
+ }
+ } else if (cm.getMapId() == 108000501) {
+ if (!(cm.haveItem(4031857,15))) {
+ cm.sendSimple("You haven't brought me all the crystals yet. I'm looking forward for your progress, mate! \r\n#b#L1#I would like to leave#l");
+ } else {
+ status++;
+ cm.sendNext("Wow, you have brought me 15 #b#t4031857##k! Congratulations. Let me warp you out now.");
+ }
+ } else {
+ cm.sendNext("Error. Please report this.");
+ cm.dispose();
+ }
+ } else if (status == 1) { // thanks Lame for noticing players getting stuck in area in certain scenarios
+ cm.removeAll(4031856);
+ cm.removeAll(4031857);
+ cm.warp(120000101,0);
+ cm.dispose();
+ } else if (status == 2) {
+ cm.warp(120000101,0);
+ cm.dispose();
+ }
}
-}
\ No newline at end of file
+}
diff --git a/scripts/npc/1090000.js b/scripts/npc/1090000.js
index 28a86324f4..9ddce6bbbd 100644
--- a/scripts/npc/1090000.js
+++ b/scripts/npc/1090000.js
@@ -39,8 +39,7 @@ function start() {
if (cm.getEventInstance() != null) { // missing script for skill test found thanks to Jade™
advQuest = 5; // string visibility thanks to iPunchEm & Glvelturall
cm.sendNext("Not bad at all. Let's discuss this outside!");
- cm.setQuestProgress(6330, 0, 1);
- } else if (cm.getQuestProgress(6330, 0) == 0) {
+ } else if (cm.getQuestProgressInt(6330, 6331) == 0) {
advQuest = 1;
cm.sendNext("You're ready, right? Now try to withstand my attacks for 2 minutes. I won't go easy on you. Good luck, because you will need it.");
} else {
@@ -54,8 +53,7 @@ function start() {
if (cm.getEventInstance() != null) {
advQuest = 6;
cm.sendNext("Not bad at all. Let's discuss this outside!");
- cm.setQuestProgress(6370, 0, 1);
- } else if (cm.getQuestProgress(6370, 0) == 0) {
+ } else if (cm.getQuestProgressInt(6370, 6371) == 0) {
advQuest = 2;
cm.sendNext("You're ready, right? Now try to withstand my attacks for 2 minutes. I won't go easy on you. Good luck, because you will need it.");
} else {
@@ -65,7 +63,7 @@ function start() {
cm.sendNext("Congratulations. You have managed to pass my test. I'll teach you a new skill called \"Battleship\".\r\n\r\n #s5221006# #b#q5221006##k");
}
- } else if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()))) {
+ } else if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()))) {
spawnPnpc = true;
var sendStr = "You have walked a long way to reach the power, wisdom and courage you hold today, haven't you? What do you say about having right now #ra NPC on the Hall of Fame holding the current image of your character#k? Do you like it?";
@@ -126,6 +124,12 @@ function action(mode, type, selection) {
cm.sendOk("Unlike most of the other skills you used as a Pirate, this one definitely is different. You can actually ride the 'Battleship' and attack enemies with it. Your DEF level will increase for the time you're on board, so that'll help you tremendously in combat situations. May you become the best Gunslinger out there...");
}
} else {
+ if (advQuest < 6) {
+ cm.setQuestProgress(6330, 6331, 2);
+ } else {
+ cm.setQuestProgress(6370, 6371, 2);
+ }
+
cm.warp(120000101);
}
@@ -138,7 +142,7 @@ function action(mode, type, selection) {
return;
}
- if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
+ if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
cm.sendOk("There you go! Hope you will like it.");
cm.gainMeso(-spawnPnpcFee);
} else {
@@ -222,7 +226,7 @@ function action(mode, type, selection) {
cm.sendOk("All the training maps are currently in use. Please try again later.");
cm.dispose();
} else {
- cm.warp(map);
+ cm.warp(map, 0);
cm.dispose();
return;
}
diff --git a/scripts/npc/1092019.js b/scripts/npc/1092019.js
index 41b6ad999b..96e333cc35 100644
--- a/scripts/npc/1092019.js
+++ b/scripts/npc/1092019.js
@@ -64,7 +64,7 @@ function action(mode, type, selection) {
cm.sendOk("Who are you talking to me? If you're just bored, go bother somebody else.");
cm.dispose();
} else {
- seagullProgress = cm.getQuestProgress(6400, 0);
+ seagullProgress = cm.getQuestProgressInt(6400, 1);
if (seagullProgress == 0) {
seagullIdx = Math.floor(Math.random() * seagullQuestion.length);
@@ -90,7 +90,7 @@ function action(mode, type, selection) {
var answer = cm.getText();
if (answer == seagullAnswer[seagullIdx]) {
cm.sendNext("What! I can't believe how incredibly smart you are! Incredible! In the seagull world, that kind of intellingence would give you a Ph.D. and then some. You're really amazing... I can't believe it... I simply can't believe it!");
- cm.setQuestProgress(6400, 0, 1);
+ cm.setQuestProgress(6400, 1, 1);
cm.dispose();
} else {
cm.sendOk("Hmm, that's not quite how I recall it. Try again!");
@@ -99,9 +99,11 @@ function action(mode, type, selection) {
} else if (seagullProgress != 2) {
cm.sendNextPrev("Anyway, only one of 9 Barts is the real Bart. You know that Pirates are known for the strength of their friendships and camaraderie with their fellow pirates. If you're a true pirate, you should be able to find your own mate with ease. Alright then, I'll send you to the room where Bart is.");
} else {
- cm.gainExp(1000000);
- cm.teachSkill(5221003, 0, 10, -1);
- cm.forceCompleteQuest(6400);
+ //cm.gainExp(1000000);
+ //cm.teachSkill(5221003, 0, 10, -1);
+ //cm.forceCompleteQuest(6400);
+
+ cm.sendNextPrev("You have met all my challenges, and passed! Good job!");
cm.dispose();
}
} else if (status == 3) {
diff --git a/scripts/npc/1092090.js b/scripts/npc/1092090.js
index 2dac576325..6b1cde8950 100644
--- a/scripts/npc/1092090.js
+++ b/scripts/npc/1092090.js
@@ -21,7 +21,7 @@
*/
function start() {
- if(cm.getQuestProgress(2180, 0) == 1) {
+ if(cm.getQuestProgressInt(2180, 1) == 1) {
cm.sendNext("You have taken milk from this cow recently, check another cow.");
cm.dispose();
return;
@@ -32,19 +32,19 @@ function start() {
cm.gainItem(4031847, -1);
cm.gainItem(4031848, 1);
- cm.setQuestProgress(2180, 0, 1);
+ cm.setQuestProgress(2180, 1, 1);
} else if (cm.canHold(4031849, 1) && cm.haveItem(4031848)) {
cm.sendNext("Now filling up the bottle with milk. The bottle is now 2/3 full of milk.");
cm.gainItem(4031848, -1);
cm.gainItem(4031849, 1);
- cm.setQuestProgress(2180, 0, 1);
+ cm.setQuestProgress(2180, 1, 1);
} else if (cm.canHold(4031850) && cm.haveItem(4031849)) {
cm.sendNext("Now filling up the bottle with milk. The bottle is now completely full of milk.");
cm.gainItem(4031849, -1);
cm.gainItem(4031850, 1);
- cm.setQuestProgress(2180, 0, 1);
+ cm.setQuestProgress(2180, 1, 1);
} else {
cm.sendNext("Your inventory is full, and there's no room for a milk bottle.");
}
diff --git a/scripts/npc/1092091.js b/scripts/npc/1092091.js
index 5d5db97d54..ec40aff0a8 100644
--- a/scripts/npc/1092091.js
+++ b/scripts/npc/1092091.js
@@ -21,7 +21,7 @@
*/
function start() {
- if(cm.getQuestProgress(2180, 0) == 2) {
+ if(cm.getQuestProgressInt(2180, 1) == 2) {
cm.sendNext("You have taken milk from this cow recently, check another cow.");
cm.dispose();
return;
@@ -32,19 +32,19 @@ function start() {
cm.gainItem(4031847, -1);
cm.gainItem(4031848, 1);
- cm.setQuestProgress(2180, 0, 2);
+ cm.setQuestProgress(2180, 1, 2);
} else if(cm.canHold(4031849) && cm.haveItem(4031848)){
cm.sendNext("Now filling up the bottle with milk. The bottle is now 2/3 full of milk.");
cm.gainItem(4031848, -1);
cm.gainItem(4031849, 1);
- cm.setQuestProgress(2180, 0, 2);
+ cm.setQuestProgress(2180, 1, 2);
} else if(cm.canHold(4031850) && cm.haveItem(4031849)){
cm.sendNext("Now filling up the bottle with milk. The bottle is now completely full of milk.");
cm.gainItem(4031849, -1);
cm.gainItem(4031850, 1);
- cm.setQuestProgress(2180, 0, 2);
+ cm.setQuestProgress(2180, 1, 2);
} else {
cm.sendNext("Your inventory is full, and there's no room for a milk bottle.");
}
diff --git a/scripts/npc/1096005.js b/scripts/npc/1096005.js
index 84f971c7e2..117a444e68 100644
--- a/scripts/npc/1096005.js
+++ b/scripts/npc/1096005.js
@@ -18,7 +18,6 @@ function action(mode, type, selection) {
cm.sendNext("All right! Let's go!");
} else if (status == 1) {
cm.removeNPC(579711);
- cm.removeNPC2(579711);
cm.updateInfo("fire", "0");
cm.playSound("cannonshooter/fire");
cm.sendDirectionInfo("Effect/Direction4.img/effect/cannonshooter/flying/0", 7000, 0, 0, -1, -1);
diff --git a/scripts/npc/1101001.js b/scripts/npc/1101001.js
index e08c21fb28..138d871853 100644
--- a/scripts/npc/1101001.js
+++ b/scripts/npc/1101001.js
@@ -3,7 +3,7 @@
Map(s): Erev
Description: 3rd job KoC Buff
*/
-importPackage(Packages.constants);
+importPackage(Packages.constants.game);
function start() {
if (cm.getPlayer().isCygnus() && GameConstants.getJobBranch(cm.getJob()) > 2) {
diff --git a/scripts/npc/1102003.js b/scripts/npc/1102003.js
index 9436dbb648..eb9c59c847 100644
--- a/scripts/npc/1102003.js
+++ b/scripts/npc/1102003.js
@@ -33,7 +33,7 @@ var maxJobType = 15;
function start() {
var jobType = parseInt(cm.getJobId() / 100);
- if (jobType >= minJobType && jobType <= maxJobType && cm.canSpawnPlayerNpc(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()))) {
+ if (jobType >= minJobType && jobType <= maxJobType && cm.canSpawnPlayerNpc(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()))) {
spawnPnpc = true;
var sendStr = "You have walked a long way to reach the power, wisdom and courage you hold today, haven't you? What do you say about having right now #ra NPC on the Hall of Fame holding the current image of your character#k? Do you like it?";
@@ -64,7 +64,7 @@ function action(mode, type, selection) {
return;
}
- if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
+ if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
cm.sendOk("There you go! Hope you will like it.");
cm.gainMeso(-spawnPnpcFee);
} else {
diff --git a/scripts/npc/1104201.js b/scripts/npc/1104201.js
index e4c22783ad..ee2f89b0ca 100644
--- a/scripts/npc/1104201.js
+++ b/scripts/npc/1104201.js
@@ -39,7 +39,7 @@ function action(mode, type, selection) {
status--;
if(status == 0) {
- if (!(cm.isQuestCompleted(20407) || cm.isQuestStarted(20407) && cm.getQuestProgress(20407, 9001010) != 0) && cm.getMap().countMonster(9001010) == 0 && cm.getMap().getNPCById(1104002) == null) {
+ if (!(cm.isQuestCompleted(20407) || cm.isQuestStarted(20407) && cm.getQuestProgressInt(20407, 9001010) != 0) && cm.getMap().countMonster(9001010) == 0 && cm.getMap().getNPCById(1104002) == null) {
cm.sendOk("... Hnngh... #b#h0##k, is that you...? #r#p1104002##k... She's already here... #b#h0##k, I'm truly sorry I can't help you right now in this state, just when a bigger threat appeared I could do nothing for my people.... Please I beg you, please defeat her, #b#h0##k!! ....");
cm.spawnNpc(1104002, new java.awt.Point(850, 0), cm.getMap());
} else {
diff --git a/scripts/npc/1202010.js b/scripts/npc/1202010.js
index da06e68e88..0978526cdf 100644
--- a/scripts/npc/1202010.js
+++ b/scripts/npc/1202010.js
@@ -5,7 +5,7 @@ var spawnPnpcFee = 7000000;
var jobType = 21;
function start() {
- if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()))) {
+ if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()))) {
spawnPnpc = true;
var sendStr = "You have walked a long way to reach the power, wisdom and courage you hold today, haven't you? What do you say about having right now #ra NPC on the Hall of Fame holding the current image of your character#k? Do you like it?";
@@ -36,7 +36,7 @@ function action(mode, type, selection) {
return;
}
- if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
+ if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
cm.sendOk("There you go! Hope you will like it.");
cm.gainMeso(-spawnPnpcFee);
} else {
diff --git a/scripts/npc/1209000.js b/scripts/npc/1209000.js
index 29b94792ff..1856337261 100644
--- a/scripts/npc/1209000.js
+++ b/scripts/npc/1209000.js
@@ -46,7 +46,7 @@ function action(mode, type, selection) {
} else if (status == 2) {
cm.sendNext("The other heroes? They've left to fight the Black Mage. They're buying us time to escape. What? You want to fight with them? No! You can't! You're hurt. You must leave with us!");
} else if (status == 3) {
- cm.updateQuest(21002, "1");
+ //cm.setQuestProgress(21002, 1);
cm.showIntro("Effect/Direction1.img/aranTutorial/Trio");
cm.dispose();
}
diff --git a/scripts/npc/1300013.js b/scripts/npc/1300013.js
index 29bd5ec7c8..56a7be723b 100644
--- a/scripts/npc/1300013.js
+++ b/scripts/npc/1300013.js
@@ -62,7 +62,7 @@ function action(mode, type, selection){
}
}
} else {
- var questProgress = cm.getQuestProgress(2330, 3300005) + cm.getQuestProgress(2330, 3300006) + cm.getQuestProgress(2330, 3300007); //3 Yetis
+ var questProgress = cm.getQuestProgressInt(2330, 3300005) + cm.getQuestProgressInt(2330, 3300006) + cm.getQuestProgressInt(2330, 3300007); //3 Yetis
if (!(cm.isQuestStarted(2330) && questProgress < 3)) { // thanks Vcoc for finding an exploit with boss entry through NPC
cm.dispose();
return;
diff --git a/scripts/npc/2010001.js b/scripts/npc/2010001.js
index a1d0b976d9..d1d53104db 100644
--- a/scripts/npc/2010001.js
+++ b/scripts/npc/2010001.js
@@ -83,7 +83,10 @@ function action(mode, type, selection) {
else if (status == 2){
cm.dispose();
if (beauty == 1){
- if (cm.haveItem(5150005) == true){
+ if (cm.haveItem(5420004)){
+ cm.setHair(hairnew[selection]);
+ cm.sendOk("Enjoy your new and improved hairstyle!");
+ } else if (cm.haveItem(5150005) == true){
cm.gainItem(5150005, -1);
cm.setHair(hairnew[selection]);
cm.sendOk("Enjoy your new and improved hairstyle!");
diff --git a/scripts/npc/2010007.js b/scripts/npc/2010007.js
index b70d2ca93a..5ea75f4e3a 100644
--- a/scripts/npc/2010007.js
+++ b/scripts/npc/2010007.js
@@ -57,8 +57,10 @@ function action(mode, type, selection) {
if (cm.getPlayer().getGuildId() < 1 || cm.getPlayer().getGuildRank() != 1) {
cm.sendOk("You can only increase your Guild's capacity if you are the leader.");
cm.dispose();
- } else
- cm.sendYesNo("Increasing your Guild capacity by #b5#k costs #b " + cm.getPlayer().getGuild().getIncreaseGuildCost(cm.getPlayer().getGuild().getCapacity()) +" mesos#k, are you sure you want to continue?");
+ } else {
+ var MapleGuild = Java.type("net.server.guild.MapleGuild"); // thanks Conrad for noticing an issue due to call on a static method here
+ cm.sendYesNo("Increasing your Guild capacity by #b5#k costs #b " + MapleGuild.getIncreaseGuildCost(cm.getPlayer().getGuild().getCapacity()) +" mesos#k, are you sure you want to continue?");
+ }
}
} else if (status == 2) {
if (sel == 0 && cm.getPlayer().getGuildId() <= 0) {
diff --git a/scripts/npc/2010009.js b/scripts/npc/2010009.js
index 3e01a7ae29..1675483490 100644
--- a/scripts/npc/2010009.js
+++ b/scripts/npc/2010009.js
@@ -22,14 +22,12 @@
var status;
var choice;
var guildName;
-var partymembers;
var allianceCost = 2000000;
var increaseCost = 1000000;
var allianceLimit = 5;
function start() {
- partymembers = cm.getPartyMembers();
status = -1;
action(1,0,0);
}
diff --git a/scripts/npc/2012027.js b/scripts/npc/2012027.js
index dbc5a36f9e..9c32b31421 100644
--- a/scripts/npc/2012027.js
+++ b/scripts/npc/2012027.js
@@ -50,13 +50,13 @@ function action(mode, type, selection) {
cm.getMap().broadcastMessage(MaplePacketCreator.playSound("orbis/" + harpSounds[cm.getNpc() - 2012027]));
if(cm.isQuestStarted(3114)) {
- var idx = cm.getQuestProgress(3114, 7777);
+ var idx = -1 * cm.getQuestProgressInt(3114); // infoEx without infoNumber, must use one progress only, critical hit!
- if(idx != -1) {
+ if(idx > -1) {
var nextNote = harpSong[idx];
if(harpNote != nextNote) {
- cm.setQuestProgress(3114, 7777, 0);
+ cm.setQuestProgress(3114, 0);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/wrong_kor"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Failed"));
@@ -70,7 +70,7 @@ function action(mode, type, selection) {
if(idx == 45) { // finished lullaby
cm.message("Twinkle, twinkle, little star, how I wonder what you are.");
- cm.setQuestProgress(3114, 7777, -1);
+ cm.setQuestProgress(3114, 42);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/clear"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Clear"));
@@ -88,7 +88,7 @@ function action(mode, type, selection) {
}
}
- cm.setQuestProgress(3114, 7777, idx + 1);
+ cm.setQuestProgress(3114, -1 * (idx + 1));
}
}
}
diff --git a/scripts/npc/2012028.js b/scripts/npc/2012028.js
index c242fd8d69..960dad19f9 100644
--- a/scripts/npc/2012028.js
+++ b/scripts/npc/2012028.js
@@ -50,13 +50,13 @@ function action(mode, type, selection) {
cm.getMap().broadcastMessage(MaplePacketCreator.playSound("orbis/" + harpSounds[cm.getNpc() - 2012027]));
if(cm.isQuestStarted(3114)) {
- var idx = cm.getQuestProgress(3114, 7777);
+ var idx = -1 * cm.getQuestProgressInt(3114);
- if(idx != -1) {
+ if(idx > -1) {
var nextNote = harpSong[idx];
if(harpNote != nextNote) {
- cm.setQuestProgress(3114, 7777, 0);
+ cm.setQuestProgress(3114, 0);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/wrong_kor"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Failed"));
@@ -70,7 +70,7 @@ function action(mode, type, selection) {
if(idx == 45) { // finished lullaby
cm.message("Twinkle, twinkle, little star, how I wonder what you are.");
- cm.setQuestProgress(3114, 7777, -1);
+ cm.setQuestProgress(3114, 42);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/clear"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Clear"));
@@ -88,7 +88,7 @@ function action(mode, type, selection) {
}
}
- cm.setQuestProgress(3114, 7777, idx + 1);
+ cm.setQuestProgress(3114, -1 * (idx + 1));
}
}
}
diff --git a/scripts/npc/2012029.js b/scripts/npc/2012029.js
index 7371a28642..3a242c3659 100644
--- a/scripts/npc/2012029.js
+++ b/scripts/npc/2012029.js
@@ -50,13 +50,13 @@ function action(mode, type, selection) {
cm.getMap().broadcastMessage(MaplePacketCreator.playSound("orbis/" + harpSounds[cm.getNpc() - 2012027]));
if(cm.isQuestStarted(3114)) {
- var idx = cm.getQuestProgress(3114, 7777);
+ var idx = -1 * cm.getQuestProgressInt(3114);
- if(idx != -1) {
+ if(idx > -1) {
var nextNote = harpSong[idx];
if(harpNote != nextNote) {
- cm.setQuestProgress(3114, 7777, 0);
+ cm.setQuestProgress(3114, 0);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/wrong_kor"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Failed"));
@@ -70,7 +70,7 @@ function action(mode, type, selection) {
if(idx == 45) { // finished lullaby
cm.message("Twinkle, twinkle, little star, how I wonder what you are.");
- cm.setQuestProgress(3114, 7777, -1);
+ cm.setQuestProgress(3114, 42);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/clear"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Clear"));
@@ -88,7 +88,7 @@ function action(mode, type, selection) {
}
}
- cm.setQuestProgress(3114, 7777, idx + 1);
+ cm.setQuestProgress(3114, -1 * (idx + 1));
}
}
}
diff --git a/scripts/npc/2012030.js b/scripts/npc/2012030.js
index f0a7eed991..05a7120a4f 100644
--- a/scripts/npc/2012030.js
+++ b/scripts/npc/2012030.js
@@ -50,13 +50,13 @@ function action(mode, type, selection) {
cm.getMap().broadcastMessage(MaplePacketCreator.playSound("orbis/" + harpSounds[cm.getNpc() - 2012027]));
if(cm.isQuestStarted(3114)) {
- var idx = cm.getQuestProgress(3114, 7777);
+ var idx = -1 * cm.getQuestProgressInt(3114);
- if(idx != -1) {
+ if(idx > -1) {
var nextNote = harpSong[idx];
if(harpNote != nextNote) {
- cm.setQuestProgress(3114, 7777, 0);
+ cm.setQuestProgress(3114, 0);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/wrong_kor"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Failed"));
@@ -70,7 +70,7 @@ function action(mode, type, selection) {
if(idx == 45) { // finished lullaby
cm.message("Twinkle, twinkle, little star, how I wonder what you are.");
- cm.setQuestProgress(3114, 7777, -1);
+ cm.setQuestProgress(3114, 42);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/clear"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Clear"));
@@ -88,7 +88,7 @@ function action(mode, type, selection) {
}
}
- cm.setQuestProgress(3114, 7777, idx + 1);
+ cm.setQuestProgress(3114, -1 * (idx + 1));
}
}
}
diff --git a/scripts/npc/2012031.js b/scripts/npc/2012031.js
index 5f06ac6ba2..71af8dd7db 100644
--- a/scripts/npc/2012031.js
+++ b/scripts/npc/2012031.js
@@ -50,13 +50,13 @@ function action(mode, type, selection) {
cm.getMap().broadcastMessage(MaplePacketCreator.playSound("orbis/" + harpSounds[cm.getNpc() - 2012027]));
if(cm.isQuestStarted(3114)) {
- var idx = cm.getQuestProgress(3114, 7777);
+ var idx = -1 * cm.getQuestProgressInt(3114);
- if(idx != -1) {
+ if(idx > -1) {
var nextNote = harpSong[idx];
if(harpNote != nextNote) {
- cm.setQuestProgress(3114, 7777, 0);
+ cm.setQuestProgress(3114, 0);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/wrong_kor"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Failed"));
@@ -70,7 +70,7 @@ function action(mode, type, selection) {
if(idx == 45) { // finished lullaby
cm.message("Twinkle, twinkle, little star, how I wonder what you are.");
- cm.setQuestProgress(3114, 7777, -1);
+ cm.setQuestProgress(3114, 42);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/clear"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Clear"));
@@ -88,7 +88,7 @@ function action(mode, type, selection) {
}
}
- cm.setQuestProgress(3114, 7777, idx + 1);
+ cm.setQuestProgress(3114, -1 * (idx + 1));
}
}
}
diff --git a/scripts/npc/2012032.js b/scripts/npc/2012032.js
index 41b41a45c2..d0d33d06ee 100644
--- a/scripts/npc/2012032.js
+++ b/scripts/npc/2012032.js
@@ -50,13 +50,13 @@ function action(mode, type, selection) {
cm.getMap().broadcastMessage(MaplePacketCreator.playSound("orbis/" + harpSounds[cm.getNpc() - 2012027]));
if(cm.isQuestStarted(3114)) {
- var idx = cm.getQuestProgress(3114, 7777);
+ var idx = -1 * cm.getQuestProgressInt(3114);
- if(idx != -1) {
+ if(idx > -1) {
var nextNote = harpSong[idx];
if(harpNote != nextNote) {
- cm.setQuestProgress(3114, 7777, 0);
+ cm.setQuestProgress(3114, 0);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/wrong_kor"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Failed"));
@@ -70,7 +70,7 @@ function action(mode, type, selection) {
if(idx == 45) { // finished lullaby
cm.message("Twinkle, twinkle, little star, how I wonder what you are.");
- cm.setQuestProgress(3114, 7777, -1);
+ cm.setQuestProgress(3114, 42);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/clear"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Clear"));
@@ -88,7 +88,7 @@ function action(mode, type, selection) {
}
}
- cm.setQuestProgress(3114, 7777, idx + 1);
+ cm.setQuestProgress(3114, -1 * (idx + 1));
}
}
}
diff --git a/scripts/npc/2012033.js b/scripts/npc/2012033.js
index d066394cb3..a70af27e4f 100644
--- a/scripts/npc/2012033.js
+++ b/scripts/npc/2012033.js
@@ -50,13 +50,13 @@ function action(mode, type, selection) {
cm.getMap().broadcastMessage(MaplePacketCreator.playSound("orbis/" + harpSounds[cm.getNpc() - 2012027]));
if(cm.isQuestStarted(3114)) {
- var idx = cm.getQuestProgress(3114, 7777);
+ var idx = -1 * cm.getQuestProgressInt(3114);
- if(idx != -1) {
+ if(idx > -1) {
var nextNote = harpSong[idx];
if(harpNote != nextNote) {
- cm.setQuestProgress(3114, 7777, 0);
+ cm.setQuestProgress(3114, 0);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/wrong_kor"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Failed"));
@@ -70,7 +70,7 @@ function action(mode, type, selection) {
if(idx == 45) { // finished lullaby
cm.message("Twinkle, twinkle, little star, how I wonder what you are.");
- cm.setQuestProgress(3114, 7777, -1);
+ cm.setQuestProgress(3114, 42);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/clear"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Clear"));
@@ -88,7 +88,7 @@ function action(mode, type, selection) {
}
}
- cm.setQuestProgress(3114, 7777, idx + 1);
+ cm.setQuestProgress(3114, -1 * (idx + 1));
}
}
}
diff --git a/scripts/npc/2013001.js b/scripts/npc/2013001.js
index 5ee0327ee6..699dd060bb 100644
--- a/scripts/npc/2013001.js
+++ b/scripts/npc/2013001.js
@@ -278,7 +278,7 @@ function action(mode, type, selection) {
if(cm.getMap().countMonsters() > 0) {
cm.sendNext("This is the hidden room of the tower. After eliminating all monsters on this room, talk to me to gain access to the treasure room, leaving the center tower access behind.");
} else {
- cm.warp(920011100);
+ cm.warp(920011100, "st00");
}
break;
}
diff --git a/scripts/npc/2020008.js b/scripts/npc/2020008.js
index ce8ab3516e..dcaec7b027 100644
--- a/scripts/npc/2020008.js
+++ b/scripts/npc/2020008.js
@@ -142,7 +142,7 @@ function action(mode, type, selection){
if (cm.getPlayer().getLevel() >= 50){
cm.sendOk("The Chief's Residence Council grants you #bconcession#k to make part of the #rcounteroffensive team against Zakum#k. Good luck on your journey ahead.");
if(!(cm.isQuestStarted(100200) || cm.isQuestCompleted(100200))) cm.startQuest(100200);
- if(Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
+ if(Packages.config.YamlConfig.config.server.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
}else
cm.sendOk("You're way too weak to make part of the #rcounteroffensive team against Zakum#k. Reach at least #blevel 50#k, then talk to me.");
cm.dispose();
diff --git a/scripts/npc/2020009.js b/scripts/npc/2020009.js
index 5e759803ef..17273222ae 100644
--- a/scripts/npc/2020009.js
+++ b/scripts/npc/2020009.js
@@ -114,7 +114,7 @@ function action(mode, type, selection){
if (cm.getPlayer().getLevel() >= 50){
cm.sendOk("The Chief's Residence Council grants you #bconcession#k to make part of the #rcounteroffensive team against Zakum#k. Good luck on your journey ahead.");
if(!(cm.isQuestStarted(100200) || cm.isQuestCompleted(100200))) cm.startQuest(100200);
- if(Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
+ if(Packages.config.YamlConfig.config.server.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
}else
cm.sendOk("You're way too weak to make part of the #rcounteroffensive team against Zakum#k. Reach at least #blevel 50#k, then talk to me.");
cm.dispose();
diff --git a/scripts/npc/2020010.js b/scripts/npc/2020010.js
index b4de6203d5..7716da2276 100644
--- a/scripts/npc/2020010.js
+++ b/scripts/npc/2020010.js
@@ -115,7 +115,7 @@ function action(mode, type, selection){
if (cm.getPlayer().getLevel() >= 50){
cm.sendOk("The Chief's Residence Council grants you #bconcession#k to make part of the #rcounteroffensive team against Zakum#k. Good luck on your journey ahead.");
if(!(cm.isQuestStarted(100200) || cm.isQuestCompleted(100200))) cm.startQuest(100200);
- if(Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
+ if(Packages.config.YamlConfig.config.server.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
}else
cm.sendOk("You're way too weak to make part of the #rcounteroffensive team against Zakum#k. Reach at least #blevel 50#k, then talk to me.");
cm.dispose();
diff --git a/scripts/npc/2020011.js b/scripts/npc/2020011.js
index 811ca153f2..670f76d8f6 100644
--- a/scripts/npc/2020011.js
+++ b/scripts/npc/2020011.js
@@ -114,7 +114,7 @@ function action(mode, type, selection){
if (cm.getPlayer().getLevel() >= 50){
cm.sendOk("The Chief's Residence Council grants you #bconcession#k to make part of the #rcounteroffensive team against Zakum#k. Good luck on your journey ahead.");
if(!(cm.isQuestStarted(100200) || cm.isQuestCompleted(100200))) cm.startQuest(100200);
- if(Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
+ if(Packages.config.YamlConfig.config.server.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
}else
cm.sendOk("You're way too weak to make part of the #rcounteroffensive team against Zakum#k. Reach at least #blevel 50#k, then talk to me.");
cm.dispose();
diff --git a/scripts/npc/2020013.js b/scripts/npc/2020013.js
index f18199331d..8e593311d4 100644
--- a/scripts/npc/2020013.js
+++ b/scripts/npc/2020013.js
@@ -113,7 +113,7 @@ function action(mode, type, selection){
if (cm.getPlayer().getLevel() >= 50){
cm.sendOk("The Chief's Residence Council grants you #bconcession#k to make part of the #rcounteroffensive team against Zakum#k. Good luck on your journey ahead.");
if(!(cm.isQuestStarted(100200) || cm.isQuestCompleted(100200))) cm.startQuest(100200);
- if(Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
+ if(Packages.config.YamlConfig.config.server.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
}else
cm.sendOk("You're way too weak to make part of the #rcounteroffensive team against Zakum#k. Reach at least #blevel 50#k, then talk to me.");
cm.dispose();
diff --git a/scripts/npc/2030000.js b/scripts/npc/2030000.js
index 77b591c37b..fc7dd3e484 100644
--- a/scripts/npc/2030000.js
+++ b/scripts/npc/2030000.js
@@ -33,7 +33,7 @@ var status = 0;
function start() {
if(cm.haveItem(4031450, 1)) {
- cm.warp(921100100);
+ cm.warp(921100100, 1);
cm.dispose();
return;
}
diff --git a/scripts/npc/2030013.js b/scripts/npc/2030013.js
index d62e8f1ee2..70b45c4906 100644
--- a/scripts/npc/2030013.js
+++ b/scripts/npc/2030013.js
@@ -66,8 +66,13 @@ function action(mode, type, selection) {
cm.sendSimple("#e#b\r\n#k#n" + em.getProperty("party") + "\r\n\r\nWould you like to assemble a team to take on #r" + expedBoss + "#k?\r\n#b#L1#Lets get this going!#l\r\n\#L2#No, I think I'll wait a bit...#l");
status = 1;
} else if (expedition.isLeader(player)) { //If you're the leader, manage the exped
- cm.sendSimple(list);
- status = 2;
+ if (expedition.isInProgress()) { // thanks Conrad for noticing exped leaders being able to still manage in-progress expeds
+ cm.sendOk("Your expedition is already in progress, for those who remain battling lets pray for those brave souls.");
+ cm.dispose();
+ } else {
+ cm.sendSimple(list);
+ status = 2;
+ }
} else if (expedition.isRegistering()) { //If the expedition is registering
if (expedition.contains(player)) { //If you're in it but it hasn't started, be patient
cm.sendOk("You have already registered for the expedition. Please wait for #r" + expedition.getLeader().getName() + "#k to begin it.");
@@ -106,8 +111,11 @@ function action(mode, type, selection) {
return;
}
- if (cm.createExpedition(exped)) {
+ var res = cm.createExpedition(exped);
+ if (res == 0) {
cm.sendOk("The #r" + expedBoss + " Expedition#k has been created.\r\n\r\nTalk to me again to view the current team, or start the fight!");
+ } else if (res > 0) {
+ cm.sendOk("Sorry, you've already reached the quota of attempts for this expedition! Try again another day...");
} else {
cm.sendOk("An unexpected error has occurred when starting the expedition, please try again later.");
}
diff --git a/scripts/npc/2040016.js b/scripts/npc/2040016.js
index 1c803d4cd8..3a2a99abf8 100644
--- a/scripts/npc/2040016.js
+++ b/scripts/npc/2040016.js
@@ -172,19 +172,7 @@ function action(mode, type, selection) {
matQty = matQtySet[selectedItem];
cost = costSet[selectedItem];
}
-
- if (selectedType == 5){ //arrow refine
- var itemSet = new Array(2060000,2061000,2060001,2061001,2060002,2061002);
- var matSet = new Array(new Array (4003001,4003004),new Array (4003001,4003004),new Array (4011000,4003001,4003004),new Array (4011000,4003001,4003004),
- new Array (4011001,4003001,4003005),new Array (4011001,4003001,4003005));
- var matQtySet = new Array (new Array (1,1),new Array (1,1),new Array (1,3,10),new Array (1,3,10),new Array (1,5,15),new Array (1,5,15));
- var costSet = new Array (0,0,0,0,0,0);
- item = itemSet[selectedItem];
- mats = matSet[selectedItem];
- matQty = matQtySet[selectedItem];
- cost = costSet[selectedItem];
- }
-
+
var prompt = "So, you want me to make some #t" + item + "#s? In that case, how many do you want me to make?";
cm.sendGetNumber(prompt,1,1,100)
@@ -197,6 +185,19 @@ function action(mode, type, selection) {
}
else
qty = (selection > 0) ? selection : (selection < 0 ? -selection : 1);
+
+ // thanks kvmba for noticing arrow selection crashing players
+ if (selectedType == 5){ //arrow refine
+ var itemSet = new Array(2060000,2061000,2060001,2061001,2060002,2061002);
+ var matSet = new Array(new Array (4003001,4003004),new Array (4003001,4003004),new Array (4011000,4003001,4003004),new Array (4011000,4003001,4003004),
+ new Array (4011001,4003001,4003005),new Array (4011001,4003001,4003005));
+ var matQtySet = new Array (new Array (1,1),new Array (1,1),new Array (1,3,10),new Array (1,3,10),new Array (1,5,15),new Array (1,5,15));
+ var costSet = new Array (0,0,0,0,0,0);
+ item = itemSet[selectedItem];
+ mats = matSet[selectedItem];
+ matQty = matQtySet[selectedItem];
+ cost = costSet[selectedItem];
+ }
var prompt = "You want me to make ";
if (qty == 1)
diff --git a/scripts/npc/2040045.js b/scripts/npc/2040045.js
index 228077ff59..01f546487b 100644
--- a/scripts/npc/2040045.js
+++ b/scripts/npc/2040045.js
@@ -54,7 +54,7 @@ function action(mode, type, selection) {
cm.sendYesNo("Would you like to leave the bonus stage?");
}
else {
- cm.warp(922011100);
+ cm.warp(922011100, "st00");
cm.dispose();
}
}
diff --git a/scripts/npc/2041007.js b/scripts/npc/2041007.js
index 59a102cd00..05a22869a6 100644
--- a/scripts/npc/2041007.js
+++ b/scripts/npc/2041007.js
@@ -81,7 +81,10 @@ function action(mode, type, selection) {
else if (status == 2){
cm.dispose();
if (beauty == 1){
- if (cm.haveItem(5150007) == true){
+ if (cm.haveItem(5420005)){
+ cm.setHair(hairnew[selection]);
+ cm.sendOk("Enjoy your new and improved hairstyle!");
+ } else if (cm.haveItem(5150007) == true){
cm.gainItem(5150007, -1);
cm.setHair(hairnew[selection]);
cm.sendOk("Enjoy your new and improved hairstyle!");
diff --git a/scripts/npc/2042000.js b/scripts/npc/2042000.js
index 010bdd7d89..1b20c94ed7 100644
--- a/scripts/npc/2042000.js
+++ b/scripts/npc/2042000.js
@@ -30,8 +30,8 @@ var feeMultiplier = 7.0;
function start() {
status = -1;
- if (!Packages.constants.ServerConstants.USE_CPQ) {
- if (Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
+ if (!Packages.config.YamlConfig.config.server.USE_CPQ) {
+ if (Packages.config.YamlConfig.config.server.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
status = 0;
action(1, 0, 4);
} else {
@@ -221,9 +221,9 @@ function action(mode, type, selection) {
}
} else {
var party = cm.getParty().getMembers();
- if ((selection >= 0 && selection <= 3) && party.size() < (Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS ? 1 : 2)) {
+ if ((selection >= 0 && selection <= 3) && party.size() < (Packages.config.YamlConfig.config.server.USE_ENABLE_SOLO_EXPEDITIONS ? 1 : 2)) {
cm.sendOk("You need at least 2 players to participate in the battle!");
- } else if ((selection >= 4 && selection <= 5) && party.size() < (Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS ? 1 : 3)) {
+ } else if ((selection >= 4 && selection <= 5) && party.size() < (Packages.config.YamlConfig.config.server.USE_ENABLE_SOLO_EXPEDITIONS ? 1 : 3)) {
cm.sendOk("You need at least 3 players to participate in the battle!");
} else {
cm.cpqLobby(selection);
@@ -236,7 +236,7 @@ function action(mode, type, selection) {
} else {
if (status == 0) {
var talk = "What would you like to do? If you have never participate in the Monster Carnival, you will need to know a few things before participating! \r\n#b#L0# Go to the Monster Carnival 1.#l \r\n#L3# Go to the Monster Carnival 2.#l \r\n#L1# Learn about the Monster Carnival.#l\r\n#L2# Trade #t4001129#.#l";
- if (Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
+ if (Packages.config.YamlConfig.config.server.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
talk += "\r\n#L4# ... Can I just refine my ores?#l";
}
cm.sendSimple(talk);
@@ -437,7 +437,7 @@ function action(mode, type, selection) {
cm.sendNext("Oh, and do not worry about turning into a ghost. In the Monster Carnival, #byou will not lose EXP after death#k. So it's really an experience like no other!");
cm.dispose();
} else if (select == 2) {
- cm.sendNext("#bProtetor#k basically an invoked item that drastically increases the abilities of the monsters invoked by your group. Protector works until it is demolished by the opposing group, so I'm hoping you'll summon several monsters first, and then bring the Protector.");
+ cm.sendNext("#bProtector#k is basically an invoked item that drastically increases the abilities of the monsters invoked by your group. Protector works until it is demolished by the opposing group, so I'm hoping you'll summon several monsters first, and then bring the Protector.");
}
} else if (status == 66) {
cm.sendNext("Lastly, while in the Monster Carnival, #byou can not use items / recovery potions that you carry around with you. #kMeanwhile, the monsters let these items fall for good. when, and when you #bget them, the item will immediately activate#k. That's why it's important to know when to get these items.");
diff --git a/scripts/npc/2042001.js b/scripts/npc/2042001.js
index 35c7190b56..7d57140f9e 100644
--- a/scripts/npc/2042001.js
+++ b/scripts/npc/2042001.js
@@ -29,8 +29,8 @@ var feeMultiplier = 7.0;
function start() {
status = -1;
- if (!Packages.constants.ServerConstants.USE_CPQ) {
- if (Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
+ if (!Packages.config.YamlConfig.config.server.USE_CPQ) {
+ if (Packages.config.YamlConfig.config.server.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
status = 0;
action(1, 0, 4);
} else {
@@ -220,9 +220,9 @@ function action(mode, type, selection) {
}
} else {
var party = cm.getParty().getMembers();
- if ((selection >= 0 && selection <= 3) && party.size() < (Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS ? 1 : 2)) {
+ if ((selection >= 0 && selection <= 3) && party.size() < (Packages.config.YamlConfig.config.server.USE_ENABLE_SOLO_EXPEDITIONS ? 1 : 2)) {
cm.sendOk("You need at least 2 players to participate in the battle!");
- } else if ((selection >= 4 && selection <= 5) && party.size() < (Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS ? 1 : 3)) {
+ } else if ((selection >= 4 && selection <= 5) && party.size() < (Packages.config.YamlConfig.config.server.USE_ENABLE_SOLO_EXPEDITIONS ? 1 : 3)) {
cm.sendOk("You need at least 3 players to participate in the battle!");
} else {
cm.cpqLobby(selection);
@@ -235,7 +235,7 @@ function action(mode, type, selection) {
} else {
if (status == 0) {
var talk = "What would you like to do? If you have never participate in the Monster Carnival, you will need to know a few things before participating! \r\n#b#L0# Go to the Monster Carnival 1.#l \r\n#L3# Go to the Monster Carnival 2.#l \r\n#L1# Learn about the Monster Carnival.#l\r\n#L2# Trade #t4001129#.#l";
- if (Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
+ if (Packages.config.YamlConfig.config.server.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
talk += "\r\n#L4# ... Can I just refine my ores?#l";
}
cm.sendSimple(talk);
diff --git a/scripts/npc/2042002.js b/scripts/npc/2042002.js
index 4a24bb8a19..8ffd18763d 100644
--- a/scripts/npc/2042002.js
+++ b/scripts/npc/2042002.js
@@ -29,8 +29,8 @@ var feeMultiplier = 7.0;
function start() {
status = -1;
- if (!Packages.constants.ServerConstants.USE_CPQ) {
- if (Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
+ if (!Packages.config.YamlConfig.config.server.USE_CPQ) {
+ if (Packages.config.YamlConfig.config.server.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
status = 0;
action(1, 0, 4);
} else {
@@ -235,7 +235,7 @@ function action(mode, type, selection) {
} else {
if (status == 0) {
var talk = "What would you like to do? If you have never participate in the Monster Carnival, you will need to know a few things before participating! \r\n#b#L0# Go to the Monster Carnival 1.#l \r\n#L3# Go to the Monster Carnival 2.#l \r\n#L1# Learn about the Monster Carnival.#l\r\n#L2# Trade #t4001129#.#l";
- if (Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
+ if (Packages.config.YamlConfig.config.server.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
talk += "\r\n#L4# ... Can I just refine my ores?#l";
}
cm.sendSimple(talk);
diff --git a/scripts/npc/2042005.js b/scripts/npc/2042005.js
index 5008b8ef80..efb085c16a 100644
--- a/scripts/npc/2042005.js
+++ b/scripts/npc/2042005.js
@@ -77,9 +77,9 @@ function action(mode, type, selection) {
}
} else {
var party = cm.getParty().getMembers();
- if ((selection === 0 || selection === 1 ) && party.size() < (Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS ? 1 : 2)) {
+ if ((selection === 0 || selection === 1 ) && party.size() < (Packages.config.YamlConfig.config.server.USE_ENABLE_SOLO_EXPEDITIONS ? 1 : 2)) {
cm.sendOk("You need at least 2 players to participate in the battle!");
- } else if ((selection === 2 ) && party.size() < (Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS ? 1 : 3)) {
+ } else if ((selection === 2 ) && party.size() < (Packages.config.YamlConfig.config.server.USE_ENABLE_SOLO_EXPEDITIONS ? 1 : 3)) {
cm.sendOk("You need at least 3 players to participate in the battle!");
} else {
cm.cpqLobby2(selection);
diff --git a/scripts/npc/2050014.js b/scripts/npc/2050014.js
index 30c337d789..26a43ecf67 100644
--- a/scripts/npc/2050014.js
+++ b/scripts/npc/2050014.js
@@ -45,13 +45,13 @@ function action(mode, type, selection) {
if(cm.isQuestStarted(3421)) {
var meteoriteId = cm.getNpc() - 2050014;
- var progress = cm.getQuestProgress(3421, 0);
+ var progress = cm.getQuestProgressInt(3421, 1);
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
if (cm.canHold(4031117, 1)) {
progress |= (1 << meteoriteId);
cm.gainItem(4031117, 1);
- cm.setQuestProgress(3421, 0, progress);
+ cm.setQuestProgress(3421, 1, progress);
} else {
cm.getPlayer().dropMessage(1, "Have a ETC slot available for this item.");
}
diff --git a/scripts/npc/2050015.js b/scripts/npc/2050015.js
index 30c337d789..26a43ecf67 100644
--- a/scripts/npc/2050015.js
+++ b/scripts/npc/2050015.js
@@ -45,13 +45,13 @@ function action(mode, type, selection) {
if(cm.isQuestStarted(3421)) {
var meteoriteId = cm.getNpc() - 2050014;
- var progress = cm.getQuestProgress(3421, 0);
+ var progress = cm.getQuestProgressInt(3421, 1);
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
if (cm.canHold(4031117, 1)) {
progress |= (1 << meteoriteId);
cm.gainItem(4031117, 1);
- cm.setQuestProgress(3421, 0, progress);
+ cm.setQuestProgress(3421, 1, progress);
} else {
cm.getPlayer().dropMessage(1, "Have a ETC slot available for this item.");
}
diff --git a/scripts/npc/2050016.js b/scripts/npc/2050016.js
index 30c337d789..26a43ecf67 100644
--- a/scripts/npc/2050016.js
+++ b/scripts/npc/2050016.js
@@ -45,13 +45,13 @@ function action(mode, type, selection) {
if(cm.isQuestStarted(3421)) {
var meteoriteId = cm.getNpc() - 2050014;
- var progress = cm.getQuestProgress(3421, 0);
+ var progress = cm.getQuestProgressInt(3421, 1);
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
if (cm.canHold(4031117, 1)) {
progress |= (1 << meteoriteId);
cm.gainItem(4031117, 1);
- cm.setQuestProgress(3421, 0, progress);
+ cm.setQuestProgress(3421, 1, progress);
} else {
cm.getPlayer().dropMessage(1, "Have a ETC slot available for this item.");
}
diff --git a/scripts/npc/2050017.js b/scripts/npc/2050017.js
index 30c337d789..26a43ecf67 100644
--- a/scripts/npc/2050017.js
+++ b/scripts/npc/2050017.js
@@ -45,13 +45,13 @@ function action(mode, type, selection) {
if(cm.isQuestStarted(3421)) {
var meteoriteId = cm.getNpc() - 2050014;
- var progress = cm.getQuestProgress(3421, 0);
+ var progress = cm.getQuestProgressInt(3421, 1);
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
if (cm.canHold(4031117, 1)) {
progress |= (1 << meteoriteId);
cm.gainItem(4031117, 1);
- cm.setQuestProgress(3421, 0, progress);
+ cm.setQuestProgress(3421, 1, progress);
} else {
cm.getPlayer().dropMessage(1, "Have a ETC slot available for this item.");
}
diff --git a/scripts/npc/2050018.js b/scripts/npc/2050018.js
index 30c337d789..26a43ecf67 100644
--- a/scripts/npc/2050018.js
+++ b/scripts/npc/2050018.js
@@ -45,13 +45,13 @@ function action(mode, type, selection) {
if(cm.isQuestStarted(3421)) {
var meteoriteId = cm.getNpc() - 2050014;
- var progress = cm.getQuestProgress(3421, 0);
+ var progress = cm.getQuestProgressInt(3421, 1);
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
if (cm.canHold(4031117, 1)) {
progress |= (1 << meteoriteId);
cm.gainItem(4031117, 1);
- cm.setQuestProgress(3421, 0, progress);
+ cm.setQuestProgress(3421, 1, progress);
} else {
cm.getPlayer().dropMessage(1, "Have a ETC slot available for this item.");
}
diff --git a/scripts/npc/2050019.js b/scripts/npc/2050019.js
index 30c337d789..26a43ecf67 100644
--- a/scripts/npc/2050019.js
+++ b/scripts/npc/2050019.js
@@ -45,13 +45,13 @@ function action(mode, type, selection) {
if(cm.isQuestStarted(3421)) {
var meteoriteId = cm.getNpc() - 2050014;
- var progress = cm.getQuestProgress(3421, 0);
+ var progress = cm.getQuestProgressInt(3421, 1);
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
if (cm.canHold(4031117, 1)) {
progress |= (1 << meteoriteId);
cm.gainItem(4031117, 1);
- cm.setQuestProgress(3421, 0, progress);
+ cm.setQuestProgress(3421, 1, progress);
} else {
cm.getPlayer().dropMessage(1, "Have a ETC slot available for this item.");
}
diff --git a/scripts/npc/2060005.js b/scripts/npc/2060005.js
index d9a2009733..e2ee871223 100644
--- a/scripts/npc/2060005.js
+++ b/scripts/npc/2060005.js
@@ -32,12 +32,19 @@ function start() {
cm.sendOk("Thanks for saving the pork.");
}
else if(cm.isQuestStarted(6002)) {
- var em = cm.getEventManager("3rdJob_mount");
- if (em == null)
- cm.sendOk("Sorry, but 3rd job advancement (mount) is closed.");
- else {
- if (!em.startInstance(cm.getPlayer())) {
- cm.sendOk("There is currently someone in this map, come back later.");
+ if (cm.haveItem(4031507, 5) && cm.haveItem(4031508,5)) {
+ cm.sendOk("Thanks for saving the pork.");
+ } else {
+ var em = cm.getEventManager("3rdJob_mount");
+ if (em == null)
+ cm.sendOk("Sorry, but 3rd job advancement (mount) is closed.");
+ else {
+ if (em.startInstance(cm.getPlayer())) {
+ cm.removeAll(4031507);
+ cm.removeAll(4031508);
+ } else {
+ cm.sendOk("There is currently someone in this map, come back later.");
+ }
}
}
}
diff --git a/scripts/npc/2071012.js b/scripts/npc/2071012.js
index c50775950a..c5d24d199a 100644
--- a/scripts/npc/2071012.js
+++ b/scripts/npc/2071012.js
@@ -23,7 +23,7 @@ function action(mode, type, selection) {
status--;
if(status == 0) {
- if(cm.getQuestProgress(23647, 0) != 0) {
+ if(cm.getQuestProgressInt(23647, 1) != 0) {
cm.dispose();
return;
}
@@ -39,7 +39,7 @@ function action(mode, type, selection) {
cm.sendNext("Teehehee~ That's your reward for taking it from me, serves you well.");
cm.gainItem(4031793, -1);
cm.gainFame(-5);
- cm.setQuestProgress(23647, 0, 1);
+ cm.setQuestProgress(23647, 1, 1);
cm.dispose();
}
diff --git a/scripts/npc/2081009.js b/scripts/npc/2081009.js
index 553e5a8596..d49ae9513a 100644
--- a/scripts/npc/2081009.js
+++ b/scripts/npc/2081009.js
@@ -36,7 +36,7 @@ function action(mode, type, selection) {
status++;
if(status == 0) {
- if(cm.isQuestStarted(6180)) {
+ if(cm.isQuestStarted(6180) && cm.getQuestProgressInt(6180, 9300096) < 200) {
cm.sendYesNo("Pay attention: during the time you stay inside the training ground make sure you #bhave equipped your #t1092041##k, it is of the utmost importance. Are you ready to proceed to the training area?");
}
@@ -47,10 +47,15 @@ function action(mode, type, selection) {
}
else if(status == 1) {
- cm.warp(924000001, 0);
- cm.sendOk("Have your shield equipped until the end of the quest, or else you will need to start all over again!");
-
- cm.resetQuestProgress(6180,9300096);
+ if (cm.getPlayer().haveItemEquipped(1092041)) {
+ cm.sendNext("Have your shield equipped until the end of the quest, or else you will need to start all over again!");
+ } else {
+ cm.sendOk("Please equip the #r#t1092041##k before entering the training ground.");
+ cm.dispose();
+ }
+ }
+ else {
+ cm.warp(924000001, 0);
cm.dispose();
}
}
diff --git a/scripts/npc/2081010.js b/scripts/npc/2081010.js
index 0b564e2398..019a545276 100644
--- a/scripts/npc/2081010.js
+++ b/scripts/npc/2081010.js
@@ -44,7 +44,7 @@ function action(mode, type, selection){
}
else if(status == 1) {
- cm.warp(exitMap);
+ cm.warp(exitMap, "st00");
cm.dispose();
}
}
diff --git a/scripts/npc/2082014.js b/scripts/npc/2082014.js
index 1ad06b94b2..6b0eac71fd 100644
--- a/scripts/npc/2082014.js
+++ b/scripts/npc/2082014.js
@@ -39,7 +39,7 @@ function action(mode, type, selection) {
status--;
if(status == 0) {
- if (Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
+ if (Packages.config.YamlConfig.config.server.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
cm.openShopNPC(2082014);
} else if (cm.isQuestStarted(3749)) {
cm.sendOk("We've already located the enemy's ultimate weapon! Follow along the ship's bow area ahead and you will find my sister #b#p2082013##k. Report to her for futher instructions on the mission.");
diff --git a/scripts/npc/2083000.js b/scripts/npc/2083000.js
index f59c817e1e..ee3b07b2f6 100644
--- a/scripts/npc/2083000.js
+++ b/scripts/npc/2083000.js
@@ -45,7 +45,7 @@ function action(mode, type, selection) {
if (status == 0) {
if(cm.haveItem(4001086)) {
cm.sendYesNo("Do you want to access #b#m240050400##k right now?");
- } else if(Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS) {
+ } else if(Packages.config.YamlConfig.config.server.USE_ENABLE_SOLO_EXPEDITIONS) {
if(canBypassHTPQ()) {
cm.sendYesNo("Do you want to access #b#m240050400##k right now?");
} else {
diff --git a/scripts/npc/2083002.js b/scripts/npc/2083002.js
index 14328826c0..c7cbd07632 100644
--- a/scripts/npc/2083002.js
+++ b/scripts/npc/2083002.js
@@ -34,7 +34,7 @@ function action(mode, type, selection) {
cm.dispose();
else {
if(cm.getMapId() > 240050400) cm.warp(240050600);
- else cm.warp(240040700);
+ else cm.warp(240040700, "out00");
cm.dispose();
}
diff --git a/scripts/npc/2083004.js b/scripts/npc/2083004.js
index b0501ee64d..f13fc27bcf 100644
--- a/scripts/npc/2083004.js
+++ b/scripts/npc/2083004.js
@@ -64,8 +64,13 @@ function action(mode, type, selection) {
cm.sendSimple("#e#b\r\n#k#n" + em.getProperty("party") + "\r\n\r\nWould you like to assemble a team to take on #r" + expedBoss + "#k?\r\n#b#L1#Lets get this going!#l\r\n\#L2#No, I think I'll wait a bit...#l");
status = 1;
} else if (expedition.isLeader(player)) { //If you're the leader, manage the exped
- cm.sendSimple(list);
- status = 2;
+ if (expedition.isInProgress()) {
+ cm.sendOk("Your expedition is already in progress, for those who remain battling lets pray for those brave souls.");
+ cm.dispose();
+ } else {
+ cm.sendSimple(list);
+ status = 2;
+ }
} else if (expedition.isRegistering()) { //If the expedition is registering
if (expedition.contains(player)) { //If you're in it but it hasn't started, be patient
cm.sendOk("You have already registered for the expedition. Please wait for #r" + expedition.getLeader().getName() + "#k to begin it.");
@@ -98,8 +103,11 @@ function action(mode, type, selection) {
return;
}
- if (cm.createExpedition(exped)) {
+ var res = cm.createExpedition(exped);
+ if (res == 0) {
cm.sendOk("The #r" + expedBoss + " Expedition#k has been created.\r\n\r\nTalk to me again to view the current team, or start the fight!");
+ } else if (res > 0) {
+ cm.sendOk("Sorry, you've already reached the quota of attempts for this expedition! Try again another day...");
} else {
cm.sendOk("An unexpected error has occurred when starting the expedition, please try again later.");
}
diff --git a/scripts/npc/2090004.js b/scripts/npc/2090004.js
index e7dc6ff8e0..c4fd175836 100644
--- a/scripts/npc/2090004.js
+++ b/scripts/npc/2090004.js
@@ -217,7 +217,7 @@ function action(mode, type, selection) {
complete = false;
}
- if(java.lang.Math.random() >= 0.9) //A lucky find! Scroll 60%
+ if(Math.random() >= 0.9) //A lucky find! Scroll 60%
item += 1;
if (!complete || !cm.canHold(item, 1))
@@ -251,7 +251,7 @@ function action(mode, type, selection) {
var reward;
if (rewdSet[selectedItem] instanceof Array) {
var length = rewdSet[selectedItem][1] - rewdSet[selectedItem][0];
- reward = rewdSet[selectedItem][0] + java.lang.Math.round(java.lang.Math.random() * length);
+ reward = rewdSet[selectedItem][0] + Math.round(Math.random() * length);
}
else reward = rewdSet[selectedItem];
diff --git a/scripts/npc/2090100.js b/scripts/npc/2090100.js
index 39b418b198..a4e7ad8b81 100644
--- a/scripts/npc/2090100.js
+++ b/scripts/npc/2090100.js
@@ -81,7 +81,10 @@ function action(mode, type, selection) {
else if (status == 2){
cm.dispose();
if (beauty == 1){
- if (cm.haveItem(5150025)){
+ if (cm.haveItem(5420006)){
+ cm.setHair(hairnew[selection]);
+ cm.sendOk("Enjoy your new and improved hairstyle!");
+ } else if (cm.haveItem(5150025)){
cm.gainItem(5150025, -1);
cm.setHair(hairnew[selection]);
cm.sendOk("Enjoy your new and improved hairstyle!");
diff --git a/scripts/npc/2091005.js b/scripts/npc/2091005.js
index 65cfa36f5d..33dbc760b4 100644
--- a/scripts/npc/2091005.js
+++ b/scripts/npc/2091005.js
@@ -25,7 +25,7 @@
* @Map(s): Dojo Hall
*/
-importPackage(Packages.constants);
+importPackage(Packages.config);
var disabled = false;
var belts = Array(1132000, 1132001, 1132002, 1132003, 1132004);
@@ -44,7 +44,7 @@ function start() {
return;
}
- belt_points = ServerConstants.USE_FAST_DOJO_UPGRADE ? Array(10, 90, 200, 460, 850) : Array(200, 1800, 4000, 9200, 17000);
+ belt_points = YamlConfig.config.server.USE_FAST_DOJO_UPGRADE ? Array(10, 90, 200, 460, 850) : Array(200, 1800, 4000, 9200, 17000);
belt_on_inventory = new Array();
for (var i = 0; i < belts.length; i++) {
@@ -330,7 +330,7 @@ function action(mode, type, selection) {
cm.sendYesNo("So, you're giving up? You're really going to leave?");
} else {
if (mode == 1) {
- cm.warp(925020002);
+ cm.warp(925020002, "st00");
}
cm.dispose();
return;
diff --git a/scripts/npc/2091005_old.js b/scripts/npc/2091005_old.js
index ffaae970cf..028204db39 100644
--- a/scripts/npc/2091005_old.js
+++ b/scripts/npc/2091005_old.js
@@ -225,7 +225,7 @@ function action(mode, type, selection) {
cm.sendAcceptDecline("So, you're giving up? You're really going to leave?");
} else {
if (mode == 1) {
- cm.warp(925020002);
+ cm.warp(925020002, "st00");
}
cm.dispose();
}
diff --git a/scripts/npc/2091009.js b/scripts/npc/2091009.js
index 2e6a02cb6e..c72fb2ca9b 100644
--- a/scripts/npc/2091009.js
+++ b/scripts/npc/2091009.js
@@ -27,10 +27,10 @@ function action(mode, type, selection){
return;
}
if(cm.getText() == "Actions speak louder than words"){
- if(cm.isQuestStarted(21747) && cm.getQuestProgress(21747, 9300351) == 0)
+ if(cm.isQuestStarted(21747) && cm.getQuestProgressInt(21747, 9300351) == 0)
cm.warp(925040100, 0);
else
- cm.playerMessage(5, "Although you said the right answer, some mysterious forces is blocking the way in.");
+ cm.playerMessage(5, "Although you said the right answer, some mysterious forces are blocking the way in.");
cm.dispose();
}
diff --git a/scripts/npc/2101014.js b/scripts/npc/2101014.js
index 95e68a20b8..3058076035 100644
--- a/scripts/npc/2101014.js
+++ b/scripts/npc/2101014.js
@@ -134,9 +134,12 @@ function enterArena(arenaPlayers) {
return;
} else if (expedicao == null) {
if (arenaPlayers != -1) {
- if (cm.createExpedition(exped, true, 0, arenaPlayers)) {
+ var res = cm.createExpedition(exped, true, 0, arenaPlayers);
+ if (res == 0) {
cm.warp(map, 0);
cm.getPlayer().dropMessage("Your arena was created successfully. Wait for people to join the battle.");
+ } else if (res > 0) {
+ cm.sendOk("Sorry, you've already reached the quota of attempts for this expedition! Try again another day...");
} else {
cm.sendOk("An unexpected error has occurred when starting the expedition, please try again later.");
}
diff --git a/scripts/npc/2101017.js b/scripts/npc/2101017.js
index 03318dabce..035e2e0b94 100644
--- a/scripts/npc/2101017.js
+++ b/scripts/npc/2101017.js
@@ -115,7 +115,7 @@ function action(mode, type, selection) {
status = 2;
}
}
- } else if (Packages.constants.GameConstants.isAriantColiseumArena(cm.getPlayer().getMapId())) {
+ } else if (Packages.constants.game.GameConstants.isAriantColiseumArena(cm.getPlayer().getMapId())) {
if (cm.getPlayer().getMapId() == 980010101) {
exped = MapleExpeditionType.ARIANT;
expedicao = cm.getExpedition(exped);
diff --git a/scripts/npc/2103000.js b/scripts/npc/2103000.js
index 2784b55ff9..ae5cd41956 100644
--- a/scripts/npc/2103000.js
+++ b/scripts/npc/2103000.js
@@ -40,9 +40,9 @@ function action(mode, type, selection) {
else
status--;
if (status == 0 && mode == 1) {
- if(cm.isQuestStarted(3900) && cm.getPlayer().getQuestInfo(3900) != 5) {
+ if(cm.isQuestStarted(3900) && cm.getQuestProgressInt(3900) != 5) {
cm.sendOk("#b(You drink the water from the oasis and feel refreshed.)", 2);
- cm.getPlayer().updateQuestInfo(3900, "5");
+ cm.setQuestProgress(3900, 5);
} else if(cm.isQuestCompleted(3938)) {
if(cm.canHold(2210005)) {
if(!cm.haveItem(2210005) && !isTigunMorphed(cm.getPlayer())) {
diff --git a/scripts/npc/2103003.js b/scripts/npc/2103003.js
index 50286a9e9f..98960f3301 100644
--- a/scripts/npc/2103003.js
+++ b/scripts/npc/2103003.js
@@ -43,11 +43,15 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3929)) {
- if(cm.getQuestProgress(3929, 0) != 1) {
- if(cm.haveItem(4031580)) {
- cm.gainItem(4031580, -1);
- cm.setQuestProgress(3929, 0, 1);
- }
+ var progress = cm.getQuestProgress(3929);
+ var slot = 0;
+
+ var ch = progress[slot];
+ if(ch == '2') {
+ var nextProgress = progress.substr(0, slot) + '3' + progress.substr(slot + 1);
+
+ cm.gainItem(4031580, -1);
+ cm.setQuestProgress(3929, nextProgress);
}
}
diff --git a/scripts/npc/2103004.js b/scripts/npc/2103004.js
index f75ae50dbc..24d3e420f5 100644
--- a/scripts/npc/2103004.js
+++ b/scripts/npc/2103004.js
@@ -43,11 +43,15 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3929)) {
- if(cm.getQuestProgress(3929, 2) != 1) {
- if(cm.haveItem(4031580)) {
- cm.gainItem(4031580, -1);
- cm.setQuestProgress(3929, 2, 1);
- }
+ var progress = cm.getQuestProgress(3929);
+ var slot = 2;
+
+ var ch = progress[slot];
+ if(ch == '2') {
+ var nextProgress = progress.substr(0, slot) + '3' + progress.substr(slot + 1);
+
+ cm.gainItem(4031580, -1);
+ cm.setQuestProgress(3929, nextProgress);
}
}
diff --git a/scripts/npc/2103005.js b/scripts/npc/2103005.js
index 8455762360..83898e072b 100644
--- a/scripts/npc/2103005.js
+++ b/scripts/npc/2103005.js
@@ -43,11 +43,15 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3929)) {
- if(cm.getQuestProgress(3929, 1) != 1) {
- if(cm.haveItem(4031580)) {
- cm.gainItem(4031580, -1);
- cm.setQuestProgress(3929, 1, 1);
- }
+ var progress = cm.getQuestProgress(3929);
+ var slot = 1;
+
+ var ch = progress[slot];
+ if(ch == '2') {
+ var nextProgress = progress.substr(0, slot) + '3' + progress.substr(slot + 1);
+
+ cm.gainItem(4031580, -1);
+ cm.setQuestProgress(3929, nextProgress);
}
}
diff --git a/scripts/npc/2103006.js b/scripts/npc/2103006.js
index df5c0e26a8..d6c45109ef 100644
--- a/scripts/npc/2103006.js
+++ b/scripts/npc/2103006.js
@@ -43,11 +43,15 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3929)) {
- if(cm.getQuestProgress(3929, 3) != 1) {
- if(cm.haveItem(4031580)) {
- cm.gainItem(4031580, -1);
- cm.setQuestProgress(3929, 3, 1);
- }
+ var progress = cm.getQuestProgress(3929);
+ var slot = 3;
+
+ var ch = progress[slot];
+ if(ch == '2') {
+ var nextProgress = progress.substr(0, slot) + '3' + progress.substr(slot + 1);
+
+ cm.gainItem(4031580, -1);
+ cm.setQuestProgress(3929, nextProgress);
}
}
diff --git a/scripts/npc/2103009.js b/scripts/npc/2103009.js
index dfa158a39f..33a4eaf1fa 100644
--- a/scripts/npc/2103009.js
+++ b/scripts/npc/2103009.js
@@ -43,11 +43,15 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3926)) {
- if(cm.getQuestProgress(3926, 0) != 1) {
- if(cm.haveItem(4031579)) {
- cm.gainItem(4031579, -1);
- cm.setQuestProgress(3926, 0, 1);
- }
+ var progress = cm.getQuestProgress(3926);
+ var slot = 0;
+
+ var ch = progress[slot];
+ if(ch == '2') {
+ var nextProgress = progress.substr(0, slot) + '3' + progress.substr(slot + 1);
+
+ cm.gainItem(4031579, -1);
+ cm.setQuestProgress(3926, nextProgress);
}
}
diff --git a/scripts/npc/2103010.js b/scripts/npc/2103010.js
index f3026eab3c..f6c8ad13e1 100644
--- a/scripts/npc/2103010.js
+++ b/scripts/npc/2103010.js
@@ -43,11 +43,15 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3926)) {
- if(cm.getQuestProgress(3926, 2) != 1) {
- if(cm.haveItem(4031579)) {
- cm.gainItem(4031579, -1);
- cm.setQuestProgress(3926, 2, 1);
- }
+ var progress = cm.getQuestProgress(3926);
+ var slot = 2;
+
+ var ch = progress[slot];
+ if(ch == '2') {
+ var nextProgress = progress.substr(0, slot) + '3' + progress.substr(slot + 1);
+
+ cm.gainItem(4031579, -1);
+ cm.setQuestProgress(3926, nextProgress);
}
}
diff --git a/scripts/npc/2103011.js b/scripts/npc/2103011.js
index 57d4b461fd..617dceae09 100644
--- a/scripts/npc/2103011.js
+++ b/scripts/npc/2103011.js
@@ -43,11 +43,15 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3926)) {
- if(cm.getQuestProgress(3926, 1) != 1) {
- if(cm.haveItem(4031579)) {
- cm.gainItem(4031579, -1);
- cm.setQuestProgress(3926, 1, 1);
- }
+ var progress = cm.getQuestProgress(3926);
+ var slot = 1;
+
+ var ch = progress[slot];
+ if(ch == '2') {
+ var nextProgress = progress.substr(0, slot) + '3' + progress.substr(slot + 1);
+
+ cm.gainItem(4031579, -1);
+ cm.setQuestProgress(3926, nextProgress);
}
}
diff --git a/scripts/npc/2103012.js b/scripts/npc/2103012.js
index f520329490..63b9f4874b 100644
--- a/scripts/npc/2103012.js
+++ b/scripts/npc/2103012.js
@@ -43,11 +43,15 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3926)) {
- if(cm.getQuestProgress(3926, 3) != 1) {
- if(cm.haveItem(4031579)) {
- cm.gainItem(4031579, -1);
- cm.setQuestProgress(3926, 3, 1);
- }
+ var progress = cm.getQuestProgress(3926);
+ var slot = 3;
+
+ var ch = progress[slot];
+ if(ch == '2') {
+ var nextProgress = progress.substr(0, slot) + '3' + progress.substr(slot + 1);
+
+ cm.gainItem(4031579, -1);
+ cm.setQuestProgress(3926, nextProgress);
}
}
diff --git a/scripts/npc/2103013.js b/scripts/npc/2103013.js
index 78f339dc10..9eddad86c0 100644
--- a/scripts/npc/2103013.js
+++ b/scripts/npc/2103013.js
@@ -66,7 +66,7 @@ function action(mode, type, selection) {
} else if (selection == 4) {
cm.sendNext("Inside Pharaoh Yeti's Tomb, you can acquire a #e#b#t2022613##k#n by proving yourself capable of defeating the #bPharaoh Jr. Yeti#k, the Pharaoh's clone. Inside that box lies a very special treasure. It is the #e#b#t1132012##k#n.\r\n#i1132012:# #t1132012#\r\n\r\n And if you are somehow able to survive Hell Mode, you will receive the #e#b#t1132013##k#n.\r\n\r\n#i1132013:# #t1132013#\r\n\r\n Though, of course, Nett won't allow that to happen.");
} else if (selection == 5) {
- var progress = cm.getQuestProgress(29932);
+ var progress = cm.getQuestProgressInt(29932);
if (progress >= 50000)
cm.dispose();
else
diff --git a/scripts/npc/2111000.js b/scripts/npc/2111000.js
index 2a40b90e32..3ae1c9dba4 100644
--- a/scripts/npc/2111000.js
+++ b/scripts/npc/2111000.js
@@ -30,7 +30,7 @@
*/
function start() {
if(cm.isQuestStarted(3310) && !cm.haveItem(4031709, 1)) {
- cm.warp(926120100);
+ cm.warp(926120100, "out00");
} else {
cm.sendNext("Alchemy....and Alchemist.....both of them are important. But more importantly, it is the Magatia that tolerate everything. The honor of Magatia should be protected by me.");
}
diff --git a/scripts/npc/2111003.js b/scripts/npc/2111003.js
index 09346b348a..82901da15b 100644
--- a/scripts/npc/2111003.js
+++ b/scripts/npc/2111003.js
@@ -33,7 +33,7 @@
function start() {
if(cm.isQuestStarted(3335) && !cm.haveItem(4031695, 1)) {
- cm.warp(926120300);
+ cm.warp(926120300, "out00");
cm.dispose();
} else {
cm.sendOk("Emotion that I feel is real? Or just illusion coming from mechanical error?");
diff --git a/scripts/npc/2111011.js b/scripts/npc/2111011.js
new file mode 100644
index 0000000000..8b8b43f8de
--- /dev/null
+++ b/scripts/npc/2111011.js
@@ -0,0 +1,25 @@
+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.dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/scripts/npc/2111012.js b/scripts/npc/2111012.js
new file mode 100644
index 0000000000..8b8b43f8de
--- /dev/null
+++ b/scripts/npc/2111012.js
@@ -0,0 +1,25 @@
+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.dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/scripts/npc/2111013.js b/scripts/npc/2111013.js
index 551ba5f46a..6a35da3229 100644
--- a/scripts/npc/2111013.js
+++ b/scripts/npc/2111013.js
@@ -40,7 +40,16 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3311)) {
- cm.setQuestProgress(3311, 0, 1);
+ var progress = cm.getQuestProgressInt(3311);
+
+ if (progress == 4) {
+ progress = 7;
+ } else {
+ progress = 5;
+ }
+
+ cm.setQuestProgress(3311, progress);
+
cm.sendOk("This is a mug picture of Dr. De Lang. It seems he is adorning a locket with the emblem of the Alcadno academy, he is a retainer of the Alcadno society.", 2);
}
diff --git a/scripts/npc/2111014.js b/scripts/npc/2111014.js
index a39a0c2c3a..5b1e454f4e 100644
--- a/scripts/npc/2111014.js
+++ b/scripts/npc/2111014.js
@@ -40,7 +40,16 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3311)) {
- cm.setQuestProgress(3311, 1, 1);
+ var progress = cm.getQuestProgressInt(3311);
+
+ if (progress == 4) {
+ progress = 7;
+ } else {
+ progress = 5;
+ }
+
+ cm.setQuestProgress(3311, progress);
+
cm.sendOk("The diary of Dr. De Lang. A lot of formulas and pompous scientific texts can be found all way through the pages, but it is worth noting that in the last entry (3 weeks ago), it is written that he concluded the researches on an improvement on the blueprints for the Neo Huroids, thus making the last preparations to show it to the 'society'... No words after this...", 2);
} else if(cm.isQuestStarted(3322) && !cm.haveItem(4031697, 1)) {
if(cm.canHold(4031697, 1))
diff --git a/scripts/npc/2111016.js b/scripts/npc/2111016.js
new file mode 100644
index 0000000000..8b8b43f8de
--- /dev/null
+++ b/scripts/npc/2111016.js
@@ -0,0 +1,25 @@
+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.dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/scripts/npc/2111017.js b/scripts/npc/2111017.js
index 49a8458d4d..95d07048f4 100644
--- a/scripts/npc/2111017.js
+++ b/scripts/npc/2111017.js
@@ -40,15 +40,15 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3339)) {
- var progress = cm.getQuestProgress(3339, 0);
+ var progress = cm.getQuestProgressInt(23339, 1);
if(progress == 3) {
cm.sendGetText("The pipe reacts as the water starts flowing. A secret compartment with a keypad shows up. #bPassword#k!");
} else if(progress == 0) {
- cm.setQuestProgress(3339, 0, 1);
+ cm.setQuestProgress(23339, 1, 1);
cm.dispose();
} else if(progress < 3) {
- cm.setQuestProgress(3339, 0, 0);
+ cm.setQuestProgress(23339, 1, 0);
cm.dispose();
} else {
cm.warp(261000001, 1);
@@ -63,7 +63,7 @@ function action(mode, type, selection) {
}
} else if(status == 1) {
if(cm.getText() == "my love Phyllia") {
- cm.setQuestProgress(3339, 0, 4);
+ cm.setQuestProgress(23339, 1, 4);
cm.warp(261000001, 1);
cm.dispose();
}
diff --git a/scripts/npc/2111018.js b/scripts/npc/2111018.js
index 6065064c69..fb0bbd845e 100644
--- a/scripts/npc/2111018.js
+++ b/scripts/npc/2111018.js
@@ -40,15 +40,15 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3339)) {
- var progress = cm.getQuestProgress(3339, 0);
+ var progress = cm.getQuestProgressInt(23339, 1);
if(progress == 3) {
cm.sendGetText("The pipe reacts as the water starts flowing. A secret compartment with a keypad shows up. #bPassword#k!");
} else if(progress == 2) {
- cm.setQuestProgress(3339, 0, 3);
+ cm.setQuestProgress(23339, 1, 3);
cm.sendGetText("The pipe reacts as the water starts flowing. A secret compartment with a keypad shows up. #bPassword#k!");
} else if(progress < 3) {
- cm.setQuestProgress(3339, 0, 0);
+ cm.setQuestProgress(23339, 1, 0);
cm.dispose();
} else {
cm.warp(261000001, 1);
@@ -63,7 +63,7 @@ function action(mode, type, selection) {
}
} else if(status == 1) {
if(cm.getText() == "my love Phyllia") {
- cm.setQuestProgress(3339, 0, 4);
+ cm.setQuestProgress(23339, 1, 4);
cm.warp(261000001, 1);
cm.dispose();
}
diff --git a/scripts/npc/2111019.js b/scripts/npc/2111019.js
index bde977fafc..28674aae7f 100644
--- a/scripts/npc/2111019.js
+++ b/scripts/npc/2111019.js
@@ -40,15 +40,15 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3339)) {
- var progress = cm.getQuestProgress(3339, 0);
+ var progress = cm.getQuestProgressInt(23339, 1);
if(progress == 3) {
cm.sendGetText("The pipe reacts as the water starts flowing. A secret compartment with a keypad shows up. #bPassword#k!");
} else if(progress == 1) {
- cm.setQuestProgress(3339, 0, 2);
+ cm.setQuestProgress(23339, 1, 2);
cm.dispose();
} else if(progress < 3) {
- cm.setQuestProgress(3339, 0, 0);
+ cm.setQuestProgress(23339, 1, 0);
cm.dispose();
} else {
cm.warp(261000001, 1);
@@ -63,7 +63,7 @@ function action(mode, type, selection) {
}
} else if(status == 1) {
if(cm.getText() == "my love Phyllia") {
- cm.setQuestProgress(3339, 0, 4);
+ cm.setQuestProgress(23339, 1, 4);
cm.warp(261000001, 1);
cm.dispose();
}
diff --git a/scripts/npc/2111020.js b/scripts/npc/2111020.js
index bc49a9de13..9e6dc25e4b 100644
--- a/scripts/npc/2111020.js
+++ b/scripts/npc/2111020.js
@@ -40,13 +40,13 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3345)) {
- var progress = cm.getQuestProgress(3345, 0);
+ var progress = cm.getQuestProgressInt(3345);
if(progress == 0) {
- cm.setQuestProgress(3345, 0, 1);
+ cm.setQuestProgress(3345, 1);
cm.dispose();
} else if(progress < 4) {
- cm.setQuestProgress(3345, 0, 0);
+ cm.setQuestProgress(3345, 0);
cm.dispose();
} else {
cm.dispose();
diff --git a/scripts/npc/2111021.js b/scripts/npc/2111021.js
index 6f46abc299..d800d3c52f 100644
--- a/scripts/npc/2111021.js
+++ b/scripts/npc/2111021.js
@@ -40,13 +40,13 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3345)) {
- var progress = cm.getQuestProgress(3345, 0);
+ var progress = cm.getQuestProgressInt(3345);
if(progress == 1) {
- cm.setQuestProgress(3345, 0, 2);
+ cm.setQuestProgress(3345, 2);
cm.dispose();
} else if(progress < 4) {
- cm.setQuestProgress(3345, 0, 0);
+ cm.setQuestProgress(3345, 0);
cm.dispose();
} else {
cm.dispose();
diff --git a/scripts/npc/2111022.js b/scripts/npc/2111022.js
index 4fd1ebb28f..17d305d19b 100644
--- a/scripts/npc/2111022.js
+++ b/scripts/npc/2111022.js
@@ -40,13 +40,13 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3345)) {
- var progress = cm.getQuestProgress(3345, 0);
+ var progress = cm.getQuestProgressInt(3345);
if(progress == 2) {
- cm.setQuestProgress(3345, 0, 3);
+ cm.setQuestProgress(3345, 3);
cm.dispose();
} else if(progress < 4) {
- cm.setQuestProgress(3345, 0, 0);
+ cm.setQuestProgress(3345, 0);
cm.dispose();
} else {
cm.dispose();
diff --git a/scripts/npc/2111023.js b/scripts/npc/2111023.js
index e8cb68005a..9516d06c41 100644
--- a/scripts/npc/2111023.js
+++ b/scripts/npc/2111023.js
@@ -40,10 +40,10 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3345)) {
- var progress = cm.getQuestProgress(3345, 0);
+ var progress = cm.getQuestProgressInt(3345);
if(progress == 3 && cm.haveItem(4031739, 1) && cm.haveItem(4031740, 1) && cm.haveItem(4031741, 1)) {
- cm.setQuestProgress(3345, 0, 4);
+ cm.setQuestProgress(3345, 4);
cm.gainItem(4031739, -1);
cm.gainItem(4031740, -1);
cm.gainItem(4031741, -1);
@@ -51,7 +51,7 @@ function action(mode, type, selection) {
cm.sendOk("(As you place the shards a light shines over the circle, repelling whatever omens were brewing inside the artifact.)", 2);
cm.dispose();
} else if(progress < 4) {
- cm.setQuestProgress(3345, 0, 0);
+ cm.setQuestProgress(3345, 0);
cm.dispose();
} else {
cm.dispose();
diff --git a/scripts/npc/2112003.js b/scripts/npc/2112003.js
index fcf7eca6a3..6e4c8f0be5 100644
--- a/scripts/npc/2112003.js
+++ b/scripts/npc/2112003.js
@@ -50,7 +50,7 @@ function action(mode, type, selection) {
if(status == 0) {
cm.sendYesNo("We must keep fighting to save Romeo, please keep your pace. If you are not feeling so well to continue, your companions and I will understand... So, are you going to retreat?");
} else if(status == 1) {
- cm.warp(926110700);
+ cm.warp(926110700, 0);
cm.dispose();
}
} else {
diff --git a/scripts/npc/2112004.js b/scripts/npc/2112004.js
index 1b4c8510ff..b637a6ba64 100644
--- a/scripts/npc/2112004.js
+++ b/scripts/npc/2112004.js
@@ -50,7 +50,7 @@ function action(mode, type, selection) {
if(status == 0) {
cm.sendYesNo("We must keep fighting to save Juliet, please keep your pace. If you are not feeling so well to continue, your companions and I will understand... So, are you going to retreat?");
} else if(status == 1) {
- cm.warp(926100700);
+ cm.warp(926100700, 0);
cm.dispose();
}
} else {
diff --git a/scripts/npc/2112005.js b/scripts/npc/2112005.js
index 29860dce6b..14de113793 100644
--- a/scripts/npc/2112005.js
+++ b/scripts/npc/2112005.js
@@ -93,7 +93,7 @@ function action(mode, type, selection) {
cm.sendYesNo("We must keep fighting to save Romeo, please keep your pace. If you are not feeling so well to continue, your companions and I will understand... So, are you going to retreat?");
}
} else {
- cm.warp(926110700);
+ cm.warp(926110700, 0);
cm.dispose();
}
} else {
@@ -111,15 +111,15 @@ function action(mode, type, selection) {
if(cm.canHold(4001160)) {
cm.gainItem(4001160, 1);
- if(eim.getIntProperty("normalClear") == 1) cm.warp(926110600);
- else cm.warp(926110500);
+ if(eim.getIntProperty("normalClear") == 1) cm.warp(926110600, 0);
+ else cm.warp(926110500, 0);
} else {
cm.sendOk("Make sure you have a space on your ETC inventory.");
}
cm.dispose();
} else {
- cm.warp(926110600);
+ cm.warp(926110600, 0);
cm.dispose();
}
}
diff --git a/scripts/npc/2112006.js b/scripts/npc/2112006.js
index 3ab1911949..2a1ad0c222 100644
--- a/scripts/npc/2112006.js
+++ b/scripts/npc/2112006.js
@@ -93,7 +93,7 @@ function action(mode, type, selection) {
cm.sendYesNo("We must keep fighting to save Juliet, please keep your pace. If you are not feeling so well to continue, your companions and I will understand... So, are you going to retreat?");
}
} else {
- cm.warp(926100700);
+ cm.warp(926100700, 0);
cm.dispose();
}
} else {
@@ -111,15 +111,15 @@ function action(mode, type, selection) {
if(cm.canHold(4001159)) {
cm.gainItem(4001159, 1);
- if(eim.getIntProperty("normalClear") == 1) cm.warp(926100600);
- else cm.warp(926100500);
+ if(eim.getIntProperty("normalClear") == 1) cm.warp(926100600, 0);
+ else cm.warp(926100500, 0);
} else {
cm.sendOk("Make sure you have a space on your ETC inventory.");
}
cm.dispose();
} else {
- cm.warp(926100600);
+ cm.warp(926100600, 0);
cm.dispose();
}
}
diff --git a/scripts/npc/2112011.js b/scripts/npc/2112011.js
index 4e3b223f7d..e6f2cc19e9 100644
--- a/scripts/npc/2112011.js
+++ b/scripts/npc/2112011.js
@@ -51,7 +51,7 @@ function action(mode, type, selection) {
} else {
if(!cm.isQuestCompleted(7770)) cm.completeQuest(7770);
- cm.warp(926110600);
+ cm.warp(926110600, 0);
cm.dispose();
}
}
diff --git a/scripts/npc/2112016.js b/scripts/npc/2112016.js
index dd9db1bf18..2615ab3ac6 100644
--- a/scripts/npc/2112016.js
+++ b/scripts/npc/2112016.js
@@ -26,15 +26,15 @@
function start() {
if(cm.isQuestStarted(3367)) {
- var c = cm.getQuestProgress(3367, 30);
- if(c == 30) {
+ var c = cm.getQuestProgressInt(3367, 30);
+ if(c >= 30) {
cm.sendNext("(All files have been organized. Report the found files to Yulete.)", 2);
cm.dispose();
return;
}
var book = (cm.getNpcObjectId() % 30);
- var prog = cm.getQuestProgress(3367, book);
+ var prog = cm.getQuestProgressInt(3367, book);
if(prog == 0) {
c++;
@@ -45,7 +45,7 @@ function start() {
return;
} else {
cm.gainItem(4031797, 1);
- cm.setQuestProgress(3367, 31, cm.getQuestProgress(3367, 31) + 1);
+ cm.setQuestProgress(3367, 31, cm.getQuestProgressInt(3367, 31) + 1);
}
}
diff --git a/scripts/npc/2131001.js b/scripts/npc/2131001.js
index ae9629790e..0c5ed72e01 100644
--- a/scripts/npc/2131001.js
+++ b/scripts/npc/2131001.js
@@ -13,13 +13,14 @@ function action(mode, type, selection) {
return;
}
if (status == 0) {
- cm.sendSimple("My name is Pergen, I am the strongest magician around these parts.#b\r\n#L0#Hey, take these rubbles. You can perform your magic on them.#l");
+ cm.sendSimple("My name is #p2131001#, I am the strongest magician around these parts.#b\r\n#L0#Hey, take these rubbles. You can perform your magic on them.#l");
} else if (status == 1) {
if (!cm.haveItem(exchangeItem, 100)) {
cm.sendNext("You don't have enough... I need at least 100.");
cm.dispose();
} else {
- cm.sendGetNumber("Hey, that's a good idea! I can give you #i4310000#Perfect Pitch for each 100 #i" + exchangeItem + "##t" + exchangeItem + "# you give me. How many do you want? (Current Items: " + cm.itemQuantity(exchangeItem) + ")", java.lang.Math.min(300, cm.itemQuantity(exchangeItem) / 100), 1, java.lang.Math.min(300, cm.itemQuantity(exchangeItem) / 100));
+ // thanks yuxaij for noticing a few methods having parameters not matching the expected Math library function parameter types
+ cm.sendGetNumber("Hey, that's a good idea! I can give you #i4310000#Perfect Pitch for each 100 #i" + exchangeItem + "##t" + exchangeItem + "# you give me. How many do you want? (Current Items: " + cm.itemQuantity(exchangeItem) + ")", Math.min(300, cm.itemQuantity(exchangeItem) / 100), 1, Math.min(300, cm.itemQuantity(exchangeItem) / 100));
}
} else if (status == 2) {
if (selection >= 1 && selection <= cm.itemQuantity(exchangeItem) / 100) {
diff --git a/scripts/npc/2131002.js b/scripts/npc/2131002.js
index b6f86ad3b1..7c253084cc 100644
--- a/scripts/npc/2131002.js
+++ b/scripts/npc/2131002.js
@@ -5,6 +5,6 @@
*/
function start(){
- cm.sendOk("My name is Euryth... As you can see, I am a fairy. People tell me I do not act fairy-like, but... I like making things out of metal objects. Shhh, don't tell this to anyone, but I also like MMA.");
+ cm.sendOk("My name is #p2131002#... As you can see, I am a fairy. People tell me I do not act fairy-like, but... I like making things out of metal objects. Shhh, don't tell this to anyone, but I also like MMA.");
cm.dispose();
}
\ No newline at end of file
diff --git a/scripts/npc/2131003.js b/scripts/npc/2131003.js
index 1c69b58d66..dd5be16d12 100644
--- a/scripts/npc/2131003.js
+++ b/scripts/npc/2131003.js
@@ -19,7 +19,7 @@ function action(mode, type, selection) {
cm.sendNext("You don't have enough... I need at least 100.");
cm.dispose();
} else {
- cm.sendGetNumber("Hey, that's a good idea! I can give you #i4310000#Perfect Pitch for each 100 #i" + exchangeItem + "##t" + exchangeItem + "# you give me. How many do you want? (Current Items: " + cm.itemQuantity(exchangeItem) + ")", java.lang.Math.min(300, cm.itemQuantity(exchangeItem) / 100), 1, java.lang.Math.min(300, cm.itemQuantity(exchangeItem) / 100));
+ cm.sendGetNumber("Hey, that's a good idea! I can give you #i4310000#Perfect Pitch for each 100 #i" + exchangeItem + "##t" + exchangeItem + "# you give me. How many do you want? (Current Items: " + cm.itemQuantity(exchangeItem) + ")", Math.min(300, cm.itemQuantity(exchangeItem) / 100), 1, Math.min(300, cm.itemQuantity(exchangeItem) / 100));
}
} else if (status == 2) {
if (selection >= 1 && selection <= cm.itemQuantity(exchangeItem) / 100) {
diff --git a/scripts/npc/2131005.js b/scripts/npc/2131005.js
index 4a1742962c..e51c35030a 100644
--- a/scripts/npc/2131005.js
+++ b/scripts/npc/2131005.js
@@ -19,7 +19,7 @@ function action(mode, type, selection) {
cm.sendNext("You don't have enough... I need at least 100.");
cm.dispose();
} else {
- cm.sendGetNumber("Hey, that's a good idea! I can give you #i4310000#Perfect Pitch for each 100 #i" + exchangeItem + "##t" + exchangeItem + "# you give me. How many do you want? (Current Items: " + cm.itemQuantity(exchangeItem) + ")", java.lang.Math.min(300, cm.itemQuantity(exchangeItem) / 100), 1, java.lang.Math.min(300, cm.itemQuantity(exchangeItem) / 100));
+ cm.sendGetNumber("Hey, that's a good idea! I can give you #i4310000#Perfect Pitch for each 100 #i" + exchangeItem + "##t" + exchangeItem + "# you give me. How many do you want? (Current Items: " + cm.itemQuantity(exchangeItem) + ")", Math.min(300, cm.itemQuantity(exchangeItem) / 100), 1, Math.min(300, cm.itemQuantity(exchangeItem) / 100));
}
} else if (status == 2) {
if (selection >= 1 && selection <= cm.itemQuantity(exchangeItem) / 100) {
diff --git a/scripts/npc/2131006.js b/scripts/npc/2131006.js
index c2910b80f4..a19b093243 100644
--- a/scripts/npc/2131006.js
+++ b/scripts/npc/2131006.js
@@ -19,7 +19,7 @@ function action(mode, type, selection) {
cm.sendNext("You don't have enough... I need at least 100.");
cm.dispose();
} else {
- cm.sendGetNumber("Hey, that's a good idea! I can give you #i4310000#Perfect Pitch for each 100 #i" + exchangeItem + "##t" + exchangeItem + "# you give me. How many do you want? (Current Items: " + cm.itemQuantity(exchangeItem) + ")", java.lang.Math.min(300, cm.itemQuantity(exchangeItem) / 100), 1, java.lang.Math.min(300, cm.itemQuantity(exchangeItem) / 100));
+ cm.sendGetNumber("Hey, that's a good idea! I can give you #i4310000#Perfect Pitch for each 100 #i" + exchangeItem + "##t" + exchangeItem + "# you give me. How many do you want? (Current Items: " + cm.itemQuantity(exchangeItem) + ")", Math.min(300, cm.itemQuantity(exchangeItem) / 100), 1, Math.min(300, cm.itemQuantity(exchangeItem) / 100));
}
} else if (status == 2) {
if (selection >= 1 && selection <= cm.itemQuantity(exchangeItem) / 100) {
diff --git a/scripts/npc/2131007.js b/scripts/npc/2131007.js
index d145bd0848..fffc7fb562 100644
--- a/scripts/npc/2131007.js
+++ b/scripts/npc/2131007.js
@@ -19,7 +19,7 @@ function action(mode, type, selection) {
cm.sendNext("You don't have enough... I need at least 100.");
cm.dispose();
} else {
- cm.sendGetNumber("Hey, that's a good idea! I can give you #i4310000#Perfect Pitch for each 100 #i" + exchangeItem + "##t" + exchangeItem + "# you give me. How many do you want? (Current Items: " + cm.itemQuantity(exchangeItem) + ")", java.lang.Math.min(300, cm.itemQuantity(exchangeItem) / 100), 1, java.lang.Math.min(300, cm.itemQuantity(exchangeItem) / 100));
+ cm.sendGetNumber("Hey, that's a good idea! I can give you #i4310000#Perfect Pitch for each 100 #i" + exchangeItem + "##t" + exchangeItem + "# you give me. How many do you want? (Current Items: " + cm.itemQuantity(exchangeItem) + ")", Math.min(300, cm.itemQuantity(exchangeItem) / 100), 1, Math.min(300, cm.itemQuantity(exchangeItem) / 100));
}
} else if (status == 2) {
if (selection >= 1 && selection <= cm.itemQuantity(exchangeItem) / 100) {
diff --git a/scripts/npc/2133000.js b/scripts/npc/2133000.js
index c342d6e69a..a91a790498 100644
--- a/scripts/npc/2133000.js
+++ b/scripts/npc/2133000.js
@@ -111,9 +111,9 @@ function action(mode, type, selection) {
cm.dispose();
}
} else if (selection == 2){
- if (cm.haveItem(1032061) && !cm.haveItem(1032101) && cm.haveItem(4001198, 10)) {
+ if (cm.haveItem(1032061) && !cm.haveItem(1032072) && cm.haveItem(4001198, 10)) {
cm.gainItem(1032061,-1);
- cm.gainItem(1032101, 1);
+ cm.gainItem(1032072, 1); // thanks yuxaij for noticing unexpected itemid here
cm.gainItem(4001198, -10);
cm.dispose();
} else {
diff --git a/scripts/npc/2133001.js b/scripts/npc/2133001.js
index 74a85d579e..d288555334 100644
--- a/scripts/npc/2133001.js
+++ b/scripts/npc/2133001.js
@@ -92,10 +92,10 @@ function action(mode, type, selection) {
cm.gainItem(4001169, -20);
cm.getEventInstance().warpEventTeam(930000500);
} else {
- cm.warp(930000800);
+ cm.warp(930000800, 0);
}
} else {
- cm.warp(930000800);
+ cm.warp(930000800, 0);
}
cm.dispose();
diff --git a/scripts/npc/2133002.js b/scripts/npc/2133002.js
index 1804c49b10..59c3d759cc 100644
--- a/scripts/npc/2133002.js
+++ b/scripts/npc/2133002.js
@@ -19,7 +19,7 @@ function action(mode, type, selection) {
cm.removeAll(4001163);
cm.removeAll(4001169);
cm.removeAll(2270004);
- cm.warp(930000800);
+ cm.warp(930000800, 0);
cm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/npc/2133004.js b/scripts/npc/2133004.js
index 4affde77cf..ef0d283fe3 100644
--- a/scripts/npc/2133004.js
+++ b/scripts/npc/2133004.js
@@ -25,7 +25,7 @@ function action(mode, type, selection) {
}
} else if(status == 1) {
if (!cm.haveItem(4001163)) {
- cm.warp(930000800);
+ cm.warp(930000800, 0);
} else {
cm.getEventInstance().warpEventTeam(930000600);
}
diff --git a/scripts/npc/2141001.js b/scripts/npc/2141001.js
index 12bdba353a..1c41cf337b 100644
--- a/scripts/npc/2141001.js
+++ b/scripts/npc/2141001.js
@@ -67,8 +67,13 @@ function action(mode, type, selection) {
cm.sendSimple("#e#b\r\n#k#n" + em.getProperty("party") + "\r\n\r\nWould you like to assemble a team to take on #r" + expedBoss + "#k?\r\n#b#L1#Lets get this going!#l\r\n\#L2#No, I think I'll wait a bit...#l");
status = 1;
} else if (expedition.isLeader(player)) { //If you're the leader, manage the exped
- cm.sendSimple(list);
- status = 2;
+ if (expedition.isInProgress()) {
+ cm.sendOk("Your expedition is already in progress, for those who remain battling lets pray for those brave souls.");
+ cm.dispose();
+ } else {
+ cm.sendSimple(list);
+ status = 2;
+ }
} else if (expedition.isRegistering()) { //If the expedition is registering
if (expedition.contains(player)) { //If you're in it but it hasn't started, be patient
cm.sendOk("You have already registered for the expedition. Please wait for #r" + expedition.getLeader().getName() + "#k to begin it.");
@@ -101,8 +106,11 @@ function action(mode, type, selection) {
return;
}
- if (cm.createExpedition(exped)) {
+ var res = cm.createExpedition(exped);
+ if (res == 0) {
cm.sendOk("The #r" + expedBoss + " Expedition#k has been created.\r\n\r\nTalk to me again to view the current team, or start the fight!");
+ } else if (res > 0) {
+ cm.sendOk("Sorry, you've already reached the quota of attempts for this expedition! Try again another day...");
} else {
cm.sendOk("An unexpected error has occurred when starting the expedition, please try again later.");
}
diff --git a/scripts/npc/9000001.js b/scripts/npc/9000001.js
index 55eaf9a278..c0501bf004 100644
--- a/scripts/npc/9000001.js
+++ b/scripts/npc/9000001.js
@@ -59,7 +59,7 @@ function action(mode, type, selection) {
cm.divideTeams();
cm.getEvent().minusLimit();
- cm.warp(cm.getEvent().getMapId());
+ cm.warp(cm.getEvent().getMapId(), 0);
cm.dispose();
} else {
cm.sendNext("Either the event has not been started, you already have the #bScroll of Secrets#k, or you have already participated in this event within the last 24 hours. Please try again later!");
diff --git a/scripts/npc/9000011.js b/scripts/npc/9000011.js
index fab1981248..67dbb825bd 100644
--- a/scripts/npc/9000011.js
+++ b/scripts/npc/9000011.js
@@ -127,7 +127,7 @@ function action(mode, type, selection) {
cm.dispose();
return;
}
- var rand = java.lang.Math.floor(java.lang.Math.random() * pri.length);
+ var rand = Math.floor(Math.random() * pri.length);
if (!cm.haveItem(ite, quan)) {
cm.sendOk("You need #b" + quan + " #t" + ite + "##k to exchange it with item.");
} else if (cm.getInventory(1).getNextFreeSlot() <= -1 || cm.getInventory(2).getNextFreeSlot() <= -1 || cm.getInventory(3).getNextFreeSlot() <= -1 || cm.getInventory(4).getNextFreeSlot() <= -1) {
diff --git a/scripts/npc/9000017.js b/scripts/npc/9000017.js
index 7f94db6a5d..5f37d9b5f9 100644
--- a/scripts/npc/9000017.js
+++ b/scripts/npc/9000017.js
@@ -51,7 +51,7 @@ function action(mode, type, selection) {
}
if (status == 0) {
- if (!Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
+ if (!Packages.config.YamlConfig.config.server.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
cm.sendOk("Hi, I'm #b#p" + cm.getNpc() + "##k.");
cm.dispose();
return;
diff --git a/scripts/npc/9000019.js b/scripts/npc/9000019.js
new file mode 100644
index 0000000000..c5c20ae161
--- /dev/null
+++ b/scripts/npc/9000019.js
@@ -0,0 +1,32 @@
+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) {
+ if(cm.getPlayer().getInventory(Packages.client.inventory.MapleInventoryType.ETC).getNumFreeSlot() < 1) {
+ cm.sendNext("Check for a available slot on your ETC inventory.");
+ cm.dispose();
+ return;
+ }
+
+ cm.getClient().announce(Packages.tools.MaplePacketCreator.openRPSNPC());
+ cm.dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/scripts/npc/9000021.js b/scripts/npc/9000021.js
index c6d7bbc9d3..b2dd15c369 100644
--- a/scripts/npc/9000021.js
+++ b/scripts/npc/9000021.js
@@ -55,7 +55,7 @@ function action(mode, type, selection) {
cm.sendOk("Very well. Remember, there you can assemble a team or take on the fightings on your own, it's up to you. Good luck!");
} else if(status == 4) {
cm.getPlayer().saveLocation("BOSSPQ");
- cm.warp(970030000);
+ cm.warp(970030000, "out00");
cm.dispose();
}
}
diff --git a/scripts/npc/9000036.js b/scripts/npc/9000036.js
index 1bcc769423..247353a8a4 100644
--- a/scripts/npc/9000036.js
+++ b/scripts/npc/9000036.js
@@ -39,7 +39,7 @@ var equip;
var maxEqp = 0;
function start() {
- if (!Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
+ if (!Packages.config.YamlConfig.config.server.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
cm.sendOk("Hi, I'm #b#p" + cm.getNpc() + "##k.");
cm.dispose();
return;
diff --git a/scripts/npc/9000040.js b/scripts/npc/9000040.js
index c1ed3286b3..d5b7153aab 100644
--- a/scripts/npc/9000040.js
+++ b/scripts/npc/9000040.js
@@ -25,7 +25,7 @@
*/
importPackage(Packages.client.processor);
-importPackage(Packages.constants);
+importPackage(Packages.config);
var status;
var mergeFee = 50000;
@@ -50,7 +50,7 @@ function action(mode, type, selection) {
status--;
if(status == 0) {
- if (!Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
+ if (!Packages.config.YamlConfig.config.server.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
cm.sendOk("The medal ranking system is currently unavailable...");
cm.dispose();
return;
@@ -59,7 +59,7 @@ function action(mode, type, selection) {
var levelLimit = !cm.getPlayer().isCygnus() ? 160 : 110;
var selStr = "The medal ranking system is currently unavailable... Therefore, I am providing the #bEquipment Merge#k service! ";
- if (!ServerConstants.USE_STARTER_MERGE && (cm.getPlayer().getLevel() < levelLimit || MakerProcessor.getMakerSkillLevel(cm.getPlayer()) < 3)) {
+ if (!YamlConfig.config.server.USE_STARTER_MERGE && (cm.getPlayer().getLevel() < levelLimit || MakerProcessor.getMakerSkillLevel(cm.getPlayer()) < 3)) {
selStr += "However, you must have #rMaker level 3#k and at least #rlevel 110#k (Cygnus Knight), #rlevel 160#k (other classes) and a fund of #r" + cm.numberWithCommas(mergeFee) + " mesos#k to use the service.";
cm.sendOk(selStr);
cm.dispose();
diff --git a/scripts/npc/9000041.js b/scripts/npc/9000041.js
index 93fd16a9e7..45d4b1aeac 100644
--- a/scripts/npc/9000041.js
+++ b/scripts/npc/9000041.js
@@ -42,7 +42,7 @@ function action(mode, type, selection) {
}
if (status == 0) {
- if (!Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
+ if (!Packages.config.YamlConfig.config.server.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
cm.sendOk("The medal ranking system is currently unavailable...");
cm.dispose();
return;
diff --git a/scripts/npc/9001102.js b/scripts/npc/9001102.js
new file mode 100644
index 0000000000..101c772a71
--- /dev/null
+++ b/scripts/npc/9001102.js
@@ -0,0 +1,54 @@
+/*
+ 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 .
+*/
+/**
+* @Author : iAkira, Kevintjuh93
+**/
+var status = 0;
+var selected = 0;
+
+function start() {
+ if (cm.getPlayer().getMapId() == 100000000) {
+ cm.sendNext("There! Did you see that? You didn't? A UFO just passed... there!! Look, someone is getting dragged into the UFO... arrrrrrgh, it's Gaga! #rGaga just got kidnapped by a UFO!#k");
+ }
+}
+
+function action(m,t,s) {
+ if (m > 0) {
+ status++;
+ if (cm.getPlayer().getMapId() == 100000000) { // warper completed
+ if (status == 1) {
+ if (cm.getPlayer().getLevel() >= 12)
+ cm.sendYesNo("What do we do now? It's just a rumor yet, but... I've heard that scary things happen to you if you get kidnapped by aliens... may be that's what happenning to Gaga right now! Please, please rescue Gaga! \r\n #bGaga may be a bit indetermined and clueless, but#k he has a really good heart. I can't let something terrible happen to him. Right! Grandpa from the moon might know how to rescue him! I will send you to the moon, so please go meet Grandpa and rescue Gaga!!!");
+ else
+ cm.sendOk("Oh! It seems you don't reach the level requirements to save Gaga. Please come back when you are level 12 or higher.");
+
+ } else if (status == 2)
+ cm.sendNext("Thank you so much. Please rescue Gaga! Grandpa from the moon will help you.");
+ else if (status == 3) {
+ cm.warp(922240200, 0);
+ cm.dispose();
+ }
+ }
+ } else if (m < 1) {
+ cm.dispose();
+ }
+}
\ No newline at end of file
diff --git a/scripts/npc/9001105.js b/scripts/npc/9001105.js
new file mode 100644
index 0000000000..d648f068ee
--- /dev/null
+++ b/scripts/npc/9001105.js
@@ -0,0 +1,77 @@
+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) {
+ if (cm.getPlayer().getMapId() == 922240200) {
+ cm.sendOk("That's a shame, come back when your ready.");
+ }
+
+ cm.dispose();
+ return;
+ }
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if(status == 0) {
+ if (cm.getMapId() == 922240200) {
+ cm.sendSimple("Did you have something to say...? #b\b\r\n#L0#I want to rescue Gaga.#l\r\n"); //#L1#I want to go to the Space Mine.#l
+ } else if (cm.getMapId() >= 922240000 && cm.getMapId() <= 922240019) {
+ cm.sendYesNo("Don't worry if you fail. You'll have 3 chances. Do you still want to give up?");
+ } else if (cm.getMapId() >= 922240100 && cm.getMapId() <= 922240119) {
+ var text = "You went through so much trouble to rescue Gaga, but it looks like we're back to square one. ";
+ var rgaga = cm.getPlayer().getEvents().get("rescueGaga");
+ if (rgaga.getCompleted() > 10) {
+ text += "Please don't give up until Gaga is rescued. To show you my appreciation for what you've accomplished thus far, I've given you a Spaceship. It's rather worn out, but it should still be operational. Check your #bSkill Window#k.";
+ rgaga.giveSkill(cm.getPlayer());
+ } else
+ text += "Let's go back now.";
+
+ cm.sendNext(text);
+ }
+ } else {
+ if (cm.getPlayer().getMapId() == 922240200) {
+ if (status == 1) {
+ if(selection == 0) {
+ selected = 1;
+ cm.sendNext("Welcome! I heard what happened from Baby Moon Bunny I'm glad you came since I was Planning on requesting some help. Gaga is a friend of mine who has helped me before and often stops by to say hello. Unfortunately, he was kidnapped by aliens.");
+ } else {
+ selected = 2;
+ cm.sendYesNo("At the Space Mine, you can find special ores called #bKrypto Crystals#k that contains the mysterious power of space. #bKrypto Crystals#l are usually emerald in color, but will turn brown if hit with the Spaceship's #bSpace Beam#k. Remember, in order to thwart this alien conspracy, #b10 Brown Krypto Crystal's and 10 Emerald Krypto Crystal's are needed. But since even #b1 Krypto Crystal#k can be of help, brign me as many as possible. Oh, and one more thing! The Space Mines are protected by the Space Mateons. They are extemely strong due to the power of the #Krypto Crystals#k, so don't try to defeat them. Simply concentrate on quickly collecting the crystals.");
+ }
+ } else if (status == 2) {
+ if(selected == 1) {
+ cm.sendYesNo("If we just leave Gaga with the aliens, something terrible will happen to him! I'll let you borrow a spaceship that the Moon Bunnies use for traveling so that you can rescue Gaga.#b Although he might appear a bit indecisive, slow, and immature at times#k, he's really a nice young man. Do you want to go rescue him now?");
+ } else if(selected == 2) {
+ cm.sendOk("Not coded yet, f4.");
+ cm.dispose();
+ }
+ } else if (status == 3) {
+ var em = cm.getEventManager("RescueGaga");
+ if (em == null) {
+ cm.sendOk("This event is currently unavailable.");
+ } else if (!em.startInstance(cm.getPlayer())) {
+ cm.sendOk("There is currently someone in this map, come back later.");
+ }
+
+ cm.dispose();
+ }
+ } else if (cm.getPlayer().getMapId() >= 922240000 && cm.getPlayer().getMapId() <= 922240019) {
+ cm.warp(922240200, 0);
+ cm.dispose();
+ } else if (cm.getPlayer().getMapId() >= 922240100 && cm.getPlayer().getMapId() <= 922240119) {
+ cm.warp(922240200, 0);
+ cm.dispose();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/scripts/npc/9001108.js b/scripts/npc/9001108.js
deleted file mode 100644
index cf56b21f87..0000000000
--- a/scripts/npc/9001108.js
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- 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 .
-*/
-/**
-* @Author : iAkira, Kevintjuh93
-**/
-var status = 0;
-var selected = 0;
-
-function start() {
- if (cm.getPlayer().getMapId() == 100000000) {
- cm.sendNext("There! Did you see that? You didn't? A UFO just passed... there!! Look, someone is getting dragged into the UFO... arrrrrrgh, it's Gaga! #rGaga just got kidnapped by a UFO!#k");
- } else if (cm.getPlayer().getMapId() == 922240200) {
- cm.sendSimple("Did you have something to say...? #b\b\r\n#L0#I want to rescue Gaga.#l\r\n#L1#I want to go to the Space Mine.#l");
- } else if (cm.getPlayer().getMapId() >= 922240000 && cm.getPlayer().getMapId() <= 922240019) {
- cm.sendYesNo("Don't worry if you fail. You'll have 3 chances. Do you still want to give up?");
- } else if (cm.getPlayer().getMapId() >= 922240100 && cm.getPlayer().getMapId() <= 922240119) {
- var text = "You went through so much trouble to rescue Gaga, but it looks like we're back to square one. ";
- var rgaga = cm.getPlayer().getEvents().get("rescueGaga");
- if (rgaga.getCompleted() == 10 || rgaga.getCompleted() == 20) {
- text += "Please don't give up untill Gaga is rescued. To show you my appreciation for what you've accomplished thus far, I've given you a Spaceship. It's rather worn out, but it should still be operational. Check your #bSkill Window#k.";
- rgaga.giveSkill(cm.getPlayer());
- } else
- text += "Let's go back now.";
-
- cm.sendNext(text);
- }
-}
-
-function action(m,t,s) {
- if (m > 0) {
- status++;
- if (cm.getPlayer().getMapId() == 100000000) { // warper completed
- if (status == 1) {
- if (cm.getPlayer().getLevel() >= 12)
- cm.sendYesNo("What do we do now? It's just a rumor yet, but... I've heard that scary things happen to you if you get kidnapped by aliens... may be that's what happenning to Gaga right now! Please, please rescue Gaga! \r\n #bGaga may be a bit indetermined and clueless, but#k he has a really good heart. I can't let something terrible happen to him. Right! Grandpa from the moon might know how to rescue him! I will send you to the moon, so please go meet Grandpa and rescue Gaga");
- else
- cm.sendOk("Oh! it seems you don't reach the level requirements to save Gaga. Please come back when you are level 12 or higher.");
-
- } else if (status == 2)
- cm.sendNext("Thank you so much. Please rescue Gaga! Grandpa from the moon will help you.");
- else if (status == 3) {
- cm.warp(922240200, 0);
- cm.dispose();
- }
- } else if (cm.getPlayer().getMapId() == 922240200) {
- if (status == 1) {
- if(s == 0) {
- selected = 1;
- cm.sendNext("Welcome! I heard what happened from Baby Moon Bunny I'm glad you came since I was Planning on requesting some help. Gaga is a friend of mine who has helped me before and often stops by to say hello. Unfortunaley, he was kidnapped by aliens.");
- } else {
- selected = 2;
- cm.sendYesNo("At the Space Mine, you can find special ores called #bKrypto Crystals#k that contains the mysterious power of space. #bKrypto Crystals#l are usually emerald in color, but will turn brown if hit with the Spaceship's #bSpace Beam#k. Remember, in order to thwart this alien conspracy, #b10 Brown Krypto Crystal's and 10 Emerald Krypto Crystal's are needed. But since even #b1 Krypto Crystal#k can be of help, brign me as many as possible. Oh, and one more thing! The Space Mines are protected by the Space Mateons. They are extemely strong due to the power of the #Krypto Crystals#k, so don't try to defeat them. Simply concentrate on quickly collecting the crystals.");
- }
- } else if (status == 2) {
- if(selected == 1) {
- cm.sendYesNo("If we just leave Gaga with the aliens, something terrible will happen to him! I'll let you borrow a spaceship that the Moon Bunnies use for traveling so that you can rescue Gaga.#b Although he might appear a bit indecieve, slow, and immature at times#k, he's really a nice young man. Do you want to go rescue him now?");
- } else if(selected == 2) {
- cm.sendOk("Not coded yet, f4.");
- cm.dispose();
- }
- } else if (status == 3) {
- var number = -1;
- for (var i = 0; i < 20; i++) {
- var mapFactory = cm.getClient().getChannelServer().getMapFactory();
- if (mapFactory.getMap(922240000 + i).getCharacters().isEmpty()) {
- number = i;
- break;
- }
- }
- if (number > -1)
- cm.warp(922240000 + number);
- else
- cm.sendOk("There are currently no empty maps, please try again later.");
-
- cm.dispose();
- }
- } else if ((cm.getPlayer().getMapId() >= 922240000 && cm.getPlayer().getMapId() <= 922240019) || (cm.getPlayer().getMapId() >= 922240100 && cm.getPlayer().getMapId() <= 922240119)) {
- cm.warp(922240200, 0);
- cm.dispose();
- }
- } else if (m < 1) {
- if(m == 0) {
- if (cm.getPlayer().getMapId() == 922240200) {
- cm.sendOk("That's a shame, come back when your ready.");
- }
- }
- cm.dispose();
- }
-}
\ No newline at end of file
diff --git a/scripts/npc/9010021.js b/scripts/npc/9010021.js
index 2d1177d94d..0abd074218 100644
--- a/scripts/npc/9010021.js
+++ b/scripts/npc/9010021.js
@@ -26,7 +26,7 @@
function start() {
status = -1;
- if (!Packages.constants.ServerConstants.USE_REBIRTH_SYSTEM) {
+ if (!Packages.config.YamlConfig.config.server.USE_REBIRTH_SYSTEM) {
cm.sendOk("... I came from distant planes to assist the fight against the #rBlack Magician#k. Right now I search my master, have you seen him?");
cm.dispose();
return;
diff --git a/scripts/npc/9010022.js b/scripts/npc/9010022.js
index a7c160e6e4..f4718a16d4 100644
--- a/scripts/npc/9010022.js
+++ b/scripts/npc/9010022.js
@@ -71,10 +71,10 @@ function action(mode, type, selection) {
cm.warp(980030000, 3);
break;
case 5:
- cm.warp(926010000);
+ cm.warp(926010000, 4);
break;
case 6:
- cm.warp(910320000);
+ cm.warp(910320000, 2);
break;
}
cm.dispose();
diff --git a/scripts/npc/9010022_old.js b/scripts/npc/9010022_old.js
index d62b2984b5..8a9e49bdbf 100644
--- a/scripts/npc/9010022_old.js
+++ b/scripts/npc/9010022_old.js
@@ -66,10 +66,10 @@ function action(mode, type, selection) {
cm.warp(980030000, 3);
break;
case 5:
- cm.warp(926010000);
+ cm.warp(926010000, 4);
break;
case 6:
- cm.warp(910320000);
+ cm.warp(910320000, 2);
break;
}
cm.dispose();
diff --git a/scripts/npc/9020001.js b/scripts/npc/9020001.js
index 55a6826e46..f6e590d54a 100644
--- a/scripts/npc/9020001.js
+++ b/scripts/npc/9020001.js
@@ -170,7 +170,8 @@ function action(mode, type, selection) {
eim.gridInsert(cm.getPlayer(), 0);
}
else {
- cm.sendNext("I'm sorry, but that is not the right answer! Please have the correct number of coupons in your inventory.");
+ var question = stage1Questions[eim.gridCheck(cm.getPlayer()) - 1];
+ cm.sendNext("I'm sorry, but that is not the right answer!\r\n" + question);
}
}
}
@@ -294,4 +295,4 @@ function action(mode, type, selection) {
cm.dispose();
}
}
-}
\ No newline at end of file
+}
diff --git a/scripts/npc/9060000.js b/scripts/npc/9060000.js
index 6120d47d68..aeb86ff6f5 100644
--- a/scripts/npc/9060000.js
+++ b/scripts/npc/9060000.js
@@ -20,9 +20,12 @@
along with this program. If not, see .
*/
var status = -1;
+var completed;
function start() {
- if (cm.haveItem(4031508, 5) && cm.haveItem(4031507,5)) {
+ completed = cm.haveItem(4031508, 5) && cm.haveItem(4031507,5);
+
+ if (completed) {
cm.sendNext("Wow~ You have succeeded in collecting 5 of each #b#t4031508##k and #b#t4031507##k. Okay then, I will send you to Zoo. Please talk to me again when you get there.");
} else {
cm.sendYesNo("You haven't completed the requirements. Are you sure you want to leave?");
@@ -36,9 +39,15 @@ function action(mode, type, selection){
return;
}
- if(status == 0) cm.sendOk("Well okay, I will send you back.");
- else {
- cm.getEventInstance().clearPQ();
+ if(status == 0) {
+ cm.sendOk("Well okay, I will send you back.");
+ } else {
+ if (completed) {
+ cm.getEventInstance().clearPQ();
+ } else {
+ cm.warp(923010100, 0);
+ }
+
cm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/npc/9120003.js b/scripts/npc/9120003.js
index fb3e89c5e8..fb08eed273 100644
--- a/scripts/npc/9120003.js
+++ b/scripts/npc/9120003.js
@@ -49,7 +49,7 @@ function action(mode, type, selection) {
cm.sendOk("Please check and see if you have " + price + " mesos to enter this place.");
else {
cm.gainMeso(-price);
- cm.warp(801000100 + 100 * cm.getPlayer().getGender());
+ cm.warp(801000100 + 100 * cm.getPlayer().getGender(), "out00");
}
cm.dispose();
}
diff --git a/scripts/npc/9120015.js b/scripts/npc/9120015.js
index bb0a9642d0..f5846c1ac1 100644
--- a/scripts/npc/9120015.js
+++ b/scripts/npc/9120015.js
@@ -50,7 +50,7 @@ function action(mode, type, selection) {
cm.dispose();
}
} else {
- cm.warp(801040000);
+ cm.warp(801040000, "in00");
cm.dispose();
}
}
diff --git a/scripts/npc/9120200.js b/scripts/npc/9120200.js
index 4d9bb231ad..e517b07837 100644
--- a/scripts/npc/9120200.js
+++ b/scripts/npc/9120200.js
@@ -30,9 +30,9 @@ function action(mode, type, selection) {
cm.dispose();
} else {
if (mode == 0) {
- cm.sendOk("If you want to return to #m801000000#, then talk to me");
+ cm.sendOk("If you want to return to #m801000000#, then talk to me.");
cm.dispose();
- } if (mode == 1) {
+ } else if (mode == 1) {
status++;
}
if (status == 1) {
diff --git a/scripts/npc/9120201.js b/scripts/npc/9120201.js
index fd201e1de3..13be378b5a 100644
--- a/scripts/npc/9120201.js
+++ b/scripts/npc/9120201.js
@@ -65,8 +65,13 @@ function action(mode, type, selection) {
cm.sendSimple("#e#b\r\n#k#n" + em.getProperty("party") + "\r\n\r\nWould you like to assemble a team to take on #r" + expedBoss + "#k?\r\n#b#L1#Lets get this going!#l\r\n\#L2#No, I think I'll wait a bit...#l");
status = 1;
} else if (expedition.isLeader(player)) { //If you're the leader, manage the exped
- cm.sendSimple(list);
- status = 2;
+ if (expedition.isInProgress()) {
+ cm.sendOk("Your expedition is already in progress, for those who remain battling lets pray for those brave souls.");
+ cm.dispose();
+ } else {
+ cm.sendSimple(list);
+ status = 2;
+ }
} else if (expedition.isRegistering()) { //If the expedition is registering
if (expedition.contains(player)) { //If you're in it but it hasn't started, be patient
cm.sendOk("You have already registered for the expedition. Please wait for #r" + expedition.getLeader().getName() + "#k to begin it.");
@@ -105,8 +110,11 @@ function action(mode, type, selection) {
return;
}
- if (cm.createExpedition(exped)) {
+ var res = cm.createExpedition(exped);
+ if (res == 0) {
cm.sendOk("The #r" + expedBoss + " Expedition#k has been created.\r\n\r\nTalk to me again to view the current team, or start the fight!");
+ } else if (res > 0) {
+ cm.sendOk("Sorry, you've already reached the quota of attempts for this expedition! Try again another day...");
} else {
cm.sendOk("An unexpected error has occurred when starting the expedition, please try again later.");
}
diff --git a/scripts/npc/9201002.js b/scripts/npc/9201002.js
index 8a9341aa87..40faa47cff 100644
--- a/scripts/npc/9201002.js
+++ b/scripts/npc/9201002.js
@@ -21,7 +21,7 @@
Marriage NPC
*/
-importPackage(Packages.constants);
+importPackage(Packages.config);
importPackage(Packages.net.server.channel.handlers);
importPackage(Packages.tools);
importPackage(Packages.tools.packets);
@@ -32,7 +32,7 @@ var eim;
var weddingEventName = "WeddingCathedral";
var cathedralWedding = true;
var weddingIndoors;
-var weddingBlessingExp = ServerConstants.WEDDING_BLESS_EXP;
+var weddingBlessingExp = YamlConfig.config.server.WEDDING_BLESS_EXP;
function isWeddingIndoors(mapid) {
return mapid >= 680000100 && mapid <= 680000500;
@@ -304,7 +304,7 @@ function action(mode, type, selection) {
if (state == 0) { // give player blessings
eim.gridInsert(cm.getPlayer(), 1);
- if (ServerConstants.WEDDING_BLESSER_SHOWFX) {
+ if (YamlConfig.config.server.WEDDING_BLESSER_SHOWFX) {
var target = cm.getPlayer();
target.announce(MaplePacketCreator.showSpecialEffect(9));
target.getMap().broadcastMessage(target, MaplePacketCreator.showForeignEffect(target.getId(), 9), false);
diff --git a/scripts/npc/9201003.js b/scripts/npc/9201003.js
index af2a3c6ecb..2f30233c03 100644
--- a/scripts/npc/9201003.js
+++ b/scripts/npc/9201003.js
@@ -63,7 +63,7 @@ function action(mode, type, selection) {
cm.sendOk("Hello we're Mom and Dad...");
cm.dispose();
} else {
- if (cm.getQuestProgress(100400, 1) == 0) {
+ if (cm.getQuestProgressInt(100400, 1) == 0) {
cm.sendNext("Mom, dad, I have a request to do to both of you... I wanna know more about the path you've already been walking since always, the path of loving and caring for someone dear to me.", 2);
} else {
if(!hasProofOfLoves(cm.getPlayer())) {
diff --git a/scripts/npc/9201005.js b/scripts/npc/9201005.js
index 354076b112..7e4006775b 100644
--- a/scripts/npc/9201005.js
+++ b/scripts/npc/9201005.js
@@ -21,6 +21,8 @@
Marriage NPC
*/
+importPackage(Packages.net.server.channel);
+
var status;
var wid;
var isMarrying;
@@ -176,7 +178,7 @@ function action(mode, type, selection) {
if(resStatus > 0) {
cm.gainItem((weddingType) ? weddingEntryTicketPremium : weddingEntryTicketCommon, -1);
- var expirationTime = cserv.getRelativeWeddingTicketExpireTime(resStatus);
+ var expirationTime = Channel.getRelativeWeddingTicketExpireTime(resStatus);
cm.gainItem(weddingSendTicket,15,false,true,expirationTime);
partner.getAbstractPlayerInteraction().gainItem(weddingSendTicket,15,false,true,expirationTime);
@@ -251,7 +253,7 @@ function action(mode, type, selection) {
if(cm.canHold(weddingSendTicket, 3)) {
cm.gainItem(5251100, -1);
- var expirationTime = cserv.getRelativeWeddingTicketExpireTime(resStatus);
+ var expirationTime = Channel.getRelativeWeddingTicketExpireTime(resStatus);
cm.gainItem(weddingSendTicket,3,false,true,expirationTime);
} else {
cm.sendOk("Please have a free ETC slot available to get more invitations.");
diff --git a/scripts/npc/9201008.js b/scripts/npc/9201008.js
index b13337fc78..8d1813e23b 100644
--- a/scripts/npc/9201008.js
+++ b/scripts/npc/9201008.js
@@ -21,6 +21,8 @@
Marriage NPC
*/
+importPackage(Packages.net.server.channel);
+
var status;
var wid;
var isMarrying;
@@ -176,7 +178,7 @@ function action(mode, type, selection) {
if(resStatus > 0) {
cm.gainItem((weddingType) ? weddingEntryTicketPremium : weddingEntryTicketCommon, -1);
- var expirationTime = cserv.getRelativeWeddingTicketExpireTime(resStatus);
+ var expirationTime = Channel.getRelativeWeddingTicketExpireTime(resStatus);
cm.gainItem(weddingSendTicket,15,false,true,expirationTime);
partner.getAbstractPlayerInteraction().gainItem(weddingSendTicket,15,false,true,expirationTime);
@@ -251,7 +253,7 @@ function action(mode, type, selection) {
if(cm.canHold(weddingSendTicket, 3)) {
cm.gainItem(5251100, -1);
- var expirationTime = cserv.getRelativeWeddingTicketExpireTime(resStatus);
+ var expirationTime = Channel.getRelativeWeddingTicketExpireTime(resStatus);
cm.gainItem(weddingSendTicket,3,false,true,expirationTime);
} else {
cm.sendOk("Please have a free ETC slot available to get more invitations.");
diff --git a/scripts/npc/9201011.js b/scripts/npc/9201011.js
index b81902eab3..0cb2c189b3 100644
--- a/scripts/npc/9201011.js
+++ b/scripts/npc/9201011.js
@@ -21,7 +21,7 @@
Marriage NPC
*/
-importPackage(Packages.constants);
+importPackage(Packages.config);
importPackage(Packages.net.server.channel.handlers);
importPackage(Packages.tools);
importPackage(Packages.tools.packets);
@@ -32,7 +32,7 @@ var eim;
var weddingEventName = "WeddingChapel";
var cathedralWedding = false;
var weddingIndoors;
-var weddingBlessingExp = ServerConstants.WEDDING_BLESS_EXP;
+var weddingBlessingExp = YamlConfig.config.server.WEDDING_BLESS_EXP;
function detectPlayerItemid(player) {
for (var x = 4031357; x <= 4031364; x++) {
@@ -174,7 +174,7 @@ function action(mode, type, selection) {
if(state == 0) { // give player blessings
eim.gridInsert(cm.getPlayer(), 1);
- if(ServerConstants.WEDDING_BLESSER_SHOWFX) {
+ if(YamlConfig.config.server.WEDDING_BLESSER_SHOWFX) {
var target = cm.getPlayer();
target.announce(MaplePacketCreator.showSpecialEffect(9));
target.getMap().broadcastMessage(target, MaplePacketCreator.showForeignEffect(target.getId(), 9), false);
diff --git a/scripts/npc/9201015.js b/scripts/npc/9201015.js
index ea75f85e19..4786e909e3 100644
--- a/scripts/npc/9201015.js
+++ b/scripts/npc/9201015.js
@@ -84,7 +84,10 @@ function action(mode, type, selection) {
else if (status == 2){
cm.dispose();
if (beauty == 1){
- if (cm.haveItem(5150020) == true){
+ if (cm.haveItem(5420000)){
+ cm.setHair(hairnew[selection]);
+ cm.sendOk("Enjoy your new and improved hairstyle!");
+ } else if (cm.haveItem(5150020) == true){
cm.gainItem(5150020, -1);
cm.setHair(hairnew[selection]);
cm.sendOk("Enjoy your new and improved hairstyle!");
diff --git a/scripts/npc/9201023.js b/scripts/npc/9201023.js
index d654fed771..8e6326a9a2 100644
--- a/scripts/npc/9201023.js
+++ b/scripts/npc/9201023.js
@@ -99,14 +99,14 @@ function action(mode, type, selection) {
if(status == 0) {
if(!cm.isQuestStarted(100400)) {
- cm.sendOk("Hello #b#h0##k, I'm #p9201001# the fairy of Love.");
+ cm.sendOk("Hello #b#h0##k, I'm #p9201023# the fairy of Love."); // thanks Periwinks (LuckyStory) for noticing Nana's introducing themselves as Nana (H)
cm.dispose();
return;
}
nanaLoc = getNanaLocation(cm.getPlayer());
if(nanaLoc == -1) {
- cm.sendOk("Hello #b#h0##k, I'm #p9201001# the fairy of Love.");
+ cm.sendOk("Hello #b#h0##k, I'm #p9201023# the fairy of Love.");
cm.dispose();
return;
}
diff --git a/scripts/npc/9201024.js b/scripts/npc/9201024.js
index d654fed771..271cf7a75b 100644
--- a/scripts/npc/9201024.js
+++ b/scripts/npc/9201024.js
@@ -99,14 +99,14 @@ function action(mode, type, selection) {
if(status == 0) {
if(!cm.isQuestStarted(100400)) {
- cm.sendOk("Hello #b#h0##k, I'm #p9201001# the fairy of Love.");
+ cm.sendOk("Hello #b#h0##k, I'm #p9201024# the fairy of Love.");
cm.dispose();
return;
}
nanaLoc = getNanaLocation(cm.getPlayer());
if(nanaLoc == -1) {
- cm.sendOk("Hello #b#h0##k, I'm #p9201001# the fairy of Love.");
+ cm.sendOk("Hello #b#h0##k, I'm #p9201024# the fairy of Love.");
cm.dispose();
return;
}
diff --git a/scripts/npc/9201025.js b/scripts/npc/9201025.js
index d654fed771..d284706f18 100644
--- a/scripts/npc/9201025.js
+++ b/scripts/npc/9201025.js
@@ -99,14 +99,14 @@ function action(mode, type, selection) {
if(status == 0) {
if(!cm.isQuestStarted(100400)) {
- cm.sendOk("Hello #b#h0##k, I'm #p9201001# the fairy of Love.");
+ cm.sendOk("Hello #b#h0##k, I'm #p9201025# the fairy of Love.");
cm.dispose();
return;
}
nanaLoc = getNanaLocation(cm.getPlayer());
if(nanaLoc == -1) {
- cm.sendOk("Hello #b#h0##k, I'm #p9201001# the fairy of Love.");
+ cm.sendOk("Hello #b#h0##k, I'm #p9201025# the fairy of Love.");
cm.dispose();
return;
}
diff --git a/scripts/npc/9201026.js b/scripts/npc/9201026.js
index d654fed771..48d97f52a3 100644
--- a/scripts/npc/9201026.js
+++ b/scripts/npc/9201026.js
@@ -99,14 +99,14 @@ function action(mode, type, selection) {
if(status == 0) {
if(!cm.isQuestStarted(100400)) {
- cm.sendOk("Hello #b#h0##k, I'm #p9201001# the fairy of Love.");
+ cm.sendOk("Hello #b#h0##k, I'm #p9201026# the fairy of Love.");
cm.dispose();
return;
}
nanaLoc = getNanaLocation(cm.getPlayer());
if(nanaLoc == -1) {
- cm.sendOk("Hello #b#h0##k, I'm #p9201001# the fairy of Love.");
+ cm.sendOk("Hello #b#h0##k, I'm #p9201026# the fairy of Love.");
cm.dispose();
return;
}
diff --git a/scripts/npc/9201027.js b/scripts/npc/9201027.js
index d654fed771..e02f52039e 100644
--- a/scripts/npc/9201027.js
+++ b/scripts/npc/9201027.js
@@ -99,14 +99,14 @@ function action(mode, type, selection) {
if(status == 0) {
if(!cm.isQuestStarted(100400)) {
- cm.sendOk("Hello #b#h0##k, I'm #p9201001# the fairy of Love.");
+ cm.sendOk("Hello #b#h0##k, I'm #p9201027# the fairy of Love.");
cm.dispose();
return;
}
nanaLoc = getNanaLocation(cm.getPlayer());
if(nanaLoc == -1) {
- cm.sendOk("Hello #b#h0##k, I'm #p9201001# the fairy of Love.");
+ cm.sendOk("Hello #b#h0##k, I'm #p9201027# the fairy of Love.");
cm.dispose();
return;
}
diff --git a/scripts/npc/9201064.js b/scripts/npc/9201064.js
index 0304261797..540e599fac 100644
--- a/scripts/npc/9201064.js
+++ b/scripts/npc/9201064.js
@@ -73,7 +73,10 @@ function action(mode, type, selection) {
else if (status == 2){
cm.dispose();
if (beauty == 1){
- if (cm.haveItem(5150031)){
+ if (cm.haveItem(5420001)){
+ cm.setHair(hairnew[selection]);
+ cm.sendOk("Enjoy your new and improved hairstyle!");
+ } else if (cm.haveItem(5150031)){
cm.gainItem(5150031, -1);
cm.setHair(hairnew[selection]);
cm.sendOk("Enjoy your new and improved hairstyle!");
diff --git a/scripts/npc/9201101.js b/scripts/npc/9201101.js
index c2fecb4580..c424e7dcd9 100644
--- a/scripts/npc/9201101.js
+++ b/scripts/npc/9201101.js
@@ -4,7 +4,7 @@
*/
function start() {
- if (Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
+ if (Packages.config.YamlConfig.config.server.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
cm.openShopNPC(9201101);
} else {
//cm.sendOk("The patrol in New Leaf City is always ready. No creatures are able to break through to the city.");
diff --git a/scripts/npc/9201113.js b/scripts/npc/9201113.js
index fa7b31b743..766cae86de 100644
--- a/scripts/npc/9201113.js
+++ b/scripts/npc/9201113.js
@@ -61,8 +61,13 @@ function action(mode, type, selection) {
cm.sendSimple("#e#b\r\n#k#n" + em.getProperty("party") + "\r\n\r\nWould you like to assemble a team to attempt the #rCrimsonwood Keep Party Quest#k?\r\n#b#L1#Lets get this going!#l\r\n\#L2#No, I think I'll wait a bit...#l");
status = 1;
} else if (expedition.isLeader(player)) { //If you're the leader, manage the exped
- cm.sendSimple(list);
- status = 2;
+ if (expedition.isInProgress()) {
+ cm.sendOk("Your expedition is already in progress, for those who remain battling lets pray for those brave souls.");
+ cm.dispose();
+ } else {
+ cm.sendSimple(list);
+ status = 2;
+ }
} else if (expedition.isRegistering()) { //If the expedition is registering
if (expedition.contains(player)) { //If you're in it but it hasn't started, be patient
cm.sendOk("You have already registered for the expedition. Please wait for #r" + expedition.getLeader().getName() + "#k to begin it.");
@@ -89,8 +94,11 @@ function action(mode, type, selection) {
return;
}
- if (cm.createExpedition(cwkpq)) {
+ var res = cm.createExpedition(cwkpq);
+ if (res == 0) {
cm.sendOk("The #rCrimsonwood Keep Party Quest Expedition#k has been created.\r\n\r\nTalk to me again to view the current team, or start the fight!");
+ } else if (res > 0) {
+ cm.sendOk("Sorry, you've already reached the quota of attempts for this expedition! Try again another day...");
} else {
cm.sendOk("An unexpected error has occurred when starting the expedition, please try again later.");
}
diff --git a/scripts/npc/9201115.js b/scripts/npc/9201115.js
index 05405fd3fb..a8c036ad81 100644
--- a/scripts/npc/9201115.js
+++ b/scripts/npc/9201115.js
@@ -35,11 +35,11 @@ function action(mode, type, selection) {
cm.mapMessage(6, "Engarde! Master Guardians approach!");
for (var i = 0; i < 10; i++) {
var mob = eim.getMonster(9400594);
- cm.getMap().spawnMonsterOnGroundBelow(mob, new java.awt.Point(-1337 + (java.lang.Math.random() * 1337), 276));
+ cm.getMap().spawnMonsterOnGroundBelow(mob, new java.awt.Point(-1337 + (Math.random() * 1337), 276));
}
for (var i = 0; i < 20; i++) {
var mob = eim.getMonster(9400582);
- cm.getMap().spawnMonsterOnGroundBelow(mob, new java.awt.Point(-1337 + (java.lang.Math.random() * 1337), 276));
+ cm.getMap().spawnMonsterOnGroundBelow(mob, new java.awt.Point(-1337 + (Math.random() * 1337), 276));
}
eim.setIntProperty("glpq6", 1);
cm.dispose();
diff --git a/scripts/npc/9270033.js b/scripts/npc/9270033.js
index b12b211261..186a9d1c41 100644
--- a/scripts/npc/9270033.js
+++ b/scripts/npc/9270033.js
@@ -60,7 +60,7 @@ function action(mode, type, selection) {
}
}
- cm.warp(541010110);
+ cm.warp(541010110, 0);
cm.dispose();
}
}
diff --git a/scripts/npc/9270047.js b/scripts/npc/9270047.js
index a660524100..b77399be54 100644
--- a/scripts/npc/9270047.js
+++ b/scripts/npc/9270047.js
@@ -66,8 +66,13 @@ function action(mode, type, selection) {
cm.sendSimple("#e#b\r\n#k#n" + em.getProperty("party") + "\r\n\r\nWould you like to assemble a team to take on #r" + expedBoss + "#k?\r\n#b#L1#Lets get this going!#l\r\n\#L2#No, I think I'll wait a bit...#l");
status = 1;
} else if (expedition.isLeader(player)) { //If you're the leader, manage the exped
- cm.sendSimple(list);
- status = 2;
+ if (expedition.isInProgress()) {
+ cm.sendOk("Your expedition is already in progress, for those who remain battling lets pray for those brave souls.");
+ cm.dispose();
+ } else {
+ cm.sendSimple(list);
+ status = 2;
+ }
} else if (expedition.isRegistering()) { //If the expedition is registering
if (expedition.contains(player)) { //If you're in it but it hasn't started, be patient
cm.sendOk("You have already registered for the expedition. Please wait for #r" + expedition.getLeader().getName() + "#k to begin it.");
@@ -106,8 +111,11 @@ function action(mode, type, selection) {
return;
}
- if (cm.createExpedition(exped)) {
+ var res = cm.createExpedition(exped);
+ if (res == 0) {
cm.sendOk("The #r" + expedBoss + " Expedition#k has been created.\r\n\r\nTalk to me again to view the current team, or start the fight!");
+ } else if (res > 0) {
+ cm.sendOk("Sorry, you've already reached the quota of attempts for this expedition! Try again another day...");
} else {
cm.sendOk("An unexpected error has occurred when starting the expedition, please try again later.");
}
diff --git a/scripts/npc/9900000.js b/scripts/npc/9900000.js
index cf5dffdb19..6407ca43f5 100644
--- a/scripts/npc/9900000.js
+++ b/scripts/npc/9900000.js
@@ -40,6 +40,12 @@ var facenew = Array();
var colors = Array();
var price = 100000;
+function pushIfItemExists(array, itemid) {
+ if ((itemid = cm.getCosmeticItem(itemid)) != -1 && !cm.isCosmeticEquipped(itemid)) { // thanks Conrad for noticing NPC crashing the player when trying to display inexistent cosmetics
+ array.push(itemid);
+ }
+}
+
function start() {
if(cm.getPlayer().gmLevel() < 1) {
cm.sendOk("Hey wassup?");
@@ -67,21 +73,21 @@ function action(mode, type, selection) {
cm.sendStyle("Pick one?", skin);
else if (selection == 1 || selection == 5) {
for each(var i in selection == 1 ? hair : fhair)
- hairnew.push(i);
+ pushIfItemExists(hairnew, i);
cm.sendStyle("Pick one?", hairnew);
} else if (selection == 2) {
var baseHair = parseInt(cm.getPlayer().getHair() / 10) * 10;
for(var k = 0; k < 8; k++)
- haircolor.push(baseHair + k);
+ pushIfItemExists(haircolor, baseHair + k);
cm.sendStyle("Pick one?", haircolor);
} else if (selection == 3 || selection == 6) {
for each(var j in selection == 3 ? face : fface)
- facenew.push(j);
+ pushIfItemExists(facenew, j);
cm.sendStyle("Pick one?", facenew);
} else if (selection == 4) {
var baseFace = parseInt(cm.getPlayer().getFace() / 1000) * 1000 + parseInt(cm.getPlayer().getFace() % 100);
for(var i = 0; i < 9; i++)
- colors.push(baseFace + (i*100));
+ pushIfItemExists(colors, baseFace + (i*100));
cm.sendStyle("Pick one?", colors);
}
} else {
diff --git a/scripts/npc/9977777.js b/scripts/npc/9977777.js
index e07fedd126..fd0d44d76c 100644
--- a/scripts/npc/9977777.js
+++ b/scripts/npc/9977777.js
@@ -43,6 +43,7 @@ function writeFeatureTab_PQs() {
addFeature("RnJPQ/HorntailPQ/TreasurePQ/ElnathPQ/HolidayPQ.");
addFeature("CWKPQ as Expedition-based instance.");
addFeature("Scarga/Horntail/Showa/Balrog/Zakum/Pinkbean.");
+ addFeature("Expeditions with entry-limit system available.");
addFeature("GuildPQ & queue with multi-lobby system available.");
addFeature("Brand-new PQs: BossRushPQ, CafePQ.");
addFeature("Mu Lung Dojo.");
@@ -57,10 +58,11 @@ function writeFeatureTab_Skills() {
addFeature("Reviewed many skills, such as Steal and M. Door.");
addFeature("Heal GMS-like: fixed HP gain & Heal skill packet.");
addFeature("Improved battleship: HP visible and map-persistent.");
- addFeature("Maker skill features properly developed.");
+ addFeature("Maker skill features developed - pckts thanks Arnah.");
addFeature("Chair Mastery - map chair boosts HP/MP rec.");
addFeature("Mu Lung Dojo skills functional.");
addFeature("Monster Magnet skill no longer crashes players.");
+ addFeature("HP/MP consumption from skills triggers pet autopot.");
}
function writeFeatureTab_Quests() {
@@ -74,6 +76,8 @@ function writeFeatureTab_Quests() {
addFeature("Rewarding system now looks up for item stacking.");
addFeature("3rd job quiz with all 40-question pool available.");
addFeature("Item raising functional.");
+ addFeature("Cleared issue with player movement during NPC talk.");
+ addFeature("Reviewed usage of quest progress data as requisite.");
}
function writeFeatureTab_PlayerSocialNetwork() {
@@ -185,6 +189,7 @@ function writeFeatureTab_Playerpotentials() {
addFeature("Optional cash shop inventory separated by classes.");
addFeature("Players manage 'same-typed' invites exclusively.");
addFeature("Player buffs with conditional active effects.");
+ addFeature("Rock-paper-scissors minigame - thanks Arnah!");
}
function writeFeatureTab_Serverpotentials() {
@@ -248,6 +253,7 @@ function writeFeatureTab_CustomNPCs() {
addFeature("Dalair: automatized equipment-merger.");
addFeature("Donation Box: automatized item-buyer.");
addFeature("Coco & Ace of Hearts: C. scroll crafters.");
+ addFeature("Barry (MapleTV): fill book & exchange items for scroll.");
}
function writeFeatureTab_Localhostedits() {
@@ -282,6 +288,7 @@ function writeFeatureTab_Project() {
addFeature("Remodeled item scripts, properly using NPC dialogs.");
addFeature("ThreadTracker: runtime tool for deadlock detection.");
addFeature("Channel, World and Server-wide timer management.");
+ addFeature("Developed services as preemptive task scheduler.");
addFeature("Thoroughly reviewed encapsulation for player stats.");
addFeature("Heavily reviewed future task management, spawning much less threads and relieving task overload on the TimerManager.");
}
@@ -293,7 +300,7 @@ function writeAllFeatures() {
feature_cursor = [];
var tabName = (tabs[i]).replace(re, "");
- eval("writeFeatureTab_" + tabName)();
+ this["writeFeatureTab_" + tabName]();
feature_tree.push(feature_cursor);
}
@@ -322,7 +329,7 @@ function action(mode, type, selection) {
status--;
if (status == 0) {
- var sendStr = "HeavenMS was developed on the timespan of 3 years, based on where Solaxia left. I'm glad to say the development itself had continuously been agraciated by dozens of contributors and cheerers (truly thanks for the trusting vow, guys & gals!).\r\n\r\nTalking about results: many nice features emerged, development aimed to get back the old GMS experience. Now many of these so-long missing features are gracefully presented to you in the shape of this server. Long live MapleStory!!\r\n\r\nThese are the features from #bHeavenMS#k:\r\n\r\n";
+ var sendStr = "HeavenMS was developed on the timespan of 4 years, based on where Solaxia left. I'm glad to say the development itself had continuously been agraciated by dozens of contributors and cheerers (truly thanks for the trusting vow, guys & gals!).\r\n\r\nTalking about results: many nice features emerged, development aimed to get back the old GMS experience. Now many of these so-long missing features are gracefully presented to you in the shape of this server. Long live MapleStory!!\r\n\r\nThese are the features from #bHeavenMS#k:\r\n\r\n";
for(var i = 0; i < tabs.length; i++) {
sendStr += "#L" + i + "##b" + tabs[i] + "#k#l\r\n";
}
diff --git a/scripts/npc/MagatiaPassword.js b/scripts/npc/MagatiaPassword.js
index a6bd7bf9d4..eaab5b7a19 100644
--- a/scripts/npc/MagatiaPassword.js
+++ b/scripts/npc/MagatiaPassword.js
@@ -19,9 +19,10 @@ function action(mode, type, selection){
cm.sendGetText("The door reacts to the entry pass inserted. #bPassword#k!");
}
else if(status == 1){
- if(cm.getText() == cm.getStringQuestProgress(3360, 0)){
- cm.setQuestProgress(3360, 1, 1);
- cm.warp((cm.getMapId() == 261010000) ? 261020200 : 261010000, "secret00");
+ if(cm.getText() == cm.getQuestProgress(3360)){
+ cm.setQuestProgress(3360, 1);
+ cm.getPlayer().announce(Packages.tools.MaplePacketCreator.playPortalSound());
+ cm.warp(261030000, "sp_" + ((cm.getMapId() == 261010000) ? "jenu" : "alca"));
}
else {
cm.sendOk("#rWrong!");
diff --git a/scripts/npc/PupeteerPassword.js b/scripts/npc/PupeteerPassword.js
index 462f8157fb..8d3ca92136 100644
--- a/scripts/npc/PupeteerPassword.js
+++ b/scripts/npc/PupeteerPassword.js
@@ -20,7 +20,7 @@ function action(mode, type, selection){
if(status == 0){
if(cm.isQuestStarted(21728)) {
cm.sendOk("You search for any hints of the Puppeteer, but it seems a powerful force blocks the path... Better return to #b#p1061019##k.");
- cm.setQuestProgress(21728, 0, 1);
+ cm.setQuestProgress(21728, 21761, 0);
cm.dispose();
return;
}
@@ -29,12 +29,12 @@ function action(mode, type, selection){
}
else if(status == 1){
if(cm.getText() == "Francis is a genius Puppeteer!"){
- if(cm.isQuestStarted(20730) && cm.getQuestProgress(20730, 9300285) == 0)
+ if(cm.isQuestStarted(20730) && cm.getQuestProgressInt(20730, 9300285) == 0)
cm.warp(910510001, 1);
- else if(cm.isQuestStarted(21731) && cm.getQuestProgress(21731, 9300346) == 0)
+ else if(cm.isQuestStarted(21731) && cm.getQuestProgressInt(21731, 9300346) == 0)
cm.warp(910510001, 1);
else
- cm.playerMessage(5, "Although you said the right answer, some mysterious forces is blocking the way in.");
+ cm.playerMessage(5, "Although you said the right answer, some mysterious forces are blocking the way in.");
cm.dispose();
}
diff --git a/scripts/npc/ThiefPassword.js b/scripts/npc/ThiefPassword.js
index ca6df9a429..efc0ff1db8 100644
--- a/scripts/npc/ThiefPassword.js
+++ b/scripts/npc/ThiefPassword.js
@@ -23,7 +23,7 @@ function action(mode, type, selection){
else if(status == 1){
if(cm.getText() == "Open Sesame"){
if(cm.isQuestCompleted(3925))
- cm.warp(260010402);
+ cm.warp(260010402, 1);
else
cm.playerMessage(5, "Although you said the right answer, the door will not budge.");
diff --git a/scripts/npc/cpqchallenge.js b/scripts/npc/cpqchallenge.js
index 1be873d469..c55c990717 100644
--- a/scripts/npc/cpqchallenge.js
+++ b/scripts/npc/cpqchallenge.js
@@ -5,7 +5,7 @@
---------------------------------------------------------------------------------------------------
**/
-importPackage(Packages.constants);
+importPackage(Packages.constants.game);
var status = 0;
var party;
diff --git a/scripts/npc/cpqchallenge2.js b/scripts/npc/cpqchallenge2.js
index 1be873d469..c55c990717 100644
--- a/scripts/npc/cpqchallenge2.js
+++ b/scripts/npc/cpqchallenge2.js
@@ -5,7 +5,7 @@
---------------------------------------------------------------------------------------------------
**/
-importPackage(Packages.constants);
+importPackage(Packages.constants.game);
var status = 0;
var party;
diff --git a/scripts/npc/credits.js b/scripts/npc/credits.js
index b683623e81..29db73a8fc 100644
--- a/scripts/npc/credits.js
+++ b/scripts/npc/credits.js
@@ -13,7 +13,7 @@ var name_cursor, role_cursor;
// new server names are to be appended at the start of the name stack, building up the chronology.
// make sure the server names are lexicograffically equivalent to their correspondent function.
-var servers = ["HeavenMS", "MapleSolaxia", "MoopleDEV", "MetroMS", "BubblesDEV", "ThePackII", "OdinMS", "Contributors"];
+var servers = ["HeavenMS", "MapleSolaxia", "MoopleDEV", "MetroMS", "BubblesDEV", "OdinMS", "Contributors"];
var servers_history = [];
function addPerson(name, role) {
@@ -41,7 +41,7 @@ function writeServerStaff_HeavenMS() {
addPerson("Masterrulax", "Contributor");
addPerson("MedicOP", "Adjunct Developer");
- setHistory(2015, 2018);
+ setHistory(2015, 2019);
}
function writeServerStaff_MapleSolaxia() {
@@ -58,26 +58,28 @@ function writeServerStaff_MapleSolaxia() {
}
function writeServerStaff_MoopleDEV() {
- addPerson("conan513", "Administrator");
addPerson("kevintjuh93", "Developer");
+ addPerson("hindie93", "Contributor");
+ addPerson("JuniarZ-", "Contributor");
+
setHistory(2010, 2012);
}
function writeServerStaff_MetroMS() {
- addPerson("Moogra", "Developer");
+ addPerson("David!", "Developer");
+ addPerson("XxOsirisxX", "Contributor");
+ addPerson("Generic", "Contributor");
+
setHistory(2009, 2010);
}
function writeServerStaff_BubblesDEV() {
- addPerson("Deagan", "Administrator");
- addPerson("XxOsirisxX", "Developer");
- setHistory(2009, 2009);
-}
-
-function writeServerStaff_ThePackII() {
- addPerson("Hofer", "Developer");
+ addPerson("David!", "Developer");
addPerson("Moogra", "Developer");
- setHistory(2008, 2009);
+ addPerson("XxOsirisxX", "Contributor");
+ addPerson("MrMysterious", "Contributor");
+
+ setHistory(2009, 2009);
}
function writeServerStaff_OdinMS() {
@@ -86,10 +88,14 @@ function writeServerStaff_OdinMS() {
addPerson("Patrick", "Developer");
addPerson("Matze", "Developer");
addPerson("Vimes", "Developer");
+
setHistory(2007, 2008);
}
function writeServerStaff_Contributors() {
+ addPerson("IxianMace", "Contributor");
+ addPerson("Conrad", "Contributor");
+ addPerson("inhyuk", "Contributor");
addPerson("Jayd", "Contributor");
addPerson("Dragohe4rt", "Contributor");
addPerson("Jvlaple", "Contributor");
@@ -112,7 +118,7 @@ function writeAllServerStaffs() {
role_cursor = [];
var srvName = servers[i];
- eval("writeServerStaff_" + srvName)();
+ this["writeServerStaff_" + srvName]();
name_tree.push(name_cursor);
role_tree.push(role_cursor);
diff --git a/scripts/npc/mapleTV.js b/scripts/npc/mapleTV.js
new file mode 100644
index 0000000000..93c58b5d66
--- /dev/null
+++ b/scripts/npc/mapleTV.js
@@ -0,0 +1,55 @@
+/*
+ This file is part of the HeavenMS MapleStory Server
+ Copyleft (L) 2016 - 2019 RonanLana
+
+ 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 .
+*/
+/*
+ Default Maple TV
+ */
+
+var status;
+
+function start() {
+ if (Packages.config.YamlConfig.config.server.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
+ cm.dispose();
+ cm.openNpc(9201088, "scroll_generator");
+ return;
+ }
+
+ 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) {
+ // do nothing
+ cm.dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/scripts/npc/rank_user.js b/scripts/npc/rank_user.js
index 61e8c1b70c..bbe07c49da 100644
--- a/scripts/npc/rank_user.js
+++ b/scripts/npc/rank_user.js
@@ -21,7 +21,7 @@
* @Author Ronan
* Player NPC Ranking System */
-importPackage(Packages.constants);
+importPackage(Packages.constants.game);
var status;
diff --git a/scripts/npc/scroll_generator.js b/scripts/npc/scroll_generator.js
new file mode 100644
index 0000000000..b3b3f038c7
--- /dev/null
+++ b/scripts/npc/scroll_generator.js
@@ -0,0 +1,408 @@
+/*
+ This file is part of the HeavenMS MapleStory Server
+ Copyleft (L) 2016 - 2019 RonanLana
+
+ 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 .
+*/
+/* NPC: MapleTV / Larry
+
+ Exchanger NPC:
+ * Scroll generator
+ *
+ * @author Ronan Lana
+*/
+
+importPackage(Packages.client);
+importPackage(Packages.config);
+importPackage(Packages.constants.game);
+importPackage(Packages.server);
+importPackage(Packages.server.life);
+
+var status;
+
+var jobWeaponRestricted = [[[2043000, 2043100, 2044000, 2044100, 2043200, 2044200]], [[2043000, 2043100, 2044000, 2044100], [2043000, 2043200, 2044000, 2044200], [2044300, 2044400]], [[2043700, 2043800], [2043700, 2043800], [2043700, 2043800]], [[2044500], [2044600]], [[2044700], [2043300]], [[2044800], [2044900]]];
+var aranWeaponRestricted = [jobWeaponRestricted[1][2][1]];
+
+var tier1Scrolls = [];
+var tier2Scrolls = [2040000, 2040400, 2040500, 2040600, 2040700, 2040800, 2040900];
+var tier3Scrolls = [2048000, 2049200, 2041000, 2041100, 2041300, 2040100, 2040200, 2040300];
+
+var typeTierScrolls = [["PAD", "MAD"], ["STR", "DEX", "INT", "LUK", "ACC", "EVA", "Speed", "Jump"], ["PDD", "MDD", "MHP", "MMP"]];
+
+var sgItems = [4003004, 4003005, 4001006, 4006000, 4006001, 4030012];
+var sgToBucket = [100, 50, 37.5, 37.5, 37.5, 200];
+var mesoToBucket = 2800000;
+
+var sgAppliedItems = [0, 0, 0, 0, 0, 0];
+var sgAppliedMeso = 0;
+
+var sgBuckets = 0.0;
+var sgBookBuckets = 0.0;
+var sgItemBuckets = 0.0;
+
+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.sendNext("This is the MapleTV Scroll Generator broadcast. Place your supplies or mesos earned throughout your adventure to redeem a prize! You can place #bany amount of supplies#k, however take note that placing #rdifferent supplies#k with #rbigger shots of any of them#k will improve the reward possibilities!");
+ } else if(status == 1) {
+ var sendStr;
+
+ //print("Book: " + sgBookBuckets + " Item: " + sgItemBuckets);
+
+ if(sgItemBuckets > 0.0) sendStr = "With the items you have currently placed, you have #r" + sgBuckets + "#k buckets (#r" + (sgItemBuckets < 1.0 ? sgItemBuckets.toFixed(2) : Math.floor(sgItemBuckets)) + "#k supply buckets) for claiming a prize. Place supplies:";
+ else sendStr = "You have placed no supplies yet. Place supplies:";
+
+ var listStr = "";
+ var i;
+ for(i = 0; i < sgItems.length; i++) {
+ listStr += "#b#L" + i + "##t" + sgItems[i] + "##k";
+ if(sgAppliedItems[i] > 0) listStr += " - " + sgAppliedItems[i];
+ listStr += "#l\r\n";
+ }
+
+ listStr += "#b#L" + i + "#Mesos#k";
+ if(sgAppliedMeso > 0) listStr += " - " + sgAppliedMeso;
+ listStr += "#l\r\n";
+
+ cm.sendSimple(sendStr + "\r\n\r\n" + listStr + "#r#L" + (sgItems.length + 2) + "#Retrieve a prize!#l#k\r\n");
+ } else if(status == 2) {
+ if(selection == (sgItems.length + 2)) {
+ if(sgItemBuckets < 1.0) {
+ cm.sendPrev("You have set not enough supplies. Insert at least one bucket of #bsupplies#k to claim a prize.");
+ } else {
+ generateRandomScroll();
+ cm.dispose();
+ }
+ } else {
+ var tickSel;
+ if(selection < sgItems.length) {
+ tickSel = "of #b#t" + sgItems[selection] + "##k";
+ curItemQty = cm.getItemQuantity(sgItems[selection]);
+ } else {
+ tickSel = "#bmesos#k";
+ curItemQty = cm.getMeso();
+ }
+
+ curItemSel = selection;
+ if(curItemQty > 0) {
+ cm.sendGetText("How many " + tickSel + " do you want to provide? (#r" + curItemQty + "#k available)#k");
+ } else {
+ cm.sendPrev("You have got #rnone#k " + tickSel + " to provide for Scroll Generation. Click '#rBack#k' to return to the main interface.");
+ }
+ }
+ } 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 #r" + (curItemSel < sgItems.length ? "#t" + sgItems[curItemSel] + "#" : "mesos") + "#k (#r" + curItemQty + "#k available). Click '#rBack#k' to return to the main interface.");
+ } else {
+ if(curItemSel < sgItems.length) sgApplyItem(curItemSel, placedQty);
+ else sgApplyMeso(placedQty);
+
+ cm.sendPrev("Operation succeeded. Click '#rBack#k' to return to the main interface.");
+ }
+ } catch(err) {
+ cm.sendPrev("You must enter a positive number of supplies to insert. Click '#rBack#k' to return to the main interface.");
+ }
+
+ status = 2;
+ } else {
+ cm.dispose();
+ }
+ }
+}
+
+function getJobTierScrolls() {
+ var scrolls = [];
+
+ var job = cm.getPlayer().getJob();
+ var jobScrolls = jobWeaponRestricted[Math.floor(cm.getPlayer().getJobStyle().getId() / 100)];
+
+ var jobBranch = GameConstants.getJobBranch(job);
+ if (jobBranch >= 2) {
+ Array.prototype.push.apply(scrolls, jobScrolls[Math.floor((job.getId() / 10) % 10) - 1]);
+ } else {
+ for (var i = 0; i < jobScrolls.length; i++) {
+ Array.prototype.push.apply(scrolls, jobScrolls[i]);
+ }
+ }
+
+ return scrolls;
+}
+
+function getScrollTypePool(rewardTier) {
+ var scrolls = [];
+ switch (rewardTier) {
+ case 1:
+ if (cm.getPlayer().isAran()) {
+ Array.prototype.push.apply(scrolls, aranWeaponRestricted);
+ } else {
+ Array.prototype.push.apply(scrolls, getJobTierScrolls());
+ }
+
+ Array.prototype.push.apply(scrolls, tier1Scrolls);
+ break;
+ case 2:
+ Array.prototype.push.apply(scrolls, tier2Scrolls);
+ break;
+ default:
+ Array.prototype.push.apply(scrolls, tier3Scrolls);
+ }
+
+ return scrolls;
+}
+
+function getScrollTier(scrollStats) {
+ for (var i = 0; i < typeTierScrolls.length; i++) {
+ for (var j = 0; j < typeTierScrolls[i].length; j++) {
+ if (scrollStats.get(typeTierScrolls[i][j]) > 0) {
+ return i + 1;
+ }
+ }
+ }
+
+ return 4;
+}
+
+function getScrollSuccessTier(scrollStats) {
+ var prop = scrollStats.get("success");
+
+ if (prop > 90) {
+ return 3;
+ } else if (prop < 50) {
+ return YamlConfig.config.server.SCROLL_CHANCE_ROLLS > 2 ? 2 : 1;
+ } else {
+ return YamlConfig.config.server.SCROLL_CHANCE_ROLLS > 2 ? 1 : 2;
+ }
+}
+
+function getAvailableScrollsPool(baseScrolls, rewardTier, successTier) {
+ var scrolls = [];
+ var ii = MapleItemInformationProvider.getInstance();
+
+ for (var i = 0; i < baseScrolls.length; i++) {
+ for (var j = 0; j < 100; j++) {
+ var scrollid = baseScrolls[i] + j;
+ var scrollStats = ii.getEquipStats(scrollid);
+ if (scrollStats != null && ii.getScrollReqs(scrollid).isEmpty()) {
+ var scrollTier = getScrollTier(scrollStats);
+ if (scrollTier == rewardTier && successTier == getScrollSuccessTier(scrollStats)) {
+ scrolls.push(scrollid);
+ }
+ }
+ }
+ }
+
+ return scrolls;
+}
+
+// passive tier buckets...
+
+function getLevelTier(level) {
+ return Math.floor((level - 1) / 15) + 1;
+}
+
+function getPlayerCardTierPower() {
+ var cardset = cm.getPlayer().getMonsterBook().getCardSet();
+ var countTier = [0, 0, 0, 0, 0, 0, 0, 0, 0];
+
+ for (var iterator = cardset.iterator(); iterator.hasNext();) {
+ var ce = iterator.next();
+
+ var cardid = ce.getKey();
+ var ceTier = Math.floor(cardid / 1000) % 10;
+ countTier[ceTier] += ce.getValue();
+
+ if (ceTier >= 8) { // is special card
+ var mobLevel = MapleLifeFactory.getMonsterLevel(MapleItemInformationProvider.getInstance().getCardMobId(cardid));
+ var mobTier = getLevelTier(mobLevel) - 1;
+
+ countTier[mobTier] += (ce.getValue() * 1.2);
+ }
+ }
+
+ return countTier;
+}
+
+function calculateMobBookTierBuckets(tierSize, playerCards, tier) {
+ if (tier < 1) {
+ return 0.0;
+ }
+
+ tier--; // started at 1
+ var tierHitRate = playerCards[tier] / (tierSize[tier] * 5);
+ if (tierHitRate > 0.5) {
+ tierHitRate = 0.5;
+ }
+
+ return tierHitRate * 4;
+}
+
+function calculateMobBookBuckets() {
+ var book = cm.getPlayer().getMonsterBook();
+ var bookLevelMult = 0.9 + (0.1 * book.getBookLevel());
+
+ var playerLevelTier = getLevelTier(cm.getPlayer().getLevel());
+ if (playerLevelTier > 8) {
+ playerLevelTier = 8;
+ }
+
+ var tierSize = MonsterBook.getCardTierSize();
+ var playerCards = getPlayerCardTierPower();
+
+ var prevBuckets = calculateMobBookTierBuckets(tierSize, playerCards, playerLevelTier - 1);
+ var currBuckets = calculateMobBookTierBuckets(tierSize, playerCards, playerLevelTier);
+
+ return (prevBuckets + currBuckets) * bookLevelMult;
+}
+
+function recalcBuckets() {
+ sgBookBuckets = calculateMobBookBuckets();
+ sgItemBuckets = calculateSuppliesBuckets();
+
+ var buckets = sgBookBuckets + sgItemBuckets;
+ if (buckets > 6.0) {
+ sgBuckets = 6;
+ } else {
+ sgBuckets = Math.floor(buckets);
+ }
+}
+
+// variable buckets...
+
+function sgApplyItem(idx, amount) {
+ if (sgAppliedItems[idx] != amount) {
+ sgAppliedItems[idx] = amount;
+ recalcBuckets();
+ }
+}
+
+function sgApplyMeso(amount) {
+ if (sgAppliedMeso != amount) {
+ sgAppliedMeso = amount;
+ recalcBuckets();
+ }
+}
+
+function calculateSuppliesBuckets() {
+ var suppliesHitRate = 0.0;
+ for (var i = 0; i < sgItems.length; i++) {
+ suppliesHitRate += sgAppliedItems[i] / sgToBucket[i];
+ }
+ suppliesHitRate *= 2;
+
+ suppliesHitRate += (sgAppliedMeso / mesoToBucket);
+ return suppliesHitRate;
+}
+
+function calculateScrollTiers() {
+ var buckets = sgBuckets;
+ var tiers = [0, 0, 0];
+ while (buckets > 0) {
+ var pool = [];
+ for (var i = 0; i < tiers.length; i++) {
+ if (tiers[i] < 2) {
+ pool.push(i);
+ }
+ }
+
+ var rnd = pool[Math.floor(Math.random() * pool.length)];
+
+ tiers[rnd]++;
+ buckets--;
+ }
+
+ // normalize tiers
+ for (var i = 0; i < tiers.length; i++) {
+ tiers[i] = 3 - tiers[i];
+ }
+
+ return tiers;
+}
+
+function getRandomScroll(tiers) {
+ var typeTier = tiers[0], subtypeTier = tiers[1], successTier = tiers[2];
+ var scrollTypePool = getScrollTypePool(typeTier);
+ var scrollPool = getAvailableScrollsPool(scrollTypePool, subtypeTier, successTier);
+
+ if (scrollPool.length > 0) {
+ return scrollPool[Math.floor(Math.random() * scrollPool.length)];
+ } else {
+ return -1;
+ }
+}
+
+function performExchange(sgItemid, sgCount) {
+ if (cm.getMeso() < sgAppliedMeso) {
+ return false;
+ }
+
+ for (var i = 0; i < sgItems.length; i++) {
+ var itemid = sgItems[i];
+ var count = sgAppliedItems[i];
+ if (count > 0 && !cm.haveItem(itemid, count)) {
+ return false;
+ }
+ }
+
+ cm.gainMeso(-sgAppliedMeso);
+
+ for (var i = 0; i < sgItems.length; i++) {
+ var itemid = sgItems[i];
+ var count = sgAppliedItems[i];
+ cm.gainItem(itemid, -count);
+ }
+
+ cm.gainItem(sgItemid, sgCount);
+ return true;
+}
+
+function generateRandomScroll() {
+ if (cm.getPlayer().getInventory(Packages.client.inventory.MapleInventoryType.USE).getNumFreeSlot() >= 1) {
+ var itemid = getRandomScroll(calculateScrollTiers());
+ if (itemid != -1) {
+ if (performExchange(itemid, 1)) {
+ cm.sendNext("Transaction accepted! You have received a #r#t" + itemid + "##k.");
+ } else {
+ cm.sendOk("Oh, it looks like some items are missing... Please double-check provided items in your inventory before trying to exchange.");
+ }
+ } else {
+ cm.sendOk("Sorry for the inconvenience, but it seems there are no scrolls on store right now... Try again later.");
+ }
+ } else {
+ cm.sendOk("Please look out for a slot available on your USE inventory before trying for a scroll.");
+ }
+}
diff --git a/scripts/portal/MC2revive.js b/scripts/portal/MC2revive.js
index 07e4002729..283d3925f5 100644
--- a/scripts/portal/MC2revive.js
+++ b/scripts/portal/MC2revive.js
@@ -1,8 +1,5 @@
function enter(pi) {
- if ( pi.getPlayer().getTeam() == 0 ) {
- pi.warp( pi.getMapId() - 100);
- } else {
- pi.warp( pi.getMapId() - 100);
- }
+ pi.playPortalSound();
+ pi.warp( pi.getMapId() - 100);
return true;
}
\ No newline at end of file
diff --git a/scripts/portal/MD_drakeroom.js b/scripts/portal/MD_drakeroom.js
index 96ee511d5d..86339e773a 100644
--- a/scripts/portal/MD_drakeroom.js
+++ b/scripts/portal/MD_drakeroom.js
@@ -32,7 +32,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warpParty(dungeonid + i);
+ pi.warpParty(dungeonid + i, "out00");
return true;
}
}
@@ -44,7 +44,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warp(dungeonid + i);
+ pi.warp(dungeonid + i, "out00");
return true;
}
}
diff --git a/scripts/portal/MD_error.js b/scripts/portal/MD_error.js
index 0d91482f3e..51018666a0 100644
--- a/scripts/portal/MD_error.js
+++ b/scripts/portal/MD_error.js
@@ -34,7 +34,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warpParty(dungeonid + i);
+ pi.warpParty(dungeonid + i, "out00");
return true;
}
}
@@ -46,7 +46,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warp(dungeonid + i);
+ pi.warp(dungeonid + i, "out00");
return true;
}
}
diff --git a/scripts/portal/MD_golem.js b/scripts/portal/MD_golem.js
index b4a46ae2f9..539e980cc7 100644
--- a/scripts/portal/MD_golem.js
+++ b/scripts/portal/MD_golem.js
@@ -34,7 +34,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warpParty(dungeonid + i);
+ pi.warpParty(dungeonid + i, "out00");
return true;
}
}
@@ -46,7 +46,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warp(dungeonid + i);
+ pi.warp(dungeonid + i, "out00");
return true;
}
}
diff --git a/scripts/portal/MD_high.js b/scripts/portal/MD_high.js
index b13aa89c32..4c429593f1 100644
--- a/scripts/portal/MD_high.js
+++ b/scripts/portal/MD_high.js
@@ -34,7 +34,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warpParty(dungeonid + i);
+ pi.warpParty(dungeonid + i, "out00");
return true;
}
}
@@ -46,7 +46,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warp(dungeonid + i);
+ pi.warp(dungeonid + i, "out00");
return true;
}
}
diff --git a/scripts/portal/MD_mushroom.js b/scripts/portal/MD_mushroom.js
index 4d15371ba3..46f12dc1bf 100644
--- a/scripts/portal/MD_mushroom.js
+++ b/scripts/portal/MD_mushroom.js
@@ -34,7 +34,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warpParty(dungeonid + i);
+ pi.warpParty(dungeonid + i, "out00");
return true;
}
}
@@ -46,7 +46,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warp(dungeonid + i);
+ pi.warp(dungeonid + i, "out00");
return true;
}
}
diff --git a/scripts/portal/MD_pig.js b/scripts/portal/MD_pig.js
index 21a3c676bc..31d1bbbdfb 100644
--- a/scripts/portal/MD_pig.js
+++ b/scripts/portal/MD_pig.js
@@ -34,7 +34,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warpParty(dungeonid + i);
+ pi.warpParty(dungeonid + i, "out00");
return true;
}
}
@@ -46,7 +46,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warp(dungeonid + i);
+ pi.warp(dungeonid + i, "out00");
return true;
}
}
diff --git a/scripts/portal/MD_protect.js b/scripts/portal/MD_protect.js
index 4dd9fdc253..7bdef62c06 100644
--- a/scripts/portal/MD_protect.js
+++ b/scripts/portal/MD_protect.js
@@ -32,7 +32,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warpParty(dungeonid + i);
+ pi.warpParty(dungeonid + i, "out00");
return true;
}
}
@@ -44,7 +44,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warp(dungeonid + i);
+ pi.warp(dungeonid + i, "out00");
return true;
}
}
diff --git a/scripts/portal/MD_rabbit.js b/scripts/portal/MD_rabbit.js
index 7e9ad57ccd..0d3737702a 100644
--- a/scripts/portal/MD_rabbit.js
+++ b/scripts/portal/MD_rabbit.js
@@ -32,7 +32,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warpParty(dungeonid + i);
+ pi.warpParty(dungeonid + i, "out00");
return true;
}
}
@@ -44,7 +44,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warp(dungeonid + i);
+ pi.warp(dungeonid + i, "out00");
return true;
}
}
diff --git a/scripts/portal/MD_remember.js b/scripts/portal/MD_remember.js
index 3c4f007a6f..21d2a3ff3d 100644
--- a/scripts/portal/MD_remember.js
+++ b/scripts/portal/MD_remember.js
@@ -32,7 +32,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warpParty(dungeonid + i);
+ pi.warpParty(dungeonid + i, "out00");
return true;
}
}
@@ -44,7 +44,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warp(dungeonid + i);
+ pi.warp(dungeonid + i, "out00");
return true;
}
}
diff --git a/scripts/portal/MD_roundTable.js b/scripts/portal/MD_roundTable.js
index 44aa8bbccd..8f4050bd66 100644
--- a/scripts/portal/MD_roundTable.js
+++ b/scripts/portal/MD_roundTable.js
@@ -32,7 +32,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warpParty(dungeonid + i);
+ pi.warpParty(dungeonid + i, "out00");
return true;
}
}
@@ -44,7 +44,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warp(dungeonid + i);
+ pi.warp(dungeonid + i, "out00");
return true;
}
}
diff --git a/scripts/portal/MD_sand.js b/scripts/portal/MD_sand.js
index 217b3efed5..d459d074bd 100644
--- a/scripts/portal/MD_sand.js
+++ b/scripts/portal/MD_sand.js
@@ -32,7 +32,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warpParty(dungeonid + i);
+ pi.warpParty(dungeonid + i, "out00");
return true;
}
}
@@ -44,7 +44,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warp(dungeonid + i);
+ pi.warp(dungeonid + i, "out00");
return true;
}
}
diff --git a/scripts/portal/MD_treasure.js b/scripts/portal/MD_treasure.js
index b811797c2b..cc37b21a8c 100644
--- a/scripts/portal/MD_treasure.js
+++ b/scripts/portal/MD_treasure.js
@@ -32,7 +32,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warpParty(dungeonid + i);
+ pi.warpParty(dungeonid + i, "out00");
return true;
}
}
@@ -44,7 +44,7 @@ function enter(pi) {
for (var i = 0; i < dungeons; i++) {
if(pi.startDungeonInstance(dungeonid + i)) {
pi.playPortalSound();
- pi.warp(dungeonid + i);
+ pi.warp(dungeonid + i, "out00");
return true;
}
}
diff --git a/scripts/portal/NextMap.js b/scripts/portal/NextMap.js
index c0cbd12fe4..c73dd26196 100644
--- a/scripts/portal/NextMap.js
+++ b/scripts/portal/NextMap.js
@@ -1,5 +1,5 @@
function enter(pi) {
pi.playPortalSound();
- pi.warp(pi.getMapId() + 100);
+ pi.warp(pi.getMapId() + 100, 0);
return true;
}
\ No newline at end of file
diff --git a/scripts/portal/Pinkin.js b/scripts/portal/Pinkin.js
index 543553d91e..886729bccf 100644
--- a/scripts/portal/Pinkin.js
+++ b/scripts/portal/Pinkin.js
@@ -19,7 +19,7 @@
*/
/*
-Vs Pink Bean - Ressurection stage portal
+Vs Pink Bean - Resurrection stage portal
@author Ronan
*/
diff --git a/scripts/portal/Populatus00.js b/scripts/portal/Populatus00.js
index 20c64ee7bb..deed0cea90 100644
--- a/scripts/portal/Populatus00.js
+++ b/scripts/portal/Populatus00.js
@@ -50,7 +50,7 @@ function enter(pi) {
}
} else {
pi.playPortalSound();
- pi.warp(922020300);
+ pi.warp(922020300, 0);
return true;
}
}
\ No newline at end of file
diff --git a/scripts/portal/Spacegaga_out0.js b/scripts/portal/Spacegaga_out0.js
index ed2c009242..8a89b22737 100644
--- a/scripts/portal/Spacegaga_out0.js
+++ b/scripts/portal/Spacegaga_out0.js
@@ -1,11 +1,15 @@
//Author: kevintjuh93
function enter(pi) {
- if (pi.getPlayer().getEvents().get("rescueGaga").fallAndGet() > 3) {
- pi.playPortalSound(); pi.warp(922240200, 0);
- pi.getPlayer().cancelEffect(2360002);
- } else
+ var eim = pi.getPlayer().getEventInstance();
+ var fc = eim.getIntProperty("falls");
+
+ if (fc >= 3) {
+ pi.playPortalSound(); pi.warp(922240200, 0);
+ } else {
+ eim.setIntProperty("falls", fc + 1);
pi.playPortalSound(); pi.warp(pi.getPlayer().getMapId(), 0);
+ }
return true;
}
\ No newline at end of file
diff --git a/scripts/portal/Spacegaga_out1.js b/scripts/portal/Spacegaga_out1.js
index ed2c009242..e27fdabbd6 100644
--- a/scripts/portal/Spacegaga_out1.js
+++ b/scripts/portal/Spacegaga_out1.js
@@ -1,11 +1,15 @@
//Author: kevintjuh93
function enter(pi) {
- if (pi.getPlayer().getEvents().get("rescueGaga").fallAndGet() > 3) {
- pi.playPortalSound(); pi.warp(922240200, 0);
- pi.getPlayer().cancelEffect(2360002);
- } else
+ var eim = pi.getPlayer().getEventInstance();
+ var fc = eim.getIntProperty("falls");
+
+ if (fc >= 3) {
+ pi.playPortalSound(); pi.warp(922240200, 0);
+ } else {
+ eim.setIntProperty("falls", fc + 1);
pi.playPortalSound(); pi.warp(pi.getPlayer().getMapId(), 0);
+ }
return true;
}
\ No newline at end of file
diff --git a/scripts/portal/Spacegaga_out2.js b/scripts/portal/Spacegaga_out2.js
index ed2c009242..e27fdabbd6 100644
--- a/scripts/portal/Spacegaga_out2.js
+++ b/scripts/portal/Spacegaga_out2.js
@@ -1,11 +1,15 @@
//Author: kevintjuh93
function enter(pi) {
- if (pi.getPlayer().getEvents().get("rescueGaga").fallAndGet() > 3) {
- pi.playPortalSound(); pi.warp(922240200, 0);
- pi.getPlayer().cancelEffect(2360002);
- } else
+ var eim = pi.getPlayer().getEventInstance();
+ var fc = eim.getIntProperty("falls");
+
+ if (fc >= 3) {
+ pi.playPortalSound(); pi.warp(922240200, 0);
+ } else {
+ eim.setIntProperty("falls", fc + 1);
pi.playPortalSound(); pi.warp(pi.getPlayer().getMapId(), 0);
+ }
return true;
}
\ No newline at end of file
diff --git a/scripts/portal/Spacegaga_out3.js b/scripts/portal/Spacegaga_out3.js
index ed2c009242..8a89b22737 100644
--- a/scripts/portal/Spacegaga_out3.js
+++ b/scripts/portal/Spacegaga_out3.js
@@ -1,11 +1,15 @@
//Author: kevintjuh93
function enter(pi) {
- if (pi.getPlayer().getEvents().get("rescueGaga").fallAndGet() > 3) {
- pi.playPortalSound(); pi.warp(922240200, 0);
- pi.getPlayer().cancelEffect(2360002);
- } else
+ var eim = pi.getPlayer().getEventInstance();
+ var fc = eim.getIntProperty("falls");
+
+ if (fc >= 3) {
+ pi.playPortalSound(); pi.warp(922240200, 0);
+ } else {
+ eim.setIntProperty("falls", fc + 1);
pi.playPortalSound(); pi.warp(pi.getPlayer().getMapId(), 0);
+ }
return true;
}
\ No newline at end of file
diff --git a/scripts/portal/TD_MC_enterboss1.js b/scripts/portal/TD_MC_enterboss1.js
index 0718c1730a..260a8cb2b4 100644
--- a/scripts/portal/TD_MC_enterboss1.js
+++ b/scripts/portal/TD_MC_enterboss1.js
@@ -1,5 +1,5 @@
function enter(pi) {
- var questProgress = pi.getQuestProgress(2330, 3300005) + pi.getQuestProgress(2330, 3300006) + pi.getQuestProgress(2330, 3300007); //3 Yetis
+ var questProgress = pi.getQuestProgressInt(2330, 3300005) + pi.getQuestProgressInt(2330, 3300006) + pi.getQuestProgressInt(2330, 3300007); //3 Yetis
if(pi.isQuestStarted(2330) && questProgress < 3){
pi.openNpc(1300013);
diff --git a/scripts/portal/TD_neo_inTree.js b/scripts/portal/TD_neo_inTree.js
index 382fab3263..0ee32c0ac8 100644
--- a/scripts/portal/TD_neo_inTree.js
+++ b/scripts/portal/TD_neo_inTree.js
@@ -10,7 +10,7 @@ function enter(pi) {
for(var i = 0; i < quests.length; i++) {
if (pi.isQuestActive(quests[i])) {
- if(pi.getQuestProgress(quests[i], mobs[i]) != 0) {
+ if(pi.getQuestProgressInt(quests[i], mobs[i]) != 0) {
pi.message("You already faced Nex. Complete your mission.");
return false;
}
diff --git a/scripts/portal/Zakum05.js b/scripts/portal/Zakum05.js
index 7f0f674aab..b23f2495a4 100644
--- a/scripts/portal/Zakum05.js
+++ b/scripts/portal/Zakum05.js
@@ -34,6 +34,17 @@ function enter(pi) {
return false;
}
+ if (!pi.haveItem(4001017)) { // thanks Conrad for pointing out missing checks for token item and unused reactor
+ pi.getPlayer().dropMessage(5,"You do not have the Eye of Fire. You may not face the boss.");
+ return false;
+ }
+
+ var react = pi.getMap().getReactorById(2118002);
+ if (react != null && react.getState() > 0) {
+ pi.getPlayer().dropMessage(5,"The entrance is currently blocked.");
+ return false;
+ }
+
pi.playPortalSound(); pi.warp(211042400,"west00");
return true;
}
\ No newline at end of file
diff --git a/scripts/portal/enterInfo.js b/scripts/portal/enterInfo.js
index 02a1b45dec..466f53f0cd 100644
--- a/scripts/portal/enterInfo.js
+++ b/scripts/portal/enterInfo.js
@@ -1,7 +1,8 @@
function enter(pi) {
var mapobj = pi.getWarpMap(104000004);
- if(pi.isQuestActive(21733) && pi.getQuestProgress(21733, 9300345) == 0 && mapobj.countMonsters() == 0) {
+ if(pi.isQuestActive(21733) && pi.getQuestProgressInt(21733, 9300345) == 0 && mapobj.countMonsters() == 0) {
mapobj.spawnMonsterOnGroundBelow(Packages.server.life.MapleLifeFactory.getMonster(9300345), new java.awt.Point(0, 0));
+ pi.setQuestProgress(21733, 21762, 2);
}
pi.playPortalSound();
diff --git a/scripts/portal/enterMCave.js b/scripts/portal/enterMCave.js
index dc2052f0e5..e121cc1b5f 100644
--- a/scripts/portal/enterMCave.js
+++ b/scripts/portal/enterMCave.js
@@ -9,8 +9,7 @@ function enter(pi) {
pi.playPortalSound();
pi.warp(i, "out00");
- pi.getPlayer().updateQuestInfo(21202, "0");
- //pi.getPlayer().announce(Packages.tools.MaplePacketCreator.questProgress(21203, "21203"));
+ pi.setQuestProgress(21202, 21203, 0);
return true;
}
pi.message("The mirror is blank due to many players recalling their memories. Please wait and try again.");
@@ -24,7 +23,7 @@ function enter(pi) {
spawnMob(-210, 454, 9001013, map);
pi.playPortalSound();
- pi.getPlayer().updateQuestInfo(21203, "1");
+ pi.setQuestProgress(21303, 21203, 1);
pi.warp(108010701, "out00");
return true;
}
diff --git a/scripts/portal/enterPort.js b/scripts/portal/enterPort.js
index 58147bee61..e79056d85c 100644
--- a/scripts/portal/enterPort.js
+++ b/scripts/portal/enterPort.js
@@ -22,7 +22,7 @@
importPackage(Packages.server.life);
function enter(pi) {
- if(pi.isQuestStarted(21301) && pi.getQuestProgress(21301, 9001013) == 0) {
+ if(pi.isQuestStarted(21301) && pi.getQuestProgressInt(21301, 9001013) == 0) {
if(pi.getPlayerCount(108010700) != 0) {
pi.message("The portal is blocked from the other side. I wonder if someone is already fighting the Thief Crow?");
return false;
diff --git a/scripts/portal/gaga_success.js b/scripts/portal/gaga_success.js
index 24d3c5d0af..c32a40e070 100644
--- a/scripts/portal/gaga_success.js
+++ b/scripts/portal/gaga_success.js
@@ -1,8 +1,6 @@
//Author: kevintjuh93
function enter(pi) {
- pi.getPlayer().getEvents().get("rescueGaga").complete();
- pi.playPortalSound(); pi.warp(922240100 + (pi.getPlayer().getMapId() - 922240000));
- pi.getPlayer().cancelEffect(2360002);
+ pi.playPortalSound(); pi.warp(922240100 + (pi.getPlayer().getMapId() - 922240000), 0);
return true;
}
\ No newline at end of file
diff --git a/scripts/portal/highposition.js b/scripts/portal/highposition.js
index 75b838464a..2496c7eed6 100644
--- a/scripts/portal/highposition.js
+++ b/scripts/portal/highposition.js
@@ -20,10 +20,9 @@
along with this program. If not, see .
*/
-/*
- * Author: kevintjuh93
- *
-*/
-function start(ms) {
- ms.touchTheSky();
+// Author: Ronan
+function enter(ms) {
+ // thanks kvmba for noticing some issues running this script
+ ms.runMapScript();
+ return false;
}
\ No newline at end of file
diff --git a/scripts/portal/jnr6_out.js b/scripts/portal/jnr6_out.js
index ba099b9be4..aec7e9956a 100644
--- a/scripts/portal/jnr6_out.js
+++ b/scripts/portal/jnr6_out.js
@@ -1,6 +1,6 @@
function enter(pi) {
if (pi.getMap().getReactorByName("jnr6_out").getState() == 1) {
- pi.playPortalSound(); pi.warp(926110300);
+ pi.playPortalSound(); pi.warp(926110300, 0);
return true;
} else {
pi.playerMessage(5, "The portal is not opened yet.");
diff --git a/scripts/portal/out_pepeking.js b/scripts/portal/out_pepeking.js
index 5532f8eef0..67d59554f4 100644
--- a/scripts/portal/out_pepeking.js
+++ b/scripts/portal/out_pepeking.js
@@ -5,7 +5,7 @@ function enter(pi) {
eim.dispose();
}
- var questProgress = pi.getQuestProgress(2330, 3300005) + pi.getQuestProgress(2330, 3300006) + pi.getQuestProgress(2330, 3300007); //3 Yetis
+ var questProgress = pi.getQuestProgressInt(2330, 3300005) + pi.getQuestProgressInt(2330, 3300006) + pi.getQuestProgressInt(2330, 3300007); //3 Yetis
if(questProgress == 3 && !pi.hasItem(4032388)) {
if(pi.canHold(4032388)){
pi.getPlayer().message("You have aquired a key to the Wedding Hall. King Pepe must have dropped it.");
diff --git a/scripts/portal/party3_jailin.js b/scripts/portal/party3_jailin.js
index f4b107c220..64847fd211 100644
--- a/scripts/portal/party3_jailin.js
+++ b/scripts/portal/party3_jailin.js
@@ -1,46 +1,72 @@
importPackage(Packages.tools);
-function enter(pi) {
- var map = pi.getMap();
+var leverSequenceExit = false;
+
+function enterLeverSequence(pi) {
+ var map = pi.getMap();
- var jailn = (pi.getMap().getId() / 10) % 10;
- var maxToggles = (jailn == 1) ? 7 : 6;
-
- var mapProp = pi.getEventInstance().getProperty("jail" + jailn);
-
- if(mapProp == null) {
- var seq = 0;
-
- for(var i = 1; i <= maxToggles; i++) {
- if(Math.random() < 0.5) seq += (1 << i);
- }
-
- pi.getEventInstance().setProperty("jail" + jailn, seq);
- mapProp = seq;
+ var jailn = (pi.getMap().getId() / 10) % 10;
+ var maxToggles = (jailn == 1) ? 7 : 6;
+
+ var mapProp = pi.getEventInstance().getProperty("jail" + jailn);
+
+ if(mapProp == null) {
+ var seq = 0;
+
+ for(var i = 1; i <= maxToggles; i++) {
+ if(Math.random() < 0.5) seq += (1 << i);
}
-
- mapProp = Number(mapProp);
- if(mapProp != 0) {
- var countMiss = 0;
- for(var i = 1; i <= maxToggles; i++) {
- if(!(pi.getMap().getReactorByName("lever" + i).getState() == (mapProp >> i) % 2)) {
- countMiss++;
- }
+
+ pi.getEventInstance().setProperty("jail" + jailn, seq);
+ mapProp = seq;
+ }
+
+ mapProp = Number(mapProp);
+ if(mapProp != 0) {
+ var countMiss = 0;
+ for(var i = 1; i <= maxToggles; i++) {
+ if(!(pi.getMap().getReactorByName("lever" + i).getState() == (mapProp >> i) % 2)) {
+ countMiss++;
}
-
- if(countMiss > 0) {
- map.broadcastMessage(MaplePacketCreator.showEffect("quest/party/wrong_kor"));
- map.broadcastMessage(MaplePacketCreator.playSound("Party1/Failed"));
-
- pi.playerMessage(5, "The right combination of levers is needed to pass. " + countMiss + " lever(s) are misplaced.");
- return false;
- }
-
- map.broadcastMessage(MaplePacketCreator.showEffect("quest/party/clear"));
- map.broadcastMessage(MaplePacketCreator.playSound("Party1/Clear"));
- pi.getEventInstance().setProperty("jail" + jailn, "0");
}
-
+
+ if(countMiss > 0) {
+ map.broadcastMessage(MaplePacketCreator.showEffect("quest/party/wrong_kor"));
+ map.broadcastMessage(MaplePacketCreator.playSound("Party1/Failed"));
+
+ pi.playerMessage(5, "The right combination of levers is needed to pass. " + countMiss + " lever(s) are misplaced.");
+ return false;
+ }
+
+ map.broadcastMessage(MaplePacketCreator.showEffect("quest/party/clear"));
+ map.broadcastMessage(MaplePacketCreator.playSound("Party1/Clear"));
+ pi.getEventInstance().setProperty("jail" + jailn, "0");
+ }
+
+ pi.playPortalSound(); pi.warp(pi.getMapId() + 2,0);
+ return true;
+}
+
+function enterNoMobs(pi) {
+ var map = pi.getMap();
+ var mobcount = map.countMonster(9300044);
+
+ if (mobcount > 0) {
+ pi.playerMessage(5, "Please use the levers to defeat all the threats before you proceed.");
+ return false;
+ } else {
pi.playPortalSound(); pi.warp(pi.getMapId() + 2,0);
return true;
+ }
+}
+
+function enter(pi) {
+ var ret;
+ if (leverSequenceExit) {
+ ret = enterLeverSequence(pi);
+ } else {
+ ret = enterNoMobs(pi);
+ }
+
+ return ret;
}
\ No newline at end of file
diff --git a/scripts/portal/party6_stage501.js b/scripts/portal/party6_stage501.js
index 887accb9f1..2788e39c89 100644
--- a/scripts/portal/party6_stage501.js
+++ b/scripts/portal/party6_stage501.js
@@ -1,5 +1,5 @@
function enter(pi) {
- if (java.lang.Math.random() < 0.1) {
+ if (Math.random() < 0.1) {
pi.playPortalSound(); pi.warp(930000300,"16st");
} else {
pi.playPortalSound(); pi.warp(930000300, "02st");
diff --git a/scripts/portal/party6_stage502.js b/scripts/portal/party6_stage502.js
index 259846a773..2b9dc73d03 100644
--- a/scripts/portal/party6_stage502.js
+++ b/scripts/portal/party6_stage502.js
@@ -1,5 +1,5 @@
function enter(pi) {
- if (java.lang.Math.random() < 0.1) {
+ if (Math.random() < 0.1) {
pi.playPortalSound(); pi.warp(930000300,"16st");
} else {
pi.playPortalSound(); pi.warp(930000300, "03st");
diff --git a/scripts/portal/party6_stage503.js b/scripts/portal/party6_stage503.js
index 38bd839b2d..29706f649b 100644
--- a/scripts/portal/party6_stage503.js
+++ b/scripts/portal/party6_stage503.js
@@ -1,5 +1,5 @@
function enter(pi) {
- if (java.lang.Math.random() < 0.1) {
+ if (Math.random() < 0.1) {
pi.playPortalSound(); pi.warp(930000300,"16st");
} else {
pi.playPortalSound(); pi.warp(930000300, "04st");
diff --git a/scripts/portal/party6_stage504.js b/scripts/portal/party6_stage504.js
index 4ec4244a85..94b7f6d513 100644
--- a/scripts/portal/party6_stage504.js
+++ b/scripts/portal/party6_stage504.js
@@ -1,5 +1,5 @@
function enter(pi) {
- if (java.lang.Math.random() < 0.1) {
+ if (Math.random() < 0.1) {
pi.playPortalSound(); pi.warp(930000300,"16st");
} else {
pi.playPortalSound(); pi.warp(930000300, "05st");
diff --git a/scripts/portal/party6_stage505.js b/scripts/portal/party6_stage505.js
index afdd71b343..5ae1c318da 100644
--- a/scripts/portal/party6_stage505.js
+++ b/scripts/portal/party6_stage505.js
@@ -1,5 +1,5 @@
function enter(pi) {
- if (java.lang.Math.random() < 0.1) {
+ if (Math.random() < 0.1) {
pi.playPortalSound(); pi.warp(930000300,"16st");
} else {
pi.playPortalSound(); pi.warp(930000300, "06st");
diff --git a/scripts/portal/party6_stage506.js b/scripts/portal/party6_stage506.js
index 7b57c7125f..1078adff06 100644
--- a/scripts/portal/party6_stage506.js
+++ b/scripts/portal/party6_stage506.js
@@ -1,5 +1,5 @@
function enter(pi) {
- if (java.lang.Math.random() < 0.1) {
+ if (Math.random() < 0.1) {
pi.playPortalSound(); pi.warp(930000300,"16st");
} else {
pi.playPortalSound(); pi.warp(930000300, "07st");
diff --git a/scripts/portal/party6_stage507.js b/scripts/portal/party6_stage507.js
index 44e43aeb1e..e8f41aa0ac 100644
--- a/scripts/portal/party6_stage507.js
+++ b/scripts/portal/party6_stage507.js
@@ -1,5 +1,5 @@
function enter(pi) {
- if (java.lang.Math.random() < 0.1) {
+ if (Math.random() < 0.1) {
pi.playPortalSound(); pi.warp(930000300,"16st");
} else {
pi.playPortalSound(); pi.warp(930000300, "08st");
diff --git a/scripts/portal/party6_stage508.js b/scripts/portal/party6_stage508.js
index 5f930d209f..acade52b73 100644
--- a/scripts/portal/party6_stage508.js
+++ b/scripts/portal/party6_stage508.js
@@ -1,5 +1,5 @@
function enter(pi) {
- if (java.lang.Math.random() < 0.1) {
+ if (Math.random() < 0.1) {
pi.playPortalSound(); pi.warp(930000300,"16st");
} else {
pi.playPortalSound(); pi.warp(930000300, "09st");
diff --git a/scripts/portal/party6_stage509.js b/scripts/portal/party6_stage509.js
index 886fcf046e..57c8694fcb 100644
--- a/scripts/portal/party6_stage509.js
+++ b/scripts/portal/party6_stage509.js
@@ -1,5 +1,5 @@
function enter(pi) {
- if (java.lang.Math.random() < 0.1) {
+ if (Math.random() < 0.1) {
pi.playPortalSound(); pi.warp(930000300,"16st");
} else {
pi.playPortalSound(); pi.warp(930000300, "10st");
diff --git a/scripts/portal/party6_stage510.js b/scripts/portal/party6_stage510.js
index 777fc0ded7..6632bbd4d1 100644
--- a/scripts/portal/party6_stage510.js
+++ b/scripts/portal/party6_stage510.js
@@ -1,5 +1,5 @@
function enter(pi) {
- if (java.lang.Math.random() < 0.1) {
+ if (Math.random() < 0.1) {
pi.playPortalSound(); pi.warp(930000300,"16st");
} else {
pi.playPortalSound(); pi.warp(930000300, "11st");
diff --git a/scripts/portal/party6_stage511.js b/scripts/portal/party6_stage511.js
index 253bd5100b..93c7f56cfb 100644
--- a/scripts/portal/party6_stage511.js
+++ b/scripts/portal/party6_stage511.js
@@ -1,5 +1,5 @@
function enter(pi) {
- if (java.lang.Math.random() < 0.1) {
+ if (Math.random() < 0.1) {
pi.playPortalSound(); pi.warp(930000300,"16st");
} else {
pi.playPortalSound(); pi.warp(930000300, "12st");
diff --git a/scripts/portal/party6_stage512.js b/scripts/portal/party6_stage512.js
index cef1f8877f..8c91b29407 100644
--- a/scripts/portal/party6_stage512.js
+++ b/scripts/portal/party6_stage512.js
@@ -1,5 +1,5 @@
function enter(pi) {
- if (java.lang.Math.random() < 0.1) {
+ if (Math.random() < 0.1) {
pi.playPortalSound(); pi.warp(930000300,"16st");
} else {
pi.playPortalSound(); pi.warp(930000300, "13st");
diff --git a/scripts/portal/party6_stage513.js b/scripts/portal/party6_stage513.js
index 15828f2585..a27b6cb44e 100644
--- a/scripts/portal/party6_stage513.js
+++ b/scripts/portal/party6_stage513.js
@@ -1,5 +1,5 @@
function enter(pi) {
- if (java.lang.Math.random() < 0.1) {
+ if (Math.random() < 0.1) {
pi.playPortalSound(); pi.warp(930000300,"16st");
} else {
pi.playPortalSound(); pi.warp(930000300, "14st");
diff --git a/scripts/portal/party6_stage514.js b/scripts/portal/party6_stage514.js
index a2c4ffa187..903971ec18 100644
--- a/scripts/portal/party6_stage514.js
+++ b/scripts/portal/party6_stage514.js
@@ -1,5 +1,5 @@
function enter(pi) {
- if (java.lang.Math.random() < 0.1) {
+ if (Math.random() < 0.1) {
pi.playPortalSound(); pi.warp(930000300,"16st");
} else {
pi.playPortalSound(); pi.warp(930000300, "15st");
diff --git a/scripts/portal/party6_stage515.js b/scripts/portal/party6_stage515.js
index 221db8bc2e..4c3f689ad4 100644
--- a/scripts/portal/party6_stage515.js
+++ b/scripts/portal/party6_stage515.js
@@ -1,5 +1,5 @@
function enter(pi) {
- if (java.lang.Math.random() < 0.1) {
+ if (Math.random() < 0.1) {
pi.playPortalSound(); pi.warp(930000300,"16st");
} else {
pi.playPortalSound(); pi.warp(930000300, "01st");
diff --git a/scripts/portal/q3367in.js b/scripts/portal/q3367in.js
index 0e2819c85a..daf52bf2cf 100644
--- a/scripts/portal/q3367in.js
+++ b/scripts/portal/q3367in.js
@@ -19,8 +19,11 @@
*/
function enter(pi) {
if(pi.isQuestStarted(3367)) {
- if(pi.getQuestProgress(3367, 31) < pi.getItemQuantity(4031797)) {
- pi.gainItem(4031797, pi.getQuestProgress(3367, 31) - pi.getItemQuantity(4031797));
+ var booksDone = pi.getQuestProgressInt(3367, 31);
+ var booksInv = pi.getItemQuantity(4031797);
+
+ if(booksInv < booksDone) {
+ pi.gainItem(4031797, booksDone - booksInv);
}
pi.playPortalSound(); pi.warp(926130102, 0);
diff --git a/scripts/portal/s4mind_end.js b/scripts/portal/s4mind_end.js
index 72ce8d568d..7067e76d11 100644
--- a/scripts/portal/s4mind_end.js
+++ b/scripts/portal/s4mind_end.js
@@ -23,7 +23,7 @@ function enter(pi) {
return false;
} else {
if (pi.isQuestStarted(6410)) {
- pi.setQuestProgress(6410, 0, 1);
+ pi.setQuestProgress(6410, 6411, "p2");
}
pi.playPortalSound();
diff --git a/scripts/portal/secretDoor.js b/scripts/portal/secretDoor.js
index a1f00a0145..43fb733eed 100644
--- a/scripts/portal/secretDoor.js
+++ b/scripts/portal/secretDoor.js
@@ -30,7 +30,8 @@ function enter(pi) {
if(pi.isQuestCompleted(3360)) {
return doorCross(pi);
} else if(pi.isQuestStarted(3360)) {
- if(pi.getQuestProgress(3360, 1) == 0) {
+ var pw = pi.getQuestProgress(3360);
+ if(pw.length() > 1) {
pi.openNpc(2111024, "MagatiaPassword");
return false;
} else {
diff --git a/scripts/portal/skyrom.js b/scripts/portal/skyrom.js
index d461b1241c..dbb7c9a4d5 100644
--- a/scripts/portal/skyrom.js
+++ b/scripts/portal/skyrom.js
@@ -21,7 +21,7 @@
function enter(pi) {
if(pi.isQuestStarted(3935) && !pi.haveItem(4031574, 1)) {
if(pi.getWarpMap(926000010).countPlayers() == 0) {
- pi.playPortalSound(); pi.warp(926000010);
+ pi.playPortalSound(); pi.warp(926000010, 0);
return true;
} else {
pi.message("Someone is already trying this map.");
diff --git a/scripts/portal/stageBogo.js b/scripts/portal/stageBogo.js
index 6ec238c3c9..115efd4a7e 100644
--- a/scripts/portal/stageBogo.js
+++ b/scripts/portal/stageBogo.js
@@ -24,6 +24,6 @@
@Author Ronan
*/
function enter(pi) {
- pi.playPortalSound(); pi.warp(670010800);
+ pi.playPortalSound(); pi.warp(670010800, 0);
return true;
}
\ No newline at end of file
diff --git a/scripts/portal/thief_in1.js b/scripts/portal/thief_in1.js
index a51f5c69ab..796f9541bf 100644
--- a/scripts/portal/thief_in1.js
+++ b/scripts/portal/thief_in1.js
@@ -1,9 +1,6 @@
function enter(pi) {
- if(pi.isQuestCompleted(20730) || pi.isQuestCompleted(21734)) { // puppeteer defeated, newfound secret path
- pi.playPortalSound(); pi.warp(105040201,2);
- return true;
- }
-
- pi.openNpc(1063011, "ThiefPassword");
+ // unexpected warp condition noticed thanks to IxianMace
+
+ pi.openNpc(1063011, "ThiefPassword");
return false;
}
\ No newline at end of file
diff --git a/scripts/quest/1021.js b/scripts/quest/1021.js
index ba16526af5..7d10f5d8f6 100644
--- a/scripts/quest/1021.js
+++ b/scripts/quest/1021.js
@@ -45,7 +45,7 @@ function start(mode, type, selection) {
status--;
if (status == 0)
- qm.sendNext("Hey, Man~ What's up? Haha! I am Roger who can teach you adorable new Maplers lots of information.");
+ qm.sendNext("Hey, " + (qm.getPlayer().getGender() == 0 ? "Man" : "Miss") + "~ What's up? Haha! I am Roger who can teach you adorable new Maplers lots of information.");
else if (status == 1)
qm.sendNextPrev("You are asking who made me do this? Ahahahaha!\r\nMyself! I wanted to do this and just be kind to you new travellers.");
else if (status == 2)
@@ -62,7 +62,7 @@ function start(mode, type, selection) {
qm.forceStartQuest();
qm.sendNext("Surprised? If HP becomes 0, then you are in trouble. Now, I will give you #rRoger's Apple#k. Please take it. You will feel stronger. Open the Item window and double click to consume. Hey, it's very simple to open the Item window. Just press #bI#k on your keyboard.");
} else if (status == 4) {
- qm.sendNextPrev("Please take all Roger's Apples that I gave you. You will be able to see the HP bar increasing. Please talk to me again when you recover your HP 100%.");
+ qm.sendPrev("Please take all Roger's Apples that I gave you. You will be able to see the HP bar increasing. Please talk to me again when you recover your HP 100%.");
} else if (status == 5) {
qm.showInfo("UI/tutorial.img/28");
qm.dispose();
@@ -93,7 +93,7 @@ function end(mode, type, selection) {
else if (status == 1)
qm.sendNextPrev("Alright! Now that you have learned alot, I will give you a present. This is a must for your travel in Maple World, so thank me! Please use this under emergency cases!");
else if (status == 2)
- qm.sendNextPrev("Okay, this is all I can teach you. I know it's sad but it is time to say good bye. Well take care if yourself and Good luck my friend!\r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0#\r\n#v2010000# 3 #t2010000#\r\n#v2010009# 3 #t2010009#\r\n\r\n#fUI/UIWindow.img/QuestIcon/8/0# 10 exp");
+ qm.sendPrev("Okay, this is all I can teach you. I know it's sad but it is time to say good bye. Well take care if yourself and Good luck my friend!\r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0#\r\n#v2010000# 3 #t2010000#\r\n#v2010009# 3 #t2010009#\r\n\r\n#fUI/UIWindow.img/QuestIcon/8/0# 10 exp");
else if (status == 3) {
if(qm.isQuestCompleted(1021))
qm.dropMessage(1,"Unknown Error");
diff --git a/scripts/quest/10940.js b/scripts/quest/10940.js
index 67c8cc0408..6590a761e0 100644
--- a/scripts/quest/10940.js
+++ b/scripts/quest/10940.js
@@ -10,14 +10,15 @@ function start(mode, type, selection) {
status++;
else
qm.dispose();
- if (status == 0)
+ if (status == 0) {
qm.sendAcceptDecline("Hello, #h0#. Welcome to Maple World. It's currently event season, and we're welcome new characters with a gift. Would you like your gift now?");
- else if (status == 1) {
+ } else if (status == 1) {
+ qm.sendOk("Open your inventory and double-click on it! These gifts will make you look stylish. Oh, one more thing! You'll get another gift at level 30. Good luck!");
qm.forceStartQuest();
qm.forceCompleteQuest();
qm.gainItem(2430191, 1, true);
- qm.sendOk("Open your inventory and double-click on it! These gifts will make you look stylish. Oh, one more thing! You'll get another gift at level 30. Good luck!");
- qm.dispose();
+ } else if (status == 2) {
+ qm.dispose();
}
}
}
\ No newline at end of file
diff --git a/scripts/quest/20002.js b/scripts/quest/20002.js
index fd11746411..8284cc250d 100644
--- a/scripts/quest/20002.js
+++ b/scripts/quest/20002.js
@@ -44,13 +44,16 @@ function start(mode, type, selection) {
else if (status == 2)
qm.sendAcceptDecline("Ah, I don't know if you are aware of this, but you won't find any monsters here in Ereve. Any form of evil will not be able to set foot on this island. Don't worry, you'll still have your opportunity to train here. Shinsoo created a fantasy creature called Mimi, which will be used as your training partners. Shall we begin?");
else if (status == 3) {
+ qm.forceStartQuest();
+ qm.forceCompleteQuest();
+
qm.gainExp(60);
qm.gainItem(2000020, 10); // Red Potion for Noblesse * 10
qm.gainItem(2000021, 10); // Blue Potion for Noblesse * 10
qm.gainItem(1002869, 1); // Elegant Noblesse Hat * 1
+
qm.sendOk("Ha, I like your enthusiasm, but you must prepare yourself for the training first before we start things off. Make sure that you are equipped with weapons, and that your skills are calibrated and ready to be used. I also gave you some potions, so have it ready just in case. Let me know when you're ready. You're going to wish that you didn't sign up to become a Cygnus Knight.");
- qm.forceStartQuest();
- qm.forceCompleteQuest();
+ } else if (status == 4) {
qm.dispose();
}
}
diff --git a/scripts/quest/20008.js b/scripts/quest/20008.js
index dca016c829..e5d7d9d617 100644
--- a/scripts/quest/20008.js
+++ b/scripts/quest/20008.js
@@ -34,17 +34,21 @@ function start(mode, type, selection) {
if (mode < 1) {
qm.dispose();
}
- if (mode > 0)
+ else if (mode > 0)
status++;
if (status == 0)
qm.sendSimple("Are you ready to take on a mission? If you can't pass this test, then you won't be able to call yourself a real Knight. Are you sure you can do this? If you are afraid to do this, let me know. I won't tell Neinheart. \r\n #L0#I'll try this later.#l \r\n #L1#I'm not afraid. Let's do this.#l");
- else if (selection == 0) {
- qm.sendNext("If you call yourself a Knight, then do not hesitate. Show everyone how much courage you have in you.");
+ else if (status == 1) {
+ if (selection == 0) {
+ qm.sendNext("If you call yourself a Knight, then do not hesitate. Show everyone how much courage you have in you.");
+ qm.dispose();
+ } else if (selection == 1) {
+ choice1 = selection;
+ qm.sendSimple("I'm glad you didn't run away, but... are you sure you want to become a Knight-in-Training? What I am asking is whether you're okay with being a Cygnus Knight, and therefore being tied to the Empress at all times? She may be an Empress, but she's also still just a kid. Are you sure you can fight for her? I won't let Neinheart know so just tell me what you really feel. \r\n #L2#If the Empress wants peace in the Maple World, then I'm down for whatever.#l \r\n #L3#As long as I can become a knight I'll endure whatever #l");
+ qm.forceStartQuest();
+ qm.forceCompleteQuest();
+ }
+ } else if (status == 2) {
qm.dispose();
- } else if (selection == 1) {
- choice1 = selection;
- qm.sendSimple("I'm glad you didn't run away, but... are you sure you want to become a Knight-in-Training? What I am asking is whether you're okay with being a Cygnus Knight, and therefore being tied to the Empress at all times? She may be an Empress, but she's also still just a kid. Are you sure you can fight for her? I won't let Neinheart know so just tell me what you really feel. \r\n #L2#If the Empress wants peace in the Maple World, then I'm down for whatever.#l \r\n #L3#As long as I can become a knight I'll endure whatever #l");
- qm.forceStartQuest();
- qm.forceCompleteQuest();
}
}
\ No newline at end of file
diff --git a/scripts/quest/20010.js b/scripts/quest/20010.js
index eb3d98ac80..e68d48f35f 100644
--- a/scripts/quest/20010.js
+++ b/scripts/quest/20010.js
@@ -5,6 +5,12 @@ function start(mode, type, selection) {
qm.sendNext("Whoa, whoa! Are you really declining my offer? Well, you'll be able to #blevel-up quicker #kwith our help, so let me know if you change your mind. Even if you've declined a Quest, you can receive the Quest again if you just come and talk to me.");
qm.dispose();
} else {
+ if(mode == 0 && type > 0) {
+ qm.sendNext("Whoa, whoa! Are you really declining my offer? Well, you'll be able to #blevel-up quicker #kwith our help, so let me know if you change your mind. Even if you've declined a Quest, you can receive the Quest again if you just come and talk to me.");
+ qm.dispose();
+ return;
+ }
+
if (mode == 1)
status++;
else
@@ -14,7 +20,7 @@ function start(mode, type, selection) {
} else if (status == 1) {
qm.sendNextPrev("If you want to officially become a part of Cygnus Knights, you must first meet the Empress. She's at the center of this island, accompained by Shinsoo. My brothers and I would like to share with you a few things that are considered #bBasic Knowledge#k in Maple World before you go. Would that be okay?");
} else if (status == 2) {
- qm.sendOk("Oh, let me warn you that this is a Quest. You may have noticed that NPCs around Maple World occasionally ask you for various favors. A favor of that sort is called a #bQuest#k. You will receive reward items or EXP upon completing Quests, so I strongly suggest you diligently fulfill the favors of Maple NPCs.");
+ qm.sendNextPrev("Oh, let me warn you that this is a Quest. You may have noticed that NPCs around Maple World occasionally ask you for various favors. A favor of that sort is called a #bQuest#k. You will receive reward items or EXP upon completing Quests, so I strongly suggest you diligently fulfill the favors of Maple NPCs.");
} else if (status == 3) {
qm.sendAcceptDecline("Would you like to meet #bKizan#k, who can tell you about hunting? You can find Kizan by following the arrow to the left.");
} else if (status == 4) {
@@ -31,7 +37,7 @@ function end(mode, type, selection) {
qm.dispose();
} else {
if (status == 0) {
- qm.sendNext("Are you the Noblesse my brother Kimu sent? Nice to meet you! I'm Kizan. I'll give you the reward Kimu asked me to give you. Remember, you can check your Inventory by pressing the #bI key#k. Red potions help you recover HP, and blue ones help recover MP. It's a good idea to learn how to use them beforehand so you'll be ready with them when you're in danger. \r\n\r\n#fUI/UIWindow.img/Quest/reward# \r\n\r\n#v2000020# #z2000020# \r\n#v2000021# #z2000021# \r\n\r\n#fUI/UIWindow.img/QuestIcon/8/0#15 exp");
+ qm.sendOk("Are you the Noblesse my brother Kimu sent? Nice to meet you! I'm Kizan. I'll give you the reward Kimu asked me to give you. Remember, you can check your Inventory by pressing the #bI key#k. Red potions help you recover HP, and blue ones help recover MP. It's a good idea to learn how to use them beforehand so you'll be ready with them when you're in danger. \r\n\r\n#fUI/UIWindow.img/Quest/reward# \r\n\r\n#v2000020# #z2000020# \r\n#v2000021# #z2000021# \r\n\r\n#fUI/UIWindow.img/QuestIcon/8/0#15 exp");
} else if (status == 1) {
if(qm.canHold(2000022) && qm.canHold(2000023)){
if(!qm.isQuestCompleted(21010)) {
diff --git a/scripts/quest/20011.js b/scripts/quest/20011.js
index 1153de5c31..be08d1c3fa 100644
--- a/scripts/quest/20011.js
+++ b/scripts/quest/20011.js
@@ -48,7 +48,7 @@ function end(mode, type, selection) {
if (status == 0) {
qm.sendNext("Ah, it seems like you've successfully hunted a #o100120#. Pretty simple, right? Regular Attacks may be easy to use, but they are pretty weak. Don't worry, though. #p1102006# will teach you how to use more powerful skills. Wait, let me give you a well-deserved quest reward before you go.");
} else if (status == 1) {
- qm.sendNextPrev("This equipment is for Noblesses. It's much cooler than what you're wearing right now, isn't it? Follow the arrows to your left to meet my younger brother #b#p1102006##k. How about you change into your new Noblesse outfit before you go? \r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0# \r\n#i1002869# #t1002869# - 1 \r\n#i1052177# #t1052177# - 1 \r\n\r\n#fUI/UIWindow.img/QuestIcon/8/0# 30 exp");
+ qm.sendPrev("This equipment is for Noblesses. It's much cooler than what you're wearing right now, isn't it? Follow the arrows to your left to meet my younger brother #b#p1102006##k. How about you change into your new Noblesse outfit before you go? \r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0# \r\n#i1002869# #t1002869# - 1 \r\n#i1052177# #t1052177# - 1 \r\n\r\n#fUI/UIWindow.img/QuestIcon/8/0# 30 exp");
} else if (status == 2) {
qm.gainItem(1002869, 1);
qm.gainItem(1052177, 1);
diff --git a/scripts/quest/20013.js b/scripts/quest/20013.js
index 6efdb7a762..6742172b5e 100644
--- a/scripts/quest/20013.js
+++ b/scripts/quest/20013.js
@@ -52,7 +52,7 @@ function end(mode, type, selection) {
if (status == 0) {
qm.sendNext("Did you bring me a Building Stone and a Drape? Let's see. Ah, these are just what I need! They indeed are a #t4032267# and a #t4032268#! I'll make you a Chair right away.");
} else if (status == 1) {
- qm.sendNextPrev("Here it is, a #t3010060#. What do you think? Nifty, huh? You can #bquickly recover your HP by sitting in this Chair#k. It will be stored in the #bSet-up#k window in your Inventory, so confirm that you've received the chair and head over to #b#p1102008##k. You'll see him if you keep following the arrow to the left. \r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0# \r\n#i3010060# 1 #t3010060# \r\n#fUI/UIWindow.img/QuestIcon/8/0# 95 exp");
+ qm.sendPrev("Here it is, a #t3010060#. What do you think? Nifty, huh? You can #bquickly recover your HP by sitting in this Chair#k. It will be stored in the #bSet-up#k window in your Inventory, so confirm that you've received the chair and head over to #b#p1102008##k. You'll see him if you keep following the arrow to the left. \r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0# \r\n#i3010060# 1 #t3010060# \r\n#fUI/UIWindow.img/QuestIcon/8/0# 95 exp");
} else if (status == 2) {
qm.gainItem(4032267, -1);
qm.gainItem(4032268, -1);
diff --git a/scripts/quest/20016.js b/scripts/quest/20016.js
index 770529ce08..9d6e0f1903 100644
--- a/scripts/quest/20016.js
+++ b/scripts/quest/20016.js
@@ -50,9 +50,10 @@ function start(mode, type, selection) {
} else if (status == 11) {
qm.sendNextPrev("But no one starts as a strong Knight on day one. The Empress didn't want someone strong. She wanted someone with courage whom she could develop into a strong Knight through rigorous training. So, you should first become a Knight-in-Training. We'll talk about your missions when you get to that point.");
} else if (status == 12) {
- qm.sendPrev("Take the portal on the left to reach the Training Forest. There, you will find #p1102000#, the Training Instructor, who will teach you how to become stronger. I don't want to find you wandering around aimlessly until you reach Lv. 10, you hear?");
qm.forceCompleteQuest();
- qm.dispose();
+ qm.sendPrev("Take the portal on the left to reach the Training Forest. There, you will find #p1102000#, the Training Instructor, who will teach you how to become stronger. I don't want to find you wandering around aimlessly until you reach Lv. 10, you hear?");
+ } else if (status == 13) {
+ qm.dispose();
}
}
diff --git a/scripts/quest/20020.js b/scripts/quest/20020.js
new file mode 100644
index 0000000000..91b02cc2f1
--- /dev/null
+++ b/scripts/quest/20020.js
@@ -0,0 +1,38 @@
+/*
+ NPC Name: Nineheart
+ Description: Quest - Cygnus movie Intro
+*/
+var status = -1;
+
+function start(mode, type, selection) {
+ if (mode == -1) {
+ qm.sendOk("Talk to me after you have decided what you really want to do. Whatever you choose, you will not miss out or lose privileges, so don't take this too seriously...");
+ qm.dispose();
+ } else {
+ if(mode == 0 && type > 0 || selection == 1) {
+ qm.sendOk("Talk to me after you have decided what you really want to do. Whatever you choose, you will not miss out or lose privileges, so don't take this too seriously...");
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ qm.sendNext("I can tell you've worked really hard by seeing that you're already at Level 10. I think it's time now for you to break out as a Nobless and officially become the Knight-in-Training. Before doing that, however, I want to ask you one thing. Have you decided which Knight you'd want to beome?");
+ } else if (status == 1) {
+ qm.sendNextPrev("There isn't a single path to becoming a Knight. In fact, there are five of them laid out for you. It's up to you to choose which path you'd like to take, but it should definitely be something you will not regret. That's why... I am offering to show you what you'll look like once you become a Knight.");
+ } else if (status == 2) {
+ qm.sendSimple("What do you think? Are you interested in seeing yourself as the leader of the Knights? If you have already decided what kind of Knight you'd like to become, then you won't necessarily have to look at it...\r\n\r\n#b#L0#Show me how I'd look like as the leader of the Knights.#l ..#b#L1#No, I'm okay.");
+ } else if (status == 3) {
+ qm.sendYesNo("Would you like to see for it yourself right now? A short clip will come out soon. Be prepared for what you are about to witness.");
+ } else if (status == 4) {
+ qm.forceStartQuest();
+ qm.forceCompleteQuest();
+ qm.warp(913040100, 0);
+ qm.dispose();
+ }
+ }
+}
diff --git a/scripts/quest/20100.js b/scripts/quest/20100.js
index 883ac2875b..697eba843d 100644
--- a/scripts/quest/20100.js
+++ b/scripts/quest/20100.js
@@ -39,9 +39,11 @@ function start(mode, type, selection) {
if (status == 0)
qm.sendAcceptDecline("Ahhh, you're back. I can see that you're at level 10 now. It looks like you're flashing a glimmer of hope towards becoming a Knight. The basic training has now ended, and it's time for you to make the decision.");
else if (status == 1) {
- qm.sendOk("Now look to the left. The leaders of the Knights will be waiting for you. There will be 5 paths for you to choose from. All you need to do is choose one of them. All 5 of them will lead you to the path of a Knight, so... I suggest you pay attention to what each path offers, and select the one you'd most like to take.");
qm.forceStartQuest();
qm.forceCompleteQuest();
+
+ qm.sendOk("Now look to the left. The leaders of the Knights will be waiting for you. There will be 5 paths for you to choose from. All you need to do is choose one of them. All 5 of them will lead you to the path of a Knight, so... I suggest you pay attention to what each path offers, and select the one you'd most like to take.");
+ } else if (status == 2) {
qm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/quest/20101.js b/scripts/quest/20101.js
index 9af9d25a2f..a53b48f168 100644
--- a/scripts/quest/20101.js
+++ b/scripts/quest/20101.js
@@ -6,6 +6,7 @@ importPackage(Packages.client);
var status = -1;
var jobType = 1;
+var canTryFirstJob = true;
function end(mode, type, selection) {
if (mode == 0) {
@@ -21,34 +22,38 @@ function end(mode, type, selection) {
if (status == 0) {
qm.sendYesNo("Have you made your decision? The decision will be final, so think carefully before deciding what to do. Are you sure you want to become a Dawn Warrior?");
} else if (status == 1) {
- if(!qm.canGetFirstJob(jobType)) {
- qm.sendOk("Train a bit more until you reach #blevel 10, " + qm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rDawn Warrior#k.");
- qm.dispose();
- return;
+ if (canTryFirstJob) {
+ canTryFirstJob = false;
+ if (qm.getPlayer().getJob().getId() != 1100) {
+ if(!qm.canGetFirstJob(jobType)) {
+ qm.sendOk("Train a bit more until you reach #blevel 10, " + qm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rDawn Warrior#k.");
+ qm.dispose();
+ return;
+ }
+
+ if (!(qm.canHoldAll([1302077, 1142066]))) {
+ qm.sendOk("Make some room in your inventory and talk back to me.");
+ qm.dispose();
+ return;
+ }
+
+ qm.gainItem(1302077, 1);
+ qm.gainItem(1142066, 1);
+ qm.changeJob(MapleJob.DAWNWARRIOR1);
+ qm.getPlayer().resetStats();
+ }
+ qm.forceCompleteQuest();
}
-
- if (!(qm.canHoldAll([1302077, 1142066]))) {
- qm.sendOk("Make some room in your inventory and talk back to me.");
- qm.dispose();
- return;
- }
-
- qm.sendNext("I have just molded your body to make it perfect for a Dawn Warrior. If you wish to become more powerful, use Stat Window (S) to raise the appropriate stats. If you aren't sure what to raise, just click on #bAuto#k.");
- if (qm.getPlayer().getJob().getId() != 1100) {
- qm.gainItem(1302077, 1);
- qm.gainItem(1142066, 1);
- qm.changeJob(MapleJob.DAWNWARRIOR1);
- qm.getPlayer().resetStats();
- }
- qm.forceCompleteQuest();
+ qm.sendNext("I have just molded your body to make it perfect for a Dawn Warrior. If you wish to become more powerful, use Stat Window (S) to raise the appropriate stats. If you aren't sure what to raise, just click on #bAuto#k.");
} else if (status == 2) {
qm.sendNextPrev("I have also expanded your inventory slot counts for your equipment and etc. inventory. Use those slots wisely and fill them up with items required for Knights to carry.");
} else if (status == 3) {
qm.sendNextPrev("I have also given you a hint of #bSP#k, so open the #bSkill Menu#k to acquire new skills. Of course, you can't raise them at all once, and there are some skills out there where you won't be able to acquire them unless you master the basic skills first.");
} else if (status == 4) {
- qm.sendNextPrev("Unlike your time as a Nobless, once you become the Dawn Warrior, you will lost a portion of your EXP when you run out of HP, okay?");
+ qm.sendNextPrev("Unlike your time as a Noblesse, once you become the Dawn Warrior, you will lost a portion of your EXP when you run out of HP, okay?");
} else if (status == 5) {
qm.sendNextPrev("Now... I want you to go out there and show the world how the Knights of Cygnus operate.");
- qm.dispose();
+ } else if (status == 6) {
+ qm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/quest/20102.js b/scripts/quest/20102.js
index cbdf5aee82..fec8015c50 100644
--- a/scripts/quest/20102.js
+++ b/scripts/quest/20102.js
@@ -6,6 +6,7 @@ importPackage(Packages.client);
var status = -1;
var jobType = 2;
+var canTryFirstJob = true;
function end(mode, type, selection) {
if (mode == 0) {
@@ -21,34 +22,38 @@ function end(mode, type, selection) {
if (status == 0) {
qm.sendYesNo("Have you made your decision? The decision will be final, so think carefully before deciding what to do. Are you sure you want to become a Blaze Wizard?");
} else if (status == 1) {
- if(!qm.canGetFirstJob(jobType)) {
- qm.sendOk("Train a bit more until you reach #blevel 10, " + qm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rBlaze Wizard#k.");
- qm.dispose();
- return;
+ if (canTryFirstJob) {
+ canTryFirstJob = false;
+ if (qm.getPlayer().getJob().getId() != 1200) {
+ if(!qm.canGetFirstJob(jobType)) {
+ qm.sendOk("Train a bit more until you reach #blevel 10, " + qm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rBlaze Wizard#k.");
+ qm.dispose();
+ return;
+ }
+
+ if (!(qm.canHoldAll([1372043, 1142066]))) {
+ qm.sendOk("Make some room in your inventory and talk back to me.");
+ qm.dispose();
+ return;
+ }
+
+ qm.gainItem(1372043, 1);
+ qm.gainItem(1142066, 1);
+ qm.changeJob(MapleJob.BLAZEWIZARD1);
+ qm.getPlayer().resetStats();
+ }
+ qm.forceCompleteQuest();
}
-
- if (!(qm.canHoldAll([1372043, 1142066]))) {
- qm.sendOk("Make some room in your inventory and talk back to me.");
- qm.dispose();
- return;
- }
-
- qm.sendNext("I have just molded your body to make it perfect for a Blaze Wizard. If you wish to become more powerful, use Stat Window (S) to raise the appropriate stats. If you aren't sure what to raise, just click on #bAuto#k.");
- if (qm.getPlayer().getJob().getId() != 1200) {
- qm.gainItem(1372043, 1);
- qm.gainItem(1142066, 1);
- qm.changeJob(MapleJob.BLAZEWIZARD1);
- qm.getPlayer().resetStats();
- }
- qm.forceCompleteQuest();
+ qm.sendNext("I have just molded your body to make it perfect for a Blaze Wizard. If you wish to become more powerful, use Stat Window (S) to raise the appropriate stats. If you aren't sure what to raise, just click on #bAuto#k.");
} else if (status == 2) {
qm.sendNextPrev("I have also expanded your inventory slot counts for your equipment and etc. inventory. Use those slots wisely and fill them up with items required for Knights to carry.");
} else if (status == 3) {
qm.sendNextPrev("I have also given you a hint of #bSP#k, so open the #bSkill Menu#k to acquire new skills. Of course, you can't raise them at all once, and there are some skills out there where you won't be able to acquire them unless you master the basic skills first.");
} else if (status == 4) {
- qm.sendNextPrev("Unlike your time as a Nobless, once you become the Blaze Wizard, you will lost a portion of your EXP when you run out of HP, okay?");
+ qm.sendNextPrev("Unlike your time as a Noblesse, once you become the Blaze Wizard, you will lost a portion of your EXP when you run out of HP, okay?");
} else if (status == 5) {
qm.sendNextPrev("Now... I want you to go out there and show the world how the Knights of Cygnus operate.");
- qm.dispose();
+ } else if (status == 6) {
+ qm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/quest/20103.js b/scripts/quest/20103.js
index 9d603bf429..8aadf16618 100644
--- a/scripts/quest/20103.js
+++ b/scripts/quest/20103.js
@@ -6,6 +6,7 @@ importPackage(Packages.client);
var status = -1;
var jobType = 3;
+var canTryFirstJob = true;
function end(mode, type, selection) {
if (mode == 0) {
@@ -21,35 +22,39 @@ function end(mode, type, selection) {
if (status == 0) {
qm.sendYesNo("Have you made your decision? The decision will be final, so think carefully before deciding what to do. Are you sure you want to become a Wind Archer?");
} else if (status == 1) {
- if(!qm.canGetFirstJob(jobType)) {
- qm.sendOk("Train a bit more until you reach #blevel 10, " + qm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rWind Archer#k.");
- qm.dispose();
- return;
+ if (canTryFirstJob) {
+ canTryFirstJob = false;
+ if (qm.getPlayer().getJob().getId() != 1300) {
+ if(!qm.canGetFirstJob(jobType)) {
+ qm.sendOk("Train a bit more until you reach #blevel 10, " + qm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rWind Archer#k.");
+ qm.dispose();
+ return;
+ }
+
+ if (!(qm.canHoldAll([1452051, 1142066]) && qm.canHold(2070000))) {
+ qm.sendOk("Make some room in your inventory and talk back to me.");
+ qm.dispose();
+ return;
+ }
+
+ qm.gainItem(2060000, 2000);
+ qm.gainItem(1452051, 1);
+ qm.gainItem(1142066, 1);
+ qm.changeJob(MapleJob.WINDARCHER1);
+ qm.getPlayer().resetStats();
+ }
+ qm.forceCompleteQuest();
}
-
- if (!(qm.canHoldAll([1452051, 1142066]) && qm.canHold(2070000))) {
- qm.sendOk("Make some room in your inventory and talk back to me.");
- qm.dispose();
- return;
- }
-
- qm.sendNext("I have just molded your body to make it perfect for a Wind Archer. If you wish to become more powerful, use Stat Window (S) to raise the appropriate stats. If you aren't sure what to raise, just click on #bAuto#k.");
- if (qm.getPlayer().getJob().getId() != 1300) {
- qm.gainItem(2060000, 2000);
- qm.gainItem(1452051, 1);
- qm.gainItem(1142066, 1);
- qm.changeJob(MapleJob.WINDARCHER1);
- qm.getPlayer().resetStats();
- }
- qm.forceCompleteQuest();
+ qm.sendNext("I have just molded your body to make it perfect for a Wind Archer. If you wish to become more powerful, use Stat Window (S) to raise the appropriate stats. If you aren't sure what to raise, just click on #bAuto#k.");
} else if (status == 2) {
qm.sendNextPrev("I have also expanded your inventory slot counts for your equipment and etc. inventory. Use those slots wisely and fill them up with items required for Knights to carry.");
} else if (status == 3) {
qm.sendNextPrev("I have also given you a hint of #bSP#k, so open the #bSkill Menu#k to acquire new skills. Of course, you can't raise them at all once, and there are some skills out there where you won't be able to acquire them unless you master the basic skills first.");
} else if (status == 4) {
- qm.sendNextPrev("Unlike your time as a Nobless, once you become the Wind Archer, you will lost a portion of your EXP when you run out of HP, okay?");
+ qm.sendNextPrev("Unlike your time as a Noblesse, once you become the Wind Archer, you will lost a portion of your EXP when you run out of HP, okay?");
} else if (status == 5) {
qm.sendNextPrev("Now... I want you to go out there and show the world how the Knights of Cygnus operate.");
- qm.dispose();
+ } else if (status == 6) {
+ qm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/quest/20104.js b/scripts/quest/20104.js
index 232a97ad5d..2f4ee320c7 100644
--- a/scripts/quest/20104.js
+++ b/scripts/quest/20104.js
@@ -6,6 +6,7 @@ importPackage(Packages.client);
var status = -1;
var jobType = 4;
+var canTryFirstJob = true;
function end(mode, type, selection) {
if (mode == 0) {
@@ -21,35 +22,39 @@ function end(mode, type, selection) {
if (status == 0) {
qm.sendYesNo("Have you made your decision? The decision will be final, so think carefully before deciding what to do. Are you sure you want to become a Night Walker?");
} else if (status == 1) {
- if(!qm.canGetFirstJob(jobType)) {
- qm.sendOk("Train a bit more until you reach #blevel 10, " + qm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rNight Walker#k.");
- qm.dispose();
- return;
+ if (canTryFirstJob) {
+ canTryFirstJob = false;
+ if (qm.getPlayer().getJob().getId() != 1400) {
+ if(!qm.canGetFirstJob(jobType)) {
+ qm.sendOk("Train a bit more until you reach #blevel 10, " + qm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rNight Walker#k.");
+ qm.dispose();
+ return;
+ }
+
+ if (!(qm.canHoldAll([1472061, 1142066]) && qm.canHold(2070000))) {
+ qm.sendOk("Make some room in your inventory and talk back to me.");
+ qm.dispose();
+ return;
+ }
+
+ qm.gainItem(1472061, 1);
+ qm.gainItem(2070000, 800);
+ qm.gainItem(1142066, 1);
+ qm.changeJob(MapleJob.NIGHTWALKER1);
+ qm.getPlayer().resetStats();
+ }
+ qm.forceCompleteQuest();
}
-
- if (!(qm.canHoldAll([1472061, 1142066]) && qm.canHold(2070000))) {
- qm.sendOk("Make some room in your inventory and talk back to me.");
- qm.dispose();
- return;
- }
-
- qm.sendNext("I have just molded your body to make it perfect for a Night Walker. If you wish to become more powerful, use Stat Window (S) to raise the appropriate stats. If you aren't sure what to raise, just click on #bAuto#k.");
- if (qm.getPlayer().getJob().getId() != 1400) {
- qm.gainItem(1472061, 1);
- qm.gainItem(2070000, 800);
- qm.gainItem(1142066, 1);
- qm.changeJob(MapleJob.NIGHTWALKER1);
- qm.getPlayer().resetStats();
- }
- qm.forceCompleteQuest();
+ qm.sendNext("I have just molded your body to make it perfect for a Night Walker. If you wish to become more powerful, use Stat Window (S) to raise the appropriate stats. If you aren't sure what to raise, just click on #bAuto#k.");
} else if (status == 2) {
qm.sendNextPrev("I have also expanded your inventory slot counts for your equipment and etc. inventory. Use those slots wisely and fill them up with items required for Knights to carry.");
} else if (status == 3) {
qm.sendNextPrev("I have also given you a hint of #bSP#k, so open the #bSkill Menu#k to acquire new skills. Of course, you can't raise them at all once, and there are some skills out there where you won't be able to acquire them unless you master the basic skills first.");
} else if (status == 4) {
- qm.sendNextPrev("Unlike your time as a Nobless, once you become the Night Walker, you will lost a portion of your EXP when you run out of HP, okay?");
+ qm.sendNextPrev("Unlike your time as a Noblesse, once you become the Night Walker, you will lost a portion of your EXP when you run out of HP, okay?");
} else if (status == 5) {
qm.sendNextPrev("Now... I want you to go out there and show the world how the Knights of Cygnus operate.");
- qm.dispose();
+ } else if (status == 6) {
+ qm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/quest/20105.js b/scripts/quest/20105.js
index 6580c083c4..03e933f019 100644
--- a/scripts/quest/20105.js
+++ b/scripts/quest/20105.js
@@ -6,6 +6,7 @@ importPackage(Packages.client);
var status = -1;
var jobType = 5;
+var canTryFirstJob = true;
function end(mode, type, selection) {
if (mode == 0) {
@@ -21,34 +22,38 @@ function end(mode, type, selection) {
if (status == 0) {
qm.sendYesNo("Have you made your decision? The decision will be final, so think carefully before deciding what to do. Are you sure you want to become a Thunder Breaker?");
} else if (status == 1) {
- if(!qm.canGetFirstJob(jobType)) {
- qm.sendOk("Train a bit more until you reach #blevel 10, " + qm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rThunder Breaker#k.");
- qm.dispose();
- return;
+ if (canTryFirstJob) {
+ canTryFirstJob = false;
+ if (qm.getPlayer().getJob().getId() != 1500) {
+ if(!qm.canGetFirstJob(jobType)) {
+ qm.sendOk("Train a bit more until you reach #blevel 10, " + qm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rThunder Breaker#k.");
+ qm.dispose();
+ return;
+ }
+
+ if (!(qm.canHoldAll([1482014, 1142066]))) {
+ qm.sendOk("Make some room in your inventory and talk back to me.");
+ qm.dispose();
+ return;
+ }
+
+ qm.gainItem(1482014, 1);
+ qm.gainItem(1142066, 1);
+ qm.getPlayer().changeJob(MapleJob.THUNDERBREAKER1);
+ qm.getPlayer().resetStats();
+ }
+ qm.forceCompleteQuest();
}
-
- if (!(qm.canHoldAll([1482014, 1142066]))) {
- qm.sendOk("Make some room in your inventory and talk back to me.");
- qm.dispose();
- return;
- }
-
- qm.sendNext("I have just molded your body to make it perfect for a Thunder Breaker. If you wish to become more powerful, use Stat Window (S) to raise the appropriate stats. If you aren't sure what to raise, just click on #bAuto#k.");
- if (qm.getPlayer().getJob().getId() != 1500) {
- qm.gainItem(1482014, 1);
- qm.gainItem(1142066, 1);
- qm.getPlayer().changeJob(MapleJob.THUNDERBREAKER1);
- qm.getPlayer().resetStats();
- }
- qm.forceCompleteQuest();
+ qm.sendNext("I have just molded your body to make it perfect for a Thunder Breaker. If you wish to become more powerful, use Stat Window (S) to raise the appropriate stats. If you aren't sure what to raise, just click on #bAuto#k.");
} else if (status == 2) {
qm.sendNextPrev("I have also expanded your inventory slot counts for your equipment and etc. inventory. Use those slots wisely and fill them up with items required for Knights to carry.");
} else if (status == 3) {
qm.sendNextPrev("I have also given you a hint of #bSP#k, so open the #bSkill Menu#k to acquire new skills. Of course, you can't raise them at all once, and there are some skills out there where you won't be able to acquire them unless you master the basic skills first.");
} else if (status == 4) {
- qm.sendNextPrev("Unlike your time as a Nobless, once you become the Thunder Breaker, you will lost a portion of your EXP when you run out of HP, okay?");
+ qm.sendNextPrev("Unlike your time as a Noblesse, once you become the Thunder Breaker, you will lost a portion of your EXP when you run out of HP, okay?");
} else if (status == 5) {
qm.sendNextPrev("Now... I want you to go out there and show the world how the Knights of Cygnus operate.");
- qm.dispose();
+ } else if (status == 6) {
+ qm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/quest/20200.js b/scripts/quest/20200.js
index a8e6afb236..a1a0752699 100644
--- a/scripts/quest/20200.js
+++ b/scripts/quest/20200.js
@@ -44,7 +44,9 @@ function start(mode, type, selection) {
} else if (status == 1) {
qm.startQuest();
qm.completeQuest();
+
qm.sendOk("If you wish to take the Knighthood Exam, please come to Ereve. Each Chief Knight will test your abilities, and if you meet their standards, then you will officially become a Knight.");
+ } else if (status == 2) {
qm.dispose();
}
}
diff --git a/scripts/quest/20311.js b/scripts/quest/20311.js
index 31be876455..4075738092 100644
--- a/scripts/quest/20311.js
+++ b/scripts/quest/20311.js
@@ -48,19 +48,18 @@ function start(mode, type, selection) {
nPSP = (qm.getPlayer().getLevel() - 70) * 3;
if (qm.getPlayer().getRemainingSp() > nPSP) {
qm.sendNext("You still have way too much #bSP#k with you. You can't earn a new title like that, I strongly urge you to use more SP on your 1st and 2nd level skills.");
- qm.dispose();
} else {
if (!qm.canHold(1142068)) {
qm.sendNext("If you wish to receive the medal befitting the title, you may want to make some room in your equipment inventory.");
- qm.dispose();
} else {
+ qm.completeQuest();
qm.gainItem(1142068, 1);
qm.getPlayer().changeJob(Packages.client.MapleJob.DAWNWARRIOR3);
qm.sendOk("#h #, as of this moment, you are an Advanced Knight. From this moment on, you shall carry yourself with dignity and respect befitting your new title, an Advanced Knight of Cygnus Knights. May your glory continue to shine as bright as this moment.");
- qm.completeQuest();
- qm.dispose();
}
}
+ } else if (status == 3) {
+ qm.dispose();
}
}
}
\ No newline at end of file
diff --git a/scripts/quest/20312.js b/scripts/quest/20312.js
index 26458ea860..b562dea87e 100644
--- a/scripts/quest/20312.js
+++ b/scripts/quest/20312.js
@@ -48,20 +48,18 @@ function start(mode, type, selection) {
nPSP = (qm.getPlayer().getLevel() - 70) * 3;
if (qm.getPlayer().getRemainingSp() > nPSP) {
qm.sendNext("You still have way too much #bSP#k with you. You can't earn a new title like that, I strongly urge you to use more SP on your 1st and 2nd level skills.");
- qm.dispose();
} else {
if (!qm.canHold(1142068)) {
qm.sendNext("If you wish to receive the medal befitting the title, you may want to make some room in your equipment inventory.");
- qm.dispose();
} else {
+ qm.completeQuest();
qm.gainItem(1142068, 1);
qm.getPlayer().changeJob(Packages.client.MapleJob.BLAZEWIZARD3);
qm.sendOk("#h #, as of this moment, you are an Advanced Knight. From this moment on, you will train yourself with fervor as you will lead your group of Knights for the safety of this world. That fervor will provide you with plenty of courage.");
- qm.completeQuest();
- qm.dispose();
}
}
-
+ } else if (status == 3) {
+ qm.dispose();
}
}
}
\ No newline at end of file
diff --git a/scripts/quest/20313.js b/scripts/quest/20313.js
index 73cb223242..58e7a89064 100644
--- a/scripts/quest/20313.js
+++ b/scripts/quest/20313.js
@@ -48,20 +48,18 @@ function start(mode, type, selection) {
nPSP = (qm.getPlayer().getLevel() - 70) * 3;
if (qm.getPlayer().getRemainingSp() > nPSP) {
qm.sendNext("You still have way too much #bSP#k with you. You can't earn a new title like that, I strongly urge you to use more SP on your 1st and 2nd level skills.");
- qm.dispose();
} else {
if (!qm.canHold(1142068)) {
qm.sendNext("If you wish to receive the medal befitting the title, you may want to make some room in your equipment inventory.");
- qm.dispose();
} else {
+ qm.completeQuest();
qm.gainItem(1142068, 1);
qm.getPlayer().changeJob(Packages.client.MapleJob.WINDARCHER3);
qm.sendOk("#h #, as of this moment, you are an Advanced Knight. From this moment on, you will be carrying a while lot of responsibility befitting your new title as an Advanced Knight of Cygnus Knights. You may view the world in a carefree mode, but please remember what your mission is.");
- qm.completeQuest();
- qm.dispose();
}
}
-
+ } else if (status == 3) {
+ qm.dispose();
}
}
}
\ No newline at end of file
diff --git a/scripts/quest/20314.js b/scripts/quest/20314.js
index 17bb317317..be6c955c90 100644
--- a/scripts/quest/20314.js
+++ b/scripts/quest/20314.js
@@ -48,20 +48,18 @@ function start(mode, type, selection) {
nPSP = (qm.getPlayer().getLevel() - 70) * 3;
if (qm.getPlayer().getRemainingSp() > nPSP) {
qm.sendNext("You still have way too much #bSP#k with you. You can't earn a new title like that, I strongly urge you to use more SP on your 1st and 2nd level skills.");
- qm.dispose();
} else {
if (!qm.canHold(1142068)) {
qm.sendNext("If you wish to receive the medal befitting the title, you may want to make some room in your equipment inventory.");
- qm.dispose();
} else {
qm.gainItem(1142068, 1);
qm.getPlayer().changeJob(Packages.client.MapleJob.NIGHTWALKER3);
- qm.sendOk("#h #, from here on out, you are an Advanced Knight of Cygnus Knights. The title comes with a newfound broad view on everything. You may encounter temptations here and there, but I want you to keep your faith and beliefs intact and do not succumb to the darkness.");
qm.completeQuest();
- qm.dispose();
+ qm.sendOk("#h #, from here on out, you are an Advanced Knight of Cygnus Knights. The title comes with a newfound broad view on everything. You may encounter temptations here and there, but I want you to keep your faith and beliefs intact and do not succumb to the darkness.");
}
}
-
+ } else if (status == 3) {
+ qm.dispose();
}
}
}
\ No newline at end of file
diff --git a/scripts/quest/20315.js b/scripts/quest/20315.js
index 05b43e4c10..073fc6da8b 100644
--- a/scripts/quest/20315.js
+++ b/scripts/quest/20315.js
@@ -48,20 +48,18 @@ function start(mode, type, selection) {
nPSP = (qm.getPlayer().getLevel() - 70) * 3;
if (qm.getPlayer().getRemainingSp() > nPSP) {
qm.sendNext("You still have way too much #bSP#k with you. You can't earn a new title like that, I strongly urge you to use more SP on your 1st and 2nd level skills.");
- qm.dispose();
} else {
if (!qm.canHold(1142068)) {
qm.sendNext("If you wish to receive the medal befitting the title, you may want to make some room in your equipment inventory.");
- qm.dispose();
} else {
qm.gainItem(1142068, 1);
qm.getPlayer().changeJob(Packages.client.MapleJob.THUNDERBREAKER3);
- qm.sendOk("#h #, from here on out, you will become an Advanced Knight of the Knights of Cygnus! As your standing rises, so does the difficulty of the tasks you will be receiving. But challenge is good, right? You have to enjoy life. Enjoy what's given to you!");
qm.completeQuest();
- qm.dispose();
+ qm.sendOk("#h #, from here on out, you will become an Advanced Knight of the Knights of Cygnus! As your standing rises, so does the difficulty of the tasks you will be receiving. But challenge is good, right? You have to enjoy life. Enjoy what's given to you!");
}
}
-
+ } else if (status == 3) {
+ qm.dispose();
}
}
}
\ No newline at end of file
diff --git a/scripts/quest/2034.js b/scripts/quest/2034.js
index d123cc9aa0..37105e5b12 100644
--- a/scripts/quest/2034.js
+++ b/scripts/quest/2034.js
@@ -1,7 +1,6 @@
importPackage(Packages.client);
var item;
-var stance;
var status = -1;
var item;
@@ -23,8 +22,7 @@ function end(mode, type, selection) {
return;
}
- stance = qm.getPlayer().getJobStyle();
-
+ var stance = qm.getPlayer().getJobStyle();
if(stance == Packages.client.MapleJob.WARRIOR) item = 1072003;
else if(stance == Packages.client.MapleJob.MAGICIAN) item = 1072077;
else if(stance == Packages.client.MapleJob.BOWMAN || stance == Packages.client.MapleJob.CROSSBOWMAN) item = 1072081;
@@ -34,11 +32,13 @@ function end(mode, type, selection) {
qm.gainItem(item, 1);
qm.gainItem(4000007, -150);
-
qm.gainExp(2200);
qm.completeQuest();
qm.sendOk("Alright, if you need work sometime down the road, feel free to come back and see me. This town sure can use a person like you for help~");
+ }
+
+ else if (status == 2) {
qm.dispose();
- }
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/20514.js b/scripts/quest/20514.js
new file mode 100644
index 0000000000..045fadc608
--- /dev/null
+++ b/scripts/quest/20514.js
@@ -0,0 +1,52 @@
+/*
+ This file is part of the HeavenMS MapleStory Server
+ Copyleft (L) 2016 - 2018 RonanLana
+
+ 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 .
+*/
+
+// @Author Ronan
+
+importPackage(Packages.constants.game);
+importPackage(Packages.server);
+
+function raiseOpen() {
+ var chr = qm.getPlayer();
+ var questStatus = chr.getQuestStatus(qm.getQuest());
+
+ if (questStatus == 0) {
+ qm.setQuestProgress(20515, 0, chr.getLevel());
+ qm.setQuestProgress(20515, 1, chr.getExp());
+ } else if (questStatus == 1) { // update mimiana progress...
+ var diffExp = chr.getExp() - qm.getQuestProgressInt(20515, 1);
+
+ var initLevel = qm.getQuestProgressInt(20515, 0);
+ for (var i = initLevel; i < chr.getLevel(); i++) {
+ diffExp += ExpTable.getExpNeededForLevel(i);
+ }
+
+ if (diffExp > 0) { // thanks IxianMace for noticing Mimiana egg not following progress by EXP
+ var consItem = MapleItemInformationProvider.getInstance().getQuestConsumablesInfo(4220137);
+ var exp = consItem.exp;
+ var grade = consItem.grade;
+
+ qm.setQuestProgress(20514, 0, Math.min(diffExp, exp * grade));
+ }
+ }
+
+ qm.dispose();
+}
+
diff --git a/scripts/quest/20520.js b/scripts/quest/20520.js
index e507450baf..6f1c5e193d 100644
--- a/scripts/quest/20520.js
+++ b/scripts/quest/20520.js
@@ -44,6 +44,7 @@ function start(mode, type, selection) {
qm.forceStartQuest();
qm.forceCompleteQuest();
qm.sendOk("There's a special mount that only the Cygnus Knights can enjoy. If you are interested, visit #bEreve#k. I will give you more information on it.");
- qm.dispose();
- }
+ } else if (status == 3) {
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/20522.js b/scripts/quest/20522.js
index e4e52c9894..862c2bf98f 100644
--- a/scripts/quest/20522.js
+++ b/scripts/quest/20522.js
@@ -54,6 +54,7 @@ function start(mode, type, selection) {
qm.forceStartQuest();
if(!qm.haveItem(4220137)) qm.gainItem(4220137);
qm.sendOk("Mimiana's egg can be raised by #bsharing your daily experiences with it#k. Once Mimiana fully grows up, please come see me.");
+ } else if (status == 4) {
qm.dispose();
}
}
@@ -70,17 +71,15 @@ function end(mode, type, selection) {
} else if (status == 1) { //pretty sure there would need to have an egg EXP condition... Whatever.
if(!qm.haveItem(4220137)) {
qm.sendOk("I see, you lost your egg... You need to be more careful when raising a baby Mimiana!");
- qm.dispose();
return;
}
- qm.sendOk("Oh, were you able to awaken Mimiana Egg? That's amazing... Most knights can't even dream of awakening it in such a short amount of time.");
-
- qm.forceCompleteQuest();
+ qm.forceCompleteQuest();
qm.gainItem(4220137, -1);
qm.gainExp(37600);
-
- qm.dispose();
+ qm.sendOk("Oh, were you able to awaken Mimiana Egg? That's amazing... Most knights can't even dream of awakening it in such a short amount of time.");
+ } else if (status == 2) {
+ qm.dispose();
}
}
diff --git a/scripts/quest/20526.js b/scripts/quest/20526.js
index 2b06a930dc..440581b89a 100644
--- a/scripts/quest/20526.js
+++ b/scripts/quest/20526.js
@@ -55,6 +55,7 @@ function start(mode, type, selection) {
if(!qm.haveItem(4220137)) qm.gainItem(4220137);
qm.sendOk("Mimiana's egg can be raised by #bsharing your daily experiences with it#k. Once Mimiana fully grows up, please come see me. One more thing, I talked with #p2060005# beforehand and retrieved the #b#t4032117##k for you. The price to charge remains the same: #r10,000,000 mesos#k.");
+ } else if (status == 4) {
qm.dispose();
}
}
@@ -80,14 +81,13 @@ function end(mode, type, selection) {
return;
}
- qm.sendOk("Okay, you now may mount Mimiana again. Take good care of it this time.");
-
+ qm.forceCompleteQuest();
qm.gainItem(1902005, 1);
qm.gainItem(4220137, -1);
qm.gainMeso(-10000000);
-
- qm.forceCompleteQuest();
- qm.dispose();
+ qm.sendOk("Okay, you now may mount Mimiana again. Take good care of it this time.");
+ } else if (status == 2) {
+ qm.dispose();
}
}
diff --git a/scripts/quest/20527.js b/scripts/quest/20527.js
index ef0a578caf..07cb063c4a 100644
--- a/scripts/quest/20527.js
+++ b/scripts/quest/20527.js
@@ -38,12 +38,12 @@ function start(mode, type, selection) {
var mount = qm.getPlayer().getMount();
if(mount != null && mount.getLevel() >= 3) {
- qm.sendNext("Alright, I'll get you started in how to train Mimio, the next step for Mimianas. When you're ready, talk to me again.");
qm.forceCompleteQuest();
+ qm.sendNext("Alright, I'll get you started in how to train Mimio, the next step for Mimianas. When you're ready, talk to me again.");
} else {
qm.sendNext("It looks like your Mimiana haven't reached #rlevel 3#k yet. Please train it a bit more before trying to advance it.");
}
-
+ } else if (status == 1) {
qm.dispose();
}
}
diff --git a/scripts/quest/20600.js b/scripts/quest/20600.js
index 76a86566ed..cee458fe5e 100644
--- a/scripts/quest/20600.js
+++ b/scripts/quest/20600.js
@@ -9,7 +9,7 @@ function start(mode, type, selection) {
if (status == 0) {
qm.sendAcceptDecline("#h0#. Have you been slacking off on training since reaching Level 100? We all know how powerful you are, but the training is not complete. Take a look at these Knight Commanders. They train day and night, preparing themselves for the possible encounter with the Black Mage.");
- } else {
+ } else if (status == 1) {
if (mode == 1) {
qm.forceStartQuest();
}
diff --git a/scripts/quest/20610.js b/scripts/quest/20610.js
index 3da0a28c20..3f15cbab65 100644
--- a/scripts/quest/20610.js
+++ b/scripts/quest/20610.js
@@ -14,8 +14,10 @@ function start(mode, type, selection) {
qm.sendOk("Well, what you're doing right now doesn't make you look like someone that's humble. You just look complacent by doing that, and that's never a good thing.");
} else {
qm.forceStartQuest();
+ qm.dispose();
}
- qm.dispose();
+ } else if (status == 2) {
+ qm.dispose();
}
}
diff --git a/scripts/quest/21011.js b/scripts/quest/21011.js
index 4275db3e1e..736aea9078 100644
--- a/scripts/quest/21011.js
+++ b/scripts/quest/21011.js
@@ -48,8 +48,9 @@ function start(mode, type, selection) {
} else if (status == 4) {
qm.forceStartQuest();
qm.sendOk("My brother #bPuir #kis just down the street, and he's been dying to meet you! I know you're busy, but could you please stop by and say hello to Puir? Please...");
+ } else if (status == 5) {
qm.dispose();
- }
+ }
}
function end(mode, type, selection) {
@@ -83,7 +84,7 @@ function end(mode, type, selection) {
qm.sendNext("#b(Your skills are nowhere close to being hero-like... But a sword? Have you ever even held a sword in your lifetime? You can't remember... How do you even equip it?)", 3);
}else
qm.dropMessage(1,"Your inventory is full");
- } else if (status == 6) {
+ } else if (status == 6) {
qm.guideHint(16);
qm.dispose();
}
diff --git a/scripts/quest/21012.js b/scripts/quest/21012.js
index 644dab447f..6b1e391063 100644
--- a/scripts/quest/21012.js
+++ b/scripts/quest/21012.js
@@ -71,14 +71,16 @@ function end(mode, type, selection) {
if(qm.isQuestCompleted(21012))
qm.dropMessage(1,"Unknown Error");
else if(qm.canHold(2000022) && qm.canHold(2000023)){
+ qm.forceCompleteQuest();
qm.gainExp(57);
qm.gainItem(2000022, 10);
qm.gainItem(2000023, 10);
- qm.forceCompleteQuest();
qm.sendOk("#b(Even if you're really the hero everyone says you are... What good are you without any skills?)", 3);
- qm.dispose();
- }else
+ } else {
qm.dropMessage(1,"Your inventory is full");
- qm.dispose();
+ qm.dispose();
+ }
+ } else if (status == 2) {
+ qm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/quest/21013.js b/scripts/quest/21013.js
index 700a6d6afc..ae758bccc5 100644
--- a/scripts/quest/21013.js
+++ b/scripts/quest/21013.js
@@ -73,7 +73,7 @@ function end(mode, type, selection) {
qm.gainItem(4032309, -1);
qm.gainItem(4032310, -1);
qm.gainItem(3010062, 1);
- qm.sendNextPrev("Here, a fully-assembled chair, just for you! I've always wanted to give you a chair as a gift, because I know a hero can occasionally use some good rest. Tee hee.", 9);
+ qm.sendNext("Here, a fully-assembled chair, just for you! I've always wanted to give you a chair as a gift, because I know a hero can occasionally use some good rest. Tee hee.", 9);
} else if (status == 2) {
qm.sendNext("A hero is not invincible. A hero is human. I'm sure you will face challenges and even falter at times. But you are a hero because you have what it takes to overcome any obstacles you may encounter.", 9);
} else if (status == 3) {
diff --git a/scripts/quest/21100.js b/scripts/quest/21100.js
index 483bc4f160..475a81af99 100644
--- a/scripts/quest/21100.js
+++ b/scripts/quest/21100.js
@@ -31,6 +31,7 @@ function start(mode, type, selection) {
qm.sendOk("If the #p1201001# reacts to you, then we'll know that you're #bAran#k, the hero that wielded a #p1201001#.", 8);
qm.showIntro("Effect/Direction1.img/aranTutorial/ClickPoleArm");
}
- qm.dispose();
- }
+ } else if (status == 8) {
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/21101.js b/scripts/quest/21101.js
index e59c0bb9a6..05636b3cbc 100644
--- a/scripts/quest/21101.js
+++ b/scripts/quest/21101.js
@@ -20,7 +20,7 @@
along with this program. If not, see .
*/
importPackage(Packages.client);
-importPackage(Packages.constants);
+importPackage(Packages.config);
status = -1;
@@ -48,7 +48,7 @@ function start(mode, type, selection) {
qm.changeJobById(2100);
qm.resetStats();
- if (ServerConstants.USE_FULL_ARAN_SKILLSET) {
+ if (YamlConfig.config.server.USE_FULL_ARAN_SKILLSET) {
qm.teachSkill(21000000, 0, 10, -1); //combo ability
qm.teachSkill(21001003, 0, 20, -1); //polearm booster
}
diff --git a/scripts/quest/21200.js b/scripts/quest/21200.js
index c034377a62..c7e7bb101d 100644
--- a/scripts/quest/21200.js
+++ b/scripts/quest/21200.js
@@ -35,6 +35,7 @@ function start(mode, type, selection) {
qm.sendAcceptDecline("How is the training going? Wow, you've reached such a high level! That's amazing. I knew you would do just fine on Victoria Island... Oh, look at me. I'm wasting your time. I know you're busy, but you'll have to return to the island for a bit.");
else if(status == 1){
qm.sendOk("Your #b#p1201001##k in #b#m140000000##k is acting strange all of a sudden. According to the records, the Polearm acts this way when it is calling for its master. #bPerhaps it's calling for you#k. Please return to the island and check things out.");
+ } else if(status == 2){
qm.startQuest();
qm.dispose();
}
diff --git a/scripts/quest/21201.js b/scripts/quest/21201.js
index 4d8f0f8d06..f03e71968e 100644
--- a/scripts/quest/21201.js
+++ b/scripts/quest/21201.js
@@ -20,7 +20,7 @@
along with this program. If not, see .
*/
importPackage(Packages.client);
-importPackage(Packages.constants);
+importPackage(Packages.config);
var status = -1;
@@ -60,14 +60,13 @@ function end(mode, type, selection) {
if(!qm.isQuestCompleted(21201)) {
if(!qm.canHold(1142130)) {
qm.sendOk("Wow, your #bequip#k inventory is full. I need you to make at least 1 empty slot to complete this quest."); // thanks MedicOP for finding an issue here
- qm.dispose();
return;
}
qm.gainItem(1142130, true);
qm.changeJobById(2110);
- if (ServerConstants.USE_FULL_ARAN_SKILLSET) {
+ if (YamlConfig.config.server.USE_FULL_ARAN_SKILLSET) {
qm.teachSkill(21100000, 0, 20, -1); //polearm mastery
qm.teachSkill(21100002, 0, 30, -1); //final charge
qm.teachSkill(21100004, 0, 20, -1); //combo smash
@@ -78,6 +77,7 @@ function end(mode, type, selection) {
}
qm.sendNext("Your level isn't what it used to be back in your glory days, so I can't restore all of your old abilities. But the few I can restore should help you level up faster. Now hurry up and train so you can return to the old you.");
+ } else if (status == 9) {
qm.dispose();
}
}
diff --git a/scripts/quest/21202.js b/scripts/quest/21202.js
index bddef9d732..4d0591fb01 100644
--- a/scripts/quest/21202.js
+++ b/scripts/quest/21202.js
@@ -42,7 +42,7 @@ function start(mode, type, selection) {
qm.sendAcceptDecline("I'm too old to make weapons now, but.. I do have a Polearm that I made way back when. It's still in excellent shape. But I can't give it to you because that Polearm is extremely sharp, so sharp it could hurt its master. Do you still want it?");
} else if(status == 5) {
qm.sendOk("Well, if you say so.. I can't object to that. I'll tell you what. I'll give you a quick test, and if you pass it, the Giant Polearm is yours. Head over to the #bTraining Center#k and take on the #rScarred Bears#k that are there. Your job is to bring back #b30 Sign of Acceptances#k.");
- } else {
+ } else if(status == 6) {
qm.startQuest();
qm.dispose();
}
diff --git a/scripts/quest/2124.js b/scripts/quest/2124.js
index 079a61dadb..a13e40968a 100644
--- a/scripts/quest/2124.js
+++ b/scripts/quest/2124.js
@@ -23,16 +23,33 @@
Author : Ronan Lana
*/
+var status = -1;
+
function end(mode, type, selection) {
-
- if(!qm.haveItem(4031619, 1)) {
- qm.sendOk("Please bring me the box with the supplies that lies with #b#p2012019##k...");
+ if (mode == -1) {
+ qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ if(!qm.haveItem(4031619, 1)) {
+ qm.sendOk("Please bring me the box with the supplies that lies with #b#p2012019##k...");
+ }
+ else {
+ qm.gainItem(4031619, -1);
+ qm.sendOk("Oh, you brought #p2012019#'s box! Thank you.");
+ qm.forceCompleteQuest();
+ }
+ } else if (status == 1) {
+ qm.dispose();
+ }
}
- else {
- qm.gainItem(4031619, -1);
- qm.sendOk("Oh, you brought #p2012019#'s box! Thank you.");
- qm.forceCompleteQuest();
- }
-
- qm.dispose();
}
\ No newline at end of file
diff --git a/scripts/quest/2126.js b/scripts/quest/2126.js
index 079a61dadb..a13e40968a 100644
--- a/scripts/quest/2126.js
+++ b/scripts/quest/2126.js
@@ -23,16 +23,33 @@
Author : Ronan Lana
*/
+var status = -1;
+
function end(mode, type, selection) {
-
- if(!qm.haveItem(4031619, 1)) {
- qm.sendOk("Please bring me the box with the supplies that lies with #b#p2012019##k...");
+ if (mode == -1) {
+ qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ if(!qm.haveItem(4031619, 1)) {
+ qm.sendOk("Please bring me the box with the supplies that lies with #b#p2012019##k...");
+ }
+ else {
+ qm.gainItem(4031619, -1);
+ qm.sendOk("Oh, you brought #p2012019#'s box! Thank you.");
+ qm.forceCompleteQuest();
+ }
+ } else if (status == 1) {
+ qm.dispose();
+ }
}
- else {
- qm.gainItem(4031619, -1);
- qm.sendOk("Oh, you brought #p2012019#'s box! Thank you.");
- qm.forceCompleteQuest();
- }
-
- qm.dispose();
}
\ No newline at end of file
diff --git a/scripts/quest/2127.js b/scripts/quest/2127.js
index 482e0fbdaf..ced26e74c3 100644
--- a/scripts/quest/2127.js
+++ b/scripts/quest/2127.js
@@ -23,9 +23,27 @@
Author : Ronan Lana
*/
+var status = -1;
+
function end(mode, type, selection) {
- qm.sendOk("I see you're ready for the task. Now, pay heed to the details of your mission...");
- qm.forceCompleteQuest();
-
- qm.dispose();
+ if (mode == -1) {
+ qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ qm.sendOk("I see you're ready for the task. Now, pay heed to the details of your mission...");
+ qm.forceCompleteQuest();
+ } else if (status == 1) {
+ qm.dispose();
+ }
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/21300.js b/scripts/quest/21300.js
index 002ea062f9..e0c454d612 100644
--- a/scripts/quest/21300.js
+++ b/scripts/quest/21300.js
@@ -11,13 +11,14 @@ function start(mode, type, selection) {
return;
}
- if (status == 0) {
- qm.sendNext("How's the training going? Hmmm... Level 70... That's still not much, but you have really made some strides since the first time I met you fresh out of ice. Keep training, and I am sure one day you'll be able to regain your pre-battle form.");
+ if (status == 0) {
+ qm.sendNext("How's the training going? Hmmm... Level 70... That's still not much, but you have really made some strides since the first time I met you fresh out of ice. Keep training, and I am sure one day you'll be able to regain your pre-battle form.");
} else if (status == 1) {
- qm.sendAcceptDecline("But before doing that, I'll need you back in Rein for a bit. #bYour pole arm is reacting strange once again. It looks like it has something it wants to tell you. #kIt might be able to awaken your hidden powers, so please come immediately.");
- } else if (status == 2) {
- qm.sendOk("Anyway, I thought it was really something that a weapon has its own identity, but seriously... this weapon does not stop talking. It first kept on crying because I wasn't really paying attention to its needs, and... ahh, please keep this a secret from the pole arm. I don't think it's a good idea to upset the weapon any further.");
- qm.forceStartQuest();
- qm.dispose();
- }
+ qm.sendAcceptDecline("But before doing that, I'll need you back in Rein for a bit. #bYour pole arm is reacting strange once again. It looks like it has something it wants to tell you. #kIt might be able to awaken your hidden powers, so please come immediately.");
+ } else if (status == 2) {
+ qm.forceStartQuest();
+ qm.sendOk("Anyway, I thought it was really something that a weapon has its own identity, but seriously... this weapon does not stop talking. It first kept on crying because I wasn't really paying attention to its needs, and... ahh, please keep this a secret from the pole arm. I don't think it's a good idea to upset the weapon any further.");
+ } else if (status == 3) {
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/21301.js b/scripts/quest/21301.js
index f09d16ba32..e9077098d6 100644
--- a/scripts/quest/21301.js
+++ b/scripts/quest/21301.js
@@ -24,8 +24,9 @@ function end(mode, type, selection) {
} else if (status == 5) {
qm.sendNextPrev("...No hope, no dreams... Nooooo!!");
} else if (status == 6) {
- qm.sendNextPrev("#b(Maha is beginning to really get hysterical. I better leave right this minute. Maybe Lirin can do something about it.)", 2);
qm.completeQuest();
- qm.dispose();
- }
+ qm.sendNextPrev("#b(Maha is beginning to really get hysterical. I better leave right this minute. Maybe Lilin can do something about it.)", 2);
+ } else if (status == 7) {
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/21302.js b/scripts/quest/21302.js
index 35556f9587..4719a4a61f 100644
--- a/scripts/quest/21302.js
+++ b/scripts/quest/21302.js
@@ -20,7 +20,7 @@
along with this program. If not, see .
*/
importPackage(Packages.client);
-importPackage(Packages.constants);
+importPackage(Packages.config);
var status = -1;
@@ -51,7 +51,7 @@ function end(mode, type, selection) {
qm.gainItem(1142131, true);
qm.changeJobById(2111);
- if (ServerConstants.USE_FULL_ARAN_SKILLSET) {
+ if (YamlConfig.config.server.USE_FULL_ARAN_SKILLSET) {
qm.teachSkill(21110002, 0, 20, -1); //full swing
}
@@ -59,6 +59,7 @@ function end(mode, type, selection) {
}
qm.sendNext("Come on, keep training so you can get all your abilities back, and that way we can explore together once more!");
+ } else if (status == 3) {
qm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/quest/21400.js b/scripts/quest/21400.js
index 363d87b00e..2caeb2de21 100644
--- a/scripts/quest/21400.js
+++ b/scripts/quest/21400.js
@@ -14,8 +14,9 @@ function start(mode, type, selection) {
if (status == 0) {
qm.sendAcceptDecline("How is the training going? I know you're busy, but please come to #bRien#k immediately. The #bMaha#k has started to act weird again... But its even weirder now. It's different from before. It's... darker than usual.");
} else if (status == 1) {
- qm.sendOk("I have a bad feeling about this. Please come back here. I've never seen or herd Maha like this, but I can sense the suffering its going through. #bOnly you, the master of Maha, can do something about it!");
- qm.startQuest();
- qm.dispose();
- }
+ qm.startQuest();
+ qm.sendOk("I have a bad feeling about this. Please come back here. I've never seen or herd Maha like this, but I can sense the suffering its going through. #bOnly you, the master of Maha, can do something about it!");
+ } else if (status == 2) {
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/21401.js b/scripts/quest/21401.js
index dea993fd17..600aaded9e 100644
--- a/scripts/quest/21401.js
+++ b/scripts/quest/21401.js
@@ -68,7 +68,9 @@ function end(mode, type, selection) {
qm.completeQuest();
}
qm.sendNext("Your skills have been restored. Those skills have been dormant for so long that you'll have to re-train yourself, but you'll be as good as new once you complete your training.");
- }
+ } else if(status == 3) {
+ qm.dispose();
+ }
}
function spawnMob(x, y, id, map) {
diff --git a/scripts/quest/2148.js b/scripts/quest/2148.js
index e333dafc56..58c7a3512e 100644
--- a/scripts/quest/2148.js
+++ b/scripts/quest/2148.js
@@ -1,9 +1,26 @@
var status = -1;
function start(mode, type, selection) {
- qm.sendNext("Some bats seems to accompany this tree wherever it goes. Creepy...");
- qm.forceCompleteQuest();
+ if (mode == -1) {
qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ qm.sendNext("Some bats seems to accompany this tree wherever it goes. Creepy...");
+ qm.forceCompleteQuest();
+ } else if (status == 1) {
+ qm.dispose();
+ }
+ }
}
function end(mode, type, selection) {
qm.dispose();
diff --git a/scripts/quest/2149.js b/scripts/quest/2149.js
index 9088a2d9cd..3e10046fd8 100644
--- a/scripts/quest/2149.js
+++ b/scripts/quest/2149.js
@@ -1,10 +1,28 @@
var status = -1;
function start(mode, type, selection) {
- qm.sendNext("It is said that a old tree gets alive whenever something sinister disturbs this land... We need a hero that fends our village of that creature!");
- qm.forceCompleteQuest();
+ if (mode == -1) {
qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ qm.sendNext("It is said that a old tree gets alive whenever something sinister disturbs this land... We need a hero that fends our village of that creature!");
+ qm.forceCompleteQuest();
+ } else if (status == 1) {
+ qm.dispose();
+ }
+ }
}
+
function end(mode, type, selection) {
qm.dispose();
}
\ No newline at end of file
diff --git a/scripts/quest/2150.js b/scripts/quest/2150.js
index a7d30cf455..38cb1538d0 100644
--- a/scripts/quest/2150.js
+++ b/scripts/quest/2150.js
@@ -1,10 +1,28 @@
var status = -1;
function start(mode, type, selection) {
- qm.sendNext("The tree has a scarf upon its branches, I tell you.");
- qm.forceCompleteQuest();
+ if (mode == -1) {
qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ qm.sendNext("The tree has a scarf upon its branches, I tell you.");
+ qm.forceCompleteQuest();
+ } else if (status == 1) {
+ qm.dispose();
+ }
+ }
}
+
function end(mode, type, selection) {
qm.dispose();
}
\ No newline at end of file
diff --git a/scripts/quest/2151.js b/scripts/quest/2151.js
index 49d470f73e..56facb7ee7 100644
--- a/scripts/quest/2151.js
+++ b/scripts/quest/2151.js
@@ -1,10 +1,28 @@
var status = -1;
function start(mode, type, selection) {
- qm.sendNext("The tree has a strange carving that resembles a scary face.");
- qm.forceCompleteQuest();
+ if (mode == -1) {
qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ qm.sendNext("The tree has a strange carving that resembles a scary face.");
+ qm.forceCompleteQuest();
+ } else if (status == 1) {
+ qm.dispose();
+ }
+ }
}
+
function end(mode, type, selection) {
qm.dispose();
}
\ No newline at end of file
diff --git a/scripts/quest/2152.js b/scripts/quest/2152.js
index 845e647770..a8453cbc3c 100644
--- a/scripts/quest/2152.js
+++ b/scripts/quest/2152.js
@@ -1,10 +1,28 @@
var status = -1;
function start(mode, type, selection) {
- qm.sendNext("That tree... I've heard of it before, I even studied its behavior! If I recall correctly, the #bStumpy#k comes alive when the soil deems infertile by some sort of magic, and those stumps who evolves under these conditions starts to drain these suspicious magical sources instead of water and minerals for living, which makes them very threathening to people and villages nearby.");
- qm.forceCompleteQuest();
+ if (mode == -1) {
qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ qm.sendNext("That tree... I've heard of it before, I even studied its behavior! If I recall correctly, the #bStumpy#k comes alive when the soil deems infertile by some sort of magic, and those stumps who evolves under these conditions starts to drain these suspicious magical sources instead of water and minerals for living, which makes them very threathening to people and villages nearby.");
+ qm.forceCompleteQuest();
+ } else if (status == 1) {
+ qm.dispose();
+ }
+ }
}
+
function end(mode, type, selection) {
qm.dispose();
}
\ No newline at end of file
diff --git a/scripts/quest/21600.js b/scripts/quest/21600.js
index 8c59614bd3..756d8157ad 100644
--- a/scripts/quest/21600.js
+++ b/scripts/quest/21600.js
@@ -39,9 +39,9 @@ function start(mode, type, selection) {
} else if (status == 1) {
qm.sendAcceptDecline("Picked your interest, huh? Very well, first you must make your way to #bAqua#k, there is a person there who makes #rfood for wolf cubs#k. Bring one portion to me, and I shall deem you able to tame and take care of one. What do you say, will you try for it?");
} else if (status == 2) {
- qm.sendNext("Alright. The one you must meet is #bNanuke#k, she is on top of a #rsnowy whale#k, somewhere in the ocean. Good luck!");
qm.forceStartQuest();
-
+ qm.sendNext("Alright. The one you must meet is #bNanuke#k, she is on top of a #rsnowy whale#k, somewhere in the ocean. Good luck!");
+ } else if (status == 3) {
qm.dispose();
}
}
diff --git a/scripts/quest/21613.js b/scripts/quest/21613.js
index 04b7e3de2e..d7648c72cf 100644
--- a/scripts/quest/21613.js
+++ b/scripts/quest/21613.js
@@ -44,7 +44,6 @@ function start(mode, type, selection) {
var em = qm.getEventManager("Aran_3rdmount");
if (em == null) {
qm.sendOk("Sorry, but the 3rd mount quest (Wolves) is closed.");
- qm.dispose();
return;
}
else {
@@ -54,9 +53,9 @@ function start(mode, type, selection) {
} else {
qm.forceStartQuest();
}
-
- qm.dispose();
}
+ } else if (status == 4) {
+ qm.dispose();
}
}
}
diff --git a/scripts/quest/21618.js b/scripts/quest/21618.js
index fb37fd1269..2d8119b21e 100644
--- a/scripts/quest/21618.js
+++ b/scripts/quest/21618.js
@@ -71,11 +71,12 @@ function end(mode, type, selection) {
}
qm.sendNext("Step aside, behold the mighty prowess of Maha!!");
- } else {
+ } else if (status == 1) {
+ qm.forceCompleteQuest();
+
qm.gainItem(1902017, -1);
qm.gainItem(1902018, 1);
- qm.forceCompleteQuest();
qm.dispose();
}
}
diff --git a/scripts/quest/21700.js b/scripts/quest/21700.js
index 4e4b8c233b..7157a1567e 100644
--- a/scripts/quest/21700.js
+++ b/scripts/quest/21700.js
@@ -33,8 +33,9 @@ function start(mode, type, selection) {
qm.forceStartQuest();
}
} else if (status == 6) {
- qm.sendPrev("You'll find a Training Center if you exit to the #bleft#k. There, you'll meet #b#p1202006##k. I'm a bit worried because I think he may be struggling with bouts of Alzheimer's, but he spent a long time researching skills to help you. I'm sure you'll learn a thing or two from him.");
- qm.dispose();
+ qm.sendPrev("You'll find a Training Center if you exit to the #bleft#k. There, you'll meet #b#p1202006##k. I'm a bit worried because I think he may be struggling with bouts of Alzheimer's, but he spent a long time researching skills to help you. I'm sure you'll learn a thing or two from him.");
+ } else if (status == 7) {
+ qm.dispose();
}
}
diff --git a/scripts/quest/21703.js b/scripts/quest/21703.js
index d6116bd8c2..380e6e59f7 100644
--- a/scripts/quest/21703.js
+++ b/scripts/quest/21703.js
@@ -35,6 +35,7 @@ function start(mode, type, selection) {
} else if (status == 7) {
qm.forceStartQuest();
qm.sendOk("Now go and take on those monstrous #o9300343#s!");
+ } else if (status == 8) {
qm.dispose();
}
}
@@ -70,6 +71,7 @@ function end(mode, type, selection) {
qm.sendNext("(You remembered the #bCombo Ability#k skill! You were skeptical of the training at first, since the old man suffers from Alzheimer's and all, but boy, was it effective!)", 2);
} else if (status == 4) {
qm.sendPrev("Now report back to #p1201000#. I know she'll be ecstatic when she sees the progress you've made!");
+ } else if (status == 5) {
qm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/quest/21712.js b/scripts/quest/21712.js
index 28f43a1f02..8d4eb2b5a0 100644
--- a/scripts/quest/21712.js
+++ b/scripts/quest/21712.js
@@ -25,7 +25,8 @@ function start(mode, type, selection) {
qm.sendNext("I wonder what triggered this in the first place. There is no way this puppet was naturally created, which means someone planned this. I should keep an eye on the #o1210102#s.", 9);
} else if (status == 3) {
qm.sendPrev("#b(You were able to find out what caused the changes in the #o1210102#s. You should report to #p1002104# and deliver the information you've gathered.)#k", 2);
- qm.dispose();
+ } else if (status == 4) {
+ qm.dispose();
}
}
diff --git a/scripts/quest/21733.js b/scripts/quest/21733.js
index db01dd4d68..95bf1964a2 100644
--- a/scripts/quest/21733.js
+++ b/scripts/quest/21733.js
@@ -61,7 +61,7 @@ function end(mode, type, selection) {
qm.sendNext("Aran, thank you very much! Somehow the Puppeteer managed to bypass the security of Lith Harbor. He was trying to seek revenge because of the other day. Luckily, you came by. Nicely done!");
} else if(status == 1) {
qm.sendNext("I will teach you the #rPolearm Mastery#k skill, to reward your actions here. You will be able to improve your accuracy and the overall mastery of your polearm arts.");
- } else {
+ } else if(status == 2) {
qm.gainExp(8000);
qm.teachSkill(21100000, 0, 20, -1); // polearm mastery
diff --git a/scripts/quest/21734.js b/scripts/quest/21734.js
index f0880766f7..fee87ea085 100644
--- a/scripts/quest/21734.js
+++ b/scripts/quest/21734.js
@@ -63,11 +63,12 @@ function end(mode, type, selection) {
qm.sendNext("They were after the #bcrystal seal of Victoria#k. These seals are what repels the Black Mage to further taking the continents into his grasp at once. Each continent has one, Victoria's now is safe and sound.");
} else if(status == 2) {
qm.sendNext("For your bravery inputted on these series of missions, I will now reward you properly. Behold, the #rCombo Drain#k Skill: that let's you heal back a portion of damage dealt to the monsters.");
- } else {
+ } else if(status == 3) {
+ qm.forceCompleteQuest();
+
qm.gainExp(12500);
qm.teachSkill(21100005, 0, 20, -1); // combo drain
- qm.forceCompleteQuest();
qm.dispose();
}
}
diff --git a/scripts/quest/21736.js b/scripts/quest/21736.js
index fbde8021e3..fdc12d5624 100644
--- a/scripts/quest/21736.js
+++ b/scripts/quest/21736.js
@@ -42,7 +42,7 @@ function start(mode, type, selection) {
qm.sendNextPrev("It seems like something strange is happening in Orbis in Ossyria. It's a bit different from when we were dealing with the puppeteer, but my instincts tell me it has to do with the Black Wings. Please head over to Orbis.");
} else if(status == 3) {
qm.sendAcceptDecline("#bLisa the Fairy#k in Orbis should know a thing or two. Go see Lisa first, she knows someone that knows the whereabouts of the sealing stone. That person #rwill require a password from you#k, when requested use the #bThere's something strange going on in Orbis....#k keyword to talk to her. Understood?");
- } else {
+ } else if(status == 4) {
qm.forceStartQuest();
qm.dispose();
}
diff --git a/scripts/quest/21738.js b/scripts/quest/21738.js
index 22d58a79c3..c1345fbb11 100644
--- a/scripts/quest/21738.js
+++ b/scripts/quest/21738.js
@@ -34,18 +34,23 @@ function start(mode, type, selection) {
else
status--;
- if (status == 0) {
- qm.sendGetText("Hm, what do you want?");
+ if (status == 0) { // thanks ZERO傑洛 for noticing this quest shouldn't need a pw -- GMS-like string data thanks to skycombat
+ qm.sendNext("What is it? I usually don't welcome uninvited guests, but you have a mysterious aura that makes me curious about what you have to say.", 9);
} else if (status == 1) {
- var text = qm.getText();
-
- if(text != "There's something strange going on in Orbis....") {
- qm.sendNext("No business to deal with? I won't brook loitering around here, go away.");
- qm.dispose();
- } else {
- qm.sendNext("Oh, that's right. I can sense the power emanating from you, as well. So I shall entrust something to you.");
- }
- } else {
+ qm.sendNext("(You tell her about Giant Nependeath.)", 3);
+ } else if (status == 2) {
+ qm.sendNext("Giant Nependeath? It's definitely a big problem, but I don't think it's enough to really affect Orbis. Wait, where did you say the Giant Nependeath was, again?", 9);
+ } else if (status == 3) {
+ qm.sendNext("Neglected Strolling Path.", 3);
+ } else if (status == 4) {
+ qm.sendNext("...Neglected Strolling Path? If Giant Nependeath is there, someone is trying to enter Sealed Garden! But why? And more importantly, who?", 9);
+ } else if (status == 5) {
+ qm.sendNext("Sealed Garden?", 3);
+ } else if (status == 6) {
+ qm.sendAcceptDecline("I can't tell you about Sealed Garden. If you want to find out, I must first see whether you are worthy of the information. Do you mind if I look into your fate?", 9);
+ } else if (status == 7) {
+ qm.sendOk("Well, now let's look into your fate. Give me a second.");
+ } else if (status == 8) {
qm.forceStartQuest();
qm.dispose();
}
diff --git a/scripts/quest/21739.js b/scripts/quest/21739.js
index ea97e9556b..e711d50f6e 100644
--- a/scripts/quest/21739.js
+++ b/scripts/quest/21739.js
@@ -36,9 +36,9 @@ function end(mode, type, selection) {
if(status == 0) {
qm.sendNext("So, have you defeated the giant? Oh, a Black Wing agent undercover? And he GOT THE SEAL STONE OF ORBIS?! Oh, no. That's horrible! We need to develop countermeasures as soon as possible! Tell the informant on Lith about the situation.");
- } else {
- qm.gainExp(29500);
+ } else if (status == 1) {
qm.forceCompleteQuest();
+ qm.gainExp(29500);
qm.dispose();
}
}
diff --git a/scripts/quest/21740.js b/scripts/quest/21740.js
index 767e00f67a..c4a4b8d64a 100644
--- a/scripts/quest/21740.js
+++ b/scripts/quest/21740.js
@@ -61,10 +61,9 @@ function end(mode, type, selection) {
qm.sendNext("Oh, hi #h0#! You won't believe what I just uncovered. It's one of your lost skills... What, the seal of Orbis got stolen by the Black Wings? Oh my...");
} else if(status == 1) {
qm.sendNext("For now, let me teach you the #bCombo Smash#k, with it you will be able to deal massive amount of damage to many monsters at once. We will need to use it if we want to stand a chance against the Black Wings now, so don't forget it!");
- } else {
- qm.teachSkill(21100004, 0, 20, -1); // combo smash
-
+ } else if(status == 2) {
qm.forceCompleteQuest();
+ qm.teachSkill(21100004, 0, 20, -1); // combo smash
qm.dispose();
}
}
diff --git a/scripts/quest/21741.js b/scripts/quest/21741.js
index 25285e520d..b2ed795614 100644
--- a/scripts/quest/21741.js
+++ b/scripts/quest/21741.js
@@ -38,9 +38,9 @@ function start(mode, type, selection) {
qm.sendNext("Have you been advancing your levels? I found an interesting piece of information about the Black Wings. This time, you'll have to travel quite a bit. Do you know a town called #bMu Lung#k? You'll have to head there.");
} else if (status == 1) {
qm.sendAcceptDecline("Apparently, #bMr. Do#k in Mu Lung somehow met with the Black Wings. I don't know the details. Please go and find out why the Black Wings contacted Mr. Do and what exactly happened between them.");
- } else {
+ } else if (status == 2) {
qm.sendNext("Mr. Do is known to be curt, so you are going to have to remain patient while talking to him. Talk to him with the #bI heard you met the Shadow Knight of the Black Wings#k keyword.");
-
+ } else if (status == 3) {
qm.forceStartQuest();
qm.dispose();
}
diff --git a/scripts/quest/21749.js b/scripts/quest/21749.js
index bb1af79100..9e4d69dfaf 100644
--- a/scripts/quest/21749.js
+++ b/scripts/quest/21749.js
@@ -38,9 +38,9 @@ function start(mode, type, selection) {
qm.sendNext("So we have lost #btwo seal stones#k so far, from the neighboring areas of #rOrbis#k and #rMu Lung#k... Things are starting to get out of control, it seems.");
} else if (status == 1) {
qm.sendNext("Aran, your next objective will be to use the #btime gate to Ellin#k again. This time you will be retrieving the long lost #rSeal Stone of Ellin Forest#k. According to informations our network have gathered, #b#p2131002##k of that time have a clue about that gem, #rfind her#k. Please be successful on this task, our world is relying on you more than ever!");
- } else {
- qm.gainExp(500);
+ } else if (status == 2) {
qm.forceCompleteQuest();
+ qm.gainExp(500);
qm.dispose();
}
}
diff --git a/scripts/quest/21750.js b/scripts/quest/21750.js
index 5ea00ec93b..04961a9a0c 100644
--- a/scripts/quest/21750.js
+++ b/scripts/quest/21750.js
@@ -36,7 +36,7 @@ function end(mode, type, selection) {
if (status == 0) {
qm.sendNext("Aran, you're finally back!!! How you've been doing? Where did you go for so long? We have so much to catch up...");
- } else {
+ } else if (status == 1) {
qm.forceCompleteQuest();
qm.dispose();
}
diff --git a/scripts/quest/21753.js b/scripts/quest/21753.js
index 6fb029d8d0..6812c3c79f 100644
--- a/scripts/quest/21753.js
+++ b/scripts/quest/21753.js
@@ -38,8 +38,8 @@ function start(mode, type, selection) {
qm.sendNext("Aran, I've discovered some disturbing news... You said you've come from the eastern forest section, right? We traced and studied the magic being used to support the portal over there. It turns out that's of a #rtemporal#k-type. The garments you're using... They were never seen around before. That must mean, #ryou must have come from the future#k.");
} else if (status == 1) {
qm.sendNext("Now about the problem: the Seal Stone that seems to have been missing in your timeline... It is a powerful artifact, that prevents the army of the #rBlack Mage#k from laying siege on our world. If that stone goes away, nothing more can prevent him. As this is a matter of great importance, find the #rself of mine#k from the future. I'm actually a #rfairy#k with a great life expectancy, I must be alive even on your timeline. Got it, #rfetch the me from the future#k!");
+ } else if (status == 2) {
qm.forceStartQuest();
-
qm.dispose();
}
}
diff --git a/scripts/quest/21757.js b/scripts/quest/21757.js
index 8e6c249739..4b37da7621 100644
--- a/scripts/quest/21757.js
+++ b/scripts/quest/21757.js
@@ -36,11 +36,10 @@ function end(mode, type, selection) {
if (status == 0) {
qm.sendNext("Oh, a letter for the #rempress#k? From the #bheroes#k?!");
- } else {
+ } else if (status == 1) {
+ qm.forceCompleteQuest();
qm.gainExp(1000);
qm.gainItem(4032330, -1);
- qm.forceCompleteQuest();
-
qm.dispose();
}
}
diff --git a/scripts/quest/21766.js b/scripts/quest/21766.js
index 8c55c5323d..dbcbb141bc 100644
--- a/scripts/quest/21766.js
+++ b/scripts/quest/21766.js
@@ -10,14 +10,14 @@ function start(mode, type, selection) {
qm.sendNext("I have a feeling there is a secret behind that wooden box. Could you stealthily look into the wooden box next to #p20000#?");
} else if (status == 3) {
qm.sendNext("You know where #p20000# is, right? He's to the right. Just keep going until you see where Vikin is, then head down past the hanging shark and octopus, and you''ll see John. The box should be right next to him.");
- } else {
+ } else if (status == 4) {
qm.forceStartQuest();
qm.dispose();
}
}
function end(mode, type, selection) {
- qm.gainExp(200);
qm.forceCompleteQuest();
+ qm.gainExp(200);
qm.dispose();
}
\ No newline at end of file
diff --git a/scripts/quest/21767.js b/scripts/quest/21767.js
index 5d8d774512..de63158d03 100644
--- a/scripts/quest/21767.js
+++ b/scripts/quest/21767.js
@@ -1,4 +1,5 @@
var status = -1;
+var canStart;
function start(mode, type, selection) {
status++;
@@ -8,12 +9,20 @@ function start(mode, type, selection) {
qm.dispose();
return;
}
+
+ canStart = qm.canHold(4032423, 1);
+ if(!canStart) {
+ qm.sendNext("Please open a slot in your ETC inventory first.");
+ return;
+ }
qm.sendNext("#bHm, there's a medicinal substance in the box. What could this be? You better take this to John and ask him what it is.#k");
- } else {
- qm.gainItem(4032423,1);
-
- qm.forceStartQuest();
+ } else if (status == 1) {
+ if(canStart) {
+ qm.gainItem(4032423,1);
+ qm.forceStartQuest();
+ }
+
qm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/quest/2186.js b/scripts/quest/2186.js
index eaaa986720..9595e7b98e 100644
--- a/scripts/quest/2186.js
+++ b/scripts/quest/2186.js
@@ -3,38 +3,56 @@
Quest: Abel Glasses Quest
*/
-function end(mode, type, selection){
- if(!qm.isQuestCompleted(2186)) {
- if(qm.haveItem(4031853)){
- if(qm.canHold(2030019)) {
- qm.gainItem(4031853, -1);
- qm.gainExp(1700);
- qm.gainItem(2030019, 10);
+var status = -1; // thanks IxianMace for noticing missing status declaration
- qm.sendOk("Geez, you found my glasses! Thank you, thank you so much. Now I'm able to see everything again!");
- qm.forceCompleteQuest();
- }
- else {
- qm.sendOk("I need you to have an USE slot available to reward you properly!");
- }
- }else if(qm.haveItem(4031854) || qm.haveItem(4031855)){ //When I figure out how to make a completance with just a pickup xD
- if(qm.canHold(2030019)) {
- if(qm.haveItem(4031854))
- qm.gainItem(4031854, -1);
- else
- qm.gainItem(4031855, -1);
-
- qm.gainExp(1000);
- qm.gainItem(2030019, 5);
-
- qm.sendOk("Hm, those aren't my glasses... But alas, I'll take it anyway. Thanks.");
- qm.forceCompleteQuest();
- }
- else {
- qm.sendOk("I need you to have an USE slot available to reward you properly!");
+function end(mode, type, selection){
+ if (mode == -1) {
+ qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ if(!qm.isQuestCompleted(2186)) {
+ if(qm.haveItem(4031853)){
+ if(qm.canHold(2030019)) {
+ qm.gainItem(4031853, -1);
+ qm.gainExp(1700);
+ qm.gainItem(2030019, 10);
+
+ qm.sendOk("Geez, you found my glasses! Thank you, thank you so much. Now I'm able to see everything again!");
+ qm.forceCompleteQuest();
+ }
+ else {
+ qm.sendOk("I need you to have an USE slot available to reward you properly!");
+ }
+ }else if(qm.haveItem(4031854) || qm.haveItem(4031855)){ //When I figure out how to make a completance with just a pickup xD
+ if(qm.canHold(2030019)) {
+ if(qm.haveItem(4031854))
+ qm.gainItem(4031854, -1);
+ else
+ qm.gainItem(4031855, -1);
+
+ qm.gainExp(1000);
+ qm.gainItem(2030019, 5);
+
+ qm.sendOk("Hm, those aren't my glasses... But alas, I'll take it anyway. Thanks.");
+ qm.forceCompleteQuest();
+ }
+ else {
+ qm.sendOk("I need you to have an USE slot available to reward you properly!");
+ }
+ }
}
+ } else if (status == 1) {
+ qm.dispose();
}
}
-
- qm.dispose();
}
\ No newline at end of file
diff --git a/scripts/quest/2197.js b/scripts/quest/2197.js
index 1f924c8e93..d2fa18169c 100644
--- a/scripts/quest/2197.js
+++ b/scripts/quest/2197.js
@@ -1,12 +1,46 @@
var status = -1;
function start(mode, type, selection) {
- qm.sendNext("Oh, you already have monster book. Good luck on your journey~!");
- qm.forceCompleteQuest();
- qm.dispose();
+ if (mode == -1) {
+ qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ qm.sendNext("Oh, you already have monster book. Good luck on your journey~!");
+ } else if (status == 1) {
+ qm.forceCompleteQuest();
+ qm.dispose();
+ }
+ }
}
function end(mode, type, selection) {
- qm.sendNext("Oh, you already have monster book. Good luck on your journey~!");
- qm.forceCompleteQuest();
- qm.dispose();
+ if (mode == -1) {
+ qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ qm.sendNext("Oh, you already have monster book. Good luck on your journey~!");
+ } else if (status == 1) {
+ qm.forceCompleteQuest();
+ qm.dispose();
+ }
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/22001.js b/scripts/quest/22001.js
index d869634657..98ce206ec0 100644
--- a/scripts/quest/22001.js
+++ b/scripts/quest/22001.js
@@ -25,7 +25,8 @@ function start(mode, type, selection) {
qm.sendNext("Hurry up and head #bleft#k to feed #b#p1013102##k. He's been barking to be fed all morning.");
}
} else if (status == 4) {
- qm.sendPrev("Feed #p1013102# and come back to see me.");
- qm.dispose();
- }
+ qm.sendNextPrev("Feed #p1013102# and come back to see me.");
+ } else if (status == 5) {
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/22002.js b/scripts/quest/22002.js
index 0ab83b73d6..d759a4ec9b 100644
--- a/scripts/quest/22002.js
+++ b/scripts/quest/22002.js
@@ -40,10 +40,10 @@ function end(mode, type, selection) {
if (status == 0) {
qm.sendNext("Did you eat your breakfast, Evan? Then, will you do me a favor? \r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0# \r\n#i1003028# 1 #t1003028# \r\n#i2022621# 5 #t2022621#s \r\n#i2022622# 5 #t2022622# \r\n#fUI/UIWindow.img/QuestIcon/8/0# 60 exp");
} else if (status == 1) {
- qm.gainItem(1003028, 1, true);
+ qm.forceCompleteQuest();
+ qm.gainItem(1003028, 1, true);
qm.gainItem(2022621, 5, true);
qm.gainItem(2022622, 5, true);
- qm.forceCompleteQuest();
qm.gainExp(60);
qm.sendImage("UI/tutorial/evan/4/0");
qm.dispose();
diff --git a/scripts/quest/22007.js b/scripts/quest/22007.js
index 9ecdb28ade..19519e5236 100644
--- a/scripts/quest/22007.js
+++ b/scripts/quest/22007.js
@@ -22,6 +22,7 @@ function end(mode, type, selection) {
qm.gainExp(360);
qm.sendImage("UI/tutorial/evan/9/0");
}
- qm.dispose();
- }
+ } else if (status == 3) {
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/22008.js b/scripts/quest/22008.js
index b59b031a8a..cf5431dadd 100644
--- a/scripts/quest/22008.js
+++ b/scripts/quest/22008.js
@@ -69,6 +69,7 @@ function end(mode, type, selection) {
qm.sendNextPrev("#bThis is a weapon that Magicians use. It's a Wand#k. You probably won't really need it, but it'll make you look important if you carry it around. Hahahahaha.");
} else if (status == 13) {
qm.sendPrev("Anyway, the Foxes have increased, right? How weird is that? Why are they growing day by day? We should really look into it and get to the bottom of this.");
- qm.dispose();
- }
+ } else if (status == 14) {
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/2214.js b/scripts/quest/2214.js
index e94aa34c8e..dd8800681c 100644
--- a/scripts/quest/2214.js
+++ b/scripts/quest/2214.js
@@ -26,6 +26,7 @@
*/
var status = -1;
+var canComplete;
function end(mode, type, selection) {
if (mode == -1) {
@@ -45,20 +46,24 @@ function end(mode, type, selection) {
var hourDay = qm.getHourOfDay();
if(!(hourDay >= 17 && hourDay < 20)) {
qm.sendNext("(Hmm, I'm searching the trash can but can't find the #t4031894# JM was talking about, maybe it's not time yet...)");
- qm.dispose();
+ canComplete = false;
return;
}
if(!qm.canHold(4031894, 1)) {
qm.sendNext("(Eh, I can't hold the #t4031894# right now, I need an ETC slot available.)");
- qm.dispose();
+ canComplete = false;
return;
}
+ canComplete = true;
qm.sendNext("(Ah, there is a crumbled note here... Hm, it contains details about some scheme that is about to happen, that must be what #r#p1052002##k was talking about.)");
- qm.gainItem(4031894, 1);
- qm.gainExp(20000);
- qm.forceCompleteQuest();
+ } else if (status == 1) {
+ if (canComplete) {
+ qm.forceCompleteQuest();
+ qm.gainItem(4031894, 1);
+ qm.gainExp(20000);
+ }
qm.dispose();
}
diff --git a/scripts/quest/2215.js b/scripts/quest/2215.js
index 457c38fa8a..0c3b24bc7b 100644
--- a/scripts/quest/2215.js
+++ b/scripts/quest/2215.js
@@ -26,6 +26,7 @@
*/
var status = -1;
+var canComplete;
function end(mode, type, selection) {
if (mode == -1) {
@@ -45,26 +46,30 @@ function end(mode, type, selection) {
var hourDay = qm.getHourOfDay();
if(!(hourDay >= 17 && hourDay < 20)) {
qm.sendNext("(Hmm, I'm searching the trash can but can't find the #t4031894# JM was talking about, maybe it's not time yet...)");
- qm.dispose();
+ canComplete = false;
return;
}
if(qm.getMeso() < 2000) {
qm.sendNext("(Oh, I don't have the combined fee amount yet.)");
- qm.dispose();
+ canComplete = false;
return;
}
if(!qm.canHold(4031894, 1)) {
qm.sendNext("(Eh, I can't hold the #t4031894# right now, I need an ETC slot available.)");
- qm.dispose();
+ canComplete = false;
return;
}
+ canComplete = true;
qm.sendNext("(Alright, now I will deposit the fee there and get the paper... That's it, yea, that's done.)");
- qm.gainItem(4031894, 1);
- qm.gainMeso(-2000);
- qm.forceCompleteQuest();
+ } else if (status == 1) {
+ if (canComplete) {
+ qm.gainMeso(-2000);
+ qm.forceCompleteQuest();
+ qm.gainItem(4031894, 1);
+ }
qm.dispose();
}
diff --git a/scripts/quest/2216.js b/scripts/quest/2216.js
index d3df6a730e..0364562ca1 100644
--- a/scripts/quest/2216.js
+++ b/scripts/quest/2216.js
@@ -36,8 +36,9 @@ function start(mode, type, selection) {
if (status == 0) {
qm.sendNext("I've just gathered an interesting information, #rDyle looks just like regular Ligators#k, but bigger.");
- qm.gainExp(7000);
+ } else if (status == 1) {
qm.forceCompleteQuest();
+ qm.gainExp(7000);
if(isAllSubquestsDone() && qm.haveItem(4031894)) {
qm.gainItem(4031894, -1);
diff --git a/scripts/quest/2217.js b/scripts/quest/2217.js
index 30c62de83d..396f4dd97a 100644
--- a/scripts/quest/2217.js
+++ b/scripts/quest/2217.js
@@ -36,8 +36,9 @@ function start(mode, type, selection) {
if (status == 0) {
qm.sendNext("Hey, did you notice already, it looks like some awful stench is emanating from the sewers... Ewww");
- qm.gainExp(7000);
+ } else if (status == 1) {
qm.forceCompleteQuest();
+ qm.gainExp(7000);
if(isAllSubquestsDone() && qm.haveItem(4031894)) {
qm.gainItem(4031894, -1);
diff --git a/scripts/quest/2218.js b/scripts/quest/2218.js
index 54cd1c9fcc..9b0f14bfb0 100644
--- a/scripts/quest/2218.js
+++ b/scripts/quest/2218.js
@@ -36,8 +36,9 @@ function start(mode, type, selection) {
if (status == 0) {
qm.sendNext("Hey did you see how strange #rLakelis#k has been acting these days? We should see what's going on aabout her, her actions have been so weird lately...");
- qm.gainExp(7000);
+ } else if (status == 1) {
qm.forceCompleteQuest();
+ qm.gainExp(7000);
if(isAllSubquestsDone() && qm.haveItem(4031894)) {
qm.gainItem(4031894, -1);
diff --git a/scripts/quest/2219.js b/scripts/quest/2219.js
index 6bfc5de0f5..833f9131bb 100644
--- a/scripts/quest/2219.js
+++ b/scripts/quest/2219.js
@@ -36,8 +36,9 @@ function start(mode, type, selection) {
if (status == 0) {
qm.sendNext("Did you know, they say someone from the sewers has been trying to #rdevelop a magic powder that let's one to grow#k, isn't that nice?");
- qm.gainExp(7000);
+ } else if (status == 1) {
qm.forceCompleteQuest();
+ qm.gainExp(7000);
if(isAllSubquestsDone() && qm.haveItem(4031894)) {
qm.gainItem(4031894, -1);
diff --git a/scripts/quest/2228.js b/scripts/quest/2228.js
index ecc2a60265..0d7ab84a4b 100644
--- a/scripts/quest/2228.js
+++ b/scripts/quest/2228.js
@@ -36,10 +36,9 @@ function start(mode, type, selection) {
if (status == 0) {
qm.sendNext("Thank you for defeating #rFaust#k. That will finally settle my spirit to rest.");
- } else {
- qm.gainFame(8);
-
+ } else if (status == 1) {
qm.forceCompleteQuest();
+ qm.gainFame(8);
qm.dispose();
}
}
diff --git a/scripts/quest/2230.js b/scripts/quest/2230.js
index 7aa7e5d5f9..2da466673c 100644
--- a/scripts/quest/2230.js
+++ b/scripts/quest/2230.js
@@ -28,6 +28,7 @@
*/
var status = -1;
+var canComplete;
function start(mode, type, selection) {
if (mode == -1) {
@@ -45,6 +46,8 @@ function start(mode, type, selection) {
qm.sendOk("Put your hand in your pocket. I think your friend has already found you.\r\nThe purple bellflower that soaks in the sun in between the skyscraping trees...Follow the path to the unknown that leads you to the bellflower. I will wait for you here.");
qm.forceStartQuest();
qm.gainItem(4032086, 1); // Mysterious Egg * 1
+ } else if (status == 3) {
+ qm.dispose();
}
}
}
@@ -76,11 +79,20 @@ function end(mode, type, selection) {
} else if (status == 5) {
qm.sendYesNo("Now do you understand? Every action comes with consequences, and pets are no exception. The egg of the snail shall hatch soon.");
} else if (status == 6) {
- qm.gainItem(5000054, 1, false, true, 5 * 60 * 60 * 1000); // rune snail (5hrs), missing expiration time detected thanks to cljnilsson
+ canComplete = qm.canHold(5000054, 1);
+ if (!canComplete) {
+ qm.sendNext("Please free a slot in your CASH inventory before you try to receive the pet...");
+ return;
+ }
- qm.gainItem(4032086, -1); // Mysterious Egg * -1
- qm.forceCompleteQuest();
qm.sendNext("This snail will only be alive for #b5 hours#k. Shower it with love. Your love will be reciprocated in the end.");
+ } else if (status == 7) {
+ if (canComplete) {
+ qm.gainItem(4032086, -1); // Mysterious Egg * -1
+ qm.forceCompleteQuest();
+ qm.gainItem(5000054, 1, false, true, 5 * 60 * 60 * 1000); // rune snail (5hrs), missing expiration time detected thanks to cljnilsson
+ }
+
qm.dispose();
}
}
diff --git a/scripts/quest/2232.js b/scripts/quest/2232.js
new file mode 100644
index 0000000000..0a674f2c08
--- /dev/null
+++ b/scripts/quest/2232.js
@@ -0,0 +1,25 @@
+var status = -1;
+
+function start(mode, type, selection) {
+ var familyEntry = qm.getPlayer().getFamilyEntry();
+ if (familyEntry != null && familyEntry.getJuniorCount() > 0) {
+ qm.forceCompleteQuest();
+ qm.gainExp(3000);
+ qm.sendNext("Good job!");
+ } else {
+ qm.sendNext("I see that you have not successfully find a Junior, ok?");
+ }
+ qm.dispose();
+}
+
+function end(mode, type, selection) {
+ var familyEntry = qm.getPlayer().getFamilyEntry();
+ if (familyEntry != null && familyEntry.getJuniorCount() > 0) { // script found thanks to kvmba
+ qm.forceCompleteQuest();
+ qm.gainExp(3000);
+ qm.sendNext("Good job!");
+ } else {
+ qm.sendNext("I see that you have not successfully find a Junior, ok?");
+ }
+ qm.dispose();
+}
\ No newline at end of file
diff --git a/scripts/quest/2236.js b/scripts/quest/2236.js
deleted file mode 100644
index e460077dd0..0000000000
--- a/scripts/quest/2236.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/* ===========================================================
- Ronan Lana
- NPC Name: Chrishrama
- Description: Quest - How to Shoo Away the Evil
-=============================================================
-Version 1.0 - Script Done.(20/3/2017)
-=============================================================
-*/
-
-var status = -1;
-
-function start(mode, type, selection) {
- status++;
- if (mode != 1) {
- if(type == 1 && mode == 0)
- status -= 2;
- else{
- qm.sendOk("If we don't place these Charms on the Shaman Rocks, evil might awaken...");
- qm.dispose();
- return;
- }
- }
- if (status == 0)
- qm.sendAcceptDecline("I can feel the forces of evil. They're deep inside the dungeon and they're very, very powerful. If we want to drive the evil away from this place, we must place Charms on the Shaman Rocks inside the dungeon. Will you do that for me?");
- if (status == 1){
- if(qm.haveItem(4032263)) qm.gainItem(4032263, -6);
- qm.gainItem(4032263, 6);
-
- qm.sendOk("Take these Charms and place them on the Shaman Rocks in the dungeon. I'm giving you a total of 6 Charms.");
- qm.forceStartQuest();
- qm.dispose();
- }
-}
-
-function end(mode, type, selection) {
- status++;
-
- if(status == 0) {
- if(qm.getQuestProgress(2236) == 63) { //111111
- qm.sendOk("I, too, felt it. The force of the Shaman Rocks began to overpower the forces of evil. I think Sleepywood is safe now. The evil has been eliminated.");
- qm.gainExp(60000);
- qm.forceCompleteQuest();
- }
- else {
- if(qm.haveItem(4032263)) qm.gainItem(4032263, -6);
- qm.gainItem(4032263, 6);
-
- qm.sendOk("Oh, not good. I still sense bad omens coming from the interior. Here, take these charms and seal them at the Shaman Rocks. We are counting on you.");
- qm.updateQuest(2236, 0);
- }
-
- qm.dispose();
- }
-}
\ No newline at end of file
diff --git a/scripts/quest/2245.js b/scripts/quest/2245.js
index 1eba8bc811..5ea4177c39 100644
--- a/scripts/quest/2245.js
+++ b/scripts/quest/2245.js
@@ -38,7 +38,6 @@ function start(mode, type, selection) {
em = qm.getEventManager("BalrogQuest");
if (em == null) {
qm.sendOk("Sorry, but the BalrogQuest is closed.");
- qm.dispose();
return;
}
@@ -47,8 +46,9 @@ function start(mode, type, selection) {
qm.sendOk("There is currently someone in this map, come back later.");
} else {
qm.forceStartQuest();
+ qm.dispose();
}
-
+ } else if (status == 1) {
qm.dispose();
}
}
diff --git a/scripts/quest/22501.js b/scripts/quest/22501.js
index 129d3d1e9c..e329b8d49c 100644
--- a/scripts/quest/22501.js
+++ b/scripts/quest/22501.js
@@ -20,11 +20,11 @@ function start(mode, type, selection) {
} else if (status == 4) {
if (mode == 0) {
qm.sendNext("*gasp* How can you refuse to feed your Dragon? This is child abuse! ");
- qm.dispose();
} else {
qm.forceStartQuest();
qm.sendOk("#b#b(#p1013000# the baby Dragon appears to be extremely hungry. You must feed him. Maybe your Dad can give you advice on what dragons eat.)");
- qm.dispose();
}
- }
+ } else if (status == 5) {
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/22502.js b/scripts/quest/22502.js
index af95553b7a..6abcf2a1c6 100644
--- a/scripts/quest/22502.js
+++ b/scripts/quest/22502.js
@@ -18,6 +18,6 @@ function start(mode, type, selection) {
qm.forceStartQuest();
qm.sendImage("UI/tutorial/evan/12/0");
}
- qm.dispose();
- }
-}
\ No newline at end of file
+ qm.dispose();
+ }
+}
diff --git a/scripts/quest/22503.js b/scripts/quest/22503.js
index 851808fa56..b1f931d2ba 100644
--- a/scripts/quest/22503.js
+++ b/scripts/quest/22503.js
@@ -22,6 +22,7 @@ function start(mode, type, selection) {
qm.forceStartQuest();
qm.sendNext("#b#b(Try giving #p1013000# some #t4032453#. You have to hunt a few #o1210100#s at the farm. Ten should be plenty...)");
}
- qm.dispose();
- }
+ } else if (status == 4) {
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/22504.js b/scripts/quest/22504.js
index 118850099d..a77be2beb5 100644
--- a/scripts/quest/22504.js
+++ b/scripts/quest/22504.js
@@ -22,5 +22,7 @@ function start(mode, type, selection) {
qm.forceStartQuest();
qm.sendNext("#b#b(You already asked Dad once, but you don't have any better ideas. Time to ask him again!)");
}
- }
+ } else if (status == 4) {
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/22507.js b/scripts/quest/22507.js
index 8e3319f496..bbd890fb0e 100644
--- a/scripts/quest/22507.js
+++ b/scripts/quest/22507.js
@@ -53,6 +53,7 @@ function start(mode, type, selection) {
qm.sendNextPrev("#b(You're a bit confused, but you are now traveling with Mir the Dragon. Perhaps you'll go on an adventure together, like he said.)", 2);
} else if (status == 17) {
qm.sendPrev("#b#b(You still have an errand to run. Your dad needs to talk to you, so go and see him now.)");
- qm.dispose();
- }
+ } else if (status == 18) {
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/2251.js b/scripts/quest/2251.js
index 31b5cbf4f0..3de79f99d4 100644
--- a/scripts/quest/2251.js
+++ b/scripts/quest/2251.js
@@ -1,21 +1,38 @@
-/*
+-/*
Author: Kevin
Quest: Zombie Mushroom Signal 3 (2251)
NPC: The Rememberer (1061011)
Item: Recording Charm (4032399)
*/
+var status = -1; // script restored thanks to kvmba
+
function end(mode, type, selection) {
-
- if(!qm.haveItem(4032399, 20)) {
- qm.sendOk("Please bring me 20 #b#t4032399##k... #i4032399#");
+ if (mode == -1) {
+ qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ if(!qm.haveItem(4032399, 20)) {
+ qm.sendOk("Please bring me 20 #b#t4032399##k... #i4032399#");
+ }
+ else {
+ qm.gainItem(4032399, -20);
+ qm.sendOk("Oh, you brought 20 #b#t4032399##k! Thank you.");
+ qm.gainExp(8000);
+ qm.forceCompleteQuest();
+ }
+ } else if (status == 1) {
+ qm.dispose();
+ }
}
- else {
- qm.gainItem(4032399, -20);
- qm.sendOk("Oh, you brought 20 #b#t4032399##k! Thank you.");
- qm.gainExp(8000);
- qm.forceCompleteQuest();
- }
-
- qm.dispose();
}
\ No newline at end of file
diff --git a/scripts/quest/2257.js b/scripts/quest/2257.js
index 3b43326858..e09bef4312 100644
--- a/scripts/quest/2257.js
+++ b/scripts/quest/2257.js
@@ -36,7 +36,7 @@ function end(mode, type, selection) {
if (status == 0) {
qm.sendNext("Hey there, do you want a ride to #r#m261000000##k? Oh a request from #b#p2101013##k?");
- } else {
+ } else if (status == 1) {
qm.forceCompleteQuest();
qm.dispose();
}
diff --git a/scripts/quest/2258.js b/scripts/quest/2258.js
index e65390eb4d..9ab0deb1ae 100644
--- a/scripts/quest/2258.js
+++ b/scripts/quest/2258.js
@@ -38,7 +38,7 @@ function start(mode, type, selection) {
qm.sendAcceptDecline("Meerkats spreads rumors like wildfire... By blackmailing me and my cab service, they are taking costumers away from me day after day... Hey, tell no one about this, if you clean some #rMeerkats#k from my way, I'll tell you an info about the #rMushroom Castle#k. What do you say?");
} else if (status == 1) {
qm.sendNext("Great, they you have #r5 minutes#k to kill #b40 Meerkats#k within this time. Good luck!");
- } else {
+ } else if (status == 2) {
qm.forceStartQuest();
qm.dispose();
}
@@ -61,7 +61,7 @@ function end(mode, type, selection) {
if (status == 0) {
qm.sendNext("You did it! ... Hey, #rMeerkats#k around here may listen to our conversation. I'm not going to talk about THAT right now.");
- } else {
+ } else if (status == 1) {
qm.forceCompleteQuest();
qm.dispose();
}
diff --git a/scripts/quest/2259.js b/scripts/quest/2259.js
index 11c961a070..7fe8f2820a 100644
--- a/scripts/quest/2259.js
+++ b/scripts/quest/2259.js
@@ -60,13 +60,12 @@ function end(mode, type, selection) {
if (status == 0) {
if(qm.getMapId() == 260020000) {
qm.sendNext("Eh you're still here? To reach #b#m260020700##k, follow #reast#k from here until you reach #rMagatia#k, I will be there. Now go.");
- qm.dispose();
return;
}
qm.sendNext("Oh there you are. There're no Meerkat's nearby, so there probably is no eavesdropping around here. Very well, you must be fit to go to the #rMushroom Castle#k. Talk to me once you've got #blevel 30#k.");
- } else {
qm.forceCompleteQuest();
+ } else if (status == 1) {
qm.dispose();
}
}
diff --git a/scripts/quest/2260.js b/scripts/quest/2260.js
index 2eb8d976ca..852411aaaa 100644
--- a/scripts/quest/2260.js
+++ b/scripts/quest/2260.js
@@ -18,7 +18,7 @@
along with this program. If not, see .
*/
-importPackage(Packages.constants);
+importPackage(Packages.constants.game);
var status = -1;
@@ -38,7 +38,7 @@ function start(mode, type, selection) {
if (status == 0) {
qm.sendNext("Once you've got #b2nd job advancement#k, I'll tell you about the #bMushroom Castle#k.");
- } else {
+ } else if (status == 1) {
qm.forceStartQuest();
qm.dispose();
}
@@ -67,8 +67,8 @@ function end(mode, type, selection) {
}
qm.sendNext("Okay you seem ready to go to the #bMushroom Castle#k. In #rHenesys#k, climb at the tree fort at #bwest#k then enter a portal over there. On the other area, #rgo west#k. From there, a portal will be readily available to access the #bMushroom Castle#k area.");
- } else {
qm.forceCompleteQuest();
+ } else if (status == 1) {
qm.dispose();
}
}
diff --git a/scripts/quest/2293.js b/scripts/quest/2293.js
index c19bb7064c..dd9cefc5d0 100644
--- a/scripts/quest/2293.js
+++ b/scripts/quest/2293.js
@@ -37,9 +37,12 @@ function start(mode, type, selection) {
if(status == 0)
{
qm.sendNext("Do you remember the last song that the Spirit of Rock played? I can think of a few songs that he may be imitating, so listen carefully and tell me which song it is. #bYou only get one chance,#k so please choose wisely.");
+ qm.forceStartQuest();
+ }
+ else if(status == 1)
+ {
+ qm.dispose();
}
- qm.forceStartQuest();
- qm.dispose();
}
function end(mode, type, selection)
@@ -92,19 +95,24 @@ function end(mode, type, selection)
if(selection == 1)
{
qm.sendOk("Obviously you don't enjoy music.");
- qm.dispose();
}
else if(selection == 2)
{
qm.sendOk("I suppose you could get #b#eone#n#k more chance.");
- qm.dispose();
}
else if(selection == 3)
{
qm.sendOk("So that was the song he was playing... Well, it wasn't my song after all, but I'm glad I can know that now with certainty. Thank you so much.");
- qm.gainExp(32500);
qm.forceCompleteQuest();
+ qm.gainExp(32500);
+ }
+ else
+ {
qm.dispose();
}
}
+ else if(status == 3)
+ {
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/2312.js b/scripts/quest/2312.js
index 12de61c803..2111510cd7 100644
--- a/scripts/quest/2312.js
+++ b/scripts/quest/2312.js
@@ -25,11 +25,12 @@ function start(mode, type, selection) {
}
if (status == 0)
qm.sendAcceptDecline("We need your help, noble explorer. Our kingdom is currently facing a big threat, and we are in desperate need of a courageous explorer willing to fight for us, and that's how you ended up here. Please understand, though, that since we need place our faith in you, we'll have to test your skills first before we can stand firmly behind you. Will it be okay for you to do this for us?");
- if (status == 1){
+ else if (status == 1){
qm.forceStartQuest();
qm.sendOk("Keep moving forward, and you'll see #bRenegade Spores#k, the Spores that turned their backs on the Kingdom of Mushroom. We'd appreciate it if you can teach them a lesson or two, and bring back #b50 Mutated Spores#k in return.");
- qm.dispose();
- }
+ } else if (status == 2){
+ qm.dispose();
+ }
}
function end(mode, type, selection) {
@@ -44,12 +45,13 @@ function end(mode, type, selection) {
}
if (status == 0)
qm.sendOk("Did you teach those Renegade Spores a lesson?");
- if (status == 1){
+ else if (status == 1){
qm.forceCompleteQuest();
qm.gainExp(11500);
qm.gainItem(4000499, -50);
qm.sendOk("That was amazing. I apologize for doubting your abilities. Please save our Kingdom of Mushroom from this crisis!");
- qm.dispose();
- }
+ } else if (status == 2){
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/2313.js b/scripts/quest/2313.js
index 8beac840f9..1deddac73e 100644
--- a/scripts/quest/2313.js
+++ b/scripts/quest/2313.js
@@ -25,11 +25,12 @@ function start(mode, type, selection) {
}
if (status == 0)
qm.sendAcceptDecline("I have told our #bMinister of Home Affairs#k of your abilities. Please go pay a visit to him immediately.");
- if (status == 1){
+ else if (status == 1){
qm.forceStartQuest();
qm.sendOk("Save our kingdom! We believe in you!");
- qm.dispose();
- }
+ } else if (status == 2){
+ qm.dispose();
+ }
}
function end(mode, type, selection) {
diff --git a/scripts/quest/2314.js b/scripts/quest/2314.js
index d2550dc558..b6fcdd41ec 100644
--- a/scripts/quest/2314.js
+++ b/scripts/quest/2314.js
@@ -23,16 +23,17 @@ function start(mode, type, selection) {
}
if (status == 0)
qm.sendAcceptDecline("In order to rescue the princess, you must first navigate the Mushroom Forest. King Pepe set up a powerful barrier forbidding anyone from entering the castle. Please investigate this matter for us.");
- if (status == 1)
+ else if (status == 1)
qm.sendNext("You'll run into the barrier at the Mushroom Forest by heading east of where you are standing right now. Please be careful. I hear that the area is infested with crazy, fear-inducing monsters.");
- if(status == 2){
+ else if(status == 2){
//qm.forceStartQuest();
//qm.forceStartQuest(2314,"1");
qm.gainExp(8300);
qm.sendOk("I see, so it was indeed not a regular barrier by any means. Great work there. If not for you help, we wouldn't have had a clue as to what that was all about.");
qm.forceCompleteQuest();
- qm.dispose();
- }
+ } else if(status == 3){
+ qm.dispose();
+ }
}
function end(mode, type, selection) {
@@ -47,11 +48,12 @@ function end(mode, type, selection) {
}
if (status == 0)
qm.sendOk("I see that you have thoroughly investigated the barrier at the Mushroom Forest. What was it like?");
- if (status == 1){
+ else if (status == 1){
+ qm.forceCompleteQuest();
qm.gainExp(8300);
qm.sendOk("I see, so it was indeed not a regular barrier by any means. Great work there. If not for you help, we wouldn't have had a clue as to what that was all about.");
- qm.forceCompleteQuest();
- qm.dispose();
- }
- }
+ } else if (status == 2){
+ qm.dispose();
+ }
+}
\ No newline at end of file
diff --git a/scripts/quest/2315.js b/scripts/quest/2315.js
index d48aa09cb7..2432054981 100644
--- a/scripts/quest/2315.js
+++ b/scripts/quest/2315.js
@@ -25,11 +25,12 @@ function start(mode, type, selection) {
}
if (status == 0)
qm.sendAcceptDecline("A powerful barrier of magic, huh? Then what should we do...? If we can't find a way to break that barrier, then we can't save the princess. If it's impossible to physically break through, as you mentioned, then how about requesting help from our #bMinister of Magic#k?");
- if (status == 1){
+ else if (status == 1){
qm.forceStartQuest();
qm.sendOk("Please go see him immediately. The #bMinister of Magic#k may seem a bit on the edge, but he's very knowledgeable, and I'm sure he'll know what to do.");
- qm.dispose();
- }
+ } else if (status == 2){
+ qm.dispose();
+ }
}
function end(mode, type, selection) {
@@ -44,11 +45,12 @@ function end(mode, type, selection) {
}
if (status == 0)
qm.sendOk("What? You investigated the barrier at the Mushroom Forest?");
- if (status == 1){
- qm.gainExp(4000);
- qm.sendOk("Hmmm...this is interesting. It's a barrier set up by someone with a powerful force of magic, which means there's no way we can manually break through it.");
+ else if (status == 1){
qm.forceCompleteQuest();
- qm.dispose();
- }
+ qm.gainExp(4000);
+ qm.sendOk("Hmmm...this is interesting. It's a barrier set up by someone with a powerful force of magic, which means there's no way we can manually break through it.");
+ } else if (status == 2) {
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/2316.js b/scripts/quest/2316.js
index 32c5b0df3a..f55d8af293 100644
--- a/scripts/quest/2316.js
+++ b/scripts/quest/2316.js
@@ -25,9 +25,10 @@ function start(mode, type, selection) {
}
if (status == 0)
qm.sendAcceptDecline("I think i've heard of a potion that breaks these kinds of barriers. I think it's called #bKiller Mushroom Spores#k? Hmmm... outside, you'll find the Mushroom Scholar #bScarrs#k waiting outside. #bScarrs#k is an expert on mushrooms, so go talk to him.");
- if (status == 1){
+ else if (status == 1){
qm.forceStartQuest();
qm.sendOk("I am confident #kScarrs#k will do everything to help you.");
+ else if (status == 2){
qm.dispose();
}
}
@@ -44,11 +45,12 @@ function end(mode, type, selection) {
}
if (status == 0)
qm.sendOk("Ah, so you're the explorer people were talking about. I'm #bScarrs, the Royal Mushroom Scholar#k representing the Kingdom of Mushroom. So you need some #kKiller Mushroom Spores#k?");
- if (status == 1){
+ } else if (status == 1){
+ qm.forceCompleteQuest();
qm.gainExp(4200);
qm.sendOk("#kKiller Mushroom Spores#k... I think i've heard of them before...");
- qm.forceCompleteQuest();
- qm.dispose();
- }
+ } else if (status == 2) {
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/2317.js b/scripts/quest/2317.js
index 562f06d61e..919c75815f 100644
--- a/scripts/quest/2317.js
+++ b/scripts/quest/2317.js
@@ -25,9 +25,10 @@ function start(mode, type, selection) {
}
if (status == 0)
qm.sendAcceptDecline("Ah! If I am not mistaken, I saw the #bKiller Mushroom Spores#k way back when I was a kid in a book. Now I remember... it's made out of extracts of powerful poisons from Poison Mushrooms, which means you'll need some Poison Mushroom Caps. If you can get me those, I think I'll be able to make it.");
- if (status == 1){
+ else if (status == 1){
qm.forceStartQuest();
qm.sendOk("Please defeat #bPoison Mushrooms#k and bring back #b100 Poison Mushroom Caps#k in return.");
+ } else if (status == 2){
qm.dispose();
}
}
@@ -44,12 +45,13 @@ function end(mode, type, selection) {
}
if (status == 0)
qm.sendOk("Have you gathered up the 100 Poison Mushroom Caps like I asked you to get?");
- if (status == 1){
- qm.gainExp(13500);
+ else if (status == 1){
+ qm.sendOk("I am amazed that you were able to gather up these 100 Poison Mushroom Caps, which is considered a difficult feat. I think I'll be able to make #bKiller Mushroom Spores#k our of these.");
+ } else if (status == 2) {
+ qm.forceCompleteQuest();
+ qm.gainExp(13500);
qm.gainItem(4000500, -100);
- qm.sendOk("I am amazed that you were able to gather up these 100 Poison Mushroom Caps, which is considered a difficult feat. I think I'll be able to make #bKiller Mushroom Spores#k our of these.");
- qm.forceCompleteQuest();
qm.dispose();
- }
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/2318.js b/scripts/quest/2318.js
index be099faaed..40fc347f56 100644
--- a/scripts/quest/2318.js
+++ b/scripts/quest/2318.js
@@ -25,9 +25,10 @@ function start(mode, type, selection) {
}
if (status == 0)
qm.sendAcceptDecline("Hmmm... I looked into the making of the Spores while you were gathering up the Poison Mushroom Caps, and realised that we'll need more materials for it. I want you to gather up one more set of items. Can you do it?");
- if (status == 1){
+ else if (status == 1){
qm.forceStartQuest();
qm.sendOk("Okay, I want you to defeat the Regenade Spores and bring back #b50 Mutated Spores#k in return.");
+ } else if (status == 2){
qm.dispose();
}
}
@@ -44,15 +45,22 @@ function end(mode, type, selection) {
}
if (status == 0)
qm.sendOk("Did you gather up all the necessary ingredients for it?")
- if (status == 1){
- qm.gainExp(11500);
+ else if (status == 1){
+ if (!qm.haveItem(4000499, 50)) {
+ qm.sendOk("Please gather all the ingredients first.");
+ status = 2;
+ return;
+ }
+
+ qm.sendNext("These should be enough for me to make the #bKiller Mushroom Spores.#k Please hold on for a bit.");
+ } else if(status == 2){
+ qm.sendOk("Okay, here are the Killer Mushroom Spores. Hopefully this will be enough for you to save our princess and help regain our kingdom. Good luck!");
+ } else if(status == 3) {
+ qm.forceCompleteQuest();
+ qm.gainExp(11500);
qm.gainItem(4000499, -50);
- qm.sendNext("Okay, these should be enough for me to make the #bKiller Mushroom Spores.#k Please hold on for a bit.");
- qm.forceCompleteQuest();
qm.gainItem(2430014, 1);
- } if(status == 2){
- qm.sendPrev("Okay, here are the Killer Mushroom Spores. Hopefully this will be enough for you to save our princess and help regain our kingdom. Good luck!");
- qm.dispose();
- }
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/2319.js b/scripts/quest/2319.js
index 28fa533c72..a7897a0978 100644
--- a/scripts/quest/2319.js
+++ b/scripts/quest/2319.js
@@ -25,10 +25,11 @@ function start(mode, type, selection) {
}
if (status == 0)
qm.sendAcceptDecline("Oh, I almost forgot! What was I thinking? I need you to hand this #bSample of Killer Mushroom Spores#k to #bMinister of Magic#k and report the results.");
- if (status == 1){
+ else if (status == 1){
qm.forceStartQuest();
qm.gainItem(4032389, 1);
qm.sendOk("The #bMinister of Magic#k told me once the #bKiller Mushroom Spores#k is complete, that he'll want a sample of it as well. I'll give you the sample; now go please hand it in to our #bMinister of Magic.#k");
+ } else if (status == 2){
qm.dispose();
}
}
@@ -45,12 +46,13 @@ function end(mode, type, selection) {
}
if (status == 0)
qm.sendOk("Are the #bKiller Mushroom Spores#k finally completed?");
- if (status == 1){
+ else if (status == 1){
+ qm.forceCompleteQuest();
qm.gainExp(4200);
qm.gainItem(4032389, -1);
qm.sendOk("Okay, so this is the #bKiller Mushroom Spores.#k Thank you, thank you, and please tell #bScarrs#k the same.");
- qm.forceCompleteQuest();
- qm.dispose();
- }
+ } else if (status == 2) {
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/2320.js b/scripts/quest/2320.js
index 87a5a68780..381d762e37 100644
--- a/scripts/quest/2320.js
+++ b/scripts/quest/2320.js
@@ -25,10 +25,11 @@ function start(mode, type, selection) {
}
if (status == 0)
qm.sendAcceptDecline("I have just one more request for you. Would you like to take a listen?");
- if (status == 1){
+ else if (status == 1){
qm.forceStartQuest();
qm.gainItem(4032389, 1);
qm.sendOk("To be honest, these #bKiller Mushroom Spores#k are not completely out of my own work. Do you remember #bBruce#k from #bHenesys#k? I have been friends with him since childhood, and #bKiller Mushroom Spores#k was completed after he shared the results of his studies with me. This was all thanks to him, so I'd like for you to give this to him for me.");
+ } else if (status == 2){
qm.dispose();
}
}
@@ -45,12 +46,13 @@ function end(mode, type, selection) {
}
if (status == 0)
qm.sendOk("Oh! You're here on behalf of #bScarrs#k? \r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0# \r\n#fUI/UIWindow.img/QuestIcon/8/0# 8800 exp");
- if (status == 1){
+ else if (status == 1){
+ qm.forceCompleteQuest();
qm.gainExp(8800);
qm.gainItem(4032389, -1);
qm.sendOk("Ahh, so this is the #bKiller Mushroom Spores#k that I was working on in the past. I had a tough time gathering up the ingredients, so I left it in theory only, but he was able to complete it, with a sample to show for as well. Please tell him I appreciate his good work.");
- qm.forceCompleteQuest();
- qm.dispose();
- }
+ } else if (status == 2) {
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/2321.js b/scripts/quest/2321.js
index 61a14f5a5c..b9fc263f00 100644
--- a/scripts/quest/2321.js
+++ b/scripts/quest/2321.js
@@ -25,9 +25,10 @@ function start(mode, type, selection) {
}
if (status == 0)
qm.sendAcceptDecline("Now you'll be able to penetrate the spiny vine barrier of Mushroom Forest, but before that, #bMinister of Home Affairs#k wants to have a word with you. Please go see him immediately.");
- if (status == 1){
+ else if (status == 1){
qm.forceStartQuest();
qm.sendOk("Good luck.");
+ } else if (status == 2){
qm.dispose();
}
}
@@ -44,11 +45,12 @@ function end(mode, type, selection) {
}
if (status == 0)
qm.sendOk("I have been keeping up on your fabulour work. I am aware that you have successfully created the #bKiller Mushroom Spores#k, which penetrates through the unpenetrable barrier of the forest. Congratulations!");
- if (status == 1){
+ else if (status == 1){
+ qm.forceCompleteQuest();
qm.gainExp(2500);
qm.sendOk("The problem now is to figure out how to enter the castle.");
- qm.forceCompleteQuest();
- qm.dispose();
- }
+ } else if (status == 2) {
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/2322.js b/scripts/quest/2322.js
index 55bb3aad54..6ce6f2309b 100644
--- a/scripts/quest/2322.js
+++ b/scripts/quest/2322.js
@@ -25,14 +25,15 @@ function start(mode, type, selection) {
}
if (status == 0)
qm.sendYesNo("Like I told you, just breaking the barrier cannot be a cause for celebration. That's because our castle for the Kingdom of Mushroom completely denies entry of anyone outside our kingdom, so it'll be hard for you to do that. Hmmm... to figure out a way to enter, can you...investigate the outer walls of the castle first?");
- if (status == 1)
+ else if (status == 1)
qm.sendNext("Walk past the Mushroom Forest and when you reach the #bSplit Road of Choice#k, just walk towards the castle. Good luck.");
- if (status == 2){
+ else if (status == 2){
//qm.forceStartQuest();
//qm.forceStartQuest(2322, "1");
qm.gainExp(11000);
qm.sendOk("Good job navigating through the area.");
qm.forceCompleteQuest();
+ } else if (status == 3){
qm.dispose();
}
}
@@ -49,11 +50,12 @@ function end(mode, type, selection) {
}
if (status == 0)
qm.sendOk("Hmmm I see... so they have completely shut off the entrance and everything.");
- if (status == 1){
- qm.gainExp(11000);
- qm.sendOk("Good job navigating through the area.");
+ else if (status == 1){
qm.forceCompleteQuest();
- qm.dispose();
- }
+ qm.gainExp(11000);
+ qm.sendOk("Good job navigating through the area.");
+ } else if (status == 2) {
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/2325.js b/scripts/quest/2325.js
index 4154deb9d5..288ab76477 100644
--- a/scripts/quest/2325.js
+++ b/scripts/quest/2325.js
@@ -22,9 +22,10 @@ function end(mode, type, selection){
qm.sendNextPrev("Don't be afriad, #b#p1300005##k sent me here.", 2);
}
else if(status == 2){
- qm.sendOk("What? My brother sent you here? Ahhh... I am safe now. Thank you so much...");
qm.forceCompleteQuest();
qm.gainExp(6000);
- qm.dispose();
- }
+ qm.sendOk("What? My brother sent you here? Ahhh... I am safe now. Thank you so much...");
+ } else if (status == 3) {
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/2338.js b/scripts/quest/2338.js
index dd29f51031..71899082da 100644
--- a/scripts/quest/2338.js
+++ b/scripts/quest/2338.js
@@ -37,7 +37,7 @@ function start(mode, type, selection) {
if (status == 0) {
if(qm.haveItem(2430014, 1)) {
qm.sendNext("It looks like you already have one #b#t2430014##k on your inventory.");
- qm.dispose();
+ status = 1;
return;
}
@@ -48,8 +48,9 @@ function start(mode, type, selection) {
} else {
qm.gainItem(2430014, 1);
qm.forceCompleteQuest();
+ qm.dispose();
}
-
+ } else if (status == 2) {
qm.dispose();
}
}
diff --git a/scripts/quest/2342.js b/scripts/quest/2342.js
index 6c8aed8d0d..6d5d2ff6e4 100644
--- a/scripts/quest/2342.js
+++ b/scripts/quest/2342.js
@@ -6,22 +6,38 @@
var status = -1;
function start(mode, type, selection){
- if(!qm.hasItem(4001318) && qm.isQuestStarted(2331) && !qm.isQuestCompleted(2331)){
- if(qm.canHold(4001318)){
- qm.forceStartQuest();
- qm.gainItem(4001318, 1);
- qm.forceCompleteQuest();
- qm.sendOk("Looks like you forgot to pick up the #b#t4001318##k when you fought with the #bPrime Minister#k. This is very important to our kingdom, so please deliver this to my father as soon as possible.");
- qm.dispose();
- }
- else{
- qm.sendOk("Please free up one spot in your ETC inventory");
- qm.dispose();
- }
- }
- else{
- qm.dispose();
- }
+ if (mode == -1) {
+ qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ if(!qm.hasItem(4001318) && qm.isQuestStarted(2331) && !qm.isQuestCompleted(2331)){
+ if(qm.canHold(4001318)){
+ qm.forceStartQuest();
+ qm.gainItem(4001318, 1);
+ qm.forceCompleteQuest();
+ qm.sendOk("Looks like you forgot to pick up the #b#t4001318##k when you fought with the #bPrime Minister#k. This is very important to our kingdom, so please deliver this to my father as soon as possible.");
+ }
+ else{
+ qm.sendOk("Please free up one spot in your ETC inventory");
+ }
+ }
+ else{
+ qm.dispose();
+ }
+ } else if (status == 1) {
+ qm.dispose();
+ }
+ }
}
function end(mode, type, selection){
diff --git a/scripts/quest/2560.js b/scripts/quest/2560.js
index d784079e1b..985edef5c4 100644
--- a/scripts/quest/2560.js
+++ b/scripts/quest/2560.js
@@ -20,8 +20,10 @@ function start(mode, type, selection) {
qm.sendNext("Ook! Ook! (The monkey looks very dissatisfied.)");
} else {
qm.forceStartQuest();
+ qm.dispose();
}
- qm.dispose();
- }
+ } else if (status == 4) {
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/2568.js b/scripts/quest/2568.js
index 6f2c64f01f..846cbd3f52 100644
--- a/scripts/quest/2568.js
+++ b/scripts/quest/2568.js
@@ -16,7 +16,7 @@ function start(mode, type, selection) {
} else {
qm.forceStartQuest();
- qm.warp(912060200);
+ qm.warp(912060200, 0);
}
qm.dispose();
}
diff --git a/scripts/quest/2573.js b/scripts/quest/2573.js
index 25f51e1264..8d05cda8e4 100644
--- a/scripts/quest/2573.js
+++ b/scripts/quest/2573.js
@@ -17,10 +17,11 @@ function start(mode, type, selection) {
if (mode == 0) {//decline
qm.sendNext("Hey, take it easy! Sometimes you just gotta wait.");
} else {
- qm.sendNext("Looks like we're all set! I think this is going to be a great voyage. Let's get underway.");
qm.warp(3000000, 0);
qm.forceCompleteQuest();
+ qm.sendNext("Looks like we're all set! I think this is going to be a great voyage. Let's get underway.");
}
- qm.dispose();
- }
+ } else if (status == 3) {
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/28004.js b/scripts/quest/28004.js
index 72186d520c..7385fbfa47 100644
--- a/scripts/quest/28004.js
+++ b/scripts/quest/28004.js
@@ -44,7 +44,7 @@ function start(mode, type, selection) {
qm.sendNext("Okay... so here's our plan to defeat Scrooge and his dastardly plans. The Force of the Spirit I gave you is an item packed with mana. It's an item you'll definitely use at the map I am about to send you. In order to do that, you'll have to bring your party members with you as well. You should bring your party members here or form one right now!");
} else if (status == 1) {
qm.sendAcceptDecline("Would you like to move forward?");
- } else {
+ } else if (status == 2) {
var level = qm.getPlayer().getLevel();
qm.warp(level <= 30 ? 889100000 : (level <= 40 ? 889100010 : 889100020));
diff --git a/scripts/quest/29900.js b/scripts/quest/29900.js
index 5a06f3b0c6..dc129556dd 100644
--- a/scripts/quest/29900.js
+++ b/scripts/quest/29900.js
@@ -41,14 +41,16 @@ function end(mode, type, selection) {
if (status == 0)
qm.sendNext("Congratulations on earning your honorable #b#k title. I wish you the best of luck in your future endeavors! Keep up the good work.\r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0#\r\n #v1142107:# #t1142107# 1");
else if (status == 1) {
- if (qm.canHold(1142107)) {
- qm.gainItem(1142107);
- qm.forceCompleteQuest();
- } else
- qm.sendNext("Please make room in your inventory");//NOT GMS LIKE
-
- qm.dispose();
- }
+ if (qm.canHold(1142107)) {
+ qm.gainItem(1142107);
+ qm.forceCompleteQuest();
+ qm.dispose();
+ } else {
+ qm.sendNext("Please make room in your inventory");//NOT GMS LIKE
+ }
+ } else if (status == 2) {
+ qm.dispose();
+ }
}
}
\ No newline at end of file
diff --git a/scripts/quest/29901.js b/scripts/quest/29901.js
index 91f9acb3d4..b38d41c0ae 100644
--- a/scripts/quest/29901.js
+++ b/scripts/quest/29901.js
@@ -41,14 +41,16 @@ function end(mode, type, selection) {
if (status == 0)
qm.sendNext("Congratulations on earning your honorable #b#k title. I wish you the best of luck in your future endeavors! Keep up the good work.\r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0#\r\n #v1142108:# #t1142108# 1");
else if (status == 1) {
- if (qm.canHold(1142108)) {
- qm.gainItem(1142108);
- qm.forceCompleteQuest();
- } else
- qm.sendNext("Please make room in your inventory");//NOT GMS LIKE
-
- qm.dispose();
- }
+ if (qm.canHold(1142108)) {
+ qm.gainItem(1142108);
+ qm.forceCompleteQuest();
+ qm.dispose();
+ } else {
+ qm.sendNext("Please make room in your inventory");//NOT GMS LIKE
+ }
+ } else if (status == 2) {
+ qm.dispose();
+ }
}
}
\ No newline at end of file
diff --git a/scripts/quest/29902.js b/scripts/quest/29902.js
index 144dea0f8c..c665731a14 100644
--- a/scripts/quest/29902.js
+++ b/scripts/quest/29902.js
@@ -41,14 +41,16 @@ function end(mode, type, selection) {
if (status == 0)
qm.sendNext("Congratulations on earning your honorable #b#k title. I wish you the best of luck in your future endeavors! Keep up the good work.\r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0#\r\n #v1142109:# #t1142109# 1");
else if (status == 1) {
- if (qm.canHold(1142109)) {
- qm.gainItem(1142109);
- qm.forceCompleteQuest();
- } else
- qm.sendNext("Please make room in your inventory");//NOT GMS LIKE
-
- qm.dispose();
- }
+ if (qm.canHold(1142109)) {
+ qm.gainItem(1142109);
+ qm.forceCompleteQuest();
+ qm.dispose();
+ } else {
+ qm.sendNext("Please make room in your inventory");//NOT GMS LIKE
+ }
+ } else if (status == 2) {
+ qm.dispose();
+ }
}
}
\ No newline at end of file
diff --git a/scripts/quest/29903.js b/scripts/quest/29903.js
index 9b29ae4a02..999075c0f9 100644
--- a/scripts/quest/29903.js
+++ b/scripts/quest/29903.js
@@ -41,14 +41,16 @@ function end(mode, type, selection) {
if (status == 0)
qm.sendNext("Congratulations on earning your honorable #b#k title. I wish you the best of luck in your future endeavors! Keep up the good work.\r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0#\r\n #v1142110:# #t1142110# 1");
else if (status == 1) {
- if (qm.canHold(1142110)) {
- qm.gainItem(1142110);
- qm.forceCompleteQuest();
- } else
- qm.sendNext("Please make room in your inventory");//NOT GMS LIKE
-
- qm.dispose();
- }
+ if (qm.canHold(1142110)) {
+ qm.gainItem(1142110);
+ qm.forceCompleteQuest();
+ qm.dispose();
+ } else {
+ qm.sendNext("Please make room in your inventory");//NOT GMS LIKE
+ }
+ } else if (status == 2) {
+ qm.dispose();
+ }
}
}
\ No newline at end of file
diff --git a/scripts/quest/3108.js b/scripts/quest/3108.js
index b12838b03e..fc17c6b6a3 100644
--- a/scripts/quest/3108.js
+++ b/scripts/quest/3108.js
@@ -37,7 +37,7 @@ function start(mode, type, selection) {
if (status == 0) {
qm.sendNext("(As you peek into the shattered statue, you might have found a clue about what happened. Better talk to #rScadur#k about this.)");
qm.forceCompleteQuest();
-
+ } else if (status == 1) {
qm.dispose();
}
}
diff --git a/scripts/quest/3114.js b/scripts/quest/3114.js
deleted file mode 100644
index 11b3c7d0f0..0000000000
--- a/scripts/quest/3114.js
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- This file is part of the HeavenMS MapleStory Server
- Copyleft (L) 2016 - 2019 RonanLana
-
- 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 .
-*/
-
-var status = -1;
-
-function end(mode, type, selection) {
- if (mode == -1) {
- qm.dispose();
- } else {
- if(mode == 0 && type > 0) {
- qm.dispose();
- return;
- }
-
- if (mode == 1)
- status++;
- else
- status--;
-
- if (status == 0) {
- if(qm.getQuestProgress(3114, 7777) != -1) {
- if(!qm.haveItem(4161036, 1)) {
- if(qm.canHold(4161036, 1)) {
- qm.gainItem(4161036, 1);
- qm.sendNext("Seems you lost a book with the notes to Little Star. Here is another one. Please play it for me.", 9);
- } else {
- qm.sendNext("Seems you lost a book with the notes to Little Star, but you don't have an ETC available. Please free some room.", 9);
- }
- } else {
- qm.sendNext(".....", 9);
- }
-
- qm.dispose();
- return;
- }
-
- qm.sendNext("(Eliza seems to be in deep sleep.)", 3);
- } else if (status == 1) {
- qm.gainFame(20);
-
- qm.forceCompleteQuest();
- qm.dispose();
- }
- }
-}
\ No newline at end of file
diff --git a/scripts/quest/3301.js b/scripts/quest/3301.js
index 38db5d56cc..3e0352f326 100644
--- a/scripts/quest/3301.js
+++ b/scripts/quest/3301.js
@@ -28,28 +28,39 @@
var status = -1;
var oreArray;
-function start(mode, type, selection) {
-}
-
function end(mode, type, selection) {
- if (mode == -1 || (mode == 0 && type > 0)) {
- qm.dispose();
+ if (mode == -1) {
+ qm.dispose();
} else {
- oreArray = getOreArray();
- if (status == -1) {
+ if (mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ oreArray = getOreArray();
if (oreArray.length > 0) {
- status++;
qm.sendSimple("Oh, looks like someone's ready to make a deal. You want to join Zenumist so badly, huh? I really don't understand you, but that's just fine. What will you give me in return?\r\n" + getOreString(oreArray));
} else {
- qm.sendOk("What is this, you don't have the ores with you. No ore, no deal.");
+ qm.sendOk("What is this, you don't have the #rjewel ores#k with you. No ore, no deal.");
qm.dispose();
+ return;
}
- } else if (status == 0) {
+ } else if (status == 1) {
+ if (!qm.haveItem(oreArray[selection], 2)) {
+ qm.sendNext("What's this, you haven't got the #rjewel ores#k. No ores no deal!");
+ qm.dispose();
+ return;
+ }
+
qm.gainItem(oreArray[selection], -2); // Take 2 ores
- qm.sendNext("Then wait for awhile. I'll go and get the stuff to help you pass the test of Chief Zanumist.");
+ qm.sendNext("Then wait for awhile. I'll go and get the stuff to help you pass the test of Chief Zenumist.");
qm.forceCompleteQuest();
- qm.dispose();
- } else {
+ } else if (status == 2) {
qm.dispose();
}
}
diff --git a/scripts/quest/3303.js b/scripts/quest/3303.js
index 806589be97..d6884ab614 100644
--- a/scripts/quest/3303.js
+++ b/scripts/quest/3303.js
@@ -28,28 +28,39 @@
var status = -1;
var oreArray;
-function start(mode, type, selection) {
-}
-
function end(mode, type, selection) {
- if (mode == -1 || (mode == 0 && type > 0)) {
- qm.dispose();
+ if (mode == -1) {
+ qm.dispose();
} else {
- oreArray = getOreArray();
- if (status == -1) {
+ if (mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ oreArray = getOreArray();
if (oreArray.length > 0) {
- status++;
- qm.sendSimple("Oh, looks like someone's ready to make a deal. You want to join Alcadno so badly, huh? I really don't understand you, but that's just fine. What will you give me in return?\r\n" + getOreString(oreArray));
+ qm.sendSimple("Oh, looks like someone's ready to make a deal. You want to join Zenumist so badly, huh? I really don't understand you, but that's just fine. What will you give me in return?\r\n" + getOreString(oreArray));
} else {
- qm.sendOk("What is this, you don't have the ores with you. No ore, no deal.");
+ qm.sendOk("What is this, you don't have the #rjewel ores#k with you. No ore, no deal."); // script would loop undefinitely at completion, thanks IxianMace for noticing
qm.dispose();
+ return;
}
- } else if (status == 0) {
+ } else if (status == 1) {
+ if (!qm.haveItem(oreArray[selection], 2)) { // thanks resinate for noticing a function missing here
+ qm.sendNext("What's this, you haven't got the #rjewel ores#k. No ores no deal!");
+ qm.dispose();
+ return;
+ }
+
qm.gainItem(oreArray[selection], -2); // Take 2 ores
- qm.sendNext("Then wait for awhile. I'll go and get the stuff to help you pass the test of Chief Alcadno.");
+ qm.sendNext("Then wait for awhile. I'll go and get the stuff to help you pass the test of Chief Zenumist.");
qm.forceCompleteQuest();
- qm.dispose();
- } else {
+ } else if (status == 2) {
qm.dispose();
}
}
diff --git a/scripts/quest/3311.js b/scripts/quest/3311.js
deleted file mode 100644
index f244fb5b26..0000000000
--- a/scripts/quest/3311.js
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- This file is part of the HeavenMS MapleStory Server
- Copyleft (L) 2016 - 2019 RonanLana
-
- 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 .
-*/
-
-var status = -1;
-
-function end(mode, type, selection) {
- if (mode == -1) {
- qm.dispose();
- } else {
- if(mode == 0 && type > 0) {
- qm.dispose();
- return;
- }
-
- if (mode == 1)
- status++;
- else
- status--;
-
- if (status == 0) {
- if(qm.getQuestProgress(3311, 0) == 1 && qm.getQuestProgress(3311, 1) == 1) {
- qm.sendNext("Hmm, so the Alcadno doctor wrote something about researching some vanguardist Neo Huroid machine, that could beat by far the existing one, and was about to prepare the last steps of his rehearsal? We don't have a word about him for about three weeks now, something must have gone wrong...");
- qm.gainExp(60000);
- qm.forceCompleteQuest();
- } else {
- qm.sendNext("Found nothing yet? Please check out Dr. De Lang's house properly, something there may give out a clue about what is going on.");
- }
-
- qm.dispose();
- }
- }
-}
\ No newline at end of file
diff --git a/scripts/quest/3314.js b/scripts/quest/3314.js
index 2d8c7591b6..e549b69e8d 100644
--- a/scripts/quest/3314.js
+++ b/scripts/quest/3314.js
@@ -58,7 +58,7 @@ function end(mode, type, selection) {
} else {
qm.sendNext("You seem pretty normal, don't you? I can't detect any possible effect from my experiment on you. Go take the pill I asked you to take and show me the effects, will you?");
}
- } else {
+ } else if (status == 1) {
qm.dispose();
}
}
diff --git a/scripts/quest/3321.js b/scripts/quest/3321.js
index 8daca5d652..e53fb914b4 100644
--- a/scripts/quest/3321.js
+++ b/scripts/quest/3321.js
@@ -48,8 +48,8 @@ function start(mode, type, selection) {
qm.sendNext("Oh, and I have a personal favor to ask, if it's not too much. I am worried about my wife, #b#p2111004##k. Since the incident with the Huroids I could send a word to her, that must have made a toll on her... Please, if you could, could you get the #bSilver Pendant#k I left #bback at home#k, and give it to her in my stead? I regret not giving the item right away to her, it was her birthday... Maybe giving it now to her can get her a good sleeping night, at least.");
} else if (status == 5) {
qm.sendNext("#rMake sure to remember this pattern!#k I've hid the pendant in my house, in a container #bbehind the water pipes#k. The pipes must be turned #bin order#k: top, bottom, middle. And then, enter the secret password: '#rmy love Phyllia#k'.");
-
qm.forceStartQuest();
+ } else if (status == 6) {
qm.dispose();
}
}
diff --git a/scripts/quest/3360.js b/scripts/quest/3360.js
index d9f572b8b2..78496c6381 100644
--- a/scripts/quest/3360.js
+++ b/scripts/quest/3360.js
@@ -24,6 +24,7 @@
Description: Quest - Verifying the password
*/
var status = -1;
+var pass;
function start(mode, type, selection) {
if (mode == -1) {
@@ -47,35 +48,16 @@ function start(mode, type, selection) {
} else if (status == 1) {
qm.sendAcceptDecline("All right, now, this key is very long and complex. I need you to memorize it very well. I won't say again, so you'd better write it down somewhere. Are you ready?");
} else if (status == 2) {
- var pass = generateString();
+ pass = generateString();
qm.sendOk("The key code is #b" + pass + "#k. Got that? Put the key into the door of the secret passage, and you will be able to walk around the passage freely.");
- qm.forceStartQuest();
- qm.setStringQuestProgress(3360, 0, pass);
+ } else if (status == 3) {
+ qm.forceStartQuest();
+ qm.setQuestProgress(3360, pass);
qm.dispose();
}
}
}
-function end(mode, type, selection) {
- if (mode == -1) {
- qm.dispose();
- } else {
- if (mode == 1)
- status++;
- else
- status--;
- if (status == 0) {
- if(qm.getQuestProgress(3360, 1) == 0) {
- qm.sendNext("What's up? You haven't opened the Secret Passage yet?");
- } else {
- qm.forceCompleteQuest();
- }
-
- qm.dispose();
- }
- }
-}
-
function generateString() {
var thestring = "";
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
diff --git a/scripts/quest/3382.js b/scripts/quest/3382.js
index 046e056dfb..c2814e3554 100644
--- a/scripts/quest/3382.js
+++ b/scripts/quest/3382.js
@@ -27,37 +27,53 @@
Quest ID: 3382
*/
+var status = -1;
+
function end(mode, type, selection) {
- if(qm.haveItem(4001159, 25) && qm.haveItem(4001160, 25) && !qm.haveItemWithId(1122010, true)) {
- if(qm.canHold(1122010)) {
- qm.gainItem(4001159, -25);
- qm.gainItem(4001160, -25);
- qm.gainItem(1122010, 1);
-
- qm.sendOk("Thank you for retrieving the marbles. Accept this pendant as a token of my appreciation.");
- } else {
- qm.sendNext("Free a slot on your EQUIP tab before claiming a prize.");
- qm.dispose();
- return;
- }
- } else if(qm.haveItem(4001159, 10) && qm.haveItem(4001160, 10)) {
- if(qm.canHold(2041212)) {
- qm.gainItem(4001159, -10);
- qm.gainItem(4001160, -10);
- qm.gainItem(2041212, 1);
-
- qm.sendOk("Thank you for retrieving the marbles. This rock, that I am giving to you, can be used to improve the stats on the #b#t1122010##k. Take it as a token of my appreciation and use it wisely.");
- } else {
- qm.sendNext("Free a slot on your USE tab before claiming a prize.");
- qm.dispose();
- return;
- }
- } else {
- qm.sendNext("I need at least #b10 of both #t4001159# and #t4001160##k to reward you appropriately. If you happen to come with #b25 of these#k instead, I can reward you with a valuable gear. Fare well.");
+ if (mode == -1) {
+ qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
qm.dispose();
return;
}
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ if(qm.haveItem(4001159, 25) && qm.haveItem(4001160, 25) && !qm.haveItemWithId(1122010, true)) {
+ if(qm.canHold(1122010)) {
+ qm.gainItem(4001159, -25);
+ qm.gainItem(4001160, -25);
+ qm.gainItem(1122010, 1);
- qm.forceCompleteQuest();
- qm.dispose();
+ qm.sendOk("Thank you for retrieving the marbles. Accept this pendant as a token of my appreciation.");
+ } else {
+ qm.sendNext("Free a slot on your EQUIP tab before claiming a prize.");
+ return;
+ }
+ } else if(qm.haveItem(4001159, 10) && qm.haveItem(4001160, 10)) {
+ if(qm.canHold(2041212)) {
+ qm.gainItem(4001159, -10);
+ qm.gainItem(4001160, -10);
+ qm.gainItem(2041212, 1);
+
+ qm.sendOk("Thank you for retrieving the marbles. This rock, that I am giving to you, can be used to improve the stats on the #b#t1122010##k. Take it as a token of my appreciation and use it wisely.");
+ } else {
+ qm.sendNext("Free a slot on your USE tab before claiming a prize.");
+ return;
+ }
+ } else {
+ qm.sendNext("I need at least #b10 of both #t4001159# and #t4001160##k to reward you appropriately. If you happen to come with #b25 of these#k instead, I can reward you with a valuable gear. Fare well.");
+ return;
+ }
+
+ qm.forceCompleteQuest();
+ } else if (status == 1) {
+ qm.dispose();
+ }
+ }
}
diff --git a/scripts/quest/3437.js b/scripts/quest/3437.js
index 2a3f4b1d5f..6c159e63f2 100644
--- a/scripts/quest/3437.js
+++ b/scripts/quest/3437.js
@@ -14,9 +14,7 @@ function end(mode, type, selection) {
if(status == 0) {
qm.sendNext("What the? Are you telling me you've already taken out 150 #o4230120#s? And these ... yes, these really are 120 #t4000122#s. I was wondering how you were going to complete this mission all by yourself, but you took care of it just fine. Alright, here ... this is a very important item for me, but please take it.");
- }
-
- else if(status == 1) {
+ } else if(status == 1) {
if(qm.getPlayer().getInventory(Packages.client.inventory.MapleInventoryType.EQUIP).getNumFreeSlot() < 1) {
qm.sendOk("Please free a EQUIP inventory slot to receive the reward.");
qm.dispose();
@@ -34,16 +32,13 @@ function end(mode, type, selection) {
else item = 1082149;
qm.sendNext(talkStr);
- }
-
- if(status == 2) {
+ } else if(status == 2) {
+ qm.completeQuest();
qm.gainItem(item, 1);
qm.gainItem(4000122, -120);
-
qm.gainExp(6100);
- qm.completeQuest();
-
qm.sendOk("Thank you so much for fulfilling your missions as one of the Mesorangers. I've told the Sector about your successful story, and the Sector seems to be very pleased with you, too. Hopefully you'll keep working with us. Bye~");
+ } else if (status == 3) {
qm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/quest/3452.js b/scripts/quest/3452.js
index 82c02a1ab2..a87f73f566 100644
--- a/scripts/quest/3452.js
+++ b/scripts/quest/3452.js
@@ -17,12 +17,13 @@ function end(mode, type, selection) {
qm.gainItem(2000011, 50);
qm.gainExp(8000);
qm.forceCompleteQuest();
+ qm.dispose();
}
else {
qm.sendNext("Hm? It looks like your inventory is full.");
}
-
+ } else if (status == 2) {
qm.dispose();
- }
+ }
}
}
\ No newline at end of file
diff --git a/scripts/quest/3454.js b/scripts/quest/3454.js
index f37a76db3c..84f2c77bf4 100644
--- a/scripts/quest/3454.js
+++ b/scripts/quest/3454.js
@@ -27,27 +27,46 @@
Quest ID: 3454
*/
+var status = -1;
+
function end(mode, type, selection) {
- if(qm.getPlayer().getInventory(Packages.client.inventory.MapleInventoryType.ETC).getNumFreeSlot() < 1) {
- qm.sendOk("Make room on your ETC inventory first.");
- qm.dispose();
- return;
- }
+ if (mode == -1) {
+ qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ if(qm.getPlayer().getInventory(Packages.client.inventory.MapleInventoryType.ETC).getNumFreeSlot() < 1) {
+ qm.sendOk("Make room on your ETC inventory first.");
+ qm.dispose();
+ return;
+ }
- qm.gainItem(4000125, -1);
- qm.gainItem(4031926, -10);
- qm.gainItem(4000119, -30);
- qm.gainItem(4000118, -30);
+ qm.gainItem(4000125, -1);
+ qm.gainItem(4031926, -10);
+ qm.gainItem(4000119, -30);
+ qm.gainItem(4000118, -30);
- rnd = Math.random();
- if(rnd < 1.0) {
- qm.gainItem(4031928, 1);
- }
- else {
- qm.gainItem(4031927, 1);
- }
+ rnd = Math.random();
+ if(rnd < 1.0) {
+ qm.gainItem(4031928, 1);
+ }
+ else {
+ qm.gainItem(4031927, 1);
+ }
- qm.sendOk("Now, go meet Alien Gray and use this undercover to read through their plans. If this fails, we will need to gather some materials once again.");
- qm.forceCompleteQuest();
- qm.dispose();
+ qm.sendOk("Now, go meet Alien Gray and use this undercover to read through their plans. If this fails, we will need to gather some materials once again.");
+ qm.forceCompleteQuest();
+ } else if (status == 1) {
+ qm.dispose();
+ }
+ }
}
diff --git a/scripts/quest/3507.js b/scripts/quest/3507.js
index 41dab043eb..f2ab5516af 100644
--- a/scripts/quest/3507.js
+++ b/scripts/quest/3507.js
@@ -1,10 +1,29 @@
+
+var status = -1;
+
function end(mode, type, selection) {
- if(qm.isQuestCompleted(3523) || qm.isQuestCompleted(3524) || qm.isQuestCompleted(3525) || qm.isQuestCompleted(3526) || qm.isQuestCompleted(3527) || qm.isQuestCompleted(3529) || qm.isQuestCompleted(3539)) {
- qm.completeQuest();
- qm.sendOk("You are now filled with all of your memories again.. You are now allowed to go to #m270020000#.");
- } else {
- qm.sendOk("You have not yet checked with your first teacher about your memories?");
- }
-
+ if (mode == -1) {
qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ if(qm.isQuestCompleted(3523) || qm.isQuestCompleted(3524) || qm.isQuestCompleted(3525) || qm.isQuestCompleted(3526) || qm.isQuestCompleted(3527) || qm.isQuestCompleted(3529) || qm.isQuestCompleted(3539)) {
+ qm.completeQuest();
+ qm.sendOk("You are now filled with all of your memories again.. You are now allowed to go to #m270020000#.");
+ } else {
+ qm.sendOk("You have not yet checked with your first teacher about your memories?");
+ }
+ } else if (status == 1) {
+ qm.dispose();
+ }
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/3523.js b/scripts/quest/3523.js
index 5ee5f05777..4f8ab2905d 100644
--- a/scripts/quest/3523.js
+++ b/scripts/quest/3523.js
@@ -23,10 +23,29 @@
* In search for the lost memory - warrior
*/
+var status = -1;
+
function start(mode, type, selection) {
- qm.startQuest();
- //qm.getPlayer().updateQuestInfo(3507, "1");
- qm.completeQuest();
- qm.sendOk("You have regained your memories, talk to #b#p2140001##k to get the pass.");
- qm.dispose();
+ if (mode == -1) {
+ qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ qm.startQuest();
+ qm.setQuestProgress(3507, 7081, 1); // thanks resinate for pointing out uncompletable quest due to non-updated progress
+ qm.completeQuest();
+ qm.sendOk("You have regained your memories, talk to #b#p2140001##k to get the pass.");
+ } else if (status == 1) {
+ qm.dispose();
+ }
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/3524.js b/scripts/quest/3524.js
index 744ca4f701..4b740dd36b 100644
--- a/scripts/quest/3524.js
+++ b/scripts/quest/3524.js
@@ -23,10 +23,29 @@
* In search for the lost memory - mage
*/
+var status = -1;
+
function start(mode, type, selection) {
- qm.startQuest();
- //qm.getPlayer().updateQuestInfo(3507, "1");
- qm.completeQuest();
- qm.sendOk("You have regained your memories, talk to #b#p2140001##k to get the pass.");
- qm.dispose();
+ if (mode == -1) {
+ qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ qm.startQuest();
+ qm.setQuestProgress(3507, 7081, 1);
+ qm.completeQuest();
+ qm.sendOk("You have regained your memories, talk to #b#p2140001##k to get the pass.");
+ } else if (status == 1) {
+ qm.dispose();
+ }
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/3525.js b/scripts/quest/3525.js
index 76d31b4b92..97bbae92c7 100644
--- a/scripts/quest/3525.js
+++ b/scripts/quest/3525.js
@@ -23,10 +23,29 @@
* In search for the lost memory - bowman
*/
+var status = -1;
+
function start(mode, type, selection) {
- qm.startQuest();
- //qm.getPlayer().updateQuestInfo(3507, "1");
- qm.completeQuest();
- qm.sendOk("You have regained your memories, talk to #b#p2140001##k to get the pass.");
- qm.dispose();
+ if (mode == -1) {
+ qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ qm.startQuest();
+ qm.setQuestProgress(3507, 7081, 1);
+ qm.completeQuest();
+ qm.sendOk("You have regained your memories, talk to #b#p2140001##k to get the pass.");
+ } else if (status == 1) {
+ qm.dispose();
+ }
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/3526.js b/scripts/quest/3526.js
index 295dc91cd5..77b49a7ce1 100644
--- a/scripts/quest/3526.js
+++ b/scripts/quest/3526.js
@@ -23,10 +23,29 @@
* In search for the lost memory - thief
*/
+var status = -1;
+
function start(mode, type, selection) {
- qm.startQuest();
- //qm.getPlayer().updateQuestInfo(3507, "1");
- qm.completeQuest();
- qm.sendOk("You have regained your memories, talk to #b#p2140001##k to get the pass.");
- qm.dispose();
+ if (mode == -1) {
+ qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ qm.startQuest();
+ qm.setQuestProgress(3507, 7081, 1);
+ qm.completeQuest();
+ qm.sendOk("You have regained your memories, talk to #b#p2140001##k to get the pass.");
+ } else if (status == 1) {
+ qm.dispose();
+ }
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/3527.js b/scripts/quest/3527.js
index 5ba2606c08..ce28f770f0 100644
--- a/scripts/quest/3527.js
+++ b/scripts/quest/3527.js
@@ -23,10 +23,29 @@
* In search for the lost memory - pirate
*/
+var status = -1;
+
function start(mode, type, selection) {
- qm.startQuest();
- //qm.getPlayer().updateQuestInfo(3507, "1");
- qm.completeQuest();
- qm.sendOk("You have regained your memories, talk to #b#p2140001##k to get the pass.");
- qm.dispose();
+ if (mode == -1) {
+ qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ qm.startQuest();
+ qm.setQuestProgress(3507, 7081, 1);
+ qm.completeQuest();
+ qm.sendOk("You have regained your memories, talk to #b#p2140001##k to get the pass.");
+ } else if (status == 1) {
+ qm.dispose();
+ }
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/3529.js b/scripts/quest/3529.js
index c2dd001165..5d1ac8f05f 100644
--- a/scripts/quest/3529.js
+++ b/scripts/quest/3529.js
@@ -36,8 +36,9 @@ function start(mode, type, selection) {
if (status == 0) {
qm.sendOk("You have regained your memories, talk to #b#p2140001##k to get the pass.");
- } else if (status == 1) {
+ qm.setQuestProgress(3507, 7081, 1);
qm.forceCompleteQuest();
+ } else if (status == 1) {
qm.dispose();
}
}
diff --git a/scripts/quest/3539.js b/scripts/quest/3539.js
index 5ba2606c08..ce28f770f0 100644
--- a/scripts/quest/3539.js
+++ b/scripts/quest/3539.js
@@ -23,10 +23,29 @@
* In search for the lost memory - pirate
*/
+var status = -1;
+
function start(mode, type, selection) {
- qm.startQuest();
- //qm.getPlayer().updateQuestInfo(3507, "1");
- qm.completeQuest();
- qm.sendOk("You have regained your memories, talk to #b#p2140001##k to get the pass.");
- qm.dispose();
+ if (mode == -1) {
+ qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ qm.startQuest();
+ qm.setQuestProgress(3507, 7081, 1);
+ qm.completeQuest();
+ qm.sendOk("You have regained your memories, talk to #b#p2140001##k to get the pass.");
+ } else if (status == 1) {
+ qm.dispose();
+ }
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/3714.js b/scripts/quest/3714.js
index f168dc4d7e..913c341fb9 100644
--- a/scripts/quest/3714.js
+++ b/scripts/quest/3714.js
@@ -55,11 +55,10 @@ function start(mode, type, selection) {
return;
}
+ qm.forceCompleteQuest();
qm.gainItem(4001094, -1);
qm.gainItem(2041200, 1); // quest not rewarding properly found thanks to MedicOP & Thora
qm.gainExp(42000);
-
- qm.forceCompleteQuest();
qm.dispose();
}
}
diff --git a/scripts/quest/3833.js b/scripts/quest/3833.js
index 7e1a3a482b..b01f5946fa 100644
--- a/scripts/quest/3833.js
+++ b/scripts/quest/3833.js
@@ -51,12 +51,14 @@ function end(mode, type, selection) {
qm.gainExp(10);
qm.forceCompleteQuest();
}
+
+ qm.dispose();
}
else {
qm.sendOk("Could you make #b2 slots available#k on your USE inventory before receiving your reward?");
- }
-
- qm.dispose();
- }
+ }
+ } else if (status == 2) {
+ qm.dispose();
+ }
}
}
\ No newline at end of file
diff --git a/scripts/quest/3926.js b/scripts/quest/3926.js
deleted file mode 100644
index a358b11be6..0000000000
--- a/scripts/quest/3926.js
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- This file is part of the HeavenMS MapleStory Server
- Copyleft (L) 2016 - 2019 RonanLana
-
- 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 .
-*/
-/* Screwing the Red Scorpions
- */
-
-var status = -1;
-
-function end(mode, type, selection) {
- if (mode == -1) {
- qm.dispose();
- } else {
- if(mode == 0 && type > 0) {
- qm.dispose();
- return;
- }
-
- if (mode == 1)
- status++;
- else
- status--;
-
- if (status == 0) {
- var c = 0;
-
- for(var i = 0; i < 4; i++) {
- if(qm.getQuestProgress(3926, i) == 1) {
- c++;
- }
- }
-
- if(c == 4) {
- qm.sendNext("You delivered all the jewels, well done!");
- qm.gainExp(6500);
- qm.forceCompleteQuest();
- } else {
- qm.sendNext("Have you brought all the jewels from the Red Scorpions? They have to be delivered to the Residential areas of the Sand Bandits.");
- }
-
- qm.dispose();
- }
- }
-}
diff --git a/scripts/quest/3927.js b/scripts/quest/3927.js
deleted file mode 100644
index 5fb4319180..0000000000
--- a/scripts/quest/3927.js
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- 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 .
-*/
-/*
- Author : Ronan Lana
-*/
-
-var status = -1;
-
-function end(mode, type, selection) {
- if (mode == -1) {
- qm.dispose();
- } else {
- if (mode == 0 && status == 0) {
- qm.dispose();
- return;
- }
-
- if (mode == 1)
- status++;
- else
- status--;
-
-
- if(qm.getQuestProgress(3927) == 0) { // didn't find the wall yet, eh?
- qm.sendOk("Did you find the wall? Look closely, the wall is more near than you think!");
- qm.dispose();
- return;
- }
-
- if (status == 0) {
- qm.sendSimple("Did you find the wall?\r\n#L0##b I did, but... I have no idea what it's talking about.#l");
- } else if (status == 1) {
- qm.sendSimple("What did it say?\r\n#L0##b 'If I had an iron hammer and a dagger, a bow and an arrow...'#l\r\n#L1# 'Byron S2 Sirin'#l\r\n#L2# 'Ahhh I forgot.'");
- } else if (status == 2) {
- if(selection == 0) {
- qm.sendOk("If I had an iron hammer and a dagger... a bow and an arrow... what does that mean? Do you want me to tell you? I don't know myself. It's something you should think about. If you need a clue... it would go something like... a weapon is just an item... until someone uses it...?");
- } else if(selection == 1) {
- qm.sendOk("Man, Jiyur wrote on the wall again! Arrgh!!");
- qm.dispose();
- return;
- } else {
- qm.sendOk("What? You forgot? Do you remember where it was written?");
- qm.dispose();
- return;
- }
- } else if (status == 3) {
- qm.gainExp(1000);
- qm.forceCompleteQuest();
- qm.dispose();
- }
- }
-}
\ No newline at end of file
diff --git a/scripts/quest/3929.js b/scripts/quest/3929.js
deleted file mode 100644
index fdbe2dddde..0000000000
--- a/scripts/quest/3929.js
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- This file is part of the HeavenMS MapleStory Server
- Copyleft (L) 2016 - 2019 RonanLana
-
- 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 .
-*/
-/* Sejan's Test
- Food delivery on Ariant
- */
-
-var status = -1;
-
-function end(mode, type, selection) {
- if (mode == -1) {
- qm.dispose();
- } else {
- if(mode == 0 && type > 0) {
- qm.dispose();
- return;
- }
-
- if (mode == 1)
- status++;
- else
- status--;
-
- if (status == 0) {
- var c = 0;
-
- for(var i = 0; i < 4; i++) {
- if(qm.getQuestProgress(3929, i) == 1) {
- c++;
- }
- }
-
- if(c == 4) {
- qm.sendNext("You delivered all the food, good.");
- qm.gainExp(2000);
- qm.forceCompleteQuest();
- } else {
- var missed = (4 - qm.getItemQuantity(4031580)) - c;
- if(missed > 0) {
- if(qm.canHold(4031580, missed)) {
- qm.gainItem(4031580, missed);
- qm.sendNext("Hey, what are you trying to pull on? To pass my test you must deliver all the foods to the Residential areas.");
- } else {
- qm.sendNext("You don't completed the task, neither has slots available on the inventory to get the food. Free a slot on your ETC please.");
- }
- } else {
- qm.sendNext("Hey, what are you trying to pull on? To pass my test you must to deliver all the foods to the Residential areas.");
- }
- }
-
- qm.dispose();
- }
- }
-}
diff --git a/scripts/quest/3933.js b/scripts/quest/3933.js
index 01dc695301..4ee82e96df 100644
--- a/scripts/quest/3933.js
+++ b/scripts/quest/3933.js
@@ -43,15 +43,15 @@ function start(mode, type, selection) {
qm.sendAcceptDecline("To truly see your strength, I'll have to face you myself. Don't worry, I'll summon my other self to face off against you. Are you ready?");
} else if (status == 2) {
qm.sendNext("Good, I like your confidence.");
- } else {
+ } else if (status == 3) {
if(qm.getWarpMap(926000000).getCharacters().size() > 0) {
qm.sendOk("There is someone currently in this map, come back later.");
+ qm.dispose();
} else {
- qm.warp(926000000);
+ qm.warp(926000000, "st00");
qm.forceStartQuest();
+ qm.dispose();
}
-
- qm.dispose();
}
}
}
diff --git a/scripts/quest/3941.js b/scripts/quest/3941.js
index c0eb4219e7..6588efd4af 100644
--- a/scripts/quest/3941.js
+++ b/scripts/quest/3941.js
@@ -42,18 +42,23 @@ function start(mode, type, selection) {
else
status--;
- if(!isTigunMorphed(qm.getPlayer())) {
- qm.sendNext("What's this? I can't simply give the Queen's silk to anyone, claiming they will hand it at once to the queen. Get out of my sights.");
- qm.dispose();
- return;
- }
-
if (status == 0) {
+ if(!isTigunMorphed(qm.getPlayer())) {
+ qm.sendNext("What's this? I can't simply give the Queen's silk to anyone, claiming they will hand it at once to the queen. Get out of my sights.");
+ status = 1;
+ return;
+ }
+
qm.sendNext("Tigun, what are you doing here?");
} else if (status == 1) {
+ if(!isTigunMorphed(qm.getPlayer())) {
+ qm.sendNext("What's this? I can't simply give the Queen's silk to anyone, claiming they will hand it at once to the queen. Get out of my sights.");
+ return;
+ }
+
qm.sendNext("The Queen wants her silk right now? Alright, I have them here. Hold on a moment.");
-
- qm.forceStartQuest();
+ qm.forceStartQuest();
+ } else if (status == 2) {
qm.dispose();
}
}
@@ -73,13 +78,13 @@ function end(mode, type, selection) {
else
status--;
- if(!isTigunMorphed(qm.getPlayer())) {
- qm.sendNext("What's this? I can't simply give the Queen's silk to anyone, claiming they will hand it at once to the queen. Get out of my sights.");
- qm.dispose();
- return;
- }
-
if (status == 0) {
+ if(!isTigunMorphed(qm.getPlayer())) {
+ qm.sendNext("What's this? I can't simply give the Queen's silk to anyone, claiming they will hand it at once to the queen. Get out of my sights.");
+ qm.dispose();
+ return;
+ }
+
if(qm.canHold(4031571, 1)) {
qm.gainItem(4031571);
@@ -88,7 +93,7 @@ function end(mode, type, selection) {
} else {
qm.sendNext("Hey, you're lacking space to hold this, man. I will stay with it while you arrange your backpack...");
}
-
+ } else if (status == 1) {
qm.dispose();
}
}
diff --git a/scripts/quest/3953.js b/scripts/quest/3953.js
index f45a2643c1..1575c21706 100644
--- a/scripts/quest/3953.js
+++ b/scripts/quest/3953.js
@@ -43,12 +43,12 @@ function end(mode, type, selection) {
} else if (status == 3) {
qm.sendSimple("They have departed on an expedition to get rid of some major threats in the desert that were ravaging Ariant, for quite some time now... It's strange, they should have already returned... Thinking about it now, the last attack on the merchants was around the direction the Guardians departed... No, that can't be... Can it?\r\n\r\n#L0##bPerhaps Deo has already turned into a monster.#k");
} else if (status == 4) {
- qm.gainItem(4011008, -1);
-
- qm.sendNext("We're in great trouble, if it is like this. And it really seems like it. If the Royal Cactus Deo has gone insane, Ariant is done for. You, can you do something to defeat Deo? We really need your help now.");
- qm.gainExp(20000);
-
qm.forceCompleteQuest();
+ qm.gainItem(4011008, -1);
+ qm.gainExp(20000);
+
+ qm.sendNext("We're in great trouble, if it is like this. And it really seems like it. If the Royal Cactus Deo has gone insane, Ariant is done for. You, can you do something to defeat Deo? We really need your help now.");
+ } else if (status == 5) {
qm.dispose();
}
}
diff --git a/scripts/quest/4647.js b/scripts/quest/4647.js
index c26f42341b..0e18b92d34 100644
--- a/scripts/quest/4647.js
+++ b/scripts/quest/4647.js
@@ -40,16 +40,14 @@ function end(mode, type, selection) {
status--;
if (status == 0) {
if(qm.haveItem(5460000)) {
- qm.sendOk("You got the Pet Snack! Thanks! You can use these to feed multiple pets at once!");
+ qm.completeQuest();
qm.teachSkill(8, 1, 1, -1);
qm.gainItem(5460000, -1, false);
- qm.completeQuest();
- qm.dispose();
+ qm.sendOk("You got the Pet Snack! Thanks! You can use these to feed multiple pets at once!");
} else {
qm.sendOk("Get me the Pet Snack! It can be found in a very big shop....");
- qm.dispose();
}
- } else {
+ } else if (status == 1) {
qm.dispose();
}
}
diff --git a/scripts/quest/4659.js b/scripts/quest/4659.js
index b2d3bb6c23..2e50f3ca01 100644
--- a/scripts/quest/4659.js
+++ b/scripts/quest/4659.js
@@ -52,9 +52,10 @@ function end(mode, type, selection) {
qm.sendNext("Great job on finding your evolution materials. I will now give you a robot.");
}
else if (status == 1) {
- if (qm.isQuestCompleted(4659))
+ if (qm.isQuestCompleted(4659)) {
qm.dropMessage(1, "how did this get here?");
- else if (qm.canHold(5000048)){
+ qm.dispose();
+ } else if (qm.canHold(5000048)){
var pet = 0;
var after;
var i;
@@ -108,8 +109,10 @@ function end(mode, type, selection) {
// var petId = MaplePet.createPet(rand + 5000049, level, closeness, fullness);
// if (petId == -1) return;
// MapleInventoryManipulator.addById(qm.getClient(), rand+5000049, 1, "", petId);
- } else
+ qm.dispose();
+ } else {
qm.dropMessage(1,"Your inventory is full");
- qm.dispose();
+ qm.dispose();
+ }
}
}
\ No newline at end of file
diff --git a/scripts/quest/6033.js b/scripts/quest/6033.js
index e410a971f7..6f0ca48ffd 100644
--- a/scripts/quest/6033.js
+++ b/scripts/quest/6033.js
@@ -41,19 +41,19 @@ function end(mode, type, selection) {
if (status == 0) {
qm.sendNext("Hm, so you claim to have brought the #b#t4260003##k? Ok, let's take a look into it.");
} else if (status == 1) {
- if(qm.getQuestProgress(6033) == 1 && qm.haveItem(4260003, 1)) {
- qm.sendNext("You indeed have crafted a fine piece of Monster Crystal, I see. You passed! Now, I shall teach you the next steps of the Maker skill. Keep the monster crystal with you as well, it's your work.");
+ if(qm.getQuestProgressInt(6033) == 1 && qm.haveItem(4260003, 1)) {
+ qm.sendNextPrev("You indeed have crafted a fine piece of Monster Crystal, I see. You passed! Now, I shall teach you the next steps of the Maker skill. Keep the monster crystal with you as well, it's your work.");
} else {
qm.sendNext("Hey, what's wrong? I did tell you to make a monster crystal to pass my test, didn't I? Buying one or crafting before the start of the test is NOT part of the deal. Go craft me an #b#t4260003##k.");
qm.dispose();
return;
}
- } else {
+ } else if (status == 2) {
+ qm.forceCompleteQuest();
+
var skillid = Math.floor(qm.getPlayer().getJob().getId() / 1000) * 10000000 + 1007;
qm.teachSkill(skillid, 2, 3, -1);
-
qm.gainExp(230000);
- qm.forceCompleteQuest();
qm.dispose();
}
}
diff --git a/scripts/quest/6036.js b/scripts/quest/6036.js
index 4e8767ca57..1407c20da6 100644
--- a/scripts/quest/6036.js
+++ b/scripts/quest/6036.js
@@ -48,14 +48,13 @@ function end(mode, type, selection) {
qm.dispose();
return;
}
- } else {
+ } else if (status == 2) {
+ qm.forceCompleteQuest();
+
qm.gainItem(4031980, -1);
-
var skillid = Math.floor(qm.getPlayer().getJob().getId() / 1000) * 10000000 + 1007;
qm.teachSkill(skillid, 3, 3, -1);
-
qm.gainExp(300000);
- qm.forceCompleteQuest();
qm.dispose();
}
diff --git a/scripts/quest/6410.js b/scripts/quest/6410.js
deleted file mode 100644
index 76b732b50b..0000000000
--- a/scripts/quest/6410.js
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- This file is part of the HeavenMS MapleStory Server
- Copyleft (L) 2016 - 2019 RonanLana
-
- 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 .
-*/
-/*
- Hypnotize skill quest
- */
-
-var status = -1;
-
-function end(mode, type, selection) {
- if (mode == -1) {
- qm.dispose();
- } else {
- if(mode == 0 && type > 0) {
- qm.dispose();
- return;
- }
-
- if (mode == 1)
- status++;
- else
- status--;
-
- if (status == 0) {
- if (qm.getQuestProgress(6410, 0) == 0) {
- qm.sendOk("You must save #r#p2095000##k first!");
- qm.dispose();
- } else {
- qm.sendNext("Again, thank you so much for rescuing me. I don't know how to repay you for all this... both Shulynch and you are the nicest people I have encountered. If you approach the mobs the same way you approached me, they may all end up becoming friends with you, as well. Please never lose the kindness you have in you.");
- }
- } else if (status == 1) {
- qm.sendNext("(Friends with the mobs... never lose the kindness.)\r\n\r\n #s5221009# #b#q5221009##k");
- } else if (status == 2) {
- qm.gainExp(1200000);
- qm.teachSkill(5221009, 0, 10, -1);
-
- qm.forceCompleteQuest();
- qm.dispose();
- }
- }
-}
\ No newline at end of file
diff --git a/scripts/quest/8185.js b/scripts/quest/8185.js
index b4623a147c..dccab63ba8 100644
--- a/scripts/quest/8185.js
+++ b/scripts/quest/8185.js
@@ -100,7 +100,8 @@ function end(mode, type, selection) {
//SpawnPetHandler.evolve(qm.getPlayer().getClient(), 5000029, after);
qm.sendOk("#bSWEET! IT WORKED!#k Your dragon has grown beautifully! #rYou may find your new pet under your 'CASH' inventory.\r #kIt used to be a #b #i5000029##t5000029##k, and now it's \r a #b#i" + after + "##t" + after + "##k!\r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0#\r\n#v"+after+"# #t"+after+"#");
- qm.dispose();
- }
+ } else if (status == 5) {
+ qm.dispose();
+ }
}
}
\ No newline at end of file
diff --git a/scripts/quest/8189.js b/scripts/quest/8189.js
index f14d596084..bc0d038f3a 100644
--- a/scripts/quest/8189.js
+++ b/scripts/quest/8189.js
@@ -47,37 +47,46 @@ function end(mode, type, selection) {
} else if (status == 1) {
qm.sendNextPrev("Then here we go...! #rHYAHH!#k");
} else if (status == 2) {
- var pet = 0;
- if (qm.getPlayer().getPet(0).getItemId() >= 5000029 && qm.getPlayer().getPet(0).getItemId() <= 5000033) {
- var pet = 0;
- } else if (qm.getPlayer().getPet(1).getItemId() >= 5000029 && qm.getPlayer().getPet(1).getItemId() <= 5000033) {
- var pet = 1;
- } else if (qm.getPlayer().getPet(2).getItemId() >= 5000029 && qm.getPlayer().getPet(2).getItemId() <= 5000033) {
- var pet = 2;
- } else {
- qm.sendOk("Something wrong, try again.");
- qm.dispose();
+ var petidx = -1;
+ var petItemid;
+ for (var i = 0; i < 3; i++) {
+ var pet = qm.getPlayer().getPet(pet);
+ if (pet != null) {
+ var id = pet.getItemId();
+ if (id >= 5000029 && id <= 5000033) {
+ petItemid = 5000030;
+ petidx = i;
+ break;
+ } else if (id >= 5000048 && id <= 5000053) { // thanks Conrad for noticing Robo pets not being able to re-evolve
+ petItemid = 5000049;
+ petidx = i;
+ break;
+ }
+ }
+ }
+
+ if (petidx == -1) {
+ qm.sendOk("Something wrong, try again.");
+ qm.dispose();
return;
- }
- var id = qm.getPlayer().getPet(pet).getItemId();
- if (id < 5000029 || id > 5000033) {
- qm.sendOk("Something wrong, try again.");
- qm.dispose();
- }
- var rand = 1 + Math.floor(Math.random() * 10);
- var after = 0;
- if (rand >= 1 && rand <= 3) {
- after = 5000030;
- } else if (rand >= 4 && rand <= 6) {
- after = 5000031;
- } else if (rand >= 7 && rand <= 9) {
- after = 5000032;
- } else if (rand == 10) {
- after = 5000033;
- } else {
- qm.sendOk("Something wrong. Try again.");
- qm.dispose();
- }
+ }
+
+ var pool = (petItemid == 5000030) ? 10 : 11;
+ do {
+ var rand = 1 + Math.floor(Math.random() * pool);
+ var after = 0;
+ if (rand >= 1 && rand <= 3) {
+ after = petItemid;
+ } else if (rand >= 4 && rand <= 6) {
+ after = petItemid + 1;
+ } else if (rand >= 7 && rand <= 9) {
+ after = petItemid + 2;
+ } else if (rand == 10) {
+ after = petItemid + 3;
+ } else {
+ after = petItemid + 4;
+ }
+ } while (after == pet.getItemId());
/*if (name.equals(MapleItemInformationProvider.getInstance().getName(id))) {
name = MapleItemInformationProvider.getInstance().getName(after);
@@ -85,10 +94,11 @@ function end(mode, type, selection) {
qm.gainMeso(-10000);
qm.gainItem(5380000, -1);
- qm.evolvePet(pet, after);
+ qm.evolvePet(petidx, after);
qm.sendOk("Woo! It worked again! #rYou may find your new pet under your 'CASH' inventory.\r #kIt used to be a #b#i" + id + "##t" + id + "##k, and now it's \r a#b #i" + after + "##t" + after + "##k! \r\n Come back with 10,000 mesos and another Rock of Evolution if you don't like it!\r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0#\r\n#v"+after+"# #t"+after+"#");
- qm.dispose();
- }
+ } else if (status == 3) {
+ qm.dispose();
+ }
}
}
\ No newline at end of file
diff --git a/scripts/quest/8219.js b/scripts/quest/8219.js
index d99e0bfd81..ff770041d5 100644
--- a/scripts/quest/8219.js
+++ b/scripts/quest/8219.js
@@ -22,9 +22,10 @@ function start(mode, type, selection) {
}
if (status == 0)
qm.sendAcceptDecline("The time is now, kid. We have all the preparations complete to further research for why all these oddities have been happening lately. I also must introduce you to my brother, Jack. ");
- if (status == 1){
+ else if (status == 1){
qm.sendOk("He is currently wandering around the Crimsonwood Mountain, past the sinister Phantom Forest, in the track to the Crimsonwood Keep. Your next destination is there, may your journey be a safe one.");
qm.forceStartQuest();
+ } else if (status == 2) {
qm.dispose();
}
}
@@ -48,14 +49,15 @@ function end(mode, type, selection) {
}
else if (status == 2){
if(qm.canHold(3992040, 1)) {
+ qm.forceCompleteQuest();
qm.gainItem(3992040, 1);
qm.gainExp(175000);
- qm.forceCompleteQuest();
+ qm.dispose();
}
else {
qm.sendOk("Hey, you don't have a slot in your SETUP inventory for what I have to give to you. Solve that minor issue of yours then talk to me.");
}
-
+ } else if (status == 3) {
qm.dispose();
- }
+ }
}
diff --git a/scripts/quest/8221.js b/scripts/quest/8221.js
index 07e77ed2e4..21a1976bc4 100644
--- a/scripts/quest/8221.js
+++ b/scripts/quest/8221.js
@@ -26,6 +26,7 @@ function start(mode, type, selection) {
else if (status == 1){
qm.sendOk("Okay, I need you to have these items on hand first: #b10 #t4010006##k, #b4 #t4032005##k and #b1 #t4004000##k. Go!");
qm.forceStartQuest();
- qm.dispose();
- }
+ } else if (status == 2) {
+ qm.dispose();
+ }
}
diff --git a/scripts/quest/8223.js b/scripts/quest/8223.js
index 84481e2964..da61f86149 100644
--- a/scripts/quest/8223.js
+++ b/scripts/quest/8223.js
@@ -22,9 +22,10 @@ function start(mode, type, selection) {
}
if (status == 0)
qm.sendAcceptDecline("Oh, Jack sent you here? Good timing, I'm planning alongside Jack and others to storm the Keep and retake it from the Twisted Masters what is ours by right. You seem ready to fight alongside us, right?");
- if (status == 1){
+ else if (status == 1){
qm.sendOk("Great! Your mission now is to rack down some numbers of their army and weaken their defenses by all effects. Defeat 75 of each: Windraider, Firebrand and Nightshadow, then return to me to report.");
qm.forceStartQuest();
- qm.dispose();
- }
+ } else if (status == 2) {
+ qm.dispose();
+ }
}
diff --git a/scripts/quest/8224.js b/scripts/quest/8224.js
index 04a3c52d39..95844d8e56 100644
--- a/scripts/quest/8224.js
+++ b/scripts/quest/8224.js
@@ -25,6 +25,7 @@ function start(mode, type, selection) {
else if (status == 1){
qm.sendOk("Ok. I need you to hunt down #bthose fake trees#k in the forest, and collect 50 of their drops as proof that you made your part on this.");
qm.forceStartQuest();
+ } else if (status == 2) {
qm.dispose();
}
}
diff --git a/scripts/quest/8225.js b/scripts/quest/8225.js
index 8bb382d08d..90fadcfb70 100644
--- a/scripts/quest/8225.js
+++ b/scripts/quest/8225.js
@@ -25,6 +25,7 @@ function start(mode, type, selection) {
else if (status == 1){
qm.sendOk("Very well. To prove your valor among our ranks, you must first pass on a little challenge: you have to be able to move extraordinaly well around here, known of all secrets these woods holds. Trace a #bmap of the Phantom Forest#k, then come talk to me. I shall then evaluate if you're worth to be with us.");
qm.forceStartQuest();
- qm.dispose();
- }
+ } else if (status == 2) {
+ qm.dispose();
+ }
}
diff --git a/scripts/quest/8226.js b/scripts/quest/8226.js
index 7f84f351b9..3c4fb90ae1 100644
--- a/scripts/quest/8226.js
+++ b/scripts/quest/8226.js
@@ -25,6 +25,7 @@ function start(mode, type, selection) {
else if (status == 1){
qm.sendOk("Your next mission is: defeat the Elderwraiths that roam this forest. These are a tough bunch though, so stay alert. I need you to bring me 100 #t4032010# as proof of your duty.");
qm.forceStartQuest();
- qm.dispose();
- }
+ } else if (status == 2) {
+ qm.dispose();
+ }
}
diff --git a/scripts/quest/8227.js b/scripts/quest/8227.js
index 4781e2d169..ab61a188d1 100644
--- a/scripts/quest/8227.js
+++ b/scripts/quest/8227.js
@@ -30,7 +30,7 @@ function start(mode, type, selection) {
} else {
qm.sendOk("Hey. There's no slot on your ETC.");
}
-
+ } else if (status == 2) {
qm.dispose();
}
}
@@ -53,7 +53,7 @@ function end(mode, type, selection) {
} else {
qm.sendOk("You don't brought the coded letter Jack said? Come on, kid, we need that to decipher our enemies' next step!");
}
-
+ } else if (status == 1){
qm.dispose();
}
}
diff --git a/scripts/quest/8228.js b/scripts/quest/8228.js
index a17465293f..ef54ea70ae 100644
--- a/scripts/quest/8228.js
+++ b/scripts/quest/8228.js
@@ -30,7 +30,7 @@ function start(mode, type, selection) {
} else {
qm.sendOk("Hey. There's no slot on your ETC.");
}
-
+ } else if (status == 2){
qm.dispose();
}
}
@@ -53,7 +53,7 @@ function end(mode, type, selection) {
} else {
qm.sendOk("I'm afraid you don't have the letter you claimed to have with you.");
}
-
+ } else if (status == 1) {
qm.dispose();
}
}
diff --git a/scripts/quest/8230.js b/scripts/quest/8230.js
index 0f3507e9a2..f1983e82d4 100644
--- a/scripts/quest/8230.js
+++ b/scripts/quest/8230.js
@@ -25,6 +25,7 @@ function start(mode, type, selection) {
else if (status == 1) {
qm.sendOk("That's the thing: the Twisted Masters, great figures that currently holds seize of the Crimsonwood Keep, have planned a large-scale attack to the New Leaf City, that may be happening on the next few days. I can't just stay here observing while they prepare for this attack. However, I can't just leave this position, I must keep an eye on their moves at all costs. There's where you enter: go find Lukan, knight of the past Crimsonwood Keep, that is currently wandering around the woods, and receive from him further orders, he knows what to do.");
qm.forceStartQuest();
+ } else if (status == 2) {
qm.dispose();
}
}
@@ -41,7 +42,7 @@ function end(mode, type, selection) {
} else {
qm.sendOk("The folks back there on the city are counting on you on this one. Please hurry up.");
}
-
- qm.dispose();
- }
+ } else if (status == 1) {
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/scripts/quest/8231.js b/scripts/quest/8231.js
index 29da40c564..8d339bb87e 100644
--- a/scripts/quest/8231.js
+++ b/scripts/quest/8231.js
@@ -28,6 +28,7 @@ function start(mode, type, selection) {
var reqs = "#r30 #t4032031##k";
qm.sendOk("Very well. Get me #r" + reqs + "#k, asap. The NLC is counting on you.");
qm.forceStartQuest();
+ } else if (status == 2) {
qm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/quest/8232.js b/scripts/quest/8232.js
index 29da40c564..8d339bb87e 100644
--- a/scripts/quest/8232.js
+++ b/scripts/quest/8232.js
@@ -28,6 +28,7 @@ function start(mode, type, selection) {
var reqs = "#r30 #t4032031##k";
qm.sendOk("Very well. Get me #r" + reqs + "#k, asap. The NLC is counting on you.");
qm.forceStartQuest();
+ } else if (status == 2) {
qm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/quest/8233.js b/scripts/quest/8233.js
index e6d894a7ab..40ff75b5ea 100644
--- a/scripts/quest/8233.js
+++ b/scripts/quest/8233.js
@@ -28,6 +28,7 @@ function start(mode, type, selection) {
var reqs = "#r30 #t4032011##k";
qm.sendOk("Very well. Get me #r" + reqs + "#k, asap. The NLC is counting on you.");
qm.forceStartQuest();
+ } else if (status == 2) {
qm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/quest/8234.js b/scripts/quest/8234.js
index e6d894a7ab..40ff75b5ea 100644
--- a/scripts/quest/8234.js
+++ b/scripts/quest/8234.js
@@ -28,6 +28,7 @@ function start(mode, type, selection) {
var reqs = "#r30 #t4032011##k";
qm.sendOk("Very well. Get me #r" + reqs + "#k, asap. The NLC is counting on you.");
qm.forceStartQuest();
+ } else if (status == 2) {
qm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/quest/8235.js b/scripts/quest/8235.js
index 3ec42e6726..1ea6062dd9 100644
--- a/scripts/quest/8235.js
+++ b/scripts/quest/8235.js
@@ -28,6 +28,7 @@ function start(mode, type, selection) {
var reqs = "#r1 #t4031903##k";
qm.sendOk("Very well. Get me #r" + reqs + "#k, asap. The NLC is counting on you.");
qm.forceStartQuest();
+ } else if (status == 2) {
qm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/quest/8236.js b/scripts/quest/8236.js
index 3ec42e6726..1ea6062dd9 100644
--- a/scripts/quest/8236.js
+++ b/scripts/quest/8236.js
@@ -28,6 +28,7 @@ function start(mode, type, selection) {
var reqs = "#r1 #t4031903##k";
qm.sendOk("Very well. Get me #r" + reqs + "#k, asap. The NLC is counting on you.");
qm.forceStartQuest();
+ } else if (status == 2) {
qm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/quest/8237.js b/scripts/quest/8237.js
index c756159db3..d47ec715ec 100644
--- a/scripts/quest/8237.js
+++ b/scripts/quest/8237.js
@@ -28,6 +28,7 @@ function start(mode, type, selection) {
var reqs = "#r1 #t4032013##k";
qm.sendOk("Very well. Get me #r" + reqs + "#k, asap. The NLC is counting on you.");
qm.forceStartQuest();
+ } else if (status == 2) {
qm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/quest/8238.js b/scripts/quest/8238.js
index c756159db3..d47ec715ec 100644
--- a/scripts/quest/8238.js
+++ b/scripts/quest/8238.js
@@ -28,6 +28,7 @@ function start(mode, type, selection) {
var reqs = "#r1 #t4032013##k";
qm.sendOk("Very well. Get me #r" + reqs + "#k, asap. The NLC is counting on you.");
qm.forceStartQuest();
+ } else if (status == 2) {
qm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/reactor/1209000.js b/scripts/reactor/1209000.js
index 2533d11888..a332e450d4 100644
--- a/scripts/reactor/1209000.js
+++ b/scripts/reactor/1209000.js
@@ -24,6 +24,10 @@
*/
function act() { // string visibility thanks to ProXAIMeRx & Glvelturall
- if (rm.isQuestStarted(6400)) rm.setQuestProgress(6400, 0, 2);
- rm.message("Real Bart has found. Return to Jonathan through portal.");
+ if (rm.isQuestStarted(6400)) {
+ rm.setQuestProgress(6400, 1, 2);
+ rm.setQuestProgress(6400, 6401, "q3");
+ }
+
+ rm.message("Real Bart has been found. Return to Jonathan through the portal.");
}
\ No newline at end of file
diff --git a/scripts/reactor/2008007.js b/scripts/reactor/2008007.js
new file mode 100644
index 0000000000..da63c803c2
--- /dev/null
+++ b/scripts/reactor/2008007.js
@@ -0,0 +1,29 @@
+/*
+ This file is part of the HeavenMS MapleStory Server
+ Copyleft (L) 2016 - 2018 RonanLana
+
+ 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 .
+*/
+
+/* @Author Ronan
+ *
+ * 2008007.js: OrbisPQ jail obstacle trigger
+*/
+
+function hit() {
+ var map = rm.getMap();
+ map.moveEnvironment("trap" + rm.getReactor().getName()[5], 1);
+}
\ No newline at end of file
diff --git a/scripts/reactor/2200001.js b/scripts/reactor/2200001.js
index 7c8117f80f..850a492c4d 100644
--- a/scripts/reactor/2200001.js
+++ b/scripts/reactor/2200001.js
@@ -28,5 +28,5 @@
function act(){
rm.playerMessage(5,"You have found a secret factory!");
- rm.warp(Math.random() < .5 ? 922000020 : 922000021);
+ rm.warp(Math.random() < .5 ? 922000020 : 922000021, 0);
}
\ No newline at end of file
diff --git a/sql/db_database.sql b/sql/db_database.sql
index 857857152e..c25e795167 100644
--- a/sql/db_database.sql
+++ b/sql/db_database.sql
@@ -1,4 +1,4 @@
-#EXECUTE THIS FIRST, THEN NEXT SQL: 'db_drops.sql'
+#EXECUTE THIS FIRST, THEN NEXT SQL: 'db_drops.sql'
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
@@ -80,6 +80,22 @@ CREATE TABLE IF NOT EXISTS `area_info` (
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+CREATE TABLE IF NOT EXISTS `bosslog_daily` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `characterid` int(11) NOT NULL,
+ `bosstype` enum('ZAKUM','HORNTAIL','PINKBEAN','SCARGA','PAPULATUS') NOT NULL,
+ `attempttime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
+CREATE TABLE IF NOT EXISTS `bosslog_weekly` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `characterid` int(11) NOT NULL,
+ `bosstype` enum('ZAKUM','HORNTAIL','PINKBEAN','SCARGA','PAPULATUS') NOT NULL,
+ `attempttime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
CREATE TABLE IF NOT EXISTS `bbs_replies` (
`replyid` int(10) unsigned NOT NULL AUTO_INCREMENT,
`threadid` int(10) unsigned NOT NULL,
@@ -10423,7 +10439,7 @@ INSERT IGNORE INTO `temp_data` (`dropperid`, `itemid`, `minimum_quantity`, `maxi
(3230104, 4031209, 1, 1, 3072, 500000),
(3230306, 4031159, 1, 1, 2074, 500000),
(9500400, 4031224, 1, 1, 3607, 1000000),
-(9500400, 4031223, 1, 1, 3607, 1000000),
+(9500400, 4031223, 1, 1, 3608, 1000000), # thanks Lame for noticing Hongbu's gourd unavailable
(9420003, 4031400, 1, 1, 8761, 1000000),
(9420001, 4031401, 1, 1, 8761, 1000000),
(9300097, 4031472, 1, 1, 6301, 100000),
@@ -12811,9 +12827,10 @@ CREATE TABLE IF NOT EXISTS `dueypackages` (
`ReceiverId` int(10) unsigned NOT NULL,
`SenderName` varchar(13) NOT NULL,
`Mesos` int(10) unsigned DEFAULT '0',
- `TimeStamp` varchar(10) NOT NULL,
- `Message` varchar(200) NOT NULL DEFAULT "",
+ `TimeStamp` timestamp NOT NULL DEFAULT '2015-01-01 05:00:00',
+ `Message` varchar(200) NULL,
`Checked` tinyint(1) unsigned DEFAULT '1',
+ `Type` tinyint(1) unsigned DEFAULT '0',
PRIMARY KEY (`PackageId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
@@ -12836,17 +12853,26 @@ CREATE TABLE IF NOT EXISTS `famelog` (
CREATE TABLE IF NOT EXISTS `family_character` (
`cid` int(11) NOT NULL,
`familyid` int(11) NOT NULL,
- `rank` int(11) NOT NULL,
- `reputation` int(11) NOT NULL,
- `todaysrep` int(11) NOT NULL,
- `totaljuniors` int(11) NOT NULL,
- `name` varchar(255) NOT NULL,
- `juniorsadded` int(11) NOT NULL,
- `totalreputation` int(11) NOT NULL,
+ `seniorid` int(11) NOT NULL,
+ `reputation` int(11) NOT NULL DEFAULT '0',
+ `todaysrep` int(11) NOT NULL DEFAULT '0',
+ `totalreputation` int(11) NOT NULL DEFAULT '0',
+ `reptosenior` int(11) NOT NULL DEFAULT '0',
+ `precepts` varchar(200) DEFAULT NULL,
+ `lastresettime` BIGINT(20) NOT NULL DEFAULT '0',
PRIMARY KEY (`cid`),
INDEX (cid, familyid)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+CREATE TABLE IF NOT EXISTS `family_entitlement` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `charid` int(11) NOT NULL,
+ `entitlementid` int(11) NOT NULL,
+ `timestamp` BIGINT(20) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ INDEX (charid)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
CREATE TABLE IF NOT EXISTS `fredstorage` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`cid` int(10) unsigned NOT NULL,
@@ -13032,36 +13058,36 @@ INSERT IGNORE INTO `makercreatedata` (`id`, `itemid`, `req_level`, `req_maker_le
(0, 4250900, 45, 1, 110000, 0, 0, 0, 1, 0),
(0, 4251000, 45, 1, 110000, 0, 0, 0, 1, 0),
(0, 4251100, 45, 1, 110000, 0, 0, 0, 1, 0),
- (0, 4251300, 75, 2, 164000, 0, 0, 0, 1, 0),
- (0, 4251400, 75, 2, 164000, 0, 0, 0, 1, 0),
- (0, 4250001, 45, 1, 328000, 0, 0, 0, 1, 0),
- (0, 4250101, 45, 1, 328000, 0, 0, 0, 1, 0),
- (0, 4250201, 45, 1, 328000, 0, 0, 0, 1, 0),
- (0, 4250301, 45, 1, 328000, 0, 0, 0, 1, 0),
- (0, 4250401, 45, 1, 328000, 0, 0, 0, 1, 0),
- (0, 4250501, 45, 1, 328000, 0, 0, 0, 1, 0),
- (0, 4250601, 45, 1, 328000, 0, 0, 0, 1, 0),
- (0, 4250701, 45, 1, 328000, 0, 0, 0, 1, 0),
- (0, 4250801, 45, 1, 328000, 0, 0, 0, 1, 0),
- (0, 4250901, 45, 1, 328000, 0, 0, 0, 1, 0),
- (0, 4251001, 45, 1, 328000, 0, 0, 0, 1, 0),
- (0, 4251101, 45, 1, 328000, 0, 0, 0, 1, 0),
- (0, 4251301, 75, 2, 491000, 0, 0, 0, 1, 0),
- (0, 4251401, 75, 2, 491000, 0, 0, 0, 1, 0),
- (0, 4250002, 45, 2, 546000, 0, 0, 0, 1, 0),
- (0, 4250102, 45, 2, 546000, 0, 0, 0, 1, 0),
- (0, 4250202, 45, 2, 546000, 0, 0, 0, 1, 0),
- (0, 4250302, 45, 2, 546000, 0, 0, 0, 1, 0),
- (0, 4250402, 45, 2, 546000, 0, 0, 0, 1, 0),
- (0, 4250502, 45, 2, 546000, 0, 0, 0, 1, 0),
- (0, 4250602, 45, 2, 546000, 0, 0, 0, 1, 0),
- (0, 4250702, 45, 2, 546000, 0, 0, 0, 1, 0),
- (0, 4250802, 45, 2, 546000, 0, 0, 0, 1, 0),
- (0, 4250902, 45, 2, 546000, 0, 0, 0, 1, 0),
- (0, 4251002, 45, 2, 546000, 0, 0, 0, 1, 0),
- (0, 4251102, 45, 2, 546000, 0, 0, 0, 1, 0),
- (0, 4251302, 75, 3, 819000, 0, 0, 0, 1, 0),
- (0, 4251402, 75, 3, 819000, 0, 0, 0, 1, 0),
+ (0, 4251300, 75, 2, 165000, 0, 0, 0, 1, 0),
+ (0, 4251400, 75, 2, 165000, 0, 0, 0, 1, 0),
+ (0, 4250001, 45, 1, 330000, 0, 0, 0, 1, 0),
+ (0, 4250101, 45, 1, 330000, 0, 0, 0, 1, 0),
+ (0, 4250201, 45, 1, 330000, 0, 0, 0, 1, 0),
+ (0, 4250301, 45, 1, 330000, 0, 0, 0, 1, 0),
+ (0, 4250401, 45, 1, 330000, 0, 0, 0, 1, 0),
+ (0, 4250501, 45, 1, 330000, 0, 0, 0, 1, 0),
+ (0, 4250601, 45, 1, 330000, 0, 0, 0, 1, 0),
+ (0, 4250701, 45, 1, 330000, 0, 0, 0, 1, 0),
+ (0, 4250801, 45, 1, 330000, 0, 0, 0, 1, 0),
+ (0, 4250901, 45, 1, 330000, 0, 0, 0, 1, 0),
+ (0, 4251001, 45, 1, 330000, 0, 0, 0, 1, 0),
+ (0, 4251101, 45, 1, 330000, 0, 0, 0, 1, 0),
+ (0, 4251301, 75, 2, 495000, 0, 0, 0, 1, 0),
+ (0, 4251401, 75, 2, 495000, 0, 0, 0, 1, 0),
+ (0, 4250002, 45, 2, 550000, 0, 0, 0, 1, 0),
+ (0, 4250102, 45, 2, 550000, 0, 0, 0, 1, 0),
+ (0, 4250202, 45, 2, 550000, 0, 0, 0, 1, 0),
+ (0, 4250302, 45, 2, 550000, 0, 0, 0, 1, 0),
+ (0, 4250402, 45, 2, 550000, 0, 0, 0, 1, 0),
+ (0, 4250502, 45, 2, 550000, 0, 0, 0, 1, 0),
+ (0, 4250602, 45, 2, 550000, 0, 0, 0, 1, 0),
+ (0, 4250702, 45, 2, 550000, 0, 0, 0, 1, 0),
+ (0, 4250802, 45, 2, 550000, 0, 0, 0, 1, 0),
+ (0, 4250902, 45, 2, 550000, 0, 0, 0, 1, 0),
+ (0, 4251002, 45, 2, 550000, 0, 0, 0, 1, 0),
+ (0, 4251102, 45, 2, 550000, 0, 0, 0, 1, 0),
+ (0, 4251302, 75, 3, 825000, 0, 0, 0, 1, 0),
+ (0, 4251402, 75, 3, 825000, 0, 0, 0, 1, 0),
(0, 4001174, 45, 1, 0, 4031966, 0, 0, 1, 0),
(0, 4001175, 50, 1, 0, 4031967, 0, 0, 1, 0),
(0, 4001176, 55, 1, 0, 4031968, 0, 0, 10, 0),
@@ -13080,6 +13106,8 @@ INSERT IGNORE INTO `makercreatedata` (`id`, `itemid`, `req_level`, `req_maker_le
(0, 4032312, 70, 1, 0, 0, 0, 0, 1, 0),
(0, 2041058, 50, 1, 55000, 0, 1122013, 0, 1, 0),
(0, 2040727, 50, 1, 55000, 0, 1122013, 0, 1, 0),
+ (0, 4260007, 105, 3, 2200000, 4001126, 0, 0, 5, 0),
+ (0, 4260008, 105, 3, 5500000, 4001126, 0, 0, 10, 0),
(1, 1002028, 45, 1, 55000, 0, 0, 4130018, 1, 1),
(1, 1002085, 45, 1, 50000, 0, 0, 4130018, 1, 1),
(1, 1002086, 45, 1, 41000, 0, 0, 4130018, 1, 1),
@@ -13963,6 +13991,10 @@ INSERT IGNORE INTO `makerrecipedata` (`itemid`, `req_item`, `count`) VALUES
(2041058, 4000299, 10),
(2040727, 4000159, 50),
(2040727, 4000299, 10),
+ (4260007, 4260006, 100),
+ (4260007, 4001126, 5),
+ (4260008, 4260007, 50),
+ (4260008, 4001126, 5),
(1002028, 4007001, 5),
(1002028, 4260000, 5),
(1002085, 4007002, 5),
@@ -14808,11 +14840,11 @@ INSERT IGNORE INTO `makerrecipedata` (`itemid`, `req_item`, `count`) VALUES
(1372016, 4011002, 3),
(1372016, 4260003, 26),
(1382008, 4011002, 3),
- (1382008, 4260003, 26),
+ (1382008, 4260004, 26),
(1372009, 4011002, 4),
(1372009, 4260004, 28),
(1382035, 4011002, 4),
- (1382035, 4260004, 28),
+ (1382035, 4260005, 28),
(1372010, 4011003, 4),
(1372010, 4260005, 30),
(1372032, 4011003, 5),
@@ -15450,7 +15482,7 @@ INSERT IGNORE INTO `makerrecipedata` (`itemid`, `req_item`, `count`) VALUES
(1072194, 4260004, 9),
(1072195, 4007006, 9),
(1072195, 4260004, 9),
- (1072213, 4007001, 10),
+ (1072213, 4007003, 10),
(1072213, 4260005, 10),
(1072214, 4007002, 10),
(1072214, 4260005, 10),
@@ -16293,6 +16325,9 @@ CREATE TABLE IF NOT EXISTS `mts_items` (
`position` int(11) DEFAULT '0',
`upgradeslots` int(11) DEFAULT '0',
`level` int(11) DEFAULT '0',
+ `itemlevel` int(11) NOT NULL DEFAULT '1',
+ `itemexp` int(11) unsigned NOT NULL DEFAULT '0',
+ `ringid` int(11) NOT NULL DEFAULT '-1',
`str` int(11) DEFAULT '0',
`dex` int(11) DEFAULT '0',
`int` int(11) DEFAULT '0',
@@ -16316,9 +16351,22 @@ CREATE TABLE IF NOT EXISTS `mts_items` (
`transfer` int(2) DEFAULT '0',
`vicious` int(2) unsigned NOT NULL DEFAULT '0',
`flag` int(2) unsigned NOT NULL DEFAULT '0',
+ `expiration` bigint(20) NOT NULL DEFAULT '-1',
+ `giftFrom` varchar(26) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+CREATE TABLE IF NOT EXISTS `namechanges` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `characterid` int(11) NOT NULL,
+ `old` varchar(13) NOT NULL,
+ `new` varchar(13) NOT NULL,
+ `requestTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `completionTime` timestamp NULL,
+ PRIMARY KEY (`id`),
+ INDEX (characterid)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
CREATE TABLE IF NOT EXISTS `newyear` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`senderid` int(10) NOT NULL DEFAULT '-1',
@@ -16415,7 +16463,7 @@ INSERT INTO `nxcoupons` (`id`, `couponid`, `rate`, `activeday`, `starthour`, `en
(40,5360042,2,254,0,24);
CREATE TABLE IF NOT EXISTS `pets` (
- `petid` int(10) unsigned NOT NULL AUTO_INCREMENT,
+ `petid` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(13) DEFAULT NULL,
`level` int(10) unsigned NOT NULL,
`closeness` int(10) unsigned NOT NULL,
@@ -16425,11 +16473,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 ,
+ `petid` int(11) unsigned NOT NULL ,
`itemid` int(10) unsigned NOT NULL ,
- PRIMARY KEY (`id`)
+ PRIMARY KEY (`id`),
+ CONSTRAINT `fk_petignorepetid` FOREIGN KEY (`petid`) REFERENCES `pets` (`petid`) ON DELETE CASCADE # thanks Optimist for noticing queries over petid taking too long, shavit for pointing out an improvement using foreign key
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `playerdiseases` (
@@ -17383,7 +17433,7 @@ CREATE TABLE IF NOT EXISTS `reports` (
`victimid` int(11) NOT NULL,
`reason` tinyint(4) NOT NULL,
`chatlog` text NOT NULL,
- `status` text NOT NULL,
+ `description` text NOT NULL, # correct field name, thanks resinate
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
@@ -20811,6 +20861,25 @@ INSERT INTO `shopitems` (`shopitemid`, `shopid`, `itemid`, `price`, `pitch`, `po
(6531, 1337, 2040711, 1, 0, 62),
(6532, 1337, 2340000, 1, 0, 63),
(20020, 1337, 1082149, 1, 0, 64),
+(20255, 1337, 2044503, 1, 0, 86), # 20255~20273: thanks to ozanrijen
+(20256, 1337, 2044703, 1, 0, 87),
+(20257, 1337, 2044603, 1, 0, 88),
+(20258, 1337, 2043303, 1, 0, 89),
+(20259, 1337, 2043103, 1, 0, 90),
+(20260, 1337, 2043203, 1, 0, 91),
+(20261, 1337, 2043003, 1, 0, 92),
+(20262, 1337, 2044403, 1, 0, 93),
+(20263, 1337, 2044303, 1, 0, 94),
+(20264, 1337, 2043803, 1, 0, 95),
+(20265, 1337, 2044103, 1, 0, 96),
+(20266, 1337, 2044203, 1, 0, 97),
+(20267, 1337, 2044003, 1, 0, 98),
+(20268, 1337, 2043703, 1, 0, 99),
+(20269, 1337, 2040806, 1, 0, 100),
+(20270, 1337, 2040007, 1, 0, 101),
+(20271, 1337, 2040506, 1, 0, 102),
+(20272, 1337, 2040710, 1, 0, 103),
+(20273, 1337, 2040711, 1, 0, 104),
(6533, 9000069, 2022503, 0, 5, 1),
(6534, 9000069, 2000004, 0, 5, 2),
(6535, 9000069, 2022514, 0, 10, 3),
@@ -21357,7 +21426,8 @@ CREATE TABLE IF NOT EXISTS `skills` (
`skilllevel` int(11) NOT NULL DEFAULT '0',
`masterlevel` int(11) NOT NULL DEFAULT '0',
`expiration` bigint(20) NOT NULL DEFAULT '-1',
- PRIMARY KEY (`id`)
+ PRIMARY KEY (`id`),
+ UNIQUE INDEX `skillpair` (`skillid`, `characterid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `specialcashitems` (
@@ -21395,12 +21465,29 @@ CREATE TABLE IF NOT EXISTS `wishlists` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+CREATE TABLE IF NOT EXISTS `worldtransfers` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `characterid` int(11) NOT NULL,
+ `from` tinyint(3) NOT NULL,
+ `to` tinyint(3) NOT NULL,
+ `requestTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `completionTime` timestamp NULL,
+ PRIMARY KEY (`id`),
+ INDEX (characterid)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
ALTER TABLE `dueyitems`
ADD CONSTRAINT `dueyitems_ibfk_1` FOREIGN KEY (`PackageId`) REFERENCES `dueypackages` (`PackageId`) ON DELETE CASCADE;
ALTER TABLE `famelog`
ADD CONSTRAINT `famelog_ibfk_1` FOREIGN KEY (`characterid`) REFERENCES `characters` (`id`) ON DELETE CASCADE;
+
+ALTER TABLE `family_character`
+ ADD CONSTRAINT `family_character_ibfk_1` FOREIGN KEY (`cid`) REFERENCES `characters` (`id`) ON DELETE CASCADE;
+
+ALTER TABLE `skills`
+ ADD CONSTRAINT `skills_chrid_fk` FOREIGN KEY (`characterid`) REFERENCES `characters` (`id`) ON DELETE CASCADE; # thanks Shavit
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
diff --git a/sql/db_drops.sql b/sql/db_drops.sql
index 568041c086..d17bc0adde 100644
--- a/sql/db_drops.sql
+++ b/sql/db_drops.sql
@@ -17932,7 +17932,7 @@ USE `heavenms`;
(8220005, 1002382, 1, 1, 0, 40000),
(8220005, 1482012, 1, 1, 0, 40000),
(8800002, 4001083, 1, 1, 0, 7000),
-(8800002, 4032133, 1, 1, 0, 10000),
+(8800002, 4032133, 1, 1, 0, 420000),
(8800002, 2000005, 1, 4, 0, 40000),
(8800002, 2020015, 1, 4, 0, 3000),
(8800002, 2000006, 1, 4, 0, 40000),
@@ -23926,527 +23926,528 @@ SET minimum_quantity = CASE
UPDATE drop_data SET `chance`=1287 WHERE `chance`=1500;
# MapleSkillbookChanceFetcher! Tuning up some skillbook drop chances in order to fit their dropper's availability (whether's a boss or not) and level.
+ # thanks unnqca for reporting some skillbooks having unusually high drop chances.
REPLACE INTO drop_data (`dropperid`, `itemid`, `minimum_quantity`, `maximum_quantity`, `questid`, `chance`) VALUES
(851000, 2290132, 1, 1, 0, 3861),
-(7090000, 2290087, 1, 1, 0, 40000),
-(8090000, 2290045, 1, 1, 0, 40000),
-(8140103, 2290044, 1, 1, 0, 2000),
-(8140511, 2290009, 1, 1, 0, 2000),
-(8140511, 2290050, 1, 1, 0, 2000),
-(8140511, 2290083, 1, 1, 0, 2000),
-(8140511, 2290134, 1, 1, 0, 6000),
-(8140512, 2290013, 1, 1, 0, 2000),
-(8140512, 2290067, 1, 1, 0, 2000),
-(8140512, 2290082, 1, 1, 0, 2000),
-(8140512, 2290097, 1, 1, 0, 2000),
-(8140512, 2290116, 1, 1, 0, 2000),
-(8140512, 2290131, 1, 1, 0, 6000),
-(8140600, 2290132, 1, 1, 0, 6000),
-(8140700, 2290106, 1, 1, 0, 2000),
-(8140700, 2290126, 1, 1, 0, 6000),
-(8140701, 2290122, 1, 1, 0, 2000),
-(8140702, 2290112, 1, 1, 0, 2000),
-(8140703, 2290088, 1, 1, 0, 2000),
-(8140703, 2290099, 1, 1, 0, 2000),
-(8141000, 2290082, 1, 1, 0, 2000),
-(8141000, 2290097, 1, 1, 0, 2000),
-(8141100, 2280005, 1, 1, 0, 2000),
-(8141300, 2290098, 1, 1, 0, 2000),
-(8142100, 2290032, 1, 1, 0, 2000),
-(8142100, 2290082, 1, 1, 0, 2000),
-(8142100, 2290114, 1, 1, 0, 2000),
-(8143000, 2280004, 1, 1, 0, 2000),
-(8150000, 2280013, 1, 1, 0, 120000),
-(8150000, 2290070, 1, 1, 0, 40000),
-(8150000, 2290091, 1, 1, 0, 40000),
-(8150100, 2290042, 1, 1, 0, 2000),
-(8150100, 2290053, 1, 1, 0, 2000),
-(8150100, 2290073, 1, 1, 0, 2000),
-(8150100, 2290102, 1, 1, 0, 2000),
-(8150100, 2290118, 1, 1, 0, 2000),
-(8150101, 2290017, 1, 1, 0, 2000),
-(8150101, 2290021, 1, 1, 0, 2000),
-(8150101, 2290035, 1, 1, 0, 2000),
-(8150101, 2290042, 1, 1, 0, 2000),
-(8150101, 2290052, 1, 1, 0, 2000),
-(8150101, 2290102, 1, 1, 0, 2000),
-(8150200, 2290024, 1, 1, 0, 2000),
-(8150200, 2290100, 1, 1, 0, 2000),
-(8150200, 2290135, 1, 1, 0, 6000),
-(8150201, 2290004, 1, 1, 0, 2000),
-(8150201, 2290006, 1, 1, 0, 2000),
-(8150201, 2290024, 1, 1, 0, 2000),
-(8150201, 2290036, 1, 1, 0, 2000),
-(8150201, 2290056, 1, 1, 0, 2000),
-(8150201, 2290072, 1, 1, 0, 2000),
-(8150201, 2290078, 1, 1, 0, 2000),
-(8150201, 2290117, 1, 1, 0, 2000),
-(8150300, 2290003, 1, 1, 0, 2000),
-(8150300, 2290033, 1, 1, 0, 2000),
-(8150300, 2290111, 1, 1, 0, 2000),
-(8150300, 2290120, 1, 1, 0, 2000),
-(8150300, 2290127, 1, 1, 0, 6000),
-(8150301, 2290023, 1, 1, 0, 2000),
-(8150301, 2290029, 1, 1, 0, 2000),
-(8150301, 2290101, 1, 1, 0, 2000),
-(8150301, 2290107, 1, 1, 0, 2000),
-(8150302, 2290010, 1, 1, 0, 2000),
-(8150302, 2290019, 1, 1, 0, 2000),
-(8150302, 2290026, 1, 1, 0, 2000),
-(8150302, 2290076, 1, 1, 0, 2000),
-(8150302, 2290085, 1, 1, 0, 2000),
-(8150302, 2290096, 1, 1, 0, 2000),
-(8150302, 2290113, 1, 1, 0, 2000),
-(8150302, 2290119, 1, 1, 0, 2000),
-(8150302, 2290128, 1, 1, 0, 6000),
-(8160000, 2290017, 1, 1, 0, 2000),
-(8160000, 2290045, 1, 1, 0, 2000),
-(8160000, 2290065, 1, 1, 0, 2000),
-(8160000, 2290067, 1, 1, 0, 2000),
-(8160000, 2290081, 1, 1, 0, 2000),
-(8170000, 2290012, 1, 1, 0, 2000),
-(8170000, 2290086, 1, 1, 0, 2000),
-(8170000, 2290087, 1, 1, 0, 2000),
-(8170000, 2290134, 1, 1, 0, 6000),
-(8180000, 2290002, 1, 1, 0, 40000),
-(8180000, 2290003, 1, 1, 0, 40000),
-(8180000, 2290014, 1, 1, 0, 40000),
-(8180000, 2290015, 1, 1, 0, 40000),
-(8180000, 2290030, 1, 1, 0, 40000),
-(8180000, 2290035, 1, 1, 0, 40000),
-(8180000, 2290036, 1, 1, 0, 40000),
-(8180000, 2290063, 1, 1, 0, 40000),
-(8180000, 2290080, 1, 1, 0, 40000),
-(8180000, 2290098, 1, 1, 0, 40000),
-(8180000, 2290101, 1, 1, 0, 40000),
-(8180000, 2290117, 1, 1, 0, 40000),
-(8180000, 2290130, 1, 1, 0, 120000),
-(8180001, 2290018, 1, 1, 0, 40000),
-(8180001, 2290019, 1, 1, 0, 40000),
-(8180001, 2290032, 1, 1, 0, 40000),
-(8180001, 2290042, 1, 1, 0, 40000),
-(8180001, 2290058, 1, 1, 0, 40000),
-(8180001, 2290059, 1, 1, 0, 40000),
-(8180001, 2290068, 1, 1, 0, 40000),
-(8180001, 2290069, 1, 1, 0, 40000),
-(8180001, 2290072, 1, 1, 0, 40000),
-(8180001, 2290092, 1, 1, 0, 40000),
-(8180001, 2290099, 1, 1, 0, 40000),
-(8180001, 2290100, 1, 1, 0, 40000),
-(8180001, 2290102, 1, 1, 0, 40000),
-(8180001, 2290119, 1, 1, 0, 40000),
-(8180001, 2290128, 1, 1, 0, 120000),
-(8190000, 2280016, 1, 1, 0, 6000),
-(8190000, 2290030, 1, 1, 0, 2000),
-(8190000, 2290044, 1, 1, 0, 2000),
-(8190000, 2290054, 1, 1, 0, 2000),
-(8190000, 2290066, 1, 1, 0, 2000),
-(8190000, 2290075, 1, 1, 0, 2000),
-(8190000, 2290092, 1, 1, 0, 2000),
-(8190000, 2290103, 1, 1, 0, 2000),
-(8190002, 2290000, 1, 1, 0, 2000),
-(8190002, 2290008, 1, 1, 0, 2000),
-(8190002, 2290018, 1, 1, 0, 2000),
-(8190002, 2290038, 1, 1, 0, 2000),
-(8190002, 2290060, 1, 1, 0, 2000),
-(8190002, 2290080, 1, 1, 0, 2000),
-(8190002, 2290124, 1, 1, 0, 2000),
-(8190003, 2280013, 1, 1, 0, 6000),
-(8190003, 2290007, 1, 1, 0, 2000),
-(8190003, 2290012, 1, 1, 0, 2000),
-(8190003, 2290014, 1, 1, 0, 2000),
-(8190003, 2290033, 1, 1, 0, 2000),
-(8190003, 2290045, 1, 1, 0, 2000),
-(8190003, 2290050, 1, 1, 0, 2000),
-(8190003, 2290055, 1, 1, 0, 2000),
-(8190003, 2290062, 1, 1, 0, 2000),
-(8190003, 2290063, 1, 1, 0, 2000),
-(8190003, 2290070, 1, 1, 0, 2000),
-(8190003, 2290086, 1, 1, 0, 2000),
-(8190003, 2290108, 1, 1, 0, 2000),
-(8190003, 2290133, 1, 1, 0, 6000),
-(8190004, 2290002, 1, 1, 0, 2000),
-(8190004, 2290009, 1, 1, 0, 2000),
-(8190004, 2290021, 1, 1, 0, 2000),
-(8190004, 2290034, 1, 1, 0, 2000),
-(8190004, 2290041, 1, 1, 0, 2000),
-(8190004, 2290052, 1, 1, 0, 2000),
-(8190004, 2290053, 1, 1, 0, 2000),
-(8190004, 2290058, 1, 1, 0, 2000),
-(8190004, 2290068, 1, 1, 0, 2000),
-(8190004, 2290071, 1, 1, 0, 2000),
-(8190004, 2290073, 1, 1, 0, 2000),
-(8190004, 2290090, 1, 1, 0, 2000),
-(8190004, 2290112, 1, 1, 0, 2000),
-(8190004, 2290121, 1, 1, 0, 2000),
-(8190004, 2290130, 1, 1, 0, 6000),
-(8190005, 2290000, 1, 1, 0, 2000),
-(8190005, 2290008, 1, 1, 0, 2000),
-(8190005, 2290018, 1, 1, 0, 2000),
-(8190005, 2290038, 1, 1, 0, 2000),
-(8190005, 2290060, 1, 1, 0, 2000),
-(8190005, 2290080, 1, 1, 0, 2000),
-(8190005, 2290124, 1, 1, 0, 2000),
-(8200000, 2290005, 1, 1, 0, 2000),
-(8200000, 2290011, 1, 1, 0, 2000),
-(8200000, 2290114, 1, 1, 0, 2000),
-(8200001, 2280015, 1, 1, 0, 6000),
-(8200001, 2290050, 1, 1, 0, 2000),
-(8200001, 2290059, 1, 1, 0, 2000),
-(8200001, 2290065, 1, 1, 0, 2000),
-(8200001, 2290129, 1, 1, 0, 6000),
-(8200002, 2290062, 1, 1, 0, 2000),
-(8200002, 2290066, 1, 1, 0, 2000),
-(8200002, 2290070, 1, 1, 0, 2000),
-(8200002, 2290131, 1, 1, 0, 6000),
-(8200002, 2290139, 1, 1, 0, 6000),
-(8200003, 2290012, 1, 1, 0, 2000),
-(8200003, 2290056, 1, 1, 0, 2000),
-(8200003, 2290071, 1, 1, 0, 2000),
-(8200003, 2290101, 1, 1, 0, 2000),
-(8200003, 2290136, 1, 1, 0, 6000),
-(8200004, 2280016, 1, 1, 0, 6000),
-(8200004, 2290069, 1, 1, 0, 2000),
-(8200004, 2290072, 1, 1, 0, 2000),
-(8200004, 2290073, 1, 1, 0, 2000),
-(8200004, 2290127, 1, 1, 0, 6000),
-(8200004, 2290134, 1, 1, 0, 6000),
-(8200005, 2280014, 1, 1, 0, 6000),
-(8200005, 2290078, 1, 1, 0, 2000),
-(8200005, 2290079, 1, 1, 0, 2000),
-(8200005, 2290095, 1, 1, 0, 2000),
-(8200006, 2290003, 1, 1, 0, 2000),
-(8200006, 2290064, 1, 1, 0, 2000),
-(8200006, 2290076, 1, 1, 0, 2000),
-(8200006, 2290077, 1, 1, 0, 2000),
-(8200006, 2290129, 1, 1, 0, 6000),
-(8200006, 2290138, 1, 1, 0, 6000),
-(8200007, 2290006, 1, 1, 0, 2000),
-(8200007, 2290007, 1, 1, 0, 2000),
-(8200007, 2290011, 1, 1, 0, 2000),
-(8200007, 2290016, 1, 1, 0, 2000),
-(8200007, 2290125, 1, 1, 0, 2000),
-(8200007, 2290136, 1, 1, 0, 6000),
-(8200008, 2290006, 1, 1, 0, 2000),
-(8200008, 2290051, 1, 1, 0, 2000),
-(8200008, 2290121, 1, 1, 0, 2000),
-(8200008, 2290122, 1, 1, 0, 2000),
-(8200008, 2290133, 1, 1, 0, 6000),
-(8200009, 2290013, 1, 1, 0, 2000),
-(8200009, 2290016, 1, 1, 0, 2000),
-(8200009, 2290031, 1, 1, 0, 2000),
-(8200009, 2290039, 1, 1, 0, 2000),
-(8200010, 2290026, 1, 1, 0, 2000),
-(8200010, 2290059, 1, 1, 0, 2000),
-(8200010, 2290088, 1, 1, 0, 2000),
-(8200010, 2290089, 1, 1, 0, 2000),
-(8200010, 2290127, 1, 1, 0, 6000),
-(8200011, 2290001, 1, 1, 0, 3000),
-(8200011, 2290040, 1, 1, 0, 3000),
-(8200011, 2290046, 1, 1, 0, 3000),
-(8200011, 2290048, 1, 1, 0, 3000),
-(8200011, 2290049, 1, 1, 0, 3000),
-(8200011, 2290114, 1, 1, 0, 3000),
-(8200011, 2290137, 1, 1, 0, 9000),
-(8200012, 2290041, 1, 1, 0, 3000),
-(8200012, 2290092, 1, 1, 0, 3000),
-(8200012, 2290093, 1, 1, 0, 3000),
-(8200012, 2290115, 1, 1, 0, 3000),
-(8200012, 2290137, 1, 1, 0, 9000),
-(8200012, 2290139, 1, 1, 0, 9000),
-(8220002, 2290020, 1, 1, 0, 40000),
-(8220002, 2290081, 1, 1, 0, 40000),
-(8220002, 2290085, 1, 1, 0, 40000),
-(8220002, 2290133, 1, 1, 0, 120000),
-(8220003, 2290006, 1, 1, 0, 40000),
-(8220003, 2290030, 1, 1, 0, 40000),
-(8220003, 2290031, 1, 1, 0, 40000),
-(8220003, 2290032, 1, 1, 0, 40000),
-(8220003, 2290033, 1, 1, 0, 40000),
-(8220003, 2290060, 1, 1, 0, 40000),
-(8220003, 2290061, 1, 1, 0, 40000),
-(8220003, 2290076, 1, 1, 0, 40000),
-(8220003, 2290077, 1, 1, 0, 40000),
-(8220003, 2290104, 1, 1, 0, 40000),
-(8220003, 2290105, 1, 1, 0, 40000),
-(8220003, 2290117, 1, 1, 0, 40000),
-(8220003, 2290118, 1, 1, 0, 40000),
-(8220004, 2290018, 1, 1, 0, 40000),
-(8220004, 2290019, 1, 1, 0, 40000),
-(8220004, 2290024, 1, 1, 0, 40000),
-(8220004, 2290025, 1, 1, 0, 40000),
-(8220004, 2290058, 1, 1, 0, 40000),
-(8220004, 2290059, 1, 1, 0, 40000),
-(8220004, 2290076, 1, 1, 0, 40000),
-(8220004, 2290077, 1, 1, 0, 40000),
-(8220004, 2290106, 1, 1, 0, 40000),
-(8220004, 2290127, 1, 1, 0, 120000),
-(8220004, 2290134, 1, 1, 0, 120000),
-(8220005, 2290002, 1, 1, 0, 60000),
-(8220005, 2290003, 1, 1, 0, 60000),
-(8220005, 2290036, 1, 1, 0, 60000),
-(8220005, 2290037, 1, 1, 0, 60000),
-(8220005, 2290055, 1, 1, 0, 60000),
-(8220005, 2290080, 1, 1, 0, 60000),
-(8220005, 2290099, 1, 1, 0, 60000),
-(8220005, 2290131, 1, 1, 0, 180000),
-(8220005, 2290136, 1, 1, 0, 180000),
-(8220006, 2290012, 1, 1, 0, 80000),
-(8220006, 2290013, 1, 1, 0, 80000),
-(8220006, 2290042, 1, 1, 0, 80000),
-(8220006, 2290043, 1, 1, 0, 80000),
-(8220006, 2290060, 1, 1, 0, 80000),
-(8220006, 2290061, 1, 1, 0, 80000),
-(8220006, 2290090, 1, 1, 0, 80000),
-(8220006, 2290119, 1, 1, 0, 80000),
-(8220006, 2290120, 1, 1, 0, 80000),
-(8220006, 2290135, 1, 1, 0, 240000),
-(8220006, 2290138, 1, 1, 0, 240000),
-(8220007, 2290035, 1, 1, 0, 40000),
-(8220007, 2290091, 1, 1, 0, 40000),
-(8220007, 2290108, 1, 1, 0, 40000),
-(8220009, 2290031, 1, 1, 0, 40000),
-(8220009, 2290129, 1, 1, 0, 120000),
-(8220015, 2280004, 1, 1, 0, 40000),
-(8220015, 2280005, 1, 1, 0, 40000),
-(8220015, 2280006, 1, 1, 0, 40000),
-(8500002, 2280007, 1, 1, 0, 60000),
-(8500002, 2280008, 1, 1, 0, 60000),
-(8500002, 2280009, 1, 1, 0, 60000),
-(8500002, 2280010, 1, 1, 0, 60000),
-(8500002, 2290006, 1, 1, 0, 60000),
-(8500002, 2290010, 1, 1, 0, 60000),
-(8500002, 2290011, 1, 1, 0, 60000),
-(8500002, 2290013, 1, 1, 0, 60000),
-(8500002, 2290028, 1, 1, 0, 60000),
-(8500002, 2290037, 1, 1, 0, 60000),
-(8500002, 2290043, 1, 1, 0, 60000),
-(8500002, 2290051, 1, 1, 0, 60000),
-(8500002, 2290056, 1, 1, 0, 60000),
-(8500002, 2290061, 1, 1, 0, 60000),
-(8500002, 2290066, 1, 1, 0, 60000),
-(8500002, 2290071, 1, 1, 0, 60000),
-(8500002, 2290078, 1, 1, 0, 60000),
-(8500002, 2290089, 1, 1, 0, 60000),
-(8500002, 2290091, 1, 1, 0, 60000),
-(8500002, 2290104, 1, 1, 0, 60000),
-(8500002, 2290107, 1, 1, 0, 60000),
-(8500002, 2290121, 1, 1, 0, 60000),
-(8500002, 2290123, 1, 1, 0, 60000),
-(8500002, 2290126, 1, 1, 0, 180000),
-(8500002, 2290129, 1, 1, 0, 180000),
-(8510000, 2280007, 1, 1, 0, 40000),
-(8510000, 2280008, 1, 1, 0, 40000),
-(8510000, 2280009, 1, 1, 0, 40000),
-(8510000, 2280010, 1, 1, 0, 40000),
-(8510000, 2290000, 1, 1, 0, 40000),
-(8510000, 2290001, 1, 1, 0, 40000),
-(8510000, 2290004, 1, 1, 0, 40000),
-(8510000, 2290005, 1, 1, 0, 40000),
-(8510000, 2290024, 1, 1, 0, 40000),
-(8510000, 2290025, 1, 1, 0, 40000),
-(8510000, 2290026, 1, 1, 0, 40000),
-(8510000, 2290027, 1, 1, 0, 40000),
-(8510000, 2290052, 1, 1, 0, 40000),
-(8510000, 2290053, 1, 1, 0, 40000),
-(8510000, 2290054, 1, 1, 0, 40000),
-(8510000, 2290055, 1, 1, 0, 40000),
-(8510000, 2290076, 1, 1, 0, 40000),
-(8510000, 2290077, 1, 1, 0, 40000),
-(8510000, 2290082, 1, 1, 0, 40000),
-(8510000, 2290083, 1, 1, 0, 40000),
-(8510000, 2290097, 1, 1, 0, 40000),
-(8510000, 2290099, 1, 1, 0, 40000),
-(8510000, 2290106, 1, 1, 0, 40000),
-(8510000, 2290108, 1, 1, 0, 40000),
-(8510000, 2290112, 1, 1, 0, 40000),
-(8510000, 2290114, 1, 1, 0, 40000),
-(8510000, 2290122, 1, 1, 0, 40000),
-(8510000, 2290124, 1, 1, 0, 40000),
-(8510000, 2290132, 1, 1, 0, 120000),
-(8520000, 2280007, 1, 1, 0, 40000),
-(8520000, 2280008, 1, 1, 0, 40000),
-(8520000, 2280009, 1, 1, 0, 40000),
-(8520000, 2280010, 1, 1, 0, 40000),
-(8520000, 2290000, 1, 1, 0, 40000),
-(8520000, 2290001, 1, 1, 0, 40000),
-(8520000, 2290004, 1, 1, 0, 40000),
-(8520000, 2290005, 1, 1, 0, 40000),
-(8520000, 2290024, 1, 1, 0, 40000),
-(8520000, 2290025, 1, 1, 0, 40000),
-(8520000, 2290026, 1, 1, 0, 40000),
-(8520000, 2290027, 1, 1, 0, 40000),
-(8520000, 2290052, 1, 1, 0, 40000),
-(8520000, 2290053, 1, 1, 0, 40000),
-(8520000, 2290054, 1, 1, 0, 40000),
-(8520000, 2290055, 1, 1, 0, 40000),
-(8520000, 2290076, 1, 1, 0, 40000),
-(8520000, 2290077, 1, 1, 0, 40000),
-(8520000, 2290082, 1, 1, 0, 40000),
-(8520000, 2290083, 1, 1, 0, 40000),
-(8520000, 2290097, 1, 1, 0, 40000),
-(8520000, 2290099, 1, 1, 0, 40000),
-(8520000, 2290106, 1, 1, 0, 40000),
-(8520000, 2290108, 1, 1, 0, 40000),
-(8520000, 2290112, 1, 1, 0, 40000),
-(8520000, 2290114, 1, 1, 0, 40000),
-(8520000, 2290122, 1, 1, 0, 40000),
-(8520000, 2290124, 1, 1, 0, 40000),
-(8520000, 2290132, 1, 1, 0, 120000),
-(8800002, 2280007, 1, 1, 0, 80000),
-(8800002, 2280008, 1, 1, 0, 80000),
-(8800002, 2280009, 1, 1, 0, 80000),
-(8800002, 2280010, 1, 1, 0, 80000),
-(8800002, 2280013, 1, 1, 0, 240000),
-(8800002, 2280014, 1, 1, 0, 240000),
-(8800002, 2280015, 1, 1, 0, 240000),
-(8800002, 2280016, 1, 1, 0, 240000),
-(8800002, 2290006, 1, 1, 0, 80000),
-(8800002, 2290007, 1, 1, 0, 80000),
-(8800002, 2290016, 1, 1, 0, 80000),
-(8800002, 2290020, 1, 1, 0, 80000),
-(8800002, 2290022, 1, 1, 0, 80000),
-(8800002, 2290024, 1, 1, 0, 80000),
-(8800002, 2290028, 1, 1, 0, 80000),
-(8800002, 2290029, 1, 1, 0, 80000),
-(8800002, 2290040, 1, 1, 0, 80000),
-(8800002, 2290046, 1, 1, 0, 80000),
-(8800002, 2290048, 1, 1, 0, 80000),
-(8800002, 2290056, 1, 1, 0, 80000),
-(8800002, 2290057, 1, 1, 0, 80000),
-(8800002, 2290058, 1, 1, 0, 80000),
-(8800002, 2290064, 1, 1, 0, 80000),
-(8800002, 2290067, 1, 1, 0, 80000),
-(8800002, 2290074, 1, 1, 0, 80000),
-(8800002, 2290079, 1, 1, 0, 80000),
-(8800002, 2290084, 1, 1, 0, 80000),
-(8800002, 2290094, 1, 1, 0, 80000),
-(8800002, 2290110, 1, 1, 0, 80000),
-(8800002, 2290115, 1, 1, 0, 80000),
-(8810018, 2290017, 1, 1, 0, 100000),
-(8810018, 2290021, 1, 1, 0, 100000),
-(8810018, 2290023, 1, 1, 0, 100000),
-(8810018, 2290041, 1, 1, 0, 100000),
-(8810018, 2290047, 1, 1, 0, 100000),
-(8810018, 2290049, 1, 1, 0, 100000),
-(8810018, 2290065, 1, 1, 0, 100000),
-(8810018, 2290075, 1, 1, 0, 100000),
-(8810018, 2290085, 1, 1, 0, 100000),
-(8810018, 2290095, 1, 1, 0, 100000),
-(8810018, 2290096, 1, 1, 0, 100000),
-(8810018, 2290111, 1, 1, 0, 100000),
-(8810018, 2290116, 1, 1, 0, 100000),
-(8810018, 2290125, 1, 1, 0, 100000),
-(8810018, 2290133, 1, 1, 0, 300000),
-(8810018, 2290137, 1, 1, 0, 300000),
-(8810018, 2290139, 1, 1, 0, 300000),
-(8820000, 2290010, 1, 1, 0, 120000),
-(8820000, 2290022, 1, 1, 0, 120000),
-(8820000, 2290040, 1, 1, 0, 120000),
-(8820000, 2290046, 1, 1, 0, 120000),
-(8820000, 2290048, 1, 1, 0, 120000),
-(8820000, 2290052, 1, 1, 0, 120000),
-(8820000, 2290084, 1, 1, 0, 120000),
-(8820000, 2290090, 1, 1, 0, 120000),
-(8820000, 2290106, 1, 1, 0, 120000),
-(8820000, 2290119, 1, 1, 0, 120000),
-(8820001, 2290010, 1, 1, 0, 120000),
-(8820001, 2290022, 1, 1, 0, 120000),
-(8820001, 2290040, 1, 1, 0, 120000),
-(8820001, 2290046, 1, 1, 0, 120000),
-(8820001, 2290048, 1, 1, 0, 120000),
-(8820001, 2290052, 1, 1, 0, 120000),
-(8820001, 2290084, 1, 1, 0, 120000),
-(8820001, 2290090, 1, 1, 0, 120000),
-(8820001, 2290106, 1, 1, 0, 120000),
-(8820001, 2290119, 1, 1, 0, 120000),
-(9300028, 2280015, 1, 1, 0, 120000),
-(9300028, 2290026, 1, 1, 0, 40000),
-(9300028, 2290064, 1, 1, 0, 40000),
-(9300028, 2290075, 1, 1, 0, 40000),
-(9300028, 2290093, 1, 1, 0, 40000),
-(9300028, 2290111, 1, 1, 0, 40000),
-(9300094, 2280004, 1, 1, 0, 40000),
-(9300094, 2280005, 1, 1, 0, 40000),
-(9300094, 2280006, 1, 1, 0, 40000),
-(9300095, 2280004, 1, 1, 0, 2000),
-(9300095, 2280005, 1, 1, 0, 2000),
-(9300095, 2280006, 1, 1, 0, 2000),
-(9303016, 2290006, 1, 1, 0, 2000),
-(9303016, 2290030, 1, 1, 0, 2000),
-(9303016, 2290032, 1, 1, 0, 2000),
-(9303016, 2290060, 1, 1, 0, 2000),
-(9303016, 2290076, 1, 1, 0, 2000),
-(9303016, 2290104, 1, 1, 0, 2000),
-(9303016, 2290117, 1, 1, 0, 2000),
-(9400014, 2290053, 1, 1, 0, 40000),
-(9400014, 2290087, 1, 1, 0, 40000),
-(9400014, 2290112, 1, 1, 0, 40000),
-(9400014, 2290122, 1, 1, 0, 40000),
-(9400120, 2290045, 1, 1, 0, 40000),
-(9400121, 2280014, 1, 1, 0, 180000),
-(9400121, 2290081, 1, 1, 0, 60000),
-(9400121, 2290087, 1, 1, 0, 60000),
-(9400121, 2290101, 1, 1, 0, 60000),
-(9400121, 2290103, 1, 1, 0, 60000),
-(9400122, 2290007, 1, 1, 0, 40000),
-(9400122, 2290062, 1, 1, 0, 40000),
-(9400122, 2290116, 1, 1, 0, 40000),
-(9400300, 2290045, 1, 1, 0, 120000),
-(9400300, 2290055, 1, 1, 0, 120000),
-(9400300, 2290063, 1, 1, 0, 120000),
-(9400300, 2290079, 1, 1, 0, 120000),
-(9400300, 2290081, 1, 1, 0, 120000),
-(9400300, 2290096, 1, 1, 0, 120000),
-(9400514, 2290023, 1, 1, 0, 40000),
-(9400514, 2290057, 1, 1, 0, 40000),
-(9400514, 2290088, 1, 1, 0, 40000),
-(9400514, 2290095, 1, 1, 0, 40000),
-(9400514, 2290115, 1, 1, 0, 40000),
-(9400514, 2290139, 1, 1, 0, 120000),
-(9400549, 2290001, 1, 1, 0, 40000),
-(9400549, 2290020, 1, 1, 0, 40000),
-(9400549, 2290045, 1, 1, 0, 40000),
-(9400549, 2290057, 1, 1, 0, 40000),
-(9400549, 2290086, 1, 1, 0, 40000),
-(9400575, 2290009, 1, 1, 0, 40000),
-(9400575, 2290051, 1, 1, 0, 40000),
-(9400575, 2290081, 1, 1, 0, 40000),
-(9400575, 2290087, 1, 1, 0, 40000),
-(9400575, 2290107, 1, 1, 0, 40000),
-(9400575, 2290123, 1, 1, 0, 40000),
-(9400580, 2290004, 1, 1, 0, 2000),
-(9400580, 2290024, 1, 1, 0, 2000),
-(9400580, 2290083, 1, 1, 0, 2000),
-(9400580, 2290087, 1, 1, 0, 2000),
-(9400580, 2290103, 1, 1, 0, 2000),
-(9400580, 2290121, 1, 1, 0, 2000),
-(9400582, 2290005, 1, 1, 0, 2000),
-(9400582, 2290010, 1, 1, 0, 2000),
-(9400582, 2290029, 1, 1, 0, 2000),
-(9400582, 2290047, 1, 1, 0, 2000),
-(9400582, 2290049, 1, 1, 0, 2000),
-(9400582, 2290074, 1, 1, 0, 2000),
-(9400582, 2290079, 1, 1, 0, 2000),
-(9400582, 2290081, 1, 1, 0, 2000),
-(9400582, 2290135, 1, 1, 0, 6000),
-(9400590, 2290088, 1, 1, 0, 60000),
-(9400590, 2290125, 1, 1, 0, 60000),
-(9400590, 2290135, 1, 1, 0, 180000),
-(9400591, 2290039, 1, 1, 0, 60000),
-(9400591, 2290074, 1, 1, 0, 60000),
-(9400591, 2290113, 1, 1, 0, 60000),
-(9400592, 2290047, 1, 1, 0, 60000),
-(9400592, 2290123, 1, 1, 0, 60000),
-(9400592, 2290131, 1, 1, 0, 180000),
-(9400593, 2290069, 1, 1, 0, 60000),
-(9400593, 2290093, 1, 1, 0, 60000),
-(9400593, 2290138, 1, 1, 0, 180000),
-(9420513, 2290039, 1, 1, 0, 40000),
-(9420513, 2290100, 1, 1, 0, 40000),
-(9420513, 2290108, 1, 1, 0, 40000),
-(9420513, 2290118, 1, 1, 0, 40000),
-(9420513, 2290138, 1, 1, 0, 120000),
+(7090000, 2290087, 1, 1, 0, 10000),
+(8090000, 2290045, 1, 1, 0, 10000),
+(8140103, 2290044, 1, 1, 0, 500),
+(8140511, 2290009, 1, 1, 0, 500),
+(8140511, 2290050, 1, 1, 0, 500),
+(8140511, 2290083, 1, 1, 0, 500),
+(8140511, 2290134, 1, 1, 0, 1500),
+(8140512, 2290013, 1, 1, 0, 500),
+(8140512, 2290067, 1, 1, 0, 500),
+(8140512, 2290082, 1, 1, 0, 500),
+(8140512, 2290097, 1, 1, 0, 500),
+(8140512, 2290116, 1, 1, 0, 500),
+(8140512, 2290131, 1, 1, 0, 1500),
+(8140600, 2290132, 1, 1, 0, 1500),
+(8140700, 2290106, 1, 1, 0, 500),
+(8140700, 2290126, 1, 1, 0, 1500),
+(8140701, 2290122, 1, 1, 0, 500),
+(8140702, 2290112, 1, 1, 0, 500),
+(8140703, 2290088, 1, 1, 0, 500),
+(8140703, 2290099, 1, 1, 0, 500),
+(8141000, 2290082, 1, 1, 0, 500),
+(8141000, 2290097, 1, 1, 0, 500),
+(8141100, 2280005, 1, 1, 0, 500),
+(8141300, 2290098, 1, 1, 0, 500),
+(8142100, 2290032, 1, 1, 0, 500),
+(8142100, 2290082, 1, 1, 0, 500),
+(8142100, 2290114, 1, 1, 0, 500),
+(8143000, 2280004, 1, 1, 0, 500),
+(8150000, 2280013, 1, 1, 0, 30000),
+(8150000, 2290070, 1, 1, 0, 10000),
+(8150000, 2290091, 1, 1, 0, 10000),
+(8150100, 2290042, 1, 1, 0, 500),
+(8150100, 2290053, 1, 1, 0, 500),
+(8150100, 2290073, 1, 1, 0, 500),
+(8150100, 2290102, 1, 1, 0, 500),
+(8150100, 2290118, 1, 1, 0, 500),
+(8150101, 2290017, 1, 1, 0, 500),
+(8150101, 2290021, 1, 1, 0, 500),
+(8150101, 2290035, 1, 1, 0, 500),
+(8150101, 2290042, 1, 1, 0, 500),
+(8150101, 2290052, 1, 1, 0, 500),
+(8150101, 2290102, 1, 1, 0, 500),
+(8150200, 2290024, 1, 1, 0, 500),
+(8150200, 2290100, 1, 1, 0, 500),
+(8150200, 2290135, 1, 1, 0, 1500),
+(8150201, 2290004, 1, 1, 0, 500),
+(8150201, 2290006, 1, 1, 0, 500),
+(8150201, 2290024, 1, 1, 0, 500),
+(8150201, 2290036, 1, 1, 0, 500),
+(8150201, 2290056, 1, 1, 0, 500),
+(8150201, 2290072, 1, 1, 0, 500),
+(8150201, 2290078, 1, 1, 0, 500),
+(8150201, 2290117, 1, 1, 0, 500),
+(8150300, 2290003, 1, 1, 0, 500),
+(8150300, 2290033, 1, 1, 0, 500),
+(8150300, 2290111, 1, 1, 0, 500),
+(8150300, 2290120, 1, 1, 0, 500),
+(8150300, 2290127, 1, 1, 0, 1500),
+(8150301, 2290023, 1, 1, 0, 500),
+(8150301, 2290029, 1, 1, 0, 500),
+(8150301, 2290101, 1, 1, 0, 500),
+(8150301, 2290107, 1, 1, 0, 500),
+(8150302, 2290010, 1, 1, 0, 500),
+(8150302, 2290019, 1, 1, 0, 500),
+(8150302, 2290026, 1, 1, 0, 500),
+(8150302, 2290076, 1, 1, 0, 500),
+(8150302, 2290085, 1, 1, 0, 500),
+(8150302, 2290096, 1, 1, 0, 500),
+(8150302, 2290113, 1, 1, 0, 500),
+(8150302, 2290119, 1, 1, 0, 500),
+(8150302, 2290128, 1, 1, 0, 1500),
+(8160000, 2290017, 1, 1, 0, 500),
+(8160000, 2290045, 1, 1, 0, 500),
+(8160000, 2290065, 1, 1, 0, 500),
+(8160000, 2290067, 1, 1, 0, 500),
+(8160000, 2290081, 1, 1, 0, 500),
+(8170000, 2290012, 1, 1, 0, 500),
+(8170000, 2290086, 1, 1, 0, 500),
+(8170000, 2290087, 1, 1, 0, 500),
+(8170000, 2290134, 1, 1, 0, 1500),
+(8180000, 2290002, 1, 1, 0, 10000),
+(8180000, 2290003, 1, 1, 0, 10000),
+(8180000, 2290014, 1, 1, 0, 10000),
+(8180000, 2290015, 1, 1, 0, 10000),
+(8180000, 2290030, 1, 1, 0, 10000),
+(8180000, 2290035, 1, 1, 0, 10000),
+(8180000, 2290036, 1, 1, 0, 10000),
+(8180000, 2290063, 1, 1, 0, 10000),
+(8180000, 2290080, 1, 1, 0, 10000),
+(8180000, 2290098, 1, 1, 0, 10000),
+(8180000, 2290101, 1, 1, 0, 10000),
+(8180000, 2290117, 1, 1, 0, 10000),
+(8180000, 2290130, 1, 1, 0, 30000),
+(8180001, 2290018, 1, 1, 0, 10000),
+(8180001, 2290019, 1, 1, 0, 10000),
+(8180001, 2290032, 1, 1, 0, 10000),
+(8180001, 2290042, 1, 1, 0, 10000),
+(8180001, 2290058, 1, 1, 0, 10000),
+(8180001, 2290059, 1, 1, 0, 10000),
+(8180001, 2290068, 1, 1, 0, 10000),
+(8180001, 2290069, 1, 1, 0, 10000),
+(8180001, 2290072, 1, 1, 0, 10000),
+(8180001, 2290092, 1, 1, 0, 10000),
+(8180001, 2290099, 1, 1, 0, 10000),
+(8180001, 2290100, 1, 1, 0, 10000),
+(8180001, 2290102, 1, 1, 0, 10000),
+(8180001, 2290119, 1, 1, 0, 10000),
+(8180001, 2290128, 1, 1, 0, 30000),
+(8190000, 2280016, 1, 1, 0, 1500),
+(8190000, 2290030, 1, 1, 0, 500),
+(8190000, 2290044, 1, 1, 0, 500),
+(8190000, 2290054, 1, 1, 0, 500),
+(8190000, 2290066, 1, 1, 0, 500),
+(8190000, 2290075, 1, 1, 0, 500),
+(8190000, 2290092, 1, 1, 0, 500),
+(8190000, 2290103, 1, 1, 0, 500),
+(8190002, 2290000, 1, 1, 0, 500),
+(8190002, 2290008, 1, 1, 0, 500),
+(8190002, 2290018, 1, 1, 0, 500),
+(8190002, 2290038, 1, 1, 0, 500),
+(8190002, 2290060, 1, 1, 0, 500),
+(8190002, 2290080, 1, 1, 0, 500),
+(8190002, 2290124, 1, 1, 0, 500),
+(8190003, 2280013, 1, 1, 0, 1500),
+(8190003, 2290007, 1, 1, 0, 500),
+(8190003, 2290012, 1, 1, 0, 500),
+(8190003, 2290014, 1, 1, 0, 500),
+(8190003, 2290033, 1, 1, 0, 500),
+(8190003, 2290045, 1, 1, 0, 500),
+(8190003, 2290050, 1, 1, 0, 500),
+(8190003, 2290055, 1, 1, 0, 500),
+(8190003, 2290062, 1, 1, 0, 500),
+(8190003, 2290063, 1, 1, 0, 500),
+(8190003, 2290070, 1, 1, 0, 500),
+(8190003, 2290086, 1, 1, 0, 500),
+(8190003, 2290108, 1, 1, 0, 500),
+(8190003, 2290133, 1, 1, 0, 1500),
+(8190004, 2290002, 1, 1, 0, 500),
+(8190004, 2290009, 1, 1, 0, 500),
+(8190004, 2290021, 1, 1, 0, 500),
+(8190004, 2290034, 1, 1, 0, 500),
+(8190004, 2290041, 1, 1, 0, 500),
+(8190004, 2290052, 1, 1, 0, 500),
+(8190004, 2290053, 1, 1, 0, 500),
+(8190004, 2290058, 1, 1, 0, 500),
+(8190004, 2290068, 1, 1, 0, 500),
+(8190004, 2290071, 1, 1, 0, 500),
+(8190004, 2290073, 1, 1, 0, 500),
+(8190004, 2290090, 1, 1, 0, 500),
+(8190004, 2290112, 1, 1, 0, 500),
+(8190004, 2290121, 1, 1, 0, 500),
+(8190004, 2290130, 1, 1, 0, 1500),
+(8190005, 2290000, 1, 1, 0, 500),
+(8190005, 2290008, 1, 1, 0, 500),
+(8190005, 2290018, 1, 1, 0, 500),
+(8190005, 2290038, 1, 1, 0, 500),
+(8190005, 2290060, 1, 1, 0, 500),
+(8190005, 2290080, 1, 1, 0, 500),
+(8190005, 2290124, 1, 1, 0, 500),
+(8200000, 2290005, 1, 1, 0, 500),
+(8200000, 2290011, 1, 1, 0, 500),
+(8200000, 2290114, 1, 1, 0, 500),
+(8200001, 2280015, 1, 1, 0, 1500),
+(8200001, 2290050, 1, 1, 0, 500),
+(8200001, 2290059, 1, 1, 0, 500),
+(8200001, 2290065, 1, 1, 0, 500),
+(8200001, 2290129, 1, 1, 0, 1500),
+(8200002, 2290062, 1, 1, 0, 500),
+(8200002, 2290066, 1, 1, 0, 500),
+(8200002, 2290070, 1, 1, 0, 500),
+(8200002, 2290131, 1, 1, 0, 1500),
+(8200002, 2290139, 1, 1, 0, 1500),
+(8200003, 2290012, 1, 1, 0, 500),
+(8200003, 2290056, 1, 1, 0, 500),
+(8200003, 2290071, 1, 1, 0, 500),
+(8200003, 2290101, 1, 1, 0, 500),
+(8200003, 2290136, 1, 1, 0, 1500),
+(8200004, 2280016, 1, 1, 0, 1500),
+(8200004, 2290069, 1, 1, 0, 500),
+(8200004, 2290072, 1, 1, 0, 500),
+(8200004, 2290073, 1, 1, 0, 500),
+(8200004, 2290127, 1, 1, 0, 1500),
+(8200004, 2290134, 1, 1, 0, 1500),
+(8200005, 2280014, 1, 1, 0, 1500),
+(8200005, 2290078, 1, 1, 0, 500),
+(8200005, 2290079, 1, 1, 0, 500),
+(8200005, 2290095, 1, 1, 0, 500),
+(8200006, 2290003, 1, 1, 0, 500),
+(8200006, 2290064, 1, 1, 0, 500),
+(8200006, 2290076, 1, 1, 0, 500),
+(8200006, 2290077, 1, 1, 0, 500),
+(8200006, 2290129, 1, 1, 0, 1500),
+(8200006, 2290138, 1, 1, 0, 1500),
+(8200007, 2290006, 1, 1, 0, 500),
+(8200007, 2290007, 1, 1, 0, 500),
+(8200007, 2290011, 1, 1, 0, 500),
+(8200007, 2290016, 1, 1, 0, 500),
+(8200007, 2290125, 1, 1, 0, 500),
+(8200007, 2290136, 1, 1, 0, 1500),
+(8200008, 2290006, 1, 1, 0, 500),
+(8200008, 2290051, 1, 1, 0, 500),
+(8200008, 2290121, 1, 1, 0, 500),
+(8200008, 2290122, 1, 1, 0, 500),
+(8200008, 2290133, 1, 1, 0, 1500),
+(8200009, 2290013, 1, 1, 0, 500),
+(8200009, 2290016, 1, 1, 0, 500),
+(8200009, 2290031, 1, 1, 0, 500),
+(8200009, 2290039, 1, 1, 0, 500),
+(8200010, 2290026, 1, 1, 0, 500),
+(8200010, 2290059, 1, 1, 0, 500),
+(8200010, 2290088, 1, 1, 0, 500),
+(8200010, 2290089, 1, 1, 0, 500),
+(8200010, 2290127, 1, 1, 0, 1500),
+(8200011, 2290001, 1, 1, 0, 750),
+(8200011, 2290040, 1, 1, 0, 750),
+(8200011, 2290046, 1, 1, 0, 750),
+(8200011, 2290048, 1, 1, 0, 750),
+(8200011, 2290049, 1, 1, 0, 750),
+(8200011, 2290114, 1, 1, 0, 750),
+(8200011, 2290137, 1, 1, 0, 2250),
+(8200012, 2290041, 1, 1, 0, 750),
+(8200012, 2290092, 1, 1, 0, 750),
+(8200012, 2290093, 1, 1, 0, 750),
+(8200012, 2290115, 1, 1, 0, 750),
+(8200012, 2290137, 1, 1, 0, 2250),
+(8200012, 2290139, 1, 1, 0, 2250),
+(8220002, 2290020, 1, 1, 0, 10000),
+(8220002, 2290081, 1, 1, 0, 10000),
+(8220002, 2290085, 1, 1, 0, 10000),
+(8220002, 2290133, 1, 1, 0, 30000),
+(8220003, 2290006, 1, 1, 0, 10000),
+(8220003, 2290030, 1, 1, 0, 10000),
+(8220003, 2290031, 1, 1, 0, 10000),
+(8220003, 2290032, 1, 1, 0, 10000),
+(8220003, 2290033, 1, 1, 0, 10000),
+(8220003, 2290060, 1, 1, 0, 10000),
+(8220003, 2290061, 1, 1, 0, 10000),
+(8220003, 2290076, 1, 1, 0, 10000),
+(8220003, 2290077, 1, 1, 0, 10000),
+(8220003, 2290104, 1, 1, 0, 10000),
+(8220003, 2290105, 1, 1, 0, 10000),
+(8220003, 2290117, 1, 1, 0, 10000),
+(8220003, 2290118, 1, 1, 0, 10000),
+(8220004, 2290018, 1, 1, 0, 10000),
+(8220004, 2290019, 1, 1, 0, 10000),
+(8220004, 2290024, 1, 1, 0, 10000),
+(8220004, 2290025, 1, 1, 0, 10000),
+(8220004, 2290058, 1, 1, 0, 10000),
+(8220004, 2290059, 1, 1, 0, 10000),
+(8220004, 2290076, 1, 1, 0, 10000),
+(8220004, 2290077, 1, 1, 0, 10000),
+(8220004, 2290106, 1, 1, 0, 10000),
+(8220004, 2290127, 1, 1, 0, 30000),
+(8220004, 2290134, 1, 1, 0, 30000),
+(8220005, 2290002, 1, 1, 0, 15000),
+(8220005, 2290003, 1, 1, 0, 15000),
+(8220005, 2290036, 1, 1, 0, 15000),
+(8220005, 2290037, 1, 1, 0, 15000),
+(8220005, 2290055, 1, 1, 0, 15000),
+(8220005, 2290080, 1, 1, 0, 15000),
+(8220005, 2290099, 1, 1, 0, 15000),
+(8220005, 2290131, 1, 1, 0, 45000),
+(8220005, 2290136, 1, 1, 0, 45000),
+(8220006, 2290012, 1, 1, 0, 20000),
+(8220006, 2290013, 1, 1, 0, 20000),
+(8220006, 2290042, 1, 1, 0, 20000),
+(8220006, 2290043, 1, 1, 0, 20000),
+(8220006, 2290060, 1, 1, 0, 20000),
+(8220006, 2290061, 1, 1, 0, 20000),
+(8220006, 2290090, 1, 1, 0, 20000),
+(8220006, 2290119, 1, 1, 0, 20000),
+(8220006, 2290120, 1, 1, 0, 20000),
+(8220006, 2290135, 1, 1, 0, 60000),
+(8220006, 2290138, 1, 1, 0, 60000),
+(8220007, 2290035, 1, 1, 0, 10000),
+(8220007, 2290091, 1, 1, 0, 10000),
+(8220007, 2290108, 1, 1, 0, 10000),
+(8220009, 2290031, 1, 1, 0, 10000),
+(8220009, 2290129, 1, 1, 0, 30000),
+(8220015, 2280004, 1, 1, 0, 10000),
+(8220015, 2280005, 1, 1, 0, 10000),
+(8220015, 2280006, 1, 1, 0, 10000),
+(8500002, 2280007, 1, 1, 0, 15000),
+(8500002, 2280008, 1, 1, 0, 15000),
+(8500002, 2280009, 1, 1, 0, 15000),
+(8500002, 2280010, 1, 1, 0, 15000),
+(8500002, 2290006, 1, 1, 0, 15000),
+(8500002, 2290010, 1, 1, 0, 15000),
+(8500002, 2290011, 1, 1, 0, 15000),
+(8500002, 2290013, 1, 1, 0, 15000),
+(8500002, 2290028, 1, 1, 0, 15000),
+(8500002, 2290037, 1, 1, 0, 15000),
+(8500002, 2290043, 1, 1, 0, 15000),
+(8500002, 2290051, 1, 1, 0, 15000),
+(8500002, 2290056, 1, 1, 0, 15000),
+(8500002, 2290061, 1, 1, 0, 15000),
+(8500002, 2290066, 1, 1, 0, 15000),
+(8500002, 2290071, 1, 1, 0, 15000),
+(8500002, 2290078, 1, 1, 0, 15000),
+(8500002, 2290089, 1, 1, 0, 15000),
+(8500002, 2290091, 1, 1, 0, 15000),
+(8500002, 2290104, 1, 1, 0, 15000),
+(8500002, 2290107, 1, 1, 0, 15000),
+(8500002, 2290121, 1, 1, 0, 15000),
+(8500002, 2290123, 1, 1, 0, 15000),
+(8500002, 2290126, 1, 1, 0, 45000),
+(8500002, 2290129, 1, 1, 0, 45000),
+(8510000, 2280007, 1, 1, 0, 10000),
+(8510000, 2280008, 1, 1, 0, 10000),
+(8510000, 2280009, 1, 1, 0, 10000),
+(8510000, 2280010, 1, 1, 0, 10000),
+(8510000, 2290000, 1, 1, 0, 10000),
+(8510000, 2290001, 1, 1, 0, 10000),
+(8510000, 2290004, 1, 1, 0, 10000),
+(8510000, 2290005, 1, 1, 0, 10000),
+(8510000, 2290024, 1, 1, 0, 10000),
+(8510000, 2290025, 1, 1, 0, 10000),
+(8510000, 2290026, 1, 1, 0, 10000),
+(8510000, 2290027, 1, 1, 0, 10000),
+(8510000, 2290052, 1, 1, 0, 10000),
+(8510000, 2290053, 1, 1, 0, 10000),
+(8510000, 2290054, 1, 1, 0, 10000),
+(8510000, 2290055, 1, 1, 0, 10000),
+(8510000, 2290076, 1, 1, 0, 10000),
+(8510000, 2290077, 1, 1, 0, 10000),
+(8510000, 2290082, 1, 1, 0, 10000),
+(8510000, 2290083, 1, 1, 0, 10000),
+(8510000, 2290097, 1, 1, 0, 10000),
+(8510000, 2290099, 1, 1, 0, 10000),
+(8510000, 2290106, 1, 1, 0, 10000),
+(8510000, 2290108, 1, 1, 0, 10000),
+(8510000, 2290112, 1, 1, 0, 10000),
+(8510000, 2290114, 1, 1, 0, 10000),
+(8510000, 2290122, 1, 1, 0, 10000),
+(8510000, 2290124, 1, 1, 0, 10000),
+(8510000, 2290132, 1, 1, 0, 30000),
+(8520000, 2280007, 1, 1, 0, 10000),
+(8520000, 2280008, 1, 1, 0, 10000),
+(8520000, 2280009, 1, 1, 0, 10000),
+(8520000, 2280010, 1, 1, 0, 10000),
+(8520000, 2290000, 1, 1, 0, 10000),
+(8520000, 2290001, 1, 1, 0, 10000),
+(8520000, 2290004, 1, 1, 0, 10000),
+(8520000, 2290005, 1, 1, 0, 10000),
+(8520000, 2290024, 1, 1, 0, 10000),
+(8520000, 2290025, 1, 1, 0, 10000),
+(8520000, 2290026, 1, 1, 0, 10000),
+(8520000, 2290027, 1, 1, 0, 10000),
+(8520000, 2290052, 1, 1, 0, 10000),
+(8520000, 2290053, 1, 1, 0, 10000),
+(8520000, 2290054, 1, 1, 0, 10000),
+(8520000, 2290055, 1, 1, 0, 10000),
+(8520000, 2290076, 1, 1, 0, 10000),
+(8520000, 2290077, 1, 1, 0, 10000),
+(8520000, 2290082, 1, 1, 0, 10000),
+(8520000, 2290083, 1, 1, 0, 10000),
+(8520000, 2290097, 1, 1, 0, 10000),
+(8520000, 2290099, 1, 1, 0, 10000),
+(8520000, 2290106, 1, 1, 0, 10000),
+(8520000, 2290108, 1, 1, 0, 10000),
+(8520000, 2290112, 1, 1, 0, 10000),
+(8520000, 2290114, 1, 1, 0, 10000),
+(8520000, 2290122, 1, 1, 0, 10000),
+(8520000, 2290124, 1, 1, 0, 10000),
+(8520000, 2290132, 1, 1, 0, 30000),
+(8800002, 2280007, 1, 1, 0, 20000),
+(8800002, 2280008, 1, 1, 0, 20000),
+(8800002, 2280009, 1, 1, 0, 20000),
+(8800002, 2280010, 1, 1, 0, 20000),
+(8800002, 2280013, 1, 1, 0, 60000),
+(8800002, 2280014, 1, 1, 0, 60000),
+(8800002, 2280015, 1, 1, 0, 60000),
+(8800002, 2280016, 1, 1, 0, 60000),
+(8800002, 2290006, 1, 1, 0, 20000),
+(8800002, 2290007, 1, 1, 0, 20000),
+(8800002, 2290016, 1, 1, 0, 20000),
+(8800002, 2290020, 1, 1, 0, 20000),
+(8800002, 2290022, 1, 1, 0, 20000),
+(8800002, 2290024, 1, 1, 0, 20000),
+(8800002, 2290028, 1, 1, 0, 20000),
+(8800002, 2290029, 1, 1, 0, 20000),
+(8800002, 2290040, 1, 1, 0, 20000),
+(8800002, 2290046, 1, 1, 0, 20000),
+(8800002, 2290048, 1, 1, 0, 20000),
+(8800002, 2290056, 1, 1, 0, 20000),
+(8800002, 2290057, 1, 1, 0, 20000),
+(8800002, 2290058, 1, 1, 0, 20000),
+(8800002, 2290064, 1, 1, 0, 20000),
+(8800002, 2290067, 1, 1, 0, 20000),
+(8800002, 2290074, 1, 1, 0, 20000),
+(8800002, 2290079, 1, 1, 0, 20000),
+(8800002, 2290084, 1, 1, 0, 20000),
+(8800002, 2290094, 1, 1, 0, 20000),
+(8800002, 2290110, 1, 1, 0, 20000),
+(8800002, 2290115, 1, 1, 0, 20000),
+(8810018, 2290017, 1, 1, 0, 25000),
+(8810018, 2290021, 1, 1, 0, 25000),
+(8810018, 2290023, 1, 1, 0, 25000),
+(8810018, 2290041, 1, 1, 0, 25000),
+(8810018, 2290047, 1, 1, 0, 25000),
+(8810018, 2290049, 1, 1, 0, 25000),
+(8810018, 2290065, 1, 1, 0, 25000),
+(8810018, 2290075, 1, 1, 0, 25000),
+(8810018, 2290085, 1, 1, 0, 25000),
+(8810018, 2290095, 1, 1, 0, 25000),
+(8810018, 2290096, 1, 1, 0, 25000),
+(8810018, 2290111, 1, 1, 0, 25000),
+(8810018, 2290116, 1, 1, 0, 25000),
+(8810018, 2290125, 1, 1, 0, 25000),
+(8810018, 2290133, 1, 1, 0, 75000),
+(8810018, 2290137, 1, 1, 0, 75000),
+(8810018, 2290139, 1, 1, 0, 75000),
+(8820000, 2290010, 1, 1, 0, 30000),
+(8820000, 2290022, 1, 1, 0, 30000),
+(8820000, 2290040, 1, 1, 0, 30000),
+(8820000, 2290046, 1, 1, 0, 30000),
+(8820000, 2290048, 1, 1, 0, 30000),
+(8820000, 2290052, 1, 1, 0, 30000),
+(8820000, 2290084, 1, 1, 0, 30000),
+(8820000, 2290090, 1, 1, 0, 30000),
+(8820000, 2290106, 1, 1, 0, 30000),
+(8820000, 2290119, 1, 1, 0, 30000),
+(8820001, 2290010, 1, 1, 0, 30000),
+(8820001, 2290022, 1, 1, 0, 30000),
+(8820001, 2290040, 1, 1, 0, 30000),
+(8820001, 2290046, 1, 1, 0, 30000),
+(8820001, 2290048, 1, 1, 0, 30000),
+(8820001, 2290052, 1, 1, 0, 30000),
+(8820001, 2290084, 1, 1, 0, 30000),
+(8820001, 2290090, 1, 1, 0, 30000),
+(8820001, 2290106, 1, 1, 0, 30000),
+(8820001, 2290119, 1, 1, 0, 30000),
+(9300028, 2280015, 1, 1, 0, 30000),
+(9300028, 2290026, 1, 1, 0, 10000),
+(9300028, 2290064, 1, 1, 0, 10000),
+(9300028, 2290075, 1, 1, 0, 10000),
+(9300028, 2290093, 1, 1, 0, 10000),
+(9300028, 2290111, 1, 1, 0, 10000),
+(9300094, 2280004, 1, 1, 0, 10000),
+(9300094, 2280005, 1, 1, 0, 10000),
+(9300094, 2280006, 1, 1, 0, 10000),
+(9300095, 2280004, 1, 1, 0, 500),
+(9300095, 2280005, 1, 1, 0, 500),
+(9300095, 2280006, 1, 1, 0, 500),
+(9303016, 2290006, 1, 1, 0, 500),
+(9303016, 2290030, 1, 1, 0, 500),
+(9303016, 2290032, 1, 1, 0, 500),
+(9303016, 2290060, 1, 1, 0, 500),
+(9303016, 2290076, 1, 1, 0, 500),
+(9303016, 2290104, 1, 1, 0, 500),
+(9303016, 2290117, 1, 1, 0, 500),
+(9400014, 2290053, 1, 1, 0, 10000),
+(9400014, 2290087, 1, 1, 0, 10000),
+(9400014, 2290112, 1, 1, 0, 10000),
+(9400014, 2290122, 1, 1, 0, 10000),
+(9400120, 2290045, 1, 1, 0, 10000),
+(9400121, 2280014, 1, 1, 0, 45000),
+(9400121, 2290081, 1, 1, 0, 15000),
+(9400121, 2290087, 1, 1, 0, 15000),
+(9400121, 2290101, 1, 1, 0, 15000),
+(9400121, 2290103, 1, 1, 0, 15000),
+(9400122, 2290007, 1, 1, 0, 10000),
+(9400122, 2290062, 1, 1, 0, 10000),
+(9400122, 2290116, 1, 1, 0, 10000),
+(9400300, 2290045, 1, 1, 0, 30000),
+(9400300, 2290055, 1, 1, 0, 30000),
+(9400300, 2290063, 1, 1, 0, 30000),
+(9400300, 2290079, 1, 1, 0, 30000),
+(9400300, 2290081, 1, 1, 0, 30000),
+(9400300, 2290096, 1, 1, 0, 30000),
+(9400514, 2290023, 1, 1, 0, 10000),
+(9400514, 2290057, 1, 1, 0, 10000),
+(9400514, 2290088, 1, 1, 0, 10000),
+(9400514, 2290095, 1, 1, 0, 10000),
+(9400514, 2290115, 1, 1, 0, 10000),
+(9400514, 2290139, 1, 1, 0, 30000),
+(9400549, 2290001, 1, 1, 0, 10000),
+(9400549, 2290020, 1, 1, 0, 10000),
+(9400549, 2290045, 1, 1, 0, 10000),
+(9400549, 2290057, 1, 1, 0, 10000),
+(9400549, 2290086, 1, 1, 0, 10000),
+(9400575, 2290009, 1, 1, 0, 10000),
+(9400575, 2290051, 1, 1, 0, 10000),
+(9400575, 2290081, 1, 1, 0, 10000),
+(9400575, 2290087, 1, 1, 0, 10000),
+(9400575, 2290107, 1, 1, 0, 10000),
+(9400575, 2290123, 1, 1, 0, 10000),
+(9400580, 2290004, 1, 1, 0, 500),
+(9400580, 2290024, 1, 1, 0, 500),
+(9400580, 2290083, 1, 1, 0, 500),
+(9400580, 2290087, 1, 1, 0, 500),
+(9400580, 2290103, 1, 1, 0, 500),
+(9400580, 2290121, 1, 1, 0, 500),
+(9400582, 2290005, 1, 1, 0, 500),
+(9400582, 2290010, 1, 1, 0, 500),
+(9400582, 2290029, 1, 1, 0, 500),
+(9400582, 2290047, 1, 1, 0, 500),
+(9400582, 2290049, 1, 1, 0, 500),
+(9400582, 2290074, 1, 1, 0, 500),
+(9400582, 2290079, 1, 1, 0, 500),
+(9400582, 2290081, 1, 1, 0, 500),
+(9400582, 2290135, 1, 1, 0, 1500),
+(9400590, 2290088, 1, 1, 0, 15000),
+(9400590, 2290125, 1, 1, 0, 15000),
+(9400590, 2290135, 1, 1, 0, 45000),
+(9400591, 2290039, 1, 1, 0, 15000),
+(9400591, 2290074, 1, 1, 0, 15000),
+(9400591, 2290113, 1, 1, 0, 15000),
+(9400592, 2290047, 1, 1, 0, 15000),
+(9400592, 2290123, 1, 1, 0, 15000),
+(9400592, 2290131, 1, 1, 0, 45000),
+(9400593, 2290069, 1, 1, 0, 15000),
+(9400593, 2290093, 1, 1, 0, 15000),
+(9400593, 2290138, 1, 1, 0, 45000),
+(9420513, 2290039, 1, 1, 0, 10000),
+(9420513, 2290100, 1, 1, 0, 10000),
+(9420513, 2290108, 1, 1, 0, 10000),
+(9420513, 2290118, 1, 1, 0, 10000),
+(9420513, 2290138, 1, 1, 0, 30000),
(9420514, 2290099, 1, 1, 0, 1287),
(9420517, 2290000, 1, 1, 0, 1287),
(9420517, 2290008, 1, 1, 0, 1287),
@@ -24470,75 +24471,75 @@ SET minimum_quantity = CASE
(9420522, 2290089, 1, 1, 0, 1287),
(9420522, 2290091, 1, 1, 0, 1287),
(9420522, 2290107, 1, 1, 0, 1287),
-(9420540, 2280006, 1, 1, 0, 2000),
-(9420540, 2290119, 1, 1, 0, 2000),
-(9420540, 2290120, 1, 1, 0, 2000),
-(9420544, 2280007, 1, 1, 0, 80000),
-(9420544, 2280008, 1, 1, 0, 80000),
-(9420544, 2280009, 1, 1, 0, 80000),
-(9420544, 2280010, 1, 1, 0, 80000),
-(9420544, 2290002, 1, 1, 0, 80000),
-(9420544, 2290015, 1, 1, 0, 80000),
-(9420544, 2290022, 1, 1, 0, 80000),
-(9420544, 2290027, 1, 1, 0, 80000),
-(9420544, 2290034, 1, 1, 0, 80000),
-(9420544, 2290052, 1, 1, 0, 80000),
-(9420544, 2290054, 1, 1, 0, 80000),
-(9420544, 2290089, 1, 1, 0, 80000),
-(9420544, 2290094, 1, 1, 0, 80000),
-(9420544, 2290098, 1, 1, 0, 80000),
-(9420544, 2290105, 1, 1, 0, 80000),
-(9420544, 2290110, 1, 1, 0, 80000),
-(9420544, 2290119, 1, 1, 0, 80000),
-(9420549, 2280007, 1, 1, 0, 80000),
-(9420549, 2280008, 1, 1, 0, 80000),
-(9420549, 2280009, 1, 1, 0, 80000),
-(9420549, 2280010, 1, 1, 0, 80000),
-(9420549, 2290002, 1, 1, 0, 80000),
-(9420549, 2290015, 1, 1, 0, 80000),
-(9420549, 2290022, 1, 1, 0, 80000),
-(9420549, 2290027, 1, 1, 0, 80000),
-(9420549, 2290034, 1, 1, 0, 80000),
-(9420549, 2290052, 1, 1, 0, 80000),
-(9420549, 2290054, 1, 1, 0, 80000),
-(9420549, 2290089, 1, 1, 0, 80000),
-(9420549, 2290094, 1, 1, 0, 80000),
-(9420549, 2290098, 1, 1, 0, 80000),
-(9420549, 2290105, 1, 1, 0, 80000),
-(9420549, 2290110, 1, 1, 0, 80000),
-(9420549, 2290119, 1, 1, 0, 80000),
-(9500166, 2290044, 1, 1, 0, 2000),
-(9500173, 2290018, 1, 1, 0, 40000),
-(9500173, 2290019, 1, 1, 0, 40000),
-(9500173, 2290032, 1, 1, 0, 40000),
-(9500173, 2290042, 1, 1, 0, 40000),
-(9500173, 2290058, 1, 1, 0, 40000),
-(9500173, 2290068, 1, 1, 0, 40000),
-(9500173, 2290072, 1, 1, 0, 40000),
-(9500173, 2290092, 1, 1, 0, 40000),
-(9500173, 2290099, 1, 1, 0, 40000),
-(9500173, 2290102, 1, 1, 0, 40000),
-(9500173, 2290119, 1, 1, 0, 40000),
-(9500173, 2290128, 1, 1, 0, 120000),
-(9500174, 2290002, 1, 1, 0, 40000),
-(9500174, 2290014, 1, 1, 0, 40000),
-(9500174, 2290030, 1, 1, 0, 40000),
-(9500174, 2290080, 1, 1, 0, 40000),
-(9500174, 2290130, 1, 1, 0, 120000),
-(9500180, 2290010, 1, 1, 0, 40000),
-(9500180, 2290028, 1, 1, 0, 40000),
-(9500180, 2290126, 1, 1, 0, 120000),
-(9500181, 2290010, 1, 1, 0, 40000),
-(9500181, 2290028, 1, 1, 0, 40000),
-(9500181, 2290126, 1, 1, 0, 120000),
-(9500331, 2290010, 1, 1, 0, 40000),
-(9500331, 2290028, 1, 1, 0, 40000),
-(9500331, 2290126, 1, 1, 0, 120000),
-(9500332, 2290132, 1, 1, 0, 120000),
-(9500333, 2290006, 1, 1, 0, 40000),
-(9500333, 2290030, 1, 1, 0, 40000),
-(9500333, 2290032, 1, 1, 0, 40000),
-(9500333, 2290060, 1, 1, 0, 40000),
-(9500333, 2290076, 1, 1, 0, 40000),
-(9500333, 2290104, 1, 1, 0, 40000),
-(9500333, 2290117, 1, 1, 0, 40000);
\ No newline at end of file
+(9420540, 2280006, 1, 1, 0, 500),
+(9420540, 2290119, 1, 1, 0, 500),
+(9420540, 2290120, 1, 1, 0, 500),
+(9420544, 2280007, 1, 1, 0, 20000),
+(9420544, 2280008, 1, 1, 0, 20000),
+(9420544, 2280009, 1, 1, 0, 20000),
+(9420544, 2280010, 1, 1, 0, 20000),
+(9420544, 2290002, 1, 1, 0, 20000),
+(9420544, 2290015, 1, 1, 0, 20000),
+(9420544, 2290022, 1, 1, 0, 20000),
+(9420544, 2290027, 1, 1, 0, 20000),
+(9420544, 2290034, 1, 1, 0, 20000),
+(9420544, 2290052, 1, 1, 0, 20000),
+(9420544, 2290054, 1, 1, 0, 20000),
+(9420544, 2290089, 1, 1, 0, 20000),
+(9420544, 2290094, 1, 1, 0, 20000),
+(9420544, 2290098, 1, 1, 0, 20000),
+(9420544, 2290105, 1, 1, 0, 20000),
+(9420544, 2290110, 1, 1, 0, 20000),
+(9420544, 2290119, 1, 1, 0, 20000),
+(9420549, 2280007, 1, 1, 0, 20000),
+(9420549, 2280008, 1, 1, 0, 20000),
+(9420549, 2280009, 1, 1, 0, 20000),
+(9420549, 2280010, 1, 1, 0, 20000),
+(9420549, 2290002, 1, 1, 0, 20000),
+(9420549, 2290015, 1, 1, 0, 20000),
+(9420549, 2290022, 1, 1, 0, 20000),
+(9420549, 2290027, 1, 1, 0, 20000),
+(9420549, 2290034, 1, 1, 0, 20000),
+(9420549, 2290052, 1, 1, 0, 20000),
+(9420549, 2290054, 1, 1, 0, 20000),
+(9420549, 2290089, 1, 1, 0, 20000),
+(9420549, 2290094, 1, 1, 0, 20000),
+(9420549, 2290098, 1, 1, 0, 20000),
+(9420549, 2290105, 1, 1, 0, 20000),
+(9420549, 2290110, 1, 1, 0, 20000),
+(9420549, 2290119, 1, 1, 0, 20000),
+(9500166, 2290044, 1, 1, 0, 500),
+(9500173, 2290018, 1, 1, 0, 10000),
+(9500173, 2290019, 1, 1, 0, 10000),
+(9500173, 2290032, 1, 1, 0, 10000),
+(9500173, 2290042, 1, 1, 0, 10000),
+(9500173, 2290058, 1, 1, 0, 10000),
+(9500173, 2290068, 1, 1, 0, 10000),
+(9500173, 2290072, 1, 1, 0, 10000),
+(9500173, 2290092, 1, 1, 0, 10000),
+(9500173, 2290099, 1, 1, 0, 10000),
+(9500173, 2290102, 1, 1, 0, 10000),
+(9500173, 2290119, 1, 1, 0, 10000),
+(9500173, 2290128, 1, 1, 0, 30000),
+(9500174, 2290002, 1, 1, 0, 10000),
+(9500174, 2290014, 1, 1, 0, 10000),
+(9500174, 2290030, 1, 1, 0, 10000),
+(9500174, 2290080, 1, 1, 0, 10000),
+(9500174, 2290130, 1, 1, 0, 30000),
+(9500180, 2290010, 1, 1, 0, 10000),
+(9500180, 2290028, 1, 1, 0, 10000),
+(9500180, 2290126, 1, 1, 0, 30000),
+(9500181, 2290010, 1, 1, 0, 10000),
+(9500181, 2290028, 1, 1, 0, 10000),
+(9500181, 2290126, 1, 1, 0, 30000),
+(9500331, 2290010, 1, 1, 0, 10000),
+(9500331, 2290028, 1, 1, 0, 10000),
+(9500331, 2290126, 1, 1, 0, 30000),
+(9500332, 2290132, 1, 1, 0, 30000),
+(9500333, 2290006, 1, 1, 0, 10000),
+(9500333, 2290030, 1, 1, 0, 10000),
+(9500333, 2290032, 1, 1, 0, 10000),
+(9500333, 2290060, 1, 1, 0, 10000),
+(9500333, 2290076, 1, 1, 0, 10000),
+(9500333, 2290104, 1, 1, 0, 10000),
+(9500333, 2290117, 1, 1, 0, 10000);
\ No newline at end of file
diff --git a/src/client/AbstractCharacterListener.java b/src/client/AbstractCharacterListener.java
index 53c9794ca0..407a1d3461 100644
--- a/src/client/AbstractCharacterListener.java
+++ b/src/client/AbstractCharacterListener.java
@@ -26,5 +26,6 @@ package client;
public interface AbstractCharacterListener {
public void onHpChanged(int oldHp);
public void onHpmpPoolUpdate();
+ public void onStatUpdate();
public void onAnnounceStatPoolUpdate();
}
diff --git a/src/client/AbstractMapleCharacterObject.java b/src/client/AbstractMapleCharacterObject.java
index 74655e5cf1..12eb374b81 100644
--- a/src/client/AbstractMapleCharacterObject.java
+++ b/src/client/AbstractMapleCharacterObject.java
@@ -19,18 +19,19 @@
*/
package client;
-import constants.GameConstants;
-import constants.ServerConstants;
+import config.YamlConfig;
+import constants.game.GameConstants;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
import net.server.audit.locks.MonitoredLockType;
+import net.server.audit.locks.MonitoredReadLock;
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
+import net.server.audit.locks.MonitoredWriteLock;
+import net.server.audit.locks.factory.MonitoredReadLockFactory;
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
+import net.server.audit.locks.factory.MonitoredWriteLockFactory;
import server.maps.AbstractAnimatedMapleMapObject;
import server.maps.MapleMap;
@@ -50,13 +51,13 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple
protected Map statUpdates = new HashMap<>();
protected Lock effLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_EFF, true);
- protected ReadLock statRlock;
- protected WriteLock statWlock;
+ protected MonitoredReadLock statRlock;
+ protected MonitoredWriteLock statWlock;
protected AbstractMapleCharacterObject() {
- ReentrantReadWriteLock locks = new MonitoredReentrantReadWriteLock(MonitoredLockType.CHARACTER_STA, true);
- statRlock = locks.readLock();
- statWlock = locks.writeLock();
+ MonitoredReentrantReadWriteLock locks = new MonitoredReentrantReadWriteLock(MonitoredLockType.CHARACTER_STA, true);
+ statRlock = MonitoredReadLockFactory.createLock(locks);
+ statWlock = MonitoredWriteLockFactory.createLock(locks);
for (int i = 0; i < remainingSp.length; i++) {
remainingSp[i] = 0;
@@ -220,6 +221,10 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple
listener.onHpmpPoolUpdate();
}
+ private void dispatchStatUpdated() {
+ listener.onStatUpdate();
+ }
+
private void dispatchStatPoolUpdateAnnounced() {
listener.onAnnounceStatPoolUpdate();
}
@@ -299,6 +304,7 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple
try {
statUpdates.clear();
boolean poolUpdate = false;
+ boolean statUpdate = false;
if (hpMpPool != null) {
short newHp = (short) (hpMpPool >> 48);
@@ -370,7 +376,7 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple
statUpdates.put(MapleStat.AVAILABLEAP, remainingAp);
}
- poolUpdate = true; // recalc stats
+ statUpdate = true;
}
if (newSp != null) {
@@ -385,6 +391,10 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple
if (poolUpdate) {
dispatchHpmpPoolUpdated();
}
+
+ if (statUpdate) {
+ dispatchStatUpdated();
+ }
if (!silent) {
dispatchStatPoolUpdateAnnounced();
@@ -626,19 +636,19 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple
}
int newStr = str + deltaStr, newDex = dex + deltaDex, newInt = int_ + deltaInt, newLuk = luk + deltaLuk;
- if (newStr < 4 && deltaStr != Short.MIN_VALUE || newStr > ServerConstants.MAX_AP) {
+ if (newStr < 4 && deltaStr != Short.MIN_VALUE || newStr > YamlConfig.config.server.MAX_AP) {
return false;
}
- if (newDex < 4 && deltaDex != Short.MIN_VALUE || newDex > ServerConstants.MAX_AP) {
+ if (newDex < 4 && deltaDex != Short.MIN_VALUE || newDex > YamlConfig.config.server.MAX_AP) {
return false;
}
- if (newInt < 4 && deltaInt != Short.MIN_VALUE || newInt > ServerConstants.MAX_AP) {
+ if (newInt < 4 && deltaInt != Short.MIN_VALUE || newInt > YamlConfig.config.server.MAX_AP) {
return false;
}
- if (newLuk < 4 && deltaLuk != Short.MIN_VALUE || newLuk > ServerConstants.MAX_AP) {
+ if (newLuk < 4 && deltaLuk != Short.MIN_VALUE || newLuk > YamlConfig.config.server.MAX_AP) {
return false;
}
diff --git a/src/client/MapleCharacter.java b/src/client/MapleCharacter.java
index 9c52ef0594..4f046b0a26 100644
--- a/src/client/MapleCharacter.java
+++ b/src/client/MapleCharacter.java
@@ -52,10 +52,13 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;
+import config.YamlConfig;
import net.server.PlayerBuffValueHolder;
import net.server.PlayerCoolDownValueHolder;
import net.server.Server;
-import net.server.coordinator.MapleInviteCoordinator;
+import net.server.audit.locks.MonitoredLockType;
+import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
+import net.server.coordinator.world.MapleInviteCoordinator;
import net.server.guild.MapleAlliance;
import net.server.guild.MapleGuild;
import net.server.guild.MapleGuildCharacter;
@@ -67,11 +70,11 @@ import net.server.world.PartyOperation;
import net.server.world.World;
import scripting.AbstractPlayerInteraction;
import scripting.event.EventInstanceManager;
+import scripting.item.ItemScriptManager;
import server.CashShop;
import server.MapleItemInformationProvider;
import server.MapleItemInformationProvider.ScriptedItem;
import server.MapleMarriage;
-import server.MaplePortal;
import server.MapleShop;
import server.MapleStatEffect;
import server.MapleStorage;
@@ -83,24 +86,29 @@ import server.events.RescueGaga;
import server.events.gm.MapleFitness;
import server.events.gm.MapleOla;
import server.life.MapleMonster;
+import server.life.MaplePlayerNPC;
import server.life.MobSkill;
+import server.life.MobSkillFactory;
+import server.maps.FieldLimit;
import server.maps.MapleHiredMerchant;
import server.maps.MapleDoor;
+import server.maps.MapleDoorObject;
import server.maps.MapleDragon;
import server.maps.MapleMap;
import server.maps.MapleMapEffect;
import server.maps.MapleMapManager;
+import server.maps.MapleMapItem;
import server.maps.MapleMapObject;
import server.maps.MapleMapObjectType;
import server.maps.MapleMiniGame;
import server.maps.MapleMiniGame.MiniGameResult;
import server.maps.MaplePlayerShop;
import server.maps.MaplePlayerShopItem;
+import server.maps.MaplePortal;
import server.maps.MapleSummon;
-import server.life.MaplePlayerNPC;
-import server.life.MonsterDropEntry;
import server.maps.SavedLocation;
import server.maps.SavedLocationType;
+import server.minigame.MapleRockPaperScissor;
import server.partyquest.AriantColiseum;
import server.partyquest.MonsterCarnival;
import server.partyquest.MonsterCarnivalParty;
@@ -129,16 +137,17 @@ import client.inventory.PetDataFactory;
import client.inventory.manipulator.MapleCashidGenerator;
import client.inventory.manipulator.MapleInventoryManipulator;
import client.newyear.NewYearCardRecord;
-import client.processor.FredrickProcessor;
-import constants.ExpTable;
-import constants.GameConstants;
-import constants.ItemConstants;
-import constants.ServerConstants;
+import client.processor.npc.FredrickProcessor;
+import client.processor.action.PetAutopotProcessor;
+import constants.game.ExpTable;
+import constants.game.GameConstants;
+import constants.inventory.ItemConstants;
import constants.skills.Aran;
import constants.skills.Beginner;
import constants.skills.Bishop;
import constants.skills.BlazeWizard;
import constants.skills.Bowmaster;
+import constants.skills.Brawler;
import constants.skills.Buccaneer;
import constants.skills.Corsair;
import constants.skills.Crusader;
@@ -160,13 +169,13 @@ import constants.skills.Priest;
import constants.skills.Ranger;
import constants.skills.Shadower;
import constants.skills.Sniper;
-import constants.skills.Swordsman;
+import constants.skills.Warrior;
import constants.skills.ThunderBreaker;
-import scripting.item.ItemScriptManager;
-import server.life.MobSkillFactory;
-import server.maps.MapleMapItem;
-import net.server.audit.locks.MonitoredLockType;
-import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
+import net.server.services.type.ChannelServices;
+import net.server.services.task.channel.FaceExpressionService;
+import net.server.services.task.world.CharacterSaveService;
+import net.server.services.type.WorldServices;
+import org.apache.mina.core.session.IoSession;
import org.apache.mina.util.ConcurrentHashSet;
public class MapleCharacter extends AbstractMapleCharacterObject {
@@ -191,7 +200,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
private int energybar;
private int gmLevel;
private int ci = 0;
- private MapleFamily family;
+ private MapleFamilyEntry familyEntry;
private int familyId;
private int bookCover;
private int battleshipHp = 0;
@@ -207,6 +216,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
private int localchairrate;
private boolean hidden, equipchanged = true, berserk, hasMerchant, hasSandboxItem = false, whiteChat = false, canRecvPartySearchInvite = true;
private boolean equippedMesoMagnet = false, equippedItemPouch = false, equippedPetItemIgnore = false;
+ private boolean usedSafetyCharm = false;
+ private float autopotHpAlert, autopotMpAlert;
private int linkedLevel = 0;
private String linkedName = null;
private boolean finishedDojoTutorial;
@@ -221,7 +232,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
private AtomicInteger exp = new AtomicInteger();
private AtomicInteger gachaexp = new AtomicInteger();
private AtomicInteger meso = new AtomicInteger();
- private AtomicInteger chair = new AtomicInteger();
+ private AtomicInteger chair = new AtomicInteger(-1);
private int merchantmeso;
private BuddyList buddylist;
private EventInstanceManager eventInstance = null;
@@ -233,6 +244,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
private MapleJob job = MapleJob.BEGINNER;
private MapleMessenger messenger = null;
private MapleMiniGame miniGame;
+ private MapleRockPaperScissor rps;
private MapleMount maplemount;
private MapleParty party;
private MaplePet[] pets = new MaplePet[3];
@@ -248,6 +260,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
private SkillMacro[] skillMacros = new SkillMacro[5];
private List lastmonthfameids;
private List> lastVisitedMaps = new LinkedList<>();
+ private WeakReference ownedMap = new WeakReference<>(null);
private final Map quests;
private Set controlled = new LinkedHashSet<>();
private Map entered = new LinkedHashMap<>();
@@ -302,6 +315,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
private List viptrockmaps = new ArrayList<>();
private Map events = new LinkedHashMap<>();
private PartyQuest partyQuest = null;
+ private List> npcUpdateQuests = new LinkedList<>();
private MapleDragon dragon = null;
private MapleRing marriageRing;
private int marriageItemid = -1;
@@ -311,7 +325,6 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
private boolean loggedIn = false;
private boolean useCS; //chaos scroll upon crafting item.
private long npcCd;
- private long petLootCd;
private long lastHpDec = 0;
private int newWarpMap = -1;
private boolean canWarpMap = true; //only one "warp" must be used per call, and this will define the right one.
@@ -325,6 +338,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
private int banishSp = -1;
private long banishTime = 0;
private long lastExpGainTime;
+ private boolean pendingNameChange; //only used to change name on logout, not to be relied upon elsewhere
+ private long loginTime;
private MapleCharacter() {
super.setListener(new AbstractCharacterListener() {
@@ -351,6 +366,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
+ @Override
+ public void onStatUpdate() {
+ recalcLocalStats();
+ }
+
@Override
public void onAnnounceStatPoolUpdate() {
List> statup = new ArrayList<>(8);
@@ -382,8 +402,6 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
quests = new LinkedHashMap<>();
setPosition(new Point(0, 0));
-
- petLootCd = Server.getInstance().getCurrentTime();
}
private static MapleJob getJobStyleInternal(int jobid, byte opt) {
@@ -423,7 +441,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
public static MapleCharacter getDefault(MapleClient c) {
MapleCharacter ret = new MapleCharacter();
ret.client = c;
- ret.gmLevel = 0;
+ ret.setGMLevel(0);
ret.hp = 50;
ret.setMaxHp(50);
ret.mp = 5;
@@ -448,7 +466,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
int[] selectedType;
int[] selectedAction;
- if(ServerConstants.USE_CUSTOM_KEYSET) {
+ if(YamlConfig.config.server.USE_CUSTOM_KEYSET) {
selectedKey = GameConstants.getCustomKey(true);
selectedType = GameConstants.getCustomType(true);
selectedAction = GameConstants.getCustomAction(true);
@@ -550,15 +568,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public void setSessionTransitionState() {
- client.getSession().setAttribute(MapleClient.CLIENT_TRANSITION);
- }
-
- public long getPetLootCd() {
- return petLootCd;
- }
-
- public void setPetLootCd(long cd) {
- petLootCd = cd;
+ client.setCharacterOnSessionTransitionState(this.getId());
}
public boolean getCS() {
@@ -789,28 +799,31 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
return false;
}
+
+ public int calculateMaxBaseDamage(int watk, MapleWeaponType weapon) {
+ int mainstat, secondarystat;
+ if (getJob().isA(MapleJob.THIEF) && weapon == MapleWeaponType.DAGGER_OTHER) {
+ weapon = MapleWeaponType.DAGGER_THIEVES;
+ }
+
+ if (weapon == MapleWeaponType.BOW || weapon == MapleWeaponType.CROSSBOW || weapon == MapleWeaponType.GUN) {
+ mainstat = localdex;
+ secondarystat = localstr;
+ } else if (weapon == MapleWeaponType.CLAW || weapon == MapleWeaponType.DAGGER_THIEVES) {
+ mainstat = localluk;
+ secondarystat = localdex + localstr;
+ } else {
+ mainstat = localstr;
+ secondarystat = localdex;
+ }
+ return (int) Math.ceil(((weapon.getMaxDamageMultiplier() * mainstat + secondarystat) / 100.0) * watk);
+ }
public int calculateMaxBaseDamage(int watk) {
int maxbasedamage;
Item weapon_item = getInventory(MapleInventoryType.EQUIPPED).getItem((short) -11);
if (weapon_item != null) {
- MapleWeaponType weapon = ii.getWeaponType(weapon_item.getItemId());
- int mainstat, secondarystat;
- if (getJob().isA(MapleJob.THIEF) && weapon == MapleWeaponType.DAGGER_OTHER) {
- weapon = MapleWeaponType.DAGGER_THIEVES;
- }
-
- if (weapon == MapleWeaponType.BOW || weapon == MapleWeaponType.CROSSBOW || weapon == MapleWeaponType.GUN) {
- mainstat = localdex;
- secondarystat = localstr;
- } else if (weapon == MapleWeaponType.CLAW || weapon == MapleWeaponType.DAGGER_THIEVES) {
- mainstat = localluk;
- secondarystat = localdex + localstr;
- } else {
- mainstat = localstr;
- secondarystat = localdex;
- }
- maxbasedamage = (int) (((weapon.getMaxDamageMultiplier() * mainstat + secondarystat) / 100.0) * watk);
+ maxbasedamage = calculateMaxBaseDamage(watk, ii.getWeaponType(weapon_item.getItemId()));
} else {
if (job.isA(MapleJob.PIRATE) || job.isA(MapleJob.THUNDERBREAKER1)) {
double weapMulti = 3;
@@ -819,13 +832,33 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
int attack = (int) Math.min(Math.floor((2 * getLevel() + 31) / 3), 31);
- maxbasedamage = (int) (localstr * weapMulti + localdex) * attack / 100;
+ maxbasedamage = (int) Math.ceil((localstr * weapMulti + localdex) * attack / 100.0);
} else {
maxbasedamage = 1;
}
}
return maxbasedamage;
}
+
+ public int calculateMaxBaseMagicDamage(int matk) {
+ int maxbasedamage = matk;
+ int totalint = getTotalInt();
+
+ if (totalint > 2000) {
+ maxbasedamage -= 2000;
+ maxbasedamage += (int) ((0.09033024267 * totalint) + 3823.8038);
+ } else {
+ maxbasedamage -= totalint;
+
+ if (totalint > 1700) {
+ maxbasedamage += (int) (0.1996049769 * Math.pow(totalint, 1.300631341));
+ } else {
+ maxbasedamage += (int) (0.1996049769 * Math.pow(totalint, 1.290631341));
+ }
+ }
+
+ return (maxbasedamage * 107) / 100;
+ }
public void setCombo(short count) {
if (count < combocounter) {
@@ -907,6 +940,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
for(MapleSummon ms: this.getSummonsValues()) {
getMap().broadcastNONGMMessage(this, MaplePacketCreator.spawnSummon(ms, false), false);
}
+
+ for (MapleMapObject mo : this.getMap().getMonsters()) {
+ MapleMonster m = (MapleMonster) mo;
+ m.aggroUpdateController();
+ }
} else {
this.hidden = true;
announce(MaplePacketCreator.getGMEffect(0x10, (byte) 1));
@@ -1087,6 +1125,29 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
}
+
+ private void broadcastChangeJob() {
+ for (MapleCharacter chr : map.getAllPlayers()) {
+ MapleClient chrC = chr.getClient();
+
+ if (chrC != null) { // propagate new job 3rd-person effects (FJ, Aran 1st strike, etc)
+ this.sendDestroyData(chrC);
+ this.sendSpawnData(chrC);
+ }
+ }
+
+ TimerManager.getInstance().schedule(new Runnable() { // need to delay to ensure clientside has finished reloading character data
+ @Override
+ public void run() {
+ MapleCharacter thisChr = MapleCharacter.this;
+ MapleMap map = thisChr.getMap();
+
+ if (map != null) {
+ map.broadcastMessage(thisChr, MaplePacketCreator.showForeignEffect(thisChr.getId(), 8), false);
+ }
+ }
+ }, 777);
+ }
public synchronized void changeJob(MapleJob newJob) {
if (newJob == null) {
@@ -1109,7 +1170,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
spGain += 2;
}
- if (ServerConstants.USE_ENFORCE_JOB_SP_RANGE) {
+ if (YamlConfig.config.server.USE_ENFORCE_JOB_SP_RANGE) {
spGain = getChangedJobSp(newJob);
}
}
@@ -1123,7 +1184,13 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
if (this.isCygnus()) {
gainAp(7, true);
} else {
- gainAp(5, true);
+ if (YamlConfig.config.server.USE_STARTING_AP_4 || newJob.getId() % 10 >= 1) {
+ gainAp(5, true);
+ }
+ }
+ } else { // thanks Periwinks for noticing an AP shortage from lower levels
+ if (YamlConfig.config.server.USE_STARTING_AP_4 && newJob.getId() % 1000 >= 1) {
+ gainAp(4, true);
}
}
@@ -1196,10 +1263,14 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
if (this.guildid > 0) {
getGuild().broadcast(MaplePacketCreator.jobMessage(0, job.getId(), name), this.getId());
}
+ MapleFamily family = getFamily();
+ if(family != null) {
+ family.broadcast(MaplePacketCreator.jobMessage(1, job.getId(), name), this.getId());
+ }
setMasteries(this.job.getId());
guildUpdate();
- getMap().broadcastMessage(this, MaplePacketCreator.showForeignEffect(this.getId(), 8), false);
+ broadcastChangeJob();
if (GameConstants.hasSPTable(newJob) && newJob.getId() != 2001) {
if (getBuffedValue(MapleBuffStat.MONSTER_RIDING) != null) {
@@ -1208,7 +1279,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
createDragon();
}
- if (ServerConstants.USE_ANNOUNCE_CHANGEJOB) {
+ if (YamlConfig.config.server.USE_ANNOUNCE_CHANGEJOB) {
if (!this.isGM()) {
broadcastAcquaintances(6, "[" + GameConstants.ordinal(GameConstants.getJobBranch(newJob)) + " Job] " + name + " has just become a " + GameConstants.getJobName(this.job.getId()) + "."); // thanks Vcoc for noticing job name appearing in uppercase here
}
@@ -1221,9 +1292,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
public void broadcastAcquaintances(byte[] packet) {
buddylist.broadcast(packet, getWorldServer().getPlayerStorage());
-
+ MapleFamily family = getFamily();
if(family != null) {
- //family.broadcast(packet, id); not yet implemented
+ family.broadcast(packet, id);
}
MapleGuild guild = getGuild();
@@ -1253,7 +1324,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public void broadcastStance() {
- map.broadcastMessage(this, MaplePacketCreator.movePlayer(id, this.getIdleMovement()), false);
+ map.broadcastMessage(this, MaplePacketCreator.movePlayer(id, this.getIdleMovement(), getIdleMovementDataLength()), false);
}
public MapleMap getWarpMap(int map) {
@@ -1309,7 +1380,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public void changeMapBanish(int mapid, String portal, String msg) {
- if(ServerConstants.USE_SPIKES_AVOID_BANISH) {
+ if(YamlConfig.config.server.USE_SPIKES_AVOID_BANISH) {
for(Item it: this.getInventory(MapleInventoryType.EQUIPPED).list()) {
if((it.getFlag() & ItemConstants.SPIKES) == ItemConstants.SPIKES) {
return;
@@ -1520,7 +1591,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
List partyMembers = new LinkedList<>();
- for(MapleCharacter mc : (exPartyMembers != null) ? exPartyMembers : this.getPartyMembers()) {
+ for(MapleCharacter mc : (exPartyMembers != null) ? exPartyMembers : this.getPartyMembersOnline()) {
if(mc.isLoggedinWorld()) {
partyMembers.add(mc);
}
@@ -1585,7 +1656,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
for(MapleDoor door : partyDoors.values()) {
for(MapleCharacter pchar : partyMembers) {
- door.getTownDoor().sendDestroyData(pchar.getClient(), true);
+ MapleDoorObject mdo = door.getTownDoor();
+ mdo.sendDestroyData(pchar.getClient(), true);
+ pchar.removeVisibleMapObject(mdo);
}
}
@@ -1593,7 +1666,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
Collection leaverDoors = partyLeaver.getDoors();
for(MapleDoor door : leaverDoors) {
for(MapleCharacter pchar : partyMembers) {
- door.getTownDoor().sendDestroyData(pchar.getClient(), true);
+ MapleDoorObject mdo = door.getTownDoor();
+ mdo.sendDestroyData(pchar.getClient(), true);
+ pchar.removeVisibleMapObject(mdo);
}
}
}
@@ -1604,7 +1679,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
if(door != null) {
for(MapleCharacter pchar : partyMembers) {
- door.getTownDoor().sendSpawnData(pchar.getClient());
+ MapleDoorObject mdo = door.getTownDoor();
+ mdo.sendSpawnData(pchar.getClient());
+ pchar.addVisibleMapObject(mdo);
}
}
}
@@ -1615,17 +1692,24 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
if(partyDoors != null) {
for(MapleDoor door : partyDoors.values()) {
- door.getTownDoor().sendDestroyData(partyLeaver.getClient(), true);
+ MapleDoorObject mdo = door.getTownDoor();
+ mdo.sendDestroyData(partyLeaver.getClient(), true);
+ partyLeaver.removeVisibleMapObject(mdo);
}
}
for(MapleDoor door : leaverDoors) {
- door.getTownDoor().sendDestroyData(partyLeaver.getClient(), true);
+ MapleDoorObject mdo = door.getTownDoor();
+ mdo.sendDestroyData(partyLeaver.getClient(), true);
+ partyLeaver.removeVisibleMapObject(mdo);
}
for(MapleDoor door : leaverDoors) {
door.updateDoorPortal(partyLeaver);
- door.getTownDoor().sendSpawnData(partyLeaver.getClient());
+
+ MapleDoorObject mdo = door.getTownDoor();
+ mdo.sendSpawnData(partyLeaver.getClient());
+ partyLeaver.addVisibleMapObject(mdo);
}
}
}
@@ -1650,7 +1734,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
int idx = getVisitedMapIndex(map);
if(idx == -1) {
- if(lastVisitedMaps.size() == ServerConstants.MAP_VISITED_SIZE) {
+ if(lastVisitedMaps.size() == YamlConfig.config.server.MAP_VISITED_SIZE) {
lastVisitedMaps.remove(0);
}
} else {
@@ -1664,6 +1748,14 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
petLock.unlock();
}
}
+
+ public void setOwnedMap(MapleMap map) {
+ ownedMap = new WeakReference<>(map);
+ }
+
+ public MapleMap getOwnedMap() {
+ return ownedMap.get();
+ }
public void notifyMapTransferToPartner(int mapid) {
if(partnerId > 0) {
@@ -2248,6 +2340,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
ps.setInt(1, cid);
ps.executeUpdate();
}
+ try (PreparedStatement ps = con.prepareStatement("DELETE FROM family_character WHERE cid = ?")) {
+ ps.setInt(1, cid);
+ ps.executeUpdate();
+ }
try (PreparedStatement ps = con.prepareStatement("DELETE FROM famelog WHERE characterid_to = ?")) {
ps.setInt(1, cid);
ps.executeUpdate();
@@ -2285,7 +2381,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
int petid = rs.getInt("petid");
- if(petid > -1) {
+ if(!rs.wasNull()) {
try (PreparedStatement ps2 = con.prepareStatement("DELETE FROM pets WHERE petid = ?")) {
ps2.setInt(1, petid);
ps2.executeUpdate();
@@ -2377,10 +2473,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
private static Pair> getChairTaskIntervalRate(int maxhp, int maxmp) {
float toHeal = Math.max(maxhp, maxmp);
- float maxDuration = ServerConstants.CHAIR_EXTRA_HEAL_MAX_DELAY * 1000;
+ float maxDuration = YamlConfig.config.server.CHAIR_EXTRA_HEAL_MAX_DELAY * 1000;
int rate = 0;
- int minRegen = 1, maxRegen = (256 * ServerConstants.CHAIR_EXTRA_HEAL_MULTIPLIER) - 1, midRegen = 1;
+ int minRegen = 1, maxRegen = (256 * YamlConfig.config.server.CHAIR_EXTRA_HEAL_MULTIPLIER) - 1, midRegen = 1;
while (minRegen < maxRegen) {
midRegen = (int) ((minRegen + maxRegen) * 0.94);
@@ -2435,7 +2531,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
private void startChairTask() {
- if (chair.get() == 0) {
+ if (chair.get() < 0) {
return;
}
@@ -2462,7 +2558,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
final int healMP = localchairmp;
if(MapleCharacter.this.getHp() < localmaxhp) {
- byte recHP = (byte) (healHP / ServerConstants.CHAIR_EXTRA_HEAL_MULTIPLIER);
+ byte recHP = (byte) (healHP / YamlConfig.config.server.CHAIR_EXTRA_HEAL_MULTIPLIER);
client.announce(MaplePacketCreator.showOwnRecovery(recHP));
getMap().broadcastMessage(MapleCharacter.this, MaplePacketCreator.showRecovery(id, recHP), false);
@@ -2534,7 +2630,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public void dispel() {
- if(!(ServerConstants.USE_UNDISPEL_HOLY_SHIELD && this.isActiveBuffedValue(Bishop.HOLY_SHIELD))) {
+ if(!(YamlConfig.config.server.USE_UNDISPEL_HOLY_SHIELD && this.hasActiveBuff(Bishop.HOLY_SHIELD))) {
List mbsvhList = getAllStatups();
for (MapleBuffStatValueHolder mbsvh : mbsvhList) {
if (mbsvh.effect.isSkill()) {
@@ -2627,10 +2723,28 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
+ public void collectDiseases() {
+ for (MapleCharacter chr : map.getAllPlayers()) {
+ int cid = chr.getId();
+
+ for (Entry> di : chr.getAllDiseases().entrySet()) {
+ MapleDisease disease = di.getKey();
+ MobSkill skill = di.getValue().getRight();
+ final List> debuff = Collections.singletonList(new Pair<>(disease, Integer.valueOf(skill.getX())));
+
+ if (disease != MapleDisease.SLOW) {
+ this.announce(MaplePacketCreator.giveForeignDebuff(cid, debuff, skill));
+ } else {
+ this.announce(MaplePacketCreator.giveForeignSlowDebuff(cid, debuff, skill));
+ }
+ }
+ }
+ }
+
public void giveDebuff(final MapleDisease disease, MobSkill skill) {
if (!hasDisease(disease) && getDiseasesSize() < 2) {
if (!(disease == MapleDisease.SEDUCE || disease == MapleDisease.STUN)) {
- if (isActiveBuffedValue(Bishop.HOLY_SHIELD)) {
+ if (hasActiveBuff(Bishop.HOLY_SHIELD)) {
return;
}
}
@@ -2644,8 +2758,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
chrLock.unlock();
}
- if (disease == MapleDisease.SEDUCE && chair.get() != 0) {
- sitChair(0);
+ if (disease == MapleDisease.SEDUCE && chair.get() < 0) {
+ sitChair(-1);
}
final List> debuff = Collections.singletonList(new Pair<>(disease, Integer.valueOf(skill.getX())));
@@ -2687,6 +2801,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
dispelDebuff(MapleDisease.SEAL);
dispelDebuff(MapleDisease.WEAKEN);
dispelDebuff(MapleDisease.SLOW);
+ dispelDebuff(MapleDisease.ZOMBIFY);
+ dispelDebuff(MapleDisease.CONFUSE);
}
public void cancelAllDebuffs() {
@@ -2734,7 +2850,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
long timeNow = Server.getInstance().getCurrentTime();
if(timeNow - lastExpression > 2000) {
lastExpression = timeNow;
- client.getChannelServer().registerFaceExpression(map, this, emote);
+
+ FaceExpressionService service = (FaceExpressionService) client.getChannelServer().getServiceAccess(ChannelServices.FACE_EXPRESSION);
+ service.registerFaceExpression(map, this, emote);
}
}
@@ -2751,7 +2869,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
public void run() {
doHurtHp();
}
- }, ServerConstants.MAP_DAMAGE_OVERTIME_INTERVAL, ServerConstants.MAP_DAMAGE_OVERTIME_INTERVAL - lastHpTask);
+ }, YamlConfig.config.server.MAP_DAMAGE_OVERTIME_INTERVAL, YamlConfig.config.server.MAP_DAMAGE_OVERTIME_INTERVAL - lastHpTask);
}
public void resetHpDecreaseTask() {
@@ -2760,7 +2878,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
long lastHpTask = Server.getInstance().getCurrentTime() - lastHpDec;
- startHpDecreaseTask((lastHpTask > ServerConstants.MAP_DAMAGE_OVERTIME_INTERVAL) ? ServerConstants.MAP_DAMAGE_OVERTIME_INTERVAL : lastHpTask);
+ startHpDecreaseTask((lastHpTask > YamlConfig.config.server.MAP_DAMAGE_OVERTIME_INTERVAL) ? YamlConfig.config.server.MAP_DAMAGE_OVERTIME_INTERVAL : lastHpTask);
}
public void dropMessage(String message) {
@@ -2926,9 +3044,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
expiration = item.getExpiration();
if (expiration != -1 && (expiration < currenttime) && ((item.getFlag() & ItemConstants.LOCK) == ItemConstants.LOCK)) {
- byte aids = item.getFlag();
- aids &= ~(ItemConstants.LOCK);
- item.setFlag(aids); //Probably need a check, else people can make expiring items into permanent items...
+ short lock = item.getFlag();
+ lock &= ~(ItemConstants.LOCK);
+ item.setFlag(lock); //Probably need a check, else people can make expiring items into permanent items...
item.setExpiration(-1);
forceUpdateItem(item); //TEST :3
} else if (expiration != -1 && expiration < currenttime) {
@@ -2939,6 +3057,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
deletedCoupon = true;
}
} else {
+ MaplePet pet = item.getPet(); // thanks Lame for noticing pets not getting despawned after expiration time
+ if (pet != null) {
+ unequipPet(pet, true);
+ }
+
if (ItemConstants.isExpirablePet(item.getItemId())) {
client.announce(MaplePacketCreator.itemExpired(item.getItemId()));
toberemove.add(item);
@@ -3409,17 +3532,44 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
+ public boolean hasActiveBuff(int sourceid) {
+ LinkedList allBuffs;
+
+ effLock.lock();
+ chrLock.lock();
+ try {
+ allBuffs = new LinkedList<>(effects.values());
+ } finally {
+ chrLock.unlock();
+ effLock.unlock();
+ }
+
+ for (MapleBuffStatValueHolder mbsvh : allBuffs) {
+ if (mbsvh.effect.getBuffSourceId() == sourceid) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private List> getActiveStatupsFromSourceid(int sourceid) { // already under effLock & chrLock
List> ret = new ArrayList<>();
-
+ List> singletonStatups = new ArrayList<>();
for(Entry bel : buffEffects.get(sourceid).entrySet()) {
MapleBuffStat mbs = bel.getKey();
MapleBuffStatValueHolder mbsvh = effects.get(bel.getKey());
+ Pair p;
if(mbsvh != null) {
- ret.add(new Pair<>(mbs, mbsvh.value));
+ p = new Pair<>(mbs, mbsvh.value);
} else {
- ret.add(new Pair<>(mbs, 0));
+ p = new Pair<>(mbs, 0);
+ }
+
+ if (!isSingletonStatup(mbs)) { // thanks resinate, Egg Daddy for pointing out morph issues when updating it along with other statups
+ ret.add(p);
+ } else {
+ singletonStatups.add(p);
}
}
@@ -3430,6 +3580,17 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
});
+ if (!singletonStatups.isEmpty()) {
+ Collections.sort(singletonStatups, new Comparator>() {
+ @Override
+ public int compare(Pair p1, Pair p2) {
+ return p1.getLeft().compareTo(p2.getLeft());
+ }
+ });
+
+ ret.addAll(singletonStatups);
+ }
+
return ret;
}
@@ -3705,12 +3866,31 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public boolean cancelEffect(MapleStatEffect effect, boolean overwrite, long startTime) {
+ boolean ret;
+
+ prtLock.lock();
effLock.lock();
try {
- return cancelEffect(effect, overwrite, startTime, true);
+ ret = cancelEffect(effect, overwrite, startTime, true);
} finally {
effLock.unlock();
+ prtLock.unlock();
}
+
+ if (effect.isMagicDoor() && ret) {
+ prtLock.lock();
+ effLock.lock();
+ try {
+ if (!hasBuffFromSourceid(Priest.MYSTIC_DOOR)) {
+ MapleDoor.attemptRemoveDoor(this);
+ }
+ } finally {
+ effLock.unlock();
+ prtLock.unlock();
+ }
+ }
+
+ return ret;
}
private static MapleStatEffect getEffectFromBuffSource(Map buffSource) {
@@ -3811,18 +3991,14 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
buffstats = extractLeastRelevantStatEffectsIfFull(effect);
}
- if (effect.isMagicDoor()) {
- MapleDoor.attemptRemoveDoor(this);
- } else if (effect.isMapChair()) {
+ if (effect.isMapChair()) {
stopChairTask();
}
List> toCancel = deregisterBuffStats(buffstats);
if (effect.isMonsterRiding()) {
- if (effect.getSourceId() != Corsair.BATTLE_SHIP) {
- this.getClient().getWorldServer().unregisterMountHunger(this);
- this.getMount().setActive(false);
- }
+ this.getClient().getWorldServer().unregisterMountHunger(this);
+ this.getMount().setActive(false);
}
if (!overwrite) {
@@ -3930,7 +4106,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
for(Entry it : stats.entrySet()) {
boolean uniqueBuff = isSingletonStatup(it.getKey());
- if(it.getValue() >= (!uniqueBuff ? ServerConstants.MAX_MONITORED_BUFFSTATS : 1) && effectStatups.contains(it.getKey())) {
+ if(it.getValue() >= (!uniqueBuff ? YamlConfig.config.server.MAX_MONITORED_BUFFSTATS : 1) && effectStatups.contains(it.getKey())) {
MapleBuffStatValueHolder mbsvh = minStatBuffs.get(it.getKey());
Map lpbe = buffEffects.get(mbsvh.effect.getBuffSourceId());
@@ -4094,6 +4270,44 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
return topologicalSortEffects(buffEffects);
}
+ private List>> propagatePriorityBuffEffectUpdates(Set retrievedStats) {
+ List>> priorityUpdateEffects = new LinkedList<>();
+ Map yokeStats = new LinkedHashMap<>();
+
+ // priority buffsources: override buffstats for the client to perceive those as "currently buffed"
+ Set mbsvhList = new LinkedHashSet<>();
+ for (MapleBuffStatValueHolder mbsvh : getAllStatups()) {
+ mbsvhList.add(mbsvh);
+ }
+
+ for (MapleBuffStatValueHolder mbsvh : mbsvhList) {
+ MapleStatEffect mse = mbsvh.effect;
+ int buffSourceId = mse.getBuffSourceId();
+ if (isPriorityBuffSourceid(buffSourceId) && !hasActiveBuff(buffSourceId)) {
+ for (Pair ps : mse.getStatups()) {
+ MapleBuffStat mbs = ps.getLeft();
+ if (retrievedStats.contains(mbs)) {
+ MapleBuffStatValueHolder mbsvhe = effects.get(mbs);
+
+ // this shouldn't even be null...
+ //if (mbsvh != null) {
+ yokeStats.put(mbsvh, mbsvhe.effect);
+ //}
+ }
+ }
+ }
+ }
+
+ for (Entry e : yokeStats.entrySet()) {
+ MapleBuffStatValueHolder mbsvhPriority = e.getKey();
+ MapleStatEffect mseActive = e.getValue();
+
+ priorityUpdateEffects.add(new Pair<>(mseActive.getBuffSourceId(), new Pair<>(mbsvhPriority.effect, mbsvhPriority.startTime)));
+ }
+
+ return priorityUpdateEffects;
+ }
+
private void propagateBuffEffectUpdates(Map> retrievedEffects, Set retrievedStats, Set removedStats) {
cancelInactiveBuffStats(retrievedStats, removedStats);
if (retrievedStats.isEmpty()) {
@@ -4182,6 +4396,18 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
activeStatups.clear();
}
+ List>> priorityEffects = propagatePriorityBuffEffectUpdates(retrievedStats);
+ for(Pair> lmse: priorityEffects) {
+ Pair msel = lmse.getRight();
+
+ for(Pair statup : getActiveStatupsFromSourceid(lmse.getLeft())) {
+ activeStatups.add(statup);
+ }
+
+ msel.getLeft().updateBuffEffect(this, activeStatups, msel.getRight());
+ activeStatups.clear();
+ }
+
if (this.isRidingBattleship()) {
List> statups = new ArrayList<>(1);
statups.add(new Pair<>(MapleBuffStat.MONSTER_RIDING, 0));
@@ -4230,6 +4456,18 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
+ private static boolean isPriorityBuffSourceid(int sourceid) {
+ switch(sourceid) {
+ case -2022631:
+ case -2022632:
+ case -2022633:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
private void addItemEffectHolderCount(MapleBuffStat stat) {
Byte val = buffEffectsCount.get(stat);
if (val != null) {
@@ -4292,7 +4530,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}, buffInterval, buffInterval);
}
} else if (effect.isRecovery()) {
- int healInterval = (ServerConstants.USE_ULTRA_RECOVERY) ? 2000 : 5000;
+ int healInterval = (YamlConfig.config.server.USE_ULTRA_RECOVERY) ? 2000 : 5000;
final byte heal = (byte) effect.getX();
chrLock.lock();
@@ -4349,6 +4587,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
startChairTask();
}
+ prtLock.lock();
effLock.lock();
chrLock.lock();
try {
@@ -4361,11 +4600,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
boolean active = effect.isActive(this);
- if(ServerConstants.USE_BUFF_MOST_SIGNIFICANT) {
+ if(YamlConfig.config.server.USE_BUFF_MOST_SIGNIFICANT) {
toDeploy = new LinkedHashMap<>();
Map> retrievedEffects = new LinkedHashMap<>();
Set retrievedStats = new LinkedHashSet<>();
-
for (Entry statup : appliedStatups.entrySet()) {
MapleBuffStatValueHolder mbsvh = effects.get(statup.getKey());
MapleBuffStatValueHolder statMbsvh = statup.getValue();
@@ -4385,6 +4623,18 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
addItemEffectHolderCount(statup.getKey());
}
+ // should also propagate update from buffs shared with priority sourceids
+ Set updated = appliedStatups.keySet();
+ for (MapleBuffStatValueHolder mbsvh : this.getAllStatups()) {
+ if (isPriorityBuffSourceid(mbsvh.effect.getBuffSourceId())) {
+ for (Pair p : mbsvh.effect.getStatups()) {
+ if (updated.contains(p.getLeft())) {
+ retrievedStats.add(p.getLeft());
+ }
+ }
+ }
+ }
+
if(!isSilent) {
addItemEffectHolder(sourceid, expirationtime, appliedStatups);
for (Entry statup : toDeploy.entrySet()) {
@@ -4412,6 +4662,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
} finally {
chrLock.unlock();
effLock.unlock();
+ prtLock.unlock();
}
updateLocalStats();
@@ -4429,7 +4680,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public boolean unregisterChairBuff() {
- if (!ServerConstants.USE_CHAIR_EXTRAHEAL) {
+ if (!YamlConfig.config.server.USE_CHAIR_EXTRAHEAL) {
return false;
}
@@ -4444,7 +4695,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public boolean registerChairBuff() {
- if (!ServerConstants.USE_CHAIR_EXTRAHEAL) {
+ if (!YamlConfig.config.server.USE_CHAIR_EXTRAHEAL) {
return false;
}
@@ -4475,19 +4726,23 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
return client.getAbstractPlayerInteraction();
}
- public final List getCompletedQuests() {
+ private List getQuests() {
synchronized (quests) {
- List ret = new LinkedList<>();
- for (MapleQuestStatus q : quests.values()) {
- if (q.getStatus().equals(MapleQuestStatus.Status.COMPLETED)) {
- ret.add(q);
- }
- }
-
- return Collections.unmodifiableList(ret);
+ return new ArrayList<>(quests.values());
}
}
+ public final List getCompletedQuests() {
+ List ret = new LinkedList<>();
+ for (MapleQuestStatus qs : getQuests()) {
+ if (qs.getStatus().equals(MapleQuestStatus.Status.COMPLETED)) {
+ ret.add(qs);
+ }
+ }
+
+ return Collections.unmodifiableList(ret);
+ }
+
public List getCrushRings() {
Collections.sort(crushRings);
return crushRings;
@@ -4720,7 +4975,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public boolean hasNoviceExpRate() {
- return ServerConstants.USE_ENFORCE_NOVICE_EXPRATE && isBeginnerJob() && level < 11;
+ return YamlConfig.config.server.USE_ENFORCE_NOVICE_EXPRATE && isBeginnerJob() && level < 11;
}
public int getExpRate() {
@@ -4769,6 +5024,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public int getQuestExpRate() {
+ if (hasNoviceExpRate()) {
+ return 1;
+ }
+
World w = getWorldServer();
return w.getExpRate() * w.getQuestRate();
}
@@ -4805,11 +5064,17 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public MapleFamily getFamily() {
- return family;
+ if(familyEntry != null) return familyEntry.getFamily();
+ else return null;
}
-
- public void setFamily(MapleFamily f) {
- this.family = f;
+
+ public MapleFamilyEntry getFamilyEntry() {
+ return familyEntry;
+ }
+
+ public void setFamilyEntry(MapleFamilyEntry entry) {
+ if(entry != null) setFamilyId(entry.getFamily().getID());
+ this.familyEntry = entry;
}
public int getFamilyId() {
@@ -5080,7 +5345,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
public int getTotalMagic() {
return localmagic;
}
-
+
public int getTotalWatk() {
return localwatk;
}
@@ -5090,7 +5355,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public int getMaxLevel() {
- if(!ServerConstants.USE_ENFORCE_JOB_LEVEL_RANGE || isGmJob()) {
+ if(!YamlConfig.config.server.USE_ENFORCE_JOB_LEVEL_RANGE || isGmJob()) {
return getMaxClassLevel();
}
@@ -5282,14 +5547,17 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
- public List getPartyMembers() {
+ public List getPartyMembersOnline() {
List list = new LinkedList<>();
prtLock.lock();
try {
if(party != null) {
- for(MaplePartyCharacter partyMembers: party.getMembers()) {
- list.add(partyMembers.getPlayer());
+ for(MaplePartyCharacter mpc: party.getMembers()) {
+ MapleCharacter mc = mpc.getPlayer();
+ if (mc != null) {
+ list.add(mc);
+ }
}
}
} finally {
@@ -5306,11 +5574,13 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
prtLock.lock();
try {
if(party != null) {
- for(MaplePartyCharacter partyMembers: party.getMembers()) {
- MapleCharacter chr = partyMembers.getPlayer();
- MapleMap chrMap = chr.getMap();
- if(chrMap != null && chrMap.hashCode() == thisMapHash && chr.isLoggedinWorld()) {
- list.add(chr);
+ for(MaplePartyCharacter mpc: party.getMembers()) {
+ MapleCharacter chr = mpc.getPlayer();
+ if (chr != null) {
+ MapleMap chrMap = chr.getMap();
+ if(chrMap != null && chrMap.hashCode() == thisMapHash && chr.isLoggedinWorld()) {
+ list.add(chr);
+ }
}
}
}
@@ -5326,10 +5596,13 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public boolean isPartyMember(int cid) {
- for(MapleCharacter mpcu: getPartyMembers()) {
- if(mpcu.getId() == cid) {
- return true;
+ prtLock.lock();
+ try {
+ if(party != null) {
+ return party.getMemberById(cid) != null;
}
+ } finally {
+ prtLock.unlock();
}
return false;
@@ -5339,9 +5612,15 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
return playerShop;
}
+ public MapleRockPaperScissor getRPS() { // thanks inhyuk for suggesting RPS addition
+ return rps;
+ }
+
public void setGMLevel(int level) {
this.gmLevel = Math.min(level, 6);
this.gmLevel = Math.max(level, 0);
+
+ whiteChat = gmLevel >= 4; // thanks ozanrijen for suggesting default white chat
}
public void closePartySearchInteractions() {
@@ -5356,6 +5635,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
closeTrade();
closePlayerShop();
closeMiniGame(true);
+ closeRPS();
closeHiredMerchant(false);
closePlayerMessenger();
@@ -5512,32 +5792,28 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
public final byte getQuestStatus(final int quest) {
synchronized (quests) {
- for (final MapleQuestStatus q : quests.values()) {
- if (q.getQuest().getId() == quest) {
- return (byte) q.getStatus().getId();
- }
+ MapleQuestStatus mqs = quests.get((short) quest);
+ if (mqs != null) {
+ return (byte) mqs.getStatus().getId();
+ } else {
+ return 0;
}
- return 0;
}
}
- public final MapleQuestStatus getMapleQuestStatus(final int quest) {
- synchronized (quests) {
- for (final MapleQuestStatus q : quests.values()) {
- if (q.getQuest().getId() == quest) {
- return q;
- }
- }
- return null;
- }
+ public MapleQuestStatus getQuest(final int quest) {
+ return getQuest(MapleQuest.getInstance(quest));
}
-
+
public MapleQuestStatus getQuest(MapleQuest quest) {
synchronized (quests) {
- if (!quests.containsKey(quest.getId())) {
- return new MapleQuestStatus(quest, MapleQuestStatus.Status.NOT_STARTED);
+ short questid = quest.getId();
+ MapleQuestStatus qs = quests.get(questid);
+ if (qs == null) {
+ qs = new MapleQuestStatus(quest, MapleQuestStatus.Status.NOT_STARTED);
+ quests.put(questid, qs);
}
- return quests.get(quest.getId());
+ return qs;
}
}
@@ -5586,13 +5862,19 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
int amountNeeded, questStatus = this.getQuestStatus(questid);
if (questStatus == 0) {
amountNeeded = MapleQuest.getInstance(questid).getStartItemAmountNeeded(itemid);
+ if (amountNeeded == Integer.MIN_VALUE) {
+ return false;
+ }
} else if (questStatus != 1) {
return false;
} else {
amountNeeded = MapleQuest.getInstance(questid).getCompleteItemAmountNeeded(itemid);
+ if (amountNeeded == Integer.MAX_VALUE) {
+ return true;
+ }
}
- return amountNeeded > 0 && getInventory(ItemConstants.getInventoryType(itemid)).countById(itemid) < amountNeeded;
+ return getInventory(ItemConstants.getInventoryType(itemid)).countById(itemid) < amountNeeded;
}
public int getRank() {
@@ -5673,32 +5955,15 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public final List getStartedQuests() {
- synchronized (quests) {
- List ret = new LinkedList<>();
- for (MapleQuestStatus q : quests.values()) {
- if (q.getStatus().equals(MapleQuestStatus.Status.STARTED)) {
- ret.add(q);
- }
+ List ret = new LinkedList<>();
+ for (MapleQuestStatus qs : getQuests()) {
+ if (qs.getStatus().equals(MapleQuestStatus.Status.STARTED)) {
+ ret.add(qs);
}
- return Collections.unmodifiableList(ret);
}
+ return Collections.unmodifiableList(ret);
}
-
- public final int getStartedQuestsSize() {
- synchronized (quests) {
- int i = 0;
- for (MapleQuestStatus q : quests.values()) {
- if (q.getStatus().equals(MapleQuestStatus.Status.STARTED)) {
- if (q.getQuest().getInfoNumber() > 0) {
- i++;
- }
- i++;
- }
- }
- return i;
- }
- }
-
+
public MapleStatEffect getStatForBuff(MapleBuffStat effect) {
effLock.lock();
chrLock.lock();
@@ -5849,12 +6114,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public boolean hasEntered(String script, int mapId) {
- if (entered.containsKey(mapId)) {
- if (entered.get(mapId).equals(script)) {
- return true;
- }
- }
- return false;
+ String e = entered.get(mapId);
+ return script.equals(e);
}
public void hasGivenFame(MapleCharacter to) {
@@ -5908,26 +6169,6 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
dropMessage(1, "Your guild already reached the maximum capacity of players.");
}
}
-
- public boolean isActiveBuffedValue(int skillid) {
- LinkedList allBuffs;
-
- effLock.lock();
- chrLock.lock();
- try {
- allBuffs = new LinkedList<>(effects.values());
- } finally {
- chrLock.unlock();
- effLock.unlock();
- }
-
- for (MapleBuffStatValueHolder mbsvh : allBuffs) {
- if (mbsvh.effect.isSkill() && mbsvh.effect.getSourceId() == skillid) {
- return true;
- }
- }
- return false;
- }
private boolean canBuyback(int fee, boolean usingMesos) {
return (usingMesos ? this.getMeso() : cashshop.getCash(1)) >= fee;
@@ -5942,7 +6183,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
private long getNextBuybackTime() {
- return lastBuyback + ServerConstants.BUYBACK_COOLDOWN_MINUTES * 60 * 1000;
+ return lastBuyback + YamlConfig.config.server.BUYBACK_COOLDOWN_MINUTES * 60 * 1000;
}
private boolean isBuybackInvincible() {
@@ -5950,30 +6191,30 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
private int getBuybackFee() {
- float fee = ServerConstants.BUYBACK_FEE;
+ float fee = YamlConfig.config.server.BUYBACK_FEE;
int grade = Math.min(Math.max(level, 30), 120) - 30;
- fee += (grade * ServerConstants.BUYBACK_LEVEL_STACK_FEE);
- if (ServerConstants.USE_BUYBACK_WITH_MESOS) {
- fee *= ServerConstants.BUYBACK_MESO_MULTIPLIER;
+ fee += (grade * YamlConfig.config.server.BUYBACK_LEVEL_STACK_FEE);
+ if (YamlConfig.config.server.USE_BUYBACK_WITH_MESOS) {
+ fee *= YamlConfig.config.server.BUYBACK_MESO_MULTIPLIER;
}
return (int) Math.floor(fee);
}
public void showBuybackInfo() {
- String s = "#eBUYBACK STATUS#n\r\n\r\nCurrent buyback fee: #b" + getBuybackFee() + " " + (ServerConstants.USE_BUYBACK_WITH_MESOS ? "mesos" : "NX") + "#k\r\n\r\n";
+ String s = "#eBUYBACK STATUS#n\r\n\r\nCurrent buyback fee: #b" + getBuybackFee() + " " + (YamlConfig.config.server.USE_BUYBACK_WITH_MESOS ? "mesos" : "NX") + "#k\r\n\r\n";
long timeNow = Server.getInstance().getCurrentTime();
boolean avail = true;
if (!isAlive()) {
long timeLapsed = timeNow - lastDeathtime;
- long timeRemaining = ServerConstants.BUYBACK_RETURN_MINUTES * 60 * 1000 - (timeLapsed + Math.max(0, getNextBuybackTime() - timeNow));
+ long timeRemaining = YamlConfig.config.server.BUYBACK_RETURN_MINUTES * 60 * 1000 - (timeLapsed + Math.max(0, getNextBuybackTime() - timeNow));
if (timeRemaining < 1) {
s += "Buyback #e#rUNAVAILABLE#k#n";
avail = false;
} else {
- s += "Buyback countdown: #e#b" + getTimeRemaining(ServerConstants.BUYBACK_RETURN_MINUTES * 60 * 1000 - timeLapsed) + "#k#n";
+ s += "Buyback countdown: #e#b" + getTimeRemaining(YamlConfig.config.server.BUYBACK_RETURN_MINUTES * 60 * 1000 - timeLapsed) + "#k#n";
}
s += "\r\n";
}
@@ -5981,6 +6222,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
if (timeNow < getNextBuybackTime() && avail) {
s += "Buyback available in #r" + getTimeRemaining(getNextBuybackTime() - timeNow) + "#k";
s += "\r\n";
+ } else {
+ s += "Buyback #bavailable#k";
}
this.showHint(s);
@@ -5996,7 +6239,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
public boolean couldBuyback() { // Ronan's buyback system
long timeNow = Server.getInstance().getCurrentTime();
- if (timeNow - lastDeathtime > ServerConstants.BUYBACK_RETURN_MINUTES * 60 * 1000) {
+ if (timeNow - lastDeathtime > YamlConfig.config.server.BUYBACK_RETURN_MINUTES * 60 * 1000) {
this.dropMessage(5, "The period of time to decide has expired, therefore you are unable to buyback.");
return false;
}
@@ -6008,7 +6251,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
return false;
}
- boolean usingMesos = ServerConstants.USE_BUYBACK_WITH_MESOS;
+ boolean usingMesos = YamlConfig.config.server.USE_BUYBACK_WITH_MESOS;
int fee = getBuybackFee();
if (!canBuyback(fee, usingMesos)) {
@@ -6068,7 +6311,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
public boolean isPartyLeader() {
prtLock.lock();
try {
- return party.getLeaderId() == getId();
+ MapleParty party = getParty();
+ return party != null && party.getLeaderId() == getId();
} finally {
prtLock.unlock();
}
@@ -6079,21 +6323,17 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public boolean attemptCatchFish(int baitLevel) {
- return ServerConstants.USE_FISHING_SYSTEM && GameConstants.isFishingArea(mapid) && this.getPosition().getY() > 0 && ItemConstants.isFishingChair(chair.get()) && this.getWorldServer().registerFisherPlayer(this, baitLevel);
+ return YamlConfig.config.server.USE_FISHING_SYSTEM && GameConstants.isFishingArea(mapid) && this.getPosition().getY() > 0 && ItemConstants.isFishingChair(chair.get()) && this.getWorldServer().registerFisherPlayer(this, baitLevel);
}
public void leaveMap() {
releaseControlledMonsters();
visibleMapObjects.clear();
- setChair(0);
+ setChair(-1);
if (hpDecreaseTask != null) {
hpDecreaseTask.cancel(false);
}
- if (map.unclaimOwnership(this)) {
- map.dropMessage(5, "This lawn is now free real estate.");
- }
-
AriantColiseum arena = this.getAriantColiseum();
if (arena != null) {
arena.leaveArena(this);
@@ -6108,7 +6348,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
spGain += (expectedSp - curSp);
}
- return getSpGain(spGain, curSp, job);
+ return getSpGain(spGain, curSp, newJob);
}
private int getUsedSp(MapleJob job) {
@@ -6169,7 +6409,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
int spGain = 3;
- if (ServerConstants.USE_ENFORCE_JOB_SP_RANGE && !GameConstants.hasSPTable(job)) {
+ if (YamlConfig.config.server.USE_ENFORCE_JOB_SP_RANGE && !GameConstants.hasSPTable(job)) {
spGain = getSpGain(spGain, job);
}
@@ -6185,7 +6425,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
int improvingMaxMPLevel = 0;
boolean isBeginner = isBeginnerJob();
- if (ServerConstants.USE_AUTOASSIGN_STARTERS_AP && isBeginner && level < 11) {
+ if (YamlConfig.config.server.USE_AUTOASSIGN_STARTERS_AP && isBeginner && level < 11) {
effLock.lock();
statWlock.lock();
try {
@@ -6225,7 +6465,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
addhp += Randomizer.rand(12, 16);
addmp += Randomizer.rand(10, 12);
} else if (job.isA(MapleJob.WARRIOR) || job.isA(MapleJob.DAWNWARRIOR1)) {
- improvingMaxHP = isCygnus() ? SkillFactory.getSkill(DawnWarrior.MAX_HP_INCREASE) : SkillFactory.getSkill(Swordsman.IMPROVED_MAX_HP_INCREASE);
+ improvingMaxHP = isCygnus() ? SkillFactory.getSkill(DawnWarrior.MAX_HP_INCREASE) : SkillFactory.getSkill(Warrior.IMPROVED_MAXHP);
if (job.isA(MapleJob.CRUSADER)) {
improvingMaxMP = SkillFactory.getSkill(1210000);
} else if (job.isA(MapleJob.DAWNWARRIOR2)) {
@@ -6246,7 +6486,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
addhp += 30000;
addmp += 30000;
} else if (job.isA(MapleJob.PIRATE) || job.isA(MapleJob.THUNDERBREAKER1)) {
- improvingMaxHP = isCygnus() ? SkillFactory.getSkill(ThunderBreaker.IMPROVE_MAX_HP) : SkillFactory.getSkill(5100000);
+ improvingMaxHP = isCygnus() ? SkillFactory.getSkill(ThunderBreaker.IMPROVE_MAX_HP) : SkillFactory.getSkill(Brawler.IMPROVE_MAX_HP);
improvingMaxHPLevel = getSkillLevel(improvingMaxHP);
addhp += Randomizer.rand(22, 28);
addmp += Randomizer.rand(18, 23);
@@ -6255,14 +6495,14 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
int aids = Randomizer.rand(4, 8);
addmp += aids + Math.floor(aids * 0.1);
}
- if (improvingMaxHPLevel > 0 && (job.isA(MapleJob.WARRIOR) || job.isA(MapleJob.PIRATE) || job.isA(MapleJob.DAWNWARRIOR1))) {
+ if (improvingMaxHPLevel > 0 && (job.isA(MapleJob.WARRIOR) || job.isA(MapleJob.PIRATE) || job.isA(MapleJob.DAWNWARRIOR1) || job.isA(MapleJob.THUNDERBREAKER1))) {
addhp += improvingMaxHP.getEffect(improvingMaxHPLevel).getX();
}
if (improvingMaxMPLevel > 0 && (job.isA(MapleJob.MAGICIAN) || job.isA(MapleJob.CRUSADER) || job.isA(MapleJob.BLAZEWIZARD1))) {
addmp += improvingMaxMP.getEffect(improvingMaxMPLevel).getX();
}
- if (ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
+ if (YamlConfig.config.server.USE_RANDOMIZE_HPMP_GAIN) {
if (getJobStyle() == MapleJob.MAGICIAN) {
addmp += localint_ / 20;
} else {
@@ -6286,7 +6526,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
int maxClassLevel = getMaxClassLevel();
if (level == maxClassLevel) {
if (!this.isGM()) {
- if (ServerConstants.PLAYERNPC_AUTODEPLOY) {
+ if (YamlConfig.config.server.PLAYERNPC_AUTODEPLOY) {
ThreadManager.getInstance().newTask(new Runnable() {
@Override
public void run() {
@@ -6338,7 +6578,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
if (level % 20 == 0) {
- if (ServerConstants.USE_ADD_SLOTS_BY_LEVEL == true) {
+ if (YamlConfig.config.server.USE_ADD_SLOTS_BY_LEVEL == true) {
if (!isGM()) {
for (byte i = 1; i < 5; i++) {
gainSlots(i, 4, true);
@@ -6347,14 +6587,14 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
this.yellowMessage("You reached level " + level + ". Congratulations! As a token of your success, your inventory has been expanded a little bit.");
}
}
- if (ServerConstants.USE_ADD_RATES_BY_LEVEL == true) { //For the rate upgrade
+ if (YamlConfig.config.server.USE_ADD_RATES_BY_LEVEL == true) { //For the rate upgrade
revertLastPlayerRates();
setPlayerRates();
this.yellowMessage("You managed to get level " + level + "! Getting experience and items seems a little easier now, huh?");
}
}
- if (ServerConstants.USE_PERFECT_PITCH && level >= 30) {
+ if (YamlConfig.config.server.USE_PERFECT_PITCH && level >= 30) {
//milestones?
if (MapleInventoryManipulator.checkSpace(client, 4310000, (short) 1, "")) {
MapleInventoryManipulator.addById(client, 4310000, (short) 1, "", -1);
@@ -6374,6 +6614,16 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
levelUpMessages();
guildUpdate();
+
+ MapleFamilyEntry familyEntry = getFamilyEntry();
+ if(familyEntry != null) {
+ familyEntry.giveReputationToSenior(YamlConfig.config.server.FAMILY_REP_PER_LEVELUP, true);
+ MapleFamilyEntry senior = familyEntry.getSenior();
+ if(senior != null) { //only send the message to direct senior
+ MapleCharacter seniorChr = senior.getChr();
+ if(seniorChr != null) seniorChr.announce(MaplePacketCreator.levelUpMessage(1, level, getName()));
+ }
+ }
}
public boolean leaveParty() {
@@ -6383,7 +6633,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
prtLock.lock();
try {
party = getParty();
- partyLeader = party != null && isPartyLeader();
+ partyLeader = isPartyLeader();
} finally {
prtLock.unlock();
}
@@ -6542,20 +6792,16 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
MapleInventory cashInv = this.getInventory(MapleInventoryType.CASH);
if (cashInv == null) return;
- if (cpnLock.tryLock()) {
- effLock.lock();
- chrLock.lock();
- cashInv.lockInventory();
- try {
- revertCouponRates();
- setCouponRates();
- } finally {
- cpnLock.unlock();
-
- cashInv.unlockInventory();
- chrLock.unlock();
- effLock.unlock();
- }
+ effLock.lock();
+ chrLock.lock();
+ cashInv.lockInventory();
+ try {
+ revertCouponRates();
+ setCouponRates();
+ } finally {
+ cashInv.unlockInventory();
+ chrLock.unlock();
+ effLock.unlock();
}
}
@@ -6597,7 +6843,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
private List activateCouponsEffects() {
List toCommitEffect = new LinkedList<>();
- if(ServerConstants.USE_STACK_COUPON_RATES) {
+ if(YamlConfig.config.server.USE_STACK_COUPON_RATES) {
for(Entry coupon: activeCoupons.entrySet()) {
int couponId = coupon.getKey();
int couponQty = coupon.getValue();
@@ -6740,8 +6986,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
ret.gachaexp.set(rs.getInt("gachaexp"));
ret.mapid = rs.getInt("map");
ret.initialSpawnPoint = rs.getInt("spawnpoint");
-
- ret.gmLevel = rs.getInt("gm");
+ ret.setGMLevel(rs.getInt("gm"));
ret.world = rs.getByte("world");
ret.rank = rs.getInt("rank");
ret.rankMove = rs.getInt("rankMove");
@@ -6794,7 +7039,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
ret.inventory[MapleInventoryType.EQUIPPED.ordinal()] = this.getInventory(MapleInventoryType.EQUIPPED);
- ret.gmLevel = this.gmLevel();
+ ret.setGMLevel(this.gmLevel());
ret.world = this.getWorld();
ret.rank = this.getRank();
ret.rankMove = this.getRankMove();
@@ -6856,7 +7101,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
ret.loadCharSkillPoints(rs.getString("sp").split(","));
ret.meso.set(rs.getInt("meso"));
ret.merchantmeso = rs.getInt("MerchantMesos");
- ret.gmLevel = rs.getInt("gm");
+ ret.setGMLevel(rs.getInt("gm"));
ret.skinColor = MapleSkinColor.getById(rs.getInt("skincolor"));
ret.gender = rs.getInt("gender");
ret.job = MapleJob.getById(rs.getInt("job"));
@@ -6905,7 +7150,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
ret.getInventory(MapleInventoryType.SETUP).setSlotLimit(rs.getByte("setupslots"));
ret.getInventory(MapleInventoryType.ETC).setSlotLimit(rs.getByte("etcslots"));
- byte sandboxCheck = 0x0;
+ short sandboxCheck = 0x0;
for (Pair- item : ItemFactory.INVENTORY.loadItems(ret.id, !channelserver)) {
sandboxCheck |= item.getLeft().getFlag();
@@ -6952,11 +7197,14 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
PreparedStatement ps2, ps3;
ResultSet rs2, rs3;
- ps3 = con.prepareStatement("SELECT petid FROM inventoryitems WHERE characterid = ? AND petid > -1");
+ ps3 = con.prepareStatement("SELECT petid FROM inventoryitems WHERE characterid = ? AND petid IS NOT NULL");
ps3.setInt(1, charid);
rs3 = ps3.executeQuery();
while(rs3.next()) {
int petId = rs3.getInt("petid");
+ if (rs3.wasNull()) {
+ petId = -1;
+ }
ps2 = con.prepareStatement("SELECT itemid FROM petignores WHERE petid = ?");
ps2.setInt(1, petId);
@@ -7035,7 +7283,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
rs.close();
ps.close();
- ps = con.prepareStatement("SELECT name, characterslots FROM accounts WHERE id = ?", Statement.RETURN_GENERATED_KEYS);
+ ps = con.prepareStatement("SELECT name, characterslots, language FROM accounts WHERE id = ?", Statement.RETURN_GENERATED_KEYS);
ps.setInt(1, ret.accountid);
rs = ps.executeQuery();
if (rs.next()) {
@@ -7043,6 +7291,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
retClient.setAccountName(rs.getString("name"));
retClient.setCharacterSlots(rs.getByte("characterslots"));
+ retClient.setLanguage(rs.getInt("language")); // thanks Zein for noticing user language not overriding default once player is in-game
}
rs.close();
ps.close();
@@ -7135,7 +7384,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
ps.setInt(1, charid);
rs = ps.executeQuery();
while (rs.next()) {
- ret.skills.put(SkillFactory.getSkill(rs.getInt("skillid")), new SkillEntry(rs.getByte("skilllevel"), rs.getInt("masterlevel"), rs.getLong("expiration")));
+ Skill pSkill = SkillFactory.getSkill(rs.getInt("skillid"));
+ if(pSkill != null) // edit reported by shavit, thanks Zein for noticing an NPE here
+ {
+ ret.skills.put(pSkill, new SkillEntry(rs.getByte("skilllevel"), rs.getInt("masterlevel"), rs.getLong("expiration")));
+ }
}
rs.close();
ps.close();
@@ -7225,7 +7478,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
rs.close();
ps.close();
ret.buddylist.loadFromDb(charid);
- ret.storage = MapleStorage.loadOrCreateFromDB(ret.accountid, ret.world);
+ ret.storage = wserv.getAccountStorage(ret.accountid);
int startHp = ret.hp, startMp = ret.mp;
ret.reapplyLocalStats();
@@ -7252,7 +7505,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public void reloadQuestExpirations() {
- for(MapleQuestStatus mqs: quests.values()) {
+ for(MapleQuestStatus mqs: getStartedQuests()) {
if(mqs.getExpirationTime() > 0) {
questTimeLimit2(mqs.getQuest(), mqs.getExpirationTime());
}
@@ -7306,31 +7559,31 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
announce(MaplePacketCreator.sendYellowTip(m));
}
- public void updateQuestMobCount(int id) {
+ public void raiseQuestMobCount(int id) {
// It seems nexon uses monsters that don't exist in the WZ (except string) to merge multiple mobs together for these 3 monsters.
// We also want to run mobKilled for both since there are some quest that don't use the updated ID...
if (id == 1110100 || id == 1110130) {
- updateQuestMobCount(9101000);
+ raiseQuestMobCount(9101000);
} else if (id == 2230101 || id == 2230131) {
- updateQuestMobCount(9101001);
+ raiseQuestMobCount(9101001);
} else if (id == 1140100 || id == 1140130) {
- updateQuestMobCount(9101002);
+ raiseQuestMobCount(9101002);
}
int lastQuestProcessed = 0;
try {
synchronized (quests) {
- for (MapleQuestStatus q : quests.values()) {
- lastQuestProcessed = q.getQuest().getId();
- if (q.getStatus() == MapleQuestStatus.Status.COMPLETED || q.getQuest().canComplete(this, null)) {
+ for (MapleQuestStatus qs : getQuests()) {
+ lastQuestProcessed = qs.getQuest().getId();
+ if (qs.getStatus() == MapleQuestStatus.Status.COMPLETED || qs.getQuest().canComplete(this, null)) {
continue;
}
- String progress = q.getProgress(id);
- if (!progress.isEmpty() && Integer.parseInt(progress) >= q.getQuest().getMobAmountNeeded(id)) {
- continue;
- }
- if (q.progress(id)) {
- client.announce(MaplePacketCreator.updateQuest(q, false));
+
+ if (qs.progress(id)) {
+ announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, false);
+ if (qs.getInfoNumber() > 0) {
+ announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, true);
+ }
}
}
}
@@ -7339,8 +7592,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
- public void mount(int id, int skillid) {
- maplemount = new MapleMount(this, id, skillid);
+ public MapleMount mount(int id, int skillid) {
+ MapleMount mount = maplemount;
+ mount.setItemId(id);
+ mount.setSkillId(skillid);
+ return mount;
}
private void playerDead() {
@@ -7372,31 +7628,33 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
break;
}
}
- if (possesed > 0) {
+ if (possesed > 0 && !GameConstants.isDojo(getMapId())) {
message("You have used a safety charm, so your EXP points have not been decreased.");
MapleInventoryManipulator.removeById(client, ItemConstants.getInventoryType(charmID[i]), charmID[i], 1, true, false);
- } else if (mapid > 925020000 && mapid < 925030000) {
- this.dojoStage = 0;
+ usedSafetyCharm = true;
} else if (getJob() != MapleJob.BEGINNER) { //Hmm...
- int XPdummy = ExpTable.getExpNeededForLevel(getLevel());
- if (getMap().isTown()) {
- XPdummy /= 100;
- }
- if (XPdummy == ExpTable.getExpNeededForLevel(getLevel())) {
- if (getLuk() <= 100 && getLuk() > 8) {
- XPdummy *= (200 - getLuk()) / 2000;
- } else if (getLuk() < 8) {
- XPdummy /= 10;
+ if (!FieldLimit.NO_EXP_DECREASE.check(getMap().getFieldLimit())) { // thanks Conrad for noticing missing FieldLimit check
+ int XPdummy = ExpTable.getExpNeededForLevel(getLevel());
+
+ if (getMap().isTown()) { // thanks MindLove, SIayerMonkey, HaItsNotOver for noting players only lose 1% on town maps
+ XPdummy /= 100;
} else {
- XPdummy /= 20;
+ if (getLuk() < 50) { // thanks Taiketo, Quit, Fishanelli for noting player EXP loss are fixed, 50-LUK threshold
+ XPdummy /= 10;
+ } else {
+ XPdummy /= 20;
+ }
+ }
+
+ int curExp = getExp();
+ if (curExp > XPdummy) {
+ loseExp(XPdummy, false, false);
+ } else {
+ loseExp(curExp, false, false);
}
}
- if (getExp() > XPdummy) {
- loseExp(XPdummy, false, false);
- } else {
- loseExp(getExp(), false, false);
- }
}
+
if (getBuffedValue(MapleBuffStat.MORPH) != null) {
cancelEffectFromBuffStat(MapleBuffStat.MORPH);
}
@@ -7411,12 +7669,12 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
private void unsitChairInternal() {
int chairid = chair.get();
- if (chairid != 0) {
+ if (chairid >= 0) {
if (ItemConstants.isFishingChair(chairid)) {
this.getWorldServer().unregisterFisherPlayer(this);
}
- setChair(0);
+ setChair(-1);
if (unregisterChairBuff()) {
getMap().broadcastMessage(this, MaplePacketCreator.cancelForeignChairSkillEffect(this.getId()), false);
}
@@ -7428,27 +7686,23 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public void sitChair(int itemId) {
- if (client.tryacquireClient()) {
- try {
- if (itemId >= 1000000) { // sit on item chair
- if (chair.get() == 0) {
- setChair(itemId);
- getMap().broadcastMessage(this, MaplePacketCreator.showChair(this.getId(), itemId), false);
- }
- announce(MaplePacketCreator.enableActions());
- } else if (itemId != 0) { // sit on map chair
- if (chair.get() == 0) {
- setChair(itemId);
- if (registerChairBuff()) {
- getMap().broadcastMessage(this, MaplePacketCreator.giveForeignChairSkillEffect(this.getId()), false);
- }
- announce(MaplePacketCreator.cancelChair(itemId));
- }
- } else { // stand up
- unsitChairInternal();
+ if (this.isLoggedinWorld()) {
+ if (itemId >= 1000000) { // sit on item chair
+ if (chair.get() < 0) {
+ setChair(itemId);
+ getMap().broadcastMessage(this, MaplePacketCreator.showChair(this.getId(), itemId), false);
}
- } finally {
- client.releaseClient();
+ announce(MaplePacketCreator.enableActions());
+ } else if (itemId >= 0) { // sit on map chair
+ if (chair.get() < 0) {
+ setChair(itemId);
+ if (registerChairBuff()) {
+ getMap().broadcastMessage(this, MaplePacketCreator.giveForeignChairSkillEffect(this.getId()), false);
+ }
+ announce(MaplePacketCreator.cancelChair(itemId));
+ }
+ } else { // stand up
+ unsitChairInternal();
}
}
}
@@ -7468,7 +7722,13 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
changeMap(returnMap);
cancelAllBuffs(false); // thanks Oblivium91 for finding out players still could revive in area and take damage before returning to town
- updateHp(50);
+
+ if (usedSafetyCharm) { // thanks kvmba for noticing safety charm not providing 30% HP/MP
+ addMPHP((int) Math.ceil(this.getClientMaxHp() * 0.3), (int) Math.ceil(this.getClientMaxMp() * 0.3));
+ } else {
+ updateHp(50);
+ }
+
setStance(0);
}
@@ -7665,7 +7925,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
reapplyLocalStats();
- if (ServerConstants.USE_FIXED_RATIO_HPMP_UPDATE) {
+ if (YamlConfig.config.server.USE_FIXED_RATIO_HPMP_UPDATE) {
if (localmaxhp != oldlocalmaxhp) {
Pair hpUpdate;
@@ -7700,6 +7960,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
private void updateLocalStats() {
+ prtLock.lock();
effLock.lock();
statWlock.lock();
try {
@@ -7711,12 +7972,13 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
client.announce(MaplePacketCreator.updatePlayerStats(hpmpupdate, true, this));
}
- if (oldmaxhp != localmaxhp) {
+ if (oldmaxhp != localmaxhp) { // thanks Wh1SK3Y for pointing out a deadlock occuring related to party members HP
updatePartyMemberHP();
}
} finally {
statWlock.unlock();
effLock.unlock();
+ prtLock.unlock();
}
}
@@ -7804,7 +8066,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public synchronized void resetStats() {
- if(!ServerConstants.USE_AUTOASSIGN_STARTERS_AP) {
+ if(!YamlConfig.config.server.USE_AUTOASSIGN_STARTERS_AP) {
return;
}
@@ -7862,15 +8124,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public void resetEnteredScript() {
- if (entered.containsKey(map.getId())) {
- entered.remove(map.getId());
- }
+ entered.remove(map.getId());
}
public void resetEnteredScript(int mapId) {
- if (entered.containsKey(mapId)) {
- entered.remove(mapId);
- }
+ entered.remove(mapId);
}
public void resetEnteredScript(String script) {
@@ -8057,7 +8315,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
int[] selectedType;
int[] selectedAction;
- if(ServerConstants.USE_CUSTOM_KEYSET) {
+ if(YamlConfig.config.server.USE_CUSTOM_KEYSET) {
selectedKey = GameConstants.getCustomKey(true);
selectedType = GameConstants.getCustomType(true);
selectedAction = GameConstants.getCustomAction(true);
@@ -8125,7 +8383,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public void saveCharToDB() {
- if(ServerConstants.USE_AUTOSAVE) {
+ if(YamlConfig.config.server.USE_AUTOSAVE) {
Runnable r = new Runnable() {
@Override
public void run() {
@@ -8133,7 +8391,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
};
- ThreadManager.getInstance().newTask(r); //spawns a new thread to deal with this
+ CharacterSaveService service = (CharacterSaveService) getWorldServer().getServiceAccess(WorldServices.SAVE_CHARACTER);
+ service.registerSaveCharacter(this.getId(), r);
} else {
saveCharToDB(true);
}
@@ -8355,8 +8614,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
ItemFactory.INVENTORY.saveItems(itemsWithType, id, con);
- deleteWhereCharacterId(con, "DELETE FROM skills WHERE characterid = ?");
- ps = con.prepareStatement("INSERT INTO skills (characterid, skillid, skilllevel, masterlevel, expiration) VALUES (?, ?, ?, ?, ?)");
+ ps = con.prepareStatement("REPLACE INTO skills (characterid, skillid, skilllevel, masterlevel, expiration) VALUES (?, ?, ?, ?, ?)");
ps.setInt(1, id);
for (Entry skill : skills.entrySet()) {
ps.setInt(2, skill.getKey().getId());
@@ -8450,43 +8708,50 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
psf = con.prepareStatement("INSERT INTO medalmaps VALUES (DEFAULT, ?, ?, ?)");
ps.setInt(1, id);
- synchronized (quests) {
- for (MapleQuestStatus q : quests.values()) {
- ps.setInt(2, q.getQuest().getId());
- ps.setInt(3, q.getStatus().getId());
- ps.setInt(4, (int) (q.getCompletionTime() / 1000));
- ps.setLong(5, q.getExpirationTime());
- ps.setInt(6, q.getForfeited());
- ps.setInt(7, q.getCompleted());
- ps.executeUpdate();
- try (ResultSet rs = ps.getGeneratedKeys()) {
- rs.next();
- for (int mob : q.getProgress().keySet()) {
- pse.setInt(1, id);
- pse.setInt(2, rs.getInt(1));
- pse.setInt(3, mob);
- pse.setString(4, q.getProgress(mob));
- pse.addBatch();
- }
- for (int i = 0; i < q.getMedalMaps().size(); i++) {
- psf.setInt(1, id);
- psf.setInt(2, rs.getInt(1));
- psf.setInt(3, q.getMedalMaps().get(i));
- psf.addBatch();
- }
- pse.executeBatch();
- psf.executeBatch();
+ for (MapleQuestStatus qs : getQuests()) {
+ ps.setInt(2, qs.getQuest().getId());
+ ps.setInt(3, qs.getStatus().getId());
+ ps.setInt(4, (int) (qs.getCompletionTime() / 1000));
+ ps.setLong(5, qs.getExpirationTime());
+ ps.setInt(6, qs.getForfeited());
+ ps.setInt(7, qs.getCompleted());
+ ps.executeUpdate();
+ try (ResultSet rs = ps.getGeneratedKeys()) {
+ rs.next();
+ for (int mob : qs.getProgress().keySet()) {
+ pse.setInt(1, id);
+ pse.setInt(2, rs.getInt(1));
+ pse.setInt(3, mob);
+ pse.setString(4, qs.getProgress(mob));
+ pse.addBatch();
}
+ for (int i = 0; i < qs.getMedalMaps().size(); i++) {
+ psf.setInt(1, id);
+ psf.setInt(2, rs.getInt(1));
+ psf.setInt(3, qs.getMedalMaps().get(i));
+ psf.addBatch();
+ }
+ pse.executeBatch();
+ psf.executeBatch();
}
}
-
}
psf.close();
ps.close();
- con.commit();
- con.setAutoCommit(true);
-
+ MapleFamilyEntry familyEntry = getFamilyEntry(); //save family rep
+ if(familyEntry != null) {
+ if(familyEntry.saveReputation(con)) familyEntry.savedSuccessfully();
+ MapleFamilyEntry senior = familyEntry.getSenior();
+ if(senior != null && senior.getChr() == null) { //only save for offline family members
+ if(senior.saveReputation(con)) senior.savedSuccessfully();
+ senior = senior.getSenior(); //save one level up as well
+ if(senior != null && senior.getChr() == null) {
+ if(senior.saveReputation(con)) senior.savedSuccessfully();
+ }
+ }
+
+ }
if (cashshop != null) {
cashshop.save(con);
@@ -8497,6 +8762,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
usedStorage = false;
}
+ con.commit();
+ con.setAutoCommit(true); // only commit after finishing all "con" usages, thanks Zygon
+
} catch (SQLException | RuntimeException t) {
FilePrinter.printError(FilePrinter.SAVE_CHAR, t, "Error saving " + name + " Level: " + level + " Job: " + job.getId());
try {
@@ -8506,6 +8774,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
} catch (Exception e) {
FilePrinter.printError(FilePrinter.SAVE_CHAR, e, "Error saving " + name + " Level: " + level + " Job: " + job.getId());
+ try {
+ con.rollback(); // thanks Zygon
+ } catch (SQLException se) {
+ FilePrinter.printError(FilePrinter.SAVE_CHAR, se, "Error trying to rollback " + name);
+ }
} finally {
try {
con.setAutoCommit(true);
@@ -8556,6 +8829,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
// Always send the macro packet to fix a client side bug when switching characters.
client.announce(MaplePacketCreator.getMacros(skillMacros));
}
+
+ public SkillMacro[] getMacros() {
+ return skillMacros;
+ }
public void sendNote(String to, String msg, byte fame) throws SQLException {
sendNote(to, this.getName(), msg, fame);
@@ -8875,11 +9152,39 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
updateHpMp(nextHp, nextMp);
- return true;
} finally {
statWlock.unlock();
effLock.unlock();
}
+
+ // autopot on HPMP deplete... thanks shavit for finding out D. Roar doesn't trigger autopot request
+ if (hpchange < 0) {
+ MapleKeyBinding autohpPot = this.getKeymap().get(91);
+ if (autohpPot != null) {
+ int autohpItemid = autohpPot.getAction();
+ if (((float) this.getHp()) / this.getCurrentMaxHp() <= this.getAutopotHpAlert()) { // try within user settings... thanks Lame, Optimist, Stealth2800
+ Item autohpItem = this.getInventory(MapleInventoryType.USE).findById(autohpItemid);
+ if (autohpItem != null) {
+ PetAutopotProcessor.runAutopotAction(client, autohpItem.getPosition(), autohpItemid);
+ }
+ }
+ }
+ }
+
+ if (mpchange < 0) {
+ MapleKeyBinding autompPot = this.getKeymap().get(92);
+ if (autompPot != null) {
+ int autompItemid = autompPot.getAction();
+ if (((float) this.getMp()) / this.getCurrentMaxMp() <= this.getAutopotMpAlert()) {
+ Item autompItem = this.getInventory(MapleInventoryType.USE).findById(autompItemid);
+ if (autompItem != null) {
+ PetAutopotProcessor.runAutopotAction(client, autompItem.getPosition(), autompItemid);
+ }
+ }
+ }
+ }
+
+ return true;
}
public void setInventory(MapleInventoryType type, MapleInventory inv) {
@@ -8955,6 +9260,18 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
public void setName(String name) {
this.name = name;
}
+
+ public void setRPS(MapleRockPaperScissor rps) {
+ this.rps = rps;
+ }
+
+ public void closeRPS() {
+ MapleRockPaperScissor rps = this.rps;
+ if (rps != null) {
+ rps.dispose(client);
+ setRPS(null);
+ }
+ }
public void changeName(String name) {
FredrickProcessor.removeFredrickReminders(this.getId());
@@ -9127,10 +9444,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
private static void setMergeFlag(Item item) {
- int flag = item.getFlag();
+ short flag = item.getFlag();
flag |= ItemConstants.MERGE_UNTRADEABLE;
flag |= ItemConstants.UNTRADEABLE;
- item.setFlag((byte) flag);
+ item.setFlag(flag);
}
private List getUpgradeableEquipped() {
@@ -9541,30 +9858,27 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
}
-
- public String getQuestInfo(int quest) {
- MapleQuestStatus qs = getQuest(MapleQuest.getInstance(quest));
- return qs.getInfo();
- }
-
- public void updateQuestInfo(int quest, String info) {
- MapleQuest q = MapleQuest.getInstance(quest);
+
+ public void setQuestProgress(int id, int infoNumber, String progress) {
+ MapleQuest q = MapleQuest.getInstance(id);
MapleQuestStatus qs = getQuest(q);
- qs.setInfo(info);
-
- synchronized (quests) {
- quests.put(q.getId(), qs);
+
+ if (qs.getInfoNumber() == infoNumber && infoNumber > 0) {
+ MapleQuest iq = MapleQuest.getInstance(infoNumber);
+ MapleQuestStatus iqs = getQuest(iq);
+ iqs.setProgress(0, progress);
+ } else {
+ qs.setProgress(infoNumber, progress); // quest progress is thoroughly a string match, infoNumber is actually another questid
}
- announce(MaplePacketCreator.updateQuest(qs, false));
- if (qs.getQuest().getInfoNumber() > 0) {
- announce(MaplePacketCreator.updateQuest(qs, true));
+ announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, false);
+ if (qs.getInfoNumber() > 0) {
+ announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, true);
}
- announce(MaplePacketCreator.updateQuestInfo((short) qs.getQuest().getId(), qs.getNpc()));
}
public void awardQuestPoint(int awardedPoints) {
- if (ServerConstants.QUEST_POINT_REQUIREMENT < 1 || awardedPoints < 1) {
+ if (YamlConfig.config.server.QUEST_POINT_REQUIREMENT < 1 || awardedPoints < 1) {
return;
}
@@ -9572,8 +9886,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
synchronized (quests) {
quest_fame += awardedPoints;
- delta = quest_fame / ServerConstants.QUEST_POINT_REQUIREMENT;
- quest_fame %= ServerConstants.QUEST_POINT_REQUIREMENT;
+ delta = quest_fame / YamlConfig.config.server.QUEST_POINT_REQUIREMENT;
+ quest_fame %= YamlConfig.config.server.QUEST_POINT_REQUIREMENT;
}
if(delta > 0) {
@@ -9581,45 +9895,91 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
- public void updateQuest(MapleQuestStatus quest) {
- synchronized (quests) {
- quests.put(quest.getQuestID(), quest);
- }
- if (quest.getStatus().equals(MapleQuestStatus.Status.STARTED)) {
- announce(MaplePacketCreator.updateQuest(quest, false));
- if (quest.getQuest().getInfoNumber() > 0) {
- announce(MaplePacketCreator.updateQuest(quest, true));
- }
- announce(MaplePacketCreator.updateQuestInfo((short) quest.getQuest().getId(), quest.getNpc()));
- } else if (quest.getStatus().equals(MapleQuestStatus.Status.COMPLETED)) {
- MapleQuest mquest = quest.getQuest();
- short questid = mquest.getId();
- if (!mquest.isSameDayRepeatable() && !MapleQuest.isExploitableQuest(questid)) {
- awardQuestPoint(ServerConstants.QUEST_POINT_PER_QUEST_COMPLETE);
- }
- quest.setCompleted(quest.getCompleted() + 1); // Jayd's idea - count quest completed
-
- announce(MaplePacketCreator.completeQuest(questid, quest.getCompletionTime()));
- } else if (quest.getStatus().equals(MapleQuestStatus.Status.NOT_STARTED)) {
- announce(MaplePacketCreator.updateQuest(quest, false));
- if (quest.getQuest().getInfoNumber() > 0) {
- announce(MaplePacketCreator.updateQuest(quest, true));
- }
+ public enum DelayedQuestUpdate { // quest updates allow player actions during NPC talk...
+ UPDATE, FORFEIT, COMPLETE, INFO
+ }
+
+ private void announceUpdateQuestInternal(MapleCharacter chr, Pair questUpdate) {
+ Object[] objs = questUpdate.getRight();
+
+ switch (questUpdate.getLeft()) {
+ case UPDATE:
+ announce(MaplePacketCreator.updateQuest(chr, (MapleQuestStatus) objs[0], (Boolean) objs[1]));
+ break;
+
+ case FORFEIT:
+ announce(MaplePacketCreator.forfeitQuest((Short) objs[0]));
+ break;
+
+ case COMPLETE:
+ announce(MaplePacketCreator.completeQuest((Short) objs[0], (Long) objs[1]));
+ break;
+
+ case INFO:
+ MapleQuestStatus qs = (MapleQuestStatus) objs[0];
+ announce(MaplePacketCreator.updateQuestInfo(qs.getQuest().getId(), qs.getNpc()));
+ break;
}
}
-
- private void expireQuest(MapleQuest quest) {
- if(getQuestStatus(quest.getId()) == MapleQuestStatus.Status.COMPLETED.getId()) {
- return;
+
+ public void announceUpdateQuest(DelayedQuestUpdate questUpdateType, Object... params) {
+ Pair p = new Pair<>(questUpdateType, params);
+ MapleClient c = this.getClient();
+ if (c.getQM() != null || c.getCM() != null) {
+ synchronized (npcUpdateQuests) {
+ npcUpdateQuests.add(p);
+ }
+ } else {
+ announceUpdateQuestInternal(this, p);
}
- if(System.currentTimeMillis() < getMapleQuestStatus(quest.getId()).getExpirationTime()) {
- return;
+ }
+
+ public void flushDelayedUpdateQuests() {
+ List> qmQuestUpdateList;
+
+ synchronized (npcUpdateQuests) {
+ qmQuestUpdateList = new ArrayList<>(npcUpdateQuests);
+ npcUpdateQuests.clear();
}
- announce(MaplePacketCreator.questExpire(quest.getId()));
- MapleQuestStatus newStatus = new MapleQuestStatus(quest, MapleQuestStatus.Status.NOT_STARTED);
- newStatus.setForfeited(getQuest(quest).getForfeited() + 1);
- updateQuest(newStatus);
+ for (Pair q : qmQuestUpdateList) {
+ announceUpdateQuestInternal(this, q);
+ }
+ }
+
+ public void updateQuestStatus(MapleQuestStatus qs) {
+ synchronized (quests) {
+ quests.put(qs.getQuestID(), qs);
+ }
+ if (qs.getStatus().equals(MapleQuestStatus.Status.STARTED)) {
+ announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, false);
+ if (qs.getInfoNumber() > 0) {
+ announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, true);
+ }
+ announceUpdateQuest(DelayedQuestUpdate.INFO, qs);
+ } else if (qs.getStatus().equals(MapleQuestStatus.Status.COMPLETED)) {
+ MapleQuest mquest = qs.getQuest();
+ short questid = mquest.getId();
+ if (!mquest.isSameDayRepeatable() && !MapleQuest.isExploitableQuest(questid)) {
+ awardQuestPoint(YamlConfig.config.server.QUEST_POINT_PER_QUEST_COMPLETE);
+ }
+ qs.setCompleted(qs.getCompleted() + 1); // count quest completed Jayd's idea
+
+ announceUpdateQuest(DelayedQuestUpdate.COMPLETE, questid, qs.getCompletionTime());
+ //announceUpdateQuest(DelayedQuestUpdate.INFO, qs); // happens after giving rewards, for non-next quests only
+ } else if (qs.getStatus().equals(MapleQuestStatus.Status.NOT_STARTED)) {
+ announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, false);
+ if (qs.getInfoNumber() > 0) {
+ announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, true);
+ }
+ // reminder: do not reset quest progress of infoNumbers, some quests cannot backtrack
+ }
+ }
+
+ private void expireQuest(MapleQuest quest) {
+ if (quest.forfeit(this)) {
+ announce(MaplePacketCreator.questExpire(quest.getId()));
+ }
}
public void cancelQuestExpirationTask() {
@@ -9758,7 +10118,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
if (!this.isHidden() || client.getPlayer().gmLevel() > 1) {
client.announce(MaplePacketCreator.spawnPlayerMapObject(client, this, false));
- if (buffEffects.containsKey(getJobMapChair(job))) { // mustn't effLock, chrLock this function
+ if (buffEffects.containsKey(getJobMapChair(job))) { // mustn't effLock, chrLock sendSpawnData
client.announce(MaplePacketCreator.giveForeignChairSkillEffect(id));
}
}
@@ -9870,6 +10230,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public void autoban(String reason) {
+ if (this.isGM() || this.isBanned()){ // thanks RedHat for noticing GM's being able to get banned
+ return;
+ }
+
this.ban(reason);
announce(MaplePacketCreator.sendPolice(String.format("You have been blocked by the#b %s Police for HACK reason.#k", "HeavenMS")));
TimerManager.getInstance().schedule(new Runnable() {
@@ -10049,7 +10413,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
private Collection
- getUpgradeableEquipList() {
Collection
- fullList = getInventory(MapleInventoryType.EQUIPPED).list();
- if (ServerConstants.USE_EQUIPMNT_LVLUP_CASH) {
+ if (YamlConfig.config.server.USE_EQUIPMNT_LVLUP_CASH) {
return fullList;
}
@@ -10193,7 +10557,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
mpc = null;
mgc = null;
party = null;
- family = null;
+ MapleFamilyEntry familyEntry = getFamilyEntry();
+ if(familyEntry != null) {
+ familyEntry.setCharacter(null);
+ setFamilyEntry(null);
+ }
getWorldServer().registerTimedMapObject(new Runnable() {
@Override
@@ -10217,6 +10585,18 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
e.printStackTrace();
}
}
+
+ public void setLoginTime(long time) {
+ this.loginTime = time;
+ }
+
+ public long getLoginTime() {
+ return loginTime;
+ }
+
+ public long getLoggedInTime() {
+ return System.currentTimeMillis() - loginTime;
+ }
public boolean isLoggedin() {
return loggedIn;
@@ -10267,6 +10647,22 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
this.dragon = dragon;
}
+ public void setAutopotHpAlert(float hpPortion) {
+ autopotHpAlert = hpPortion;
+ }
+
+ public float getAutopotHpAlert() {
+ return autopotHpAlert;
+ }
+
+ public void setAutopotMpAlert(float mpPortion) {
+ autopotMpAlert = mpPortion;
+ }
+
+ public float getAutopotMpAlert() {
+ return autopotMpAlert;
+ }
+
public long getJailExpirationTimeLeft() {
return jailExpiration - System.currentTimeMillis();
}
@@ -10289,6 +10685,379 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
jailExpiration = 0;
}
+ public boolean registerNameChange(String newName) {
+ try (Connection con = DatabaseConnection.getConnection()) {
+ //check for pending name change
+ long currentTimeMillis = System.currentTimeMillis();
+ try (PreparedStatement ps = con.prepareStatement("SELECT completionTime FROM namechanges WHERE characterid=?")) { //double check, just in case
+ ps.setInt(1, getId());
+ ResultSet rs = ps.executeQuery();
+ while(rs.next()) {
+ Timestamp completedTimestamp = rs.getTimestamp("completionTime");
+ if(completedTimestamp == null) return false; //pending
+ else if(completedTimestamp.getTime() + YamlConfig.config.server.NAME_CHANGE_COOLDOWN > currentTimeMillis) return false;
+ }
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Failed to register name change for character " + getName() + ".");
+ return false;
+ }
+ try (PreparedStatement ps = con.prepareStatement("INSERT INTO namechanges (characterid, old, new) VALUES (?, ?, ?)")){
+ ps.setInt(1, getId());
+ ps.setString(2, getName());
+ ps.setString(3, newName);
+ ps.executeUpdate();
+ this.pendingNameChange = true;
+ return true;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Failed to register name change for character " + getName() + ".");
+ }
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Failed to get DB connection.");
+ }
+ return false;
+ }
+
+ public boolean cancelPendingNameChange() {
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("DELETE FROM namechanges WHERE characterid=? AND completionTime IS NULL")) {
+ ps.setInt(1, getId());
+ int affectedRows = ps.executeUpdate();
+ if(affectedRows > 0) pendingNameChange = false;
+ return affectedRows > 0; //rows affected
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Failed to cancel name change for character " + getName() + ".");
+ return false;
+ }
+ }
+
+ public void doPendingNameChange() { //called on logout
+ if(!pendingNameChange) return;
+ try (Connection con = DatabaseConnection.getConnection()) {
+ int nameChangeId = -1;
+ String newName = null;
+ try (PreparedStatement ps = con.prepareStatement("SELECT * FROM namechanges WHERE characterid = ? AND completionTime IS NULL")) {
+ ps.setInt(1, getId());
+ ResultSet rs = ps.executeQuery();
+ if(!rs.next()) return;
+ nameChangeId = rs.getInt("id");
+ newName = rs.getString("new");
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Failed to retrieve pending name changes for character " + getName() + ".");
+ }
+ con.setAutoCommit(false);
+ boolean success = doNameChange(con, getId(), getName(), newName, nameChangeId);
+ if(!success) con.rollback();
+ else FilePrinter.print(FilePrinter.CHANGE_CHARACTER_NAME, "Name change applied : from \"" + getName() + "\" to \"" + newName + "\" at " + Calendar.getInstance().getTime().toString());
+ con.setAutoCommit(true);
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Failed to get DB connection.");
+ }
+ }
+
+ public static void doNameChange(int characterId, String oldName, String newName, int nameChangeId) { //Don't do this while player is online
+ try (Connection con = DatabaseConnection.getConnection()) {
+ con.setAutoCommit(false);
+ boolean success = doNameChange(con, characterId, oldName, newName, nameChangeId);
+ if(!success) con.rollback();
+ con.setAutoCommit(true);
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Failed to get DB connection.");
+ }
+ }
+
+ public static boolean doNameChange(Connection con, int characterId, String oldName, String newName, int nameChangeId) {
+ try (PreparedStatement ps = con.prepareStatement("UPDATE characters SET name = ? WHERE id = ?")) {
+ ps.setString(1, newName);
+ ps.setInt(2, characterId);
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Character ID : " + characterId);
+ return false;
+ }
+ try (PreparedStatement ps = con.prepareStatement("UPDATE rings SET partnername = ? WHERE partnername = ?")) {
+ ps.setString(1, newName);
+ ps.setString(2, oldName);
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Character ID : " + characterId);
+ return false;
+ }
+ /*try (PreparedStatement ps = con.prepareStatement("UPDATE playernpcs SET name = ? WHERE name = ?")) {
+ ps.setString(1, newName);
+ ps.setString(2, oldName);
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Character ID : " + characterId);
+ return false;
+ }
+ try (PreparedStatement ps = con.prepareStatement("UPDATE gifts SET `from` = ? WHERE `from` = ?")) {
+ ps.setString(1, newName);
+ ps.setString(2, oldName);
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Character ID : " + characterId);
+ return false;
+ }
+ try (PreparedStatement ps = con.prepareStatement("UPDATE dueypackages SET SenderName = ? WHERE SenderName = ?")) {
+ ps.setString(1, newName);
+ ps.setString(2, oldName);
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Character ID : " + characterId);
+ return false;
+ }
+ try (PreparedStatement ps = con.prepareStatement("UPDATE dueypackages SET SenderName = ? WHERE SenderName = ?")) {
+ ps.setString(1, newName);
+ ps.setString(2, oldName);
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Character ID : " + characterId);
+ return false;
+ }
+ try (PreparedStatement ps = con.prepareStatement("UPDATE inventoryitems SET owner = ? WHERE owner = ?")) { //GMS doesn't do this
+ ps.setString(1, newName);
+ ps.setString(2, oldName);
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Character ID : " + characterId);
+ return false;
+ }
+ try (PreparedStatement ps = con.prepareStatement("UPDATE mts_items SET owner = ? WHERE owner = ?")) { //GMS doesn't do this
+ ps.setString(1, newName);
+ ps.setString(2, oldName);
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Character ID : " + characterId);
+ return false;
+ }
+ try (PreparedStatement ps = con.prepareStatement("UPDATE newyear SET sendername = ? WHERE sendername = ?")) {
+ ps.setString(1, newName);
+ ps.setString(2, oldName);
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Character ID : " + characterId);
+ return false;
+ }
+ try (PreparedStatement ps = con.prepareStatement("UPDATE newyear SET receivername = ? WHERE receivername = ?")) {
+ ps.setString(1, newName);
+ ps.setString(2, oldName);
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Character ID : " + characterId);
+ return false;
+ }
+ try (PreparedStatement ps = con.prepareStatement("UPDATE notes SET `to` = ? WHERE `to` = ?")) {
+ ps.setString(1, newName);
+ ps.setString(2, oldName);
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Character ID : " + characterId);
+ return false;
+ }
+ try (PreparedStatement ps = con.prepareStatement("UPDATE notes SET `from` = ? WHERE `from` = ?")) {
+ ps.setString(1, newName);
+ ps.setString(2, oldName);
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Character ID : " + characterId);
+ return false;
+ }
+ try (PreparedStatement ps = con.prepareStatement("UPDATE nxcode SET retriever = ? WHERE retriever = ?")) {
+ ps.setString(1, newName);
+ ps.setString(2, oldName);
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Character ID : " + characterId);
+ return false;
+ }*/
+ if(nameChangeId != -1) {
+ try (PreparedStatement ps = con.prepareStatement("UPDATE namechanges SET completionTime = ? WHERE id = ?")) {
+ ps.setTimestamp(1, new Timestamp(System.currentTimeMillis()));
+ ps.setInt(2, nameChangeId);
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Character ID : " + characterId);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public int checkWorldTransferEligibility() {
+ if(getLevel() < 20) {
+ return 2;
+ } else if(getClient().getTempBanCalendar() != null && getClient().getTempBanCalendar().getTimeInMillis() + (30*24*60*60*1000) < Calendar.getInstance().getTimeInMillis()) {
+ return 3;
+ } else if(isMarried()) {
+ return 4;
+ } else if(getGuildRank() < 2) {
+ return 5;
+ } else if(getFamily() != null) {
+ return 8;
+ } else {
+ return 0;
+ }
+ }
+
+ public static String checkWorldTransferEligibility(Connection con, int characterId, int oldWorld, int newWorld) {
+ if(!YamlConfig.config.server.ALLOW_CASHSHOP_WORLD_TRANSFER) return "World transfers disabled.";
+ int accountId = -1;
+ try (PreparedStatement ps = con.prepareStatement("SELECT accountid, level, guildid, guildrank, partnerId, familyId FROM characters WHERE id = ?")) {
+ ps.setInt(1, characterId);
+ ResultSet rs = ps.executeQuery();
+ if(!rs.next()) return "Character does not exist.";
+ accountId = rs.getInt("accountid");
+ if(rs.getInt("level") < 20) return "Character is under level 20.";
+ if(rs.getInt("familyId") != -1) return "Character is in family.";
+ if(rs.getInt("partnerId") != 0) return "Character is married.";
+ if(rs.getInt("guildid") != 0 && rs.getInt("guildrank") < 2) return "Character is the leader of a guild.";
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e);
+ return "SQL Error";
+ }
+ try (PreparedStatement ps = con.prepareStatement("SELECT tempban FROM accounts WHERE id = ?")) {
+ ps.setInt(1, accountId);
+ ResultSet rs = ps.executeQuery();
+ if(!rs.next()) return "Account does not exist.";
+ if(rs.getLong("tempban") != 0 && !rs.getString("tempban").equals("2018-06-20 00:00:00.0")) return "Account has been banned.";
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e);
+ return "SQL Error";
+ }
+ try (PreparedStatement ps = con.prepareStatement("SELECT COUNT(*) AS rowcount FROM characters WHERE accountid = ? AND world = ?")) {
+ ps.setInt(1, accountId);
+ ps.setInt(2, newWorld);
+ ResultSet rs = ps.executeQuery();
+ if(!rs.next()) return "SQL Error";
+ if(rs.getInt("rowcount") >= 3) return "Too many characters on destination world.";
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e);
+ return "SQL Error";
+ }
+ return null;
+ }
+
+ public boolean registerWorldTransfer(int newWorld) {
+ try (Connection con = DatabaseConnection.getConnection()) {
+ //check for pending world transfer
+ long currentTimeMillis = System.currentTimeMillis();
+ try (PreparedStatement ps = con.prepareStatement("SELECT completionTime FROM worldtransfers WHERE characterid=?")) { //double check, just in case
+ ps.setInt(1, getId());
+ ResultSet rs = ps.executeQuery();
+ while(rs.next()) {
+ Timestamp completedTimestamp = rs.getTimestamp("completionTime");
+ if(completedTimestamp == null) return false; //pending
+ else if(completedTimestamp.getTime() + YamlConfig.config.server.WORLD_TRANSFER_COOLDOWN > currentTimeMillis) return false;
+ }
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.WORLD_TRANSFER, e, "Failed to register world transfer for character " + getName() + ".");
+ return false;
+ }
+ try (PreparedStatement ps = con.prepareStatement("INSERT INTO worldtransfers (characterid, `from`, `to`) VALUES (?, ?, ?)")){
+ ps.setInt(1, getId());
+ ps.setInt(2, getWorld());
+ ps.setInt(3, newWorld);
+ ps.executeUpdate();
+ return true;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.WORLD_TRANSFER, e, "Failed to register world transfer for character " + getName() + ".");
+ }
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.WORLD_TRANSFER, e, "Failed to get DB connection.");
+ }
+ return false;
+ }
+
+ public boolean cancelPendingWorldTranfer() {
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("DELETE FROM worldtransfers WHERE characterid=? AND completionTime IS NULL")) {
+ ps.setInt(1, getId());
+ int affectedRows = ps.executeUpdate();
+ return affectedRows > 0; //rows affected
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.WORLD_TRANSFER, e, "Failed to cancel pending world transfer for character " + getName() + ".");
+ return false;
+ }
+ }
+
+ public static boolean doWorldTransfer(Connection con, int characterId, int oldWorld, int newWorld, int worldTransferId) {
+ int mesos = 0;
+ try (PreparedStatement ps = con.prepareStatement("SELECT meso FROM characters WHERE id = ?")) {
+ ps.setInt(1, characterId);
+ ResultSet rs = ps.executeQuery();
+ if(!rs.next()) {
+ FilePrinter.printError(FilePrinter.WORLD_TRANSFER, "Character data invalid? (charid " + characterId + ")");
+ return false;
+ }
+ mesos = rs.getInt("meso");
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.WORLD_TRANSFER, e, "Character ID : " + characterId);
+ return false;
+ }
+ try (PreparedStatement ps = con.prepareStatement("UPDATE characters SET world = ?, meso = ?, guildid = ?, guildrank = ? WHERE id = ?")) {
+ ps.setInt(1, newWorld);
+ ps.setInt(2, Math.min(mesos, 1000000)); // might want a limit in "YamlConfig.config.server" for this
+ ps.setInt(3, 0);
+ ps.setInt(4, 5);
+ ps.setInt(5, characterId);
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.WORLD_TRANSFER, e, "Character ID : " + characterId);
+ return false;
+ }
+ try (PreparedStatement ps = con.prepareStatement("DELETE FROM buddies WHERE characterid = ? OR buddyid = ?")) {
+ ps.setInt(1, characterId);
+ ps.setInt(2, characterId);
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.WORLD_TRANSFER, e, "Character ID : " + characterId);
+ return false;
+ }
+ if(worldTransferId != -1) {
+ try (PreparedStatement ps = con.prepareStatement("UPDATE worldtransfers SET completionTime = ? WHERE id = ?")) {
+ ps.setTimestamp(1, new Timestamp(System.currentTimeMillis()));
+ ps.setInt(2, worldTransferId);
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.WORLD_TRANSFER, e, "Character ID : " + characterId);
+ return false;
+ }
+ }
+ return true;
+ }
+
public String getLastCommandMessage() {
return this.commandtext;
}
@@ -10337,7 +11106,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public void setReborns(int value) {
- if (!ServerConstants.USE_REBIRTH_SYSTEM) {
+ if (!YamlConfig.config.server.USE_REBIRTH_SYSTEM) {
yellowMessage("Rebirth system is not enabled!");
throw new NotEnabledException();
}
@@ -10362,7 +11131,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public int getReborns() {
- if (!ServerConstants.USE_REBIRTH_SYSTEM) {
+ if (!YamlConfig.config.server.USE_REBIRTH_SYSTEM) {
yellowMessage("Rebirth system is not enabled!");
throw new NotEnabledException();
}
@@ -10385,7 +11154,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public void executeReborn() {
- if (!ServerConstants.USE_REBIRTH_SYSTEM) {
+ if (!YamlConfig.config.server.USE_REBIRTH_SYSTEM) {
yellowMessage("Rebirth system is not enabled!");
throw new NotEnabledException();
}
diff --git a/src/client/MapleClient.java b/src/client/MapleClient.java
index 67589efabb..aad0849b22 100644
--- a/src/client/MapleClient.java
+++ b/src/client/MapleClient.java
@@ -44,13 +44,13 @@ import java.util.Set;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Lock;
+import config.YamlConfig;
+import jdk.nashorn.api.scripting.NashornScriptEngine;
import tools.*;
-import javax.script.ScriptEngine;
-
import net.server.Server;
-import net.server.coordinator.MapleSessionCoordinator;
-import net.server.coordinator.MapleSessionCoordinator.AntiMulticlientResult;
+import net.server.coordinator.session.MapleSessionCoordinator;
+import net.server.coordinator.session.MapleSessionCoordinator.AntiMulticlientResult;
import net.server.channel.Channel;
import net.server.guild.MapleGuild;
import net.server.guild.MapleGuildCharacter;
@@ -63,8 +63,7 @@ import net.server.world.World;
import org.apache.mina.core.session.IoSession;
import client.inventory.MapleInventoryType;
-import constants.GameConstants;
-import constants.ServerConstants;
+import constants.game.GameConstants;
import scripting.AbstractPlayerInteraction;
import scripting.event.EventInstanceManager;
import scripting.event.EventManager;
@@ -73,18 +72,16 @@ import scripting.npc.NPCScriptManager;
import scripting.quest.QuestActionManager;
import scripting.quest.QuestScriptManager;
import server.life.MapleMonster;
-import server.MapleTrade;
import server.ThreadManager;
import server.maps.*;
-import server.quest.MapleQuest;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
-import net.server.coordinator.MapleLoginBypassCoordinator;
+import net.server.coordinator.login.MapleLoginBypassCoordinator;
public class MapleClient {
- public static final int LOGIN_NOTLOGGEDIN = 0;
+ public static final int LOGIN_NOTLOGGEDIN = 0;
public static final int LOGIN_SERVER_TRANSITION = 1;
public static final int LOGIN_LOGGEDIN = 2;
public static final String CLIENT_KEY = "CLIENT";
@@ -95,7 +92,7 @@ public class MapleClient {
private MapleAESOFB send;
private MapleAESOFB receive;
private final IoSession session;
- private MapleCharacter player;
+ private MapleCharacter player;
private int channel = 1;
private int accId = -4;
private boolean loggedIn = false;
@@ -106,7 +103,7 @@ public class MapleClient {
private long lastPong;
private int gmlevel;
private Set macs = new HashSet<>();
- private Map engines = new HashMap<>();
+ private Map engines = new HashMap<>();
private byte characterSlots = 3;
private byte loginattempt = 0;
private String pin = "";
@@ -120,19 +117,31 @@ public class MapleClient {
private final Semaphore actionsSemaphore = new Semaphore(7);
private final Lock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT, true);
private final Lock encoderLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT_ENCODER, true);
- private static final Lock loginLocks[] = new Lock[200]; // thanks Masterrulax & try2hack for pointing out a bottleneck issue here
+ private final Lock announcerLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT_ANNOUNCER, true);
+ private static final int lockCount = 200;
+ private static final Lock loginLocks[] = new Lock[lockCount]; // thanks Masterrulax & try2hack for pointing out a bottleneck issue here
+ private Calendar tempBanCalendar;
private int votePoints;
private int voteTime = -1;
private int visibleWorlds;
private long lastNpcClick;
private long sessionId;
+ private long lastPacket = System.currentTimeMillis();
private int lang = 0;
static {
- for (int i = 0; i < 200; i++) {
+ for (int i = 0; i < lockCount; i++) {
loginLocks[i] = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT_LOGIN, true);
}
}
+
+ public void updateLastPacket() {
+ lastPacket = System.currentTimeMillis();
+ }
+
+ public long getLastPacket() {
+ return lastPacket;
+ }
public MapleClient(MapleAESOFB send, MapleAESOFB receive, IoSession session) {
this.send = send;
@@ -444,14 +453,14 @@ public class MapleClient {
}
public int finishLogin() {
- Lock loginLock = loginLocks[this.getAccID() % 200];
+ Lock loginLock = loginLocks[this.getAccID() % lockCount];
loginLock.lock();
try {
if (getLoginState() > LOGIN_NOTLOGGEDIN) { // 0 = LOGIN_NOTLOGGEDIN, 1= LOGIN_SERVER_TRANSITION, 2 = LOGIN_LOGGEDIN
loggedIn = false;
return 7;
}
- updateLoginState(LOGIN_LOGGEDIN);
+ updateLoginState(MapleClient.LOGIN_LOGGEDIN);
} finally {
loginLock.unlock();
}
@@ -480,7 +489,7 @@ public class MapleClient {
}
public boolean checkPin(String other) {
- if (!(ServerConstants.ENABLE_PIN && !canBypassPin())) {
+ if (!(YamlConfig.config.server.ENABLE_PIN && !canBypassPin())) {
return true;
}
@@ -517,7 +526,7 @@ public class MapleClient {
}
public boolean checkPic(String other) {
- if (!(ServerConstants.ENABLE_PIC && !canBypassPic())) {
+ if (!(YamlConfig.config.server.ENABLE_PIC && !canBypassPic())) {
return true;
}
@@ -583,7 +592,7 @@ public class MapleClient {
loginok = (tos == 0) ? 23 : 0;
} else if (pwd.equals(passhash) || checkHash(passhash, "SHA-1", pwd) || checkHash(passhash, "SHA-512", pwd)) {
// thanks GabrielSin for detecting some no-bcrypt inconsistencies here
- loginok = (tos == 0) ? (!ServerConstants.BCRYPT_MIGRATION ? 23 : -23) : (!ServerConstants.BCRYPT_MIGRATION ? 0 : -10); // migrate to bcrypt
+ loginok = (tos == 0) ? (!YamlConfig.config.server.BCRYPT_MIGRATION ? 23 : -23) : (!YamlConfig.config.server.BCRYPT_MIGRATION ? 0 : -10); // migrate to bcrypt
} else {
loggedIn = false;
loginok = 4;
@@ -640,7 +649,7 @@ public class MapleClient {
}
}
- public Calendar getTempBanCalendar() {
+ public Calendar getTempBanCalendarFromDB() {
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
@@ -654,10 +663,12 @@ public class MapleClient {
return null;
}
long blubb = rs.getLong("tempban");
- if (blubb == 0) { // basically if timestamp in db is 0000-00-00
+
+ if (blubb == 0 || rs.getString("tempban").equals("2018-06-20 00:00:00.0")) { // 0000-00-00 or 2018-06-20 (default set in LoginPasswordHandler)
return null;
}
lTempban.setTimeInMillis(rs.getTimestamp("tempban").getTime());
+ tempBanCalendar = lTempban;
return lTempban;
} catch (SQLException e) {
e.printStackTrace();
@@ -678,6 +689,14 @@ public class MapleClient {
}
return null;//why oh why!?!
}
+
+ public Calendar getTempBanCalendar() {
+ return tempBanCalendar;
+ }
+
+ public boolean hasBeenBanned() {
+ return tempBanCalendar != null;
+ }
public static long dottedQuadToLong(String dottedQuad) throws RuntimeException {
String[] quads = dottedQuad.split("\\.");
@@ -831,7 +850,7 @@ public class MapleClient {
if (rs.getTimestamp("lastlogin").getTime() + 30000 < Server.getInstance().getCurrentTime()) {
int accountId = accId;
state = LOGIN_NOTLOGGEDIN;
- updateLoginState(LOGIN_NOTLOGGEDIN); // ACCID = 0, issue found thanks to Tochi & K u ssss o & Thora & Omo Oppa
+ updateLoginState(MapleClient.LOGIN_NOTLOGGEDIN); // ACCID = 0, issue found thanks to Tochi & K u ssss o & Thora & Omo Oppa
this.setAccID(accountId);
}
}
@@ -865,9 +884,9 @@ public class MapleClient {
MapleMap map = player.getMap();
final MapleParty party = player.getParty();
final int idz = player.getId();
- final MaplePartyCharacter chrp = new MaplePartyCharacter(player);
if (party != null) {
+ final MaplePartyCharacter chrp = new MaplePartyCharacter(player);
chrp.setOnline(false);
wserv.updateParty(party.getId(), PartyOperation.LOG_ONOFF, chrp);
if (party.getLeader().getId() == idz && map != null) {
@@ -977,14 +996,9 @@ public class MapleClient {
family.
}
*/
- for (MapleQuestStatus status : player.getStartedQuests()) { //This is for those quests that you have to stay logged in for a certain amount of time
- MapleQuest quest = status.getQuest();
- if (quest.getTimeLimit() > 0) {
- MapleQuestStatus newStatus = new MapleQuestStatus(quest, MapleQuestStatus.Status.NOT_STARTED);
- newStatus.setForfeited(player.getQuest(quest).getForfeited() + 1);
- player.updateQuest(newStatus);
- }
- }
+
+ player.forfeitExpirableQuests(); //This is for those quests that you have to stay logged in for a certain amount of time
+
if (guild != null) {
final Server server = Server.getInstance();
server.setGuildMemberOnline(player, false, player.getClient().getChannel());
@@ -1017,6 +1031,7 @@ public class MapleClient {
player.saveCharToDB(true);
player.logOff();
+ if(YamlConfig.config.server.INSTANT_NAME_CHANGE) player.doPendingNameChange();
clear();
} else {
getChannelServer().removePlayer(player);
@@ -1038,7 +1053,8 @@ public class MapleClient {
MapleSessionCoordinator.getInstance().closeSession(session, false);
session.removeAttribute(MapleClient.CLIENT_KEY);
}
- if (!Server.getInstance().hasCharacteridInTransition(session)) {
+
+ if (!Server.getInstance().hasCharacteridInTransition(this)) {
updateLoginState(MapleClient.LOGIN_NOTLOGGEDIN);
}
@@ -1064,6 +1080,12 @@ public class MapleClient {
this.send = null;
//this.session = null;
}
+
+ public void setCharacterOnSessionTransitionState(int cid) {
+ this.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
+ session.setAttribute(MapleClient.CLIENT_TRANSITION);
+ Server.getInstance().setCharacteridInTransition(this, cid);
+ }
public int getChannel() {
return channel;
@@ -1162,11 +1184,11 @@ public class MapleClient {
gmlevel = level;
}
- public void setScriptEngine(String name, ScriptEngine e) {
+ public void setScriptEngine(String name, NashornScriptEngine e) {
engines.put(name, e);
}
- public ScriptEngine getScriptEngine(String name) {
+ public NashornScriptEngine getScriptEngine(String name) {
return engines.get(name);
}
@@ -1210,6 +1232,22 @@ public class MapleClient {
}
return disconnectForBeingAFaggot;
}
+
+ public void checkChar(int accid) { /// issue with multiple chars from same account login found by shavit, resinate
+ if (!YamlConfig.config.server.USE_CHARACTER_ACCOUNT_CHECK) {
+ return;
+ }
+
+ for (World w : Server.getInstance().getWorlds()) {
+ for (MapleCharacter chr : w.getPlayerStorage().getAllCharacters()) {
+ if (accid == chr.getAccountID()) {
+ FilePrinter.print(FilePrinter.EXPLOITS, "Player: " + chr.getName() + " has been removed from " + GameConstants.WORLD_NAMES[w.getId()] + ". Possible Dupe attempt.");
+ chr.getClient().forceDisconnect();
+ w.getPlayerStorage().removePlayer(chr.getId());
+ }
+ }
+ }
+ }
public int getVotePoints(){
int points = 0;
@@ -1285,12 +1323,18 @@ public class MapleClient {
actionsSemaphore.release();
}
- public void lockEncoder() {
- encoderLock.lock();
+ public boolean tryacquireEncoder() {
+ if (actionsSemaphore.tryAcquire()) {
+ encoderLock.lock();
+ return true;
+ } else {
+ return false;
+ }
}
public void unlockEncoder() {
encoderLock.unlock();
+ actionsSemaphore.release();
}
private static class CharNameAndId {
@@ -1323,6 +1367,10 @@ public class MapleClient {
return (short) Math.max(0, characterSlots - Server.getInstance().getAccountWorldCharacterCount(accId, world));
}
+ public short getAvailableCharacterWorldSlots(int world) {
+ return (short) Math.max(0, characterSlots - Server.getInstance().getAccountWorldCharacterCount(accId, world));
+ }
+
public short getCharacterSlots() {
return characterSlots;
}
@@ -1436,8 +1484,13 @@ public class MapleClient {
}
}
- public synchronized void announce(final byte[] packet) {//MINA CORE IS A FUCKING BITCH AND I HATE IT <3
- session.write(packet);
+ public void announce(final byte[] packet) { // thanks GitGud for noticing an opportunity for improvement by overcoming "synchronized announce"
+ announcerLock.lock();
+ try {
+ session.write(packet);
+ } finally {
+ announcerLock.unlock();
+ }
}
public void announceHint(String msg, int length) {
@@ -1492,8 +1545,7 @@ public class MapleClient {
player.saveCharToDB();
- player.getClient().updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
- player.setSessionTransitionState();
+ player.setSessionTransitionState();
try {
announce(MaplePacketCreator.getChannelChange(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1])));
} catch (IOException e) {
diff --git a/src/client/MapleDisease.java b/src/client/MapleDisease.java
index 14984e7293..4dd866f050 100644
--- a/src/client/MapleDisease.java
+++ b/src/client/MapleDisease.java
@@ -21,7 +21,7 @@
*/
package client;
-import constants.GameConstants;
+import constants.game.GameConstants;
public enum MapleDisease {
NULL(0x0),
diff --git a/src/client/MapleFamily.java b/src/client/MapleFamily.java
index 51eb441159..bae907b941 100644
--- a/src/client/MapleFamily.java
+++ b/src/client/MapleFamily.java
@@ -25,75 +25,279 @@ import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
-import java.util.HashMap;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import net.server.Server;
+import net.server.world.World;
import tools.DatabaseConnection;
+import tools.FilePrinter;
+import tools.MaplePacketCreator;
+import tools.Pair;
/**
*
* @author Jay Estrella - Mr.Trash :3
+ * @author Ubaware
*/
public class MapleFamily {
- private static int id;
- private static Map members = new HashMap();
- public MapleFamily(int cid) {
- try {
- Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("SELECT familyid FROM family_character WHERE cid = ?");
- ps.setInt(1, cid);
- ResultSet rs = ps.executeQuery();
- if (rs.next()) {
- id = rs.getInt("familyid");
- }
- ps.close();
- rs.close();
- con.close();
- getMapleFamily();
- } catch (SQLException ex) {
- ex.printStackTrace();
- }
- }
+ private static final AtomicInteger familyIDCounter = new AtomicInteger();
- private static void getMapleFamily() {
- try {
- Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("SELECT * FROM family_character WHERE familyid = ?");
- ps.setInt(1, id);
- ResultSet rs = ps.executeQuery();
- while (rs.next()) {
- MapleFamilyEntry ret = new MapleFamilyEntry();
- ret.setFamilyId(id);
- ret.setRank(rs.getInt("rank"));
- ret.setReputation(rs.getInt("reputation"));
- ret.setTotalJuniors(rs.getInt("totaljuniors"));
- ret.setFamilyName(rs.getString("name"));
- ret.setJuniors(rs.getInt("juniorsadded"));
- ret.setTodaysRep(rs.getInt("todaysrep"));
- int cid = rs.getInt("cid");
- ret.setChrId(cid);
- members.put(cid, ret);
- }
- rs.close();
- ps.close();
- con.close();
- } catch (SQLException sqle) {
- sqle.printStackTrace();
- }
- }
+ private final int id, world;
+ private final Map members = new ConcurrentHashMap();
+ private MapleFamilyEntry leader;
+ private String name;
+ private String preceptsMessage = "";
+ private int totalGenerations;
- public MapleFamilyEntry getMember(int cid) {
- if (members.containsKey(cid)){
- return members.get(cid);
- }
- return null;
- }
-
- public Map getMembers() {
- return members;
- }
-
- public void broadcast(byte[] packet) {
- // family currently not developed
+ public MapleFamily(int id, int world) {
+ int newId = id;
+ if(id == -1) {
+ // get next available family id
+ while(idInUse(newId = familyIDCounter.incrementAndGet())) {
+ }
}
+ this.id = newId;
+ this.world = world;
+ }
+
+ private static boolean idInUse(int id) {
+ for(World world : Server.getInstance().getWorlds()) {
+ if(world.getFamily(id) != null) return true;
+ }
+ return false;
+ }
+
+ public int getID() {
+ return id;
+ }
+
+ public int getWorld() {
+ return world;
+ }
+
+ public void setLeader(MapleFamilyEntry leader) {
+ this.leader = leader;
+ setName(leader.getName());
+ }
+
+ public MapleFamilyEntry getLeader() {
+ return leader;
+ }
+
+ private void setName(String name) {
+ this.name = name;
+ }
+
+ public int getTotalMembers() {
+ return members.size();
+ }
+
+ public int getTotalGenerations() {
+ return totalGenerations;
+ }
+
+ public void setTotalGenerations(int generations) {
+ this.totalGenerations = generations;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void setMessage(String message, boolean save) {
+ this.preceptsMessage = message;
+ if(save) {
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("UPDATE family_character SET precepts = ? WHERE cid = ?")) {
+ ps.setString(1, message);
+ ps.setInt(2, getLeader().getChrId());
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ FilePrinter.printError(FilePrinter.FAMILY_ERROR, e, "Could not save new precepts for family " + getID() + ".");
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public String getMessage() {
+ return preceptsMessage;
+ }
+
+ public void addEntry(MapleFamilyEntry entry) {
+ members.put(entry.getChrId(), entry);
+ }
+
+ public void removeEntryBranch(MapleFamilyEntry root) {
+ members.remove(root.getChrId());
+ for(MapleFamilyEntry junior : root.getJuniors()) {
+ if(junior != null) removeEntryBranch(junior);
+ }
+ }
+
+ public void addEntryTree(MapleFamilyEntry root) {
+ members.put(root.getChrId(), root);
+ for(MapleFamilyEntry junior : root.getJuniors()) {
+ if(junior != null) addEntryTree(junior);
+ }
+ }
+
+ public MapleFamilyEntry getEntryByID(int cid) {
+ return members.get(cid);
+ }
+
+ public void broadcast(byte[] packet) {
+ broadcast(packet, -1);
+ }
+
+ public void broadcast(byte[] packet, int ignoreID) {
+ for(MapleFamilyEntry entry : members.values()) {
+ MapleCharacter chr = entry.getChr();
+ if(chr != null) {
+ if(chr.getId() == ignoreID) continue;
+ chr.getClient().announce(packet);
+ }
+ }
+ }
+
+ public void broadcastFamilyInfoUpdate() {
+ for(MapleFamilyEntry entry : members.values()) {
+ MapleCharacter chr = entry.getChr();
+ if(chr != null) {
+ chr.getClient().announce(MaplePacketCreator.getFamilyInfo(entry));
+ }
+ }
+ }
+
+ public void resetDailyReps() {
+ for(MapleFamilyEntry entry : members.values()) {
+ entry.setTodaysRep(0);
+ entry.setRepsToSenior(0);
+ entry.resetEntitlementUsages();
+ }
+ }
+
+ public static void loadAllFamilies() {
+ try(Connection con = DatabaseConnection.getConnection()) {
+ List, MapleFamilyEntry>> unmatchedJuniors = new ArrayList, MapleFamilyEntry>>(200); // < familyEntry>
+ try(PreparedStatement psEntries = con.prepareStatement("SELECT * FROM family_character")) {
+ ResultSet rsEntries = psEntries.executeQuery();
+ while(rsEntries.next()) { // can be optimized
+ int cid = rsEntries.getInt("cid");
+ String name = null;
+ int level = -1;
+ int jobID = -1;
+ int world = -1;
+ try(PreparedStatement ps = con.prepareStatement("SELECT world, name, level, job FROM characters WHERE id = ?")) {
+ ps.setInt(1, cid);
+ ResultSet rs = ps.executeQuery();
+ if(rs.next()) {
+ world = rs.getInt("world");
+ name = rs.getString("name");
+ level = rs.getInt("level");
+ jobID = rs.getInt("job");
+ } else {
+ FilePrinter.printError(FilePrinter.FAMILY_ERROR, "Could not load character information of " + cid + " in loadAllFamilies(). (RECORD DOES NOT EXIST)");
+ continue;
+ }
+ } catch(SQLException e) {
+ FilePrinter.printError(FilePrinter.FAMILY_ERROR, e, "Could not load character information of " + cid + " in loadAllFamilies(). (SQL ERROR)");
+ continue;
+ }
+ int familyid = rsEntries.getInt("familyid");
+ int seniorid = rsEntries.getInt("seniorid");
+ int reputation = rsEntries.getInt("reputation");
+ int todaysRep = rsEntries.getInt("todaysrep");
+ int totalRep = rsEntries.getInt("totalreputation");
+ int repsToSenior = rsEntries.getInt("reptosenior");
+ String precepts = rsEntries.getString("precepts");
+ //Timestamp lastResetTime = rsEntries.getTimestamp("lastresettime"); //taken care of by FamilyDailyResetTask
+ World wserv = Server.getInstance().getWorld(world);
+ if (wserv == null) {
+ continue;
+ }
+ MapleFamily family = wserv.getFamily(familyid);
+ if(family == null) {
+ family = new MapleFamily(familyid, world);
+ Server.getInstance().getWorld(world).addFamily(familyid, family);
+ }
+ MapleFamilyEntry familyEntry = new MapleFamilyEntry(family, cid, name, level, MapleJob.getById(jobID));
+ family.addEntry(familyEntry);
+ if(seniorid <= 0) {
+ family.setLeader(familyEntry);
+ family.setMessage(precepts, false);
+ }
+ MapleFamilyEntry senior = family.getEntryByID(seniorid);
+ if(senior != null) {
+ familyEntry.setSenior(family.getEntryByID(seniorid), false);
+ } else {
+ if(seniorid > 0) unmatchedJuniors.add(new Pair, MapleFamilyEntry>(new Pair(world, seniorid), familyEntry));
+ }
+ familyEntry.setReputation(reputation);
+ familyEntry.setTodaysRep(todaysRep);
+ familyEntry.setTotalReputation(totalRep);
+ familyEntry.setRepsToSenior(repsToSenior);
+ //load used entitlements
+ try (PreparedStatement ps = con.prepareStatement("SELECT entitlementid FROM family_entitlement WHERE charid = ?")) {
+ ps.setInt(1, familyEntry.getChrId());
+ ResultSet rs = ps.executeQuery();
+ while(rs.next()) {
+ familyEntry.setEntitlementUsed(rs.getInt("entitlementid"));
+ }
+ }
+ }
+ } catch(SQLException e) {
+ FilePrinter.printError(FilePrinter.FAMILY_ERROR, e, "Could not get family_character entries.");
+ e.printStackTrace();
+ }
+ // link missing ones (out of order)
+ for(Pair, MapleFamilyEntry> unmatchedJunior : unmatchedJuniors) {
+ int world = unmatchedJunior.getLeft().getLeft();
+ int seniorid = unmatchedJunior.getLeft().getRight();
+ MapleFamilyEntry junior = unmatchedJunior.getRight();
+ MapleFamilyEntry senior = Server.getInstance().getWorld(world).getFamily(junior.getFamily().getID()).getEntryByID(seniorid);
+ if(senior != null) {
+ junior.setSenior(senior, false);
+ } else {
+ FilePrinter.printError(FilePrinter.FAMILY_ERROR, "Missing senior for character " + junior.getName() + " in world " + world);
+ }
+ }
+ } catch(SQLException e) {
+ FilePrinter.printError(FilePrinter.FAMILY_ERROR, e, "Could not get DB connection.");
+ e.printStackTrace();
+ }
+ for(World world : Server.getInstance().getWorlds()) {
+ for(MapleFamily family : world.getFamilies()) {
+ family.getLeader().doFullCount();
+ }
+ }
+ }
+
+ public void saveAllMembersRep() { //was used for autosave task, but character autosave should be enough
+ try(Connection con = DatabaseConnection.getConnection()) {
+ con.setAutoCommit(false);
+ boolean success = true;
+ for(MapleFamilyEntry entry : members.values()) {
+ success = entry.saveReputation(con);
+ if(!success) break;
+ }
+ if(!success) {
+ con.rollback();
+ FilePrinter.printError(FilePrinter.FAMILY_ERROR, "Family rep autosave failed for family " + getID() + " on " + Calendar.getInstance().getTime().toString() + ".");
+ }
+ con.setAutoCommit(true);
+ //reset repChanged after successful save
+ for(MapleFamilyEntry entry : members.values()) {
+ entry.savedSuccessfully();
+ }
+ } catch(SQLException e) {
+ FilePrinter.printError(FilePrinter.FAMILY_ERROR, e, "Could not get connection to DB.");
+ e.printStackTrace();
+ }
+ }
}
diff --git a/src/client/MapleFamilyEntitlement.java b/src/client/MapleFamilyEntitlement.java
new file mode 100644
index 0000000000..fed32c302f
--- /dev/null
+++ b/src/client/MapleFamilyEntitlement.java
@@ -0,0 +1,41 @@
+package client;
+
+public enum MapleFamilyEntitlement {
+ FAMILY_REUINION(1, 300, "Family Reunion", "[Target] Me\\n[Effect] Teleport directly to the Family member of your choice."),
+ SUMMON_FAMILY(1, 500, "Summon Family", "[Target] 1 Family member\\n[Effect] Summon a Family member of choice to the map you're in."),
+ SELF_DROP_1_5(1, 700, "My Drop Rate 1.5x (15 min)", "[Target] Me\\n[Time] 15 min.\\n[Effect] Monster drop rate will be increased #c1.5x#.\\n* If the Drop Rate event is in progress, this will be nullified."),
+ SELF_EXP_1_5(1, 800, "My EXP 1.5x (15 min)", "[Target] Me\\n[Time] 15 min.\\n[Effect] EXP earned from hunting will be increased #c1.5x#.\\n* If the EXP event is in progress, this will be nullified."),
+ FAMILY_BONDING(1, 1000, "Family Bonding (30 min)", "[Target] At least 6 Family members online that are below me in the Pedigree\\n[Time] 30 min.\\n[Effect] Monster drop rate and EXP earned will be increased #c2x#. \\n* If the EXP event is in progress, this will be nullified."),
+ SELF_DROP_2(1, 1200, "My Drop Rate 2x (15 min)", "[Target] Me\\n[Time] 15 min.\\n[Effect] Monster drop rate will be increased #c2x#.\\n* If the Drop Rate event is in progress, this will be nullified."),
+ SELF_EXP_2(1, 1500, "My EXP 2x (15 min)", "[Target] Me\\n[Time] 15 min.\\n[Effect] EXP earned from hunting will be increased #c2x#.\\n* If the EXP event is in progress, this will be nullified."),
+ SELF_DROP_2_30MIN(1, 2000, "My Drop Rate 2x (30 min)", "[Target] Me\\n[Time] 30 min.\\n[Effect] Monster drop rate will be increased #c2x#.\\n* If the Drop Rate event is in progress, this will be nullified."),
+ SELF_EXP_2_30MIN(1, 2500, "My EXP 2x (30 min)", "[Target] Me\\n[Time] 30 min.\\n[Effect] EXP earned from hunting will be increased #c2x#. \\n* If the EXP event is in progress, this will be nullified."),
+ PARTY_DROP_2_30MIN(1, 4000, "My Party Drop Rate 2x (30 min)", "[Target] My party\\n[Time] 30 min.\\n[Effect] Monster drop rate will be increased #c2x#.\\n* If the Drop Rate event is in progress, this will be nullified."),
+ PARTY_EXP_2_30MIN(1, 5000, "My Party EXP 2x (30 min)", "[Target] My party\\n[Time] 30 min.\\n[Effect] EXP earned from hunting will be increased #c2x#.\\n* If the EXP event is in progress, this will be nullified.");
+
+ private final int usageLimit, repCost;
+ private final String name, description;
+
+ private MapleFamilyEntitlement(int usageLimit, int repCost, String name, String description) {
+ this.usageLimit = usageLimit;
+ this.repCost = repCost;
+ this.name = name;
+ this.description = description;
+ }
+
+ public int getUsageLimit() {
+ return usageLimit;
+ }
+
+ public int getRepCost() {
+ return repCost;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+}
diff --git a/src/client/MapleFamilyEntry.java b/src/client/MapleFamilyEntry.java
index af8ac7e37a..82858ae131 100644
--- a/src/client/MapleFamilyEntry.java
+++ b/src/client/MapleFamilyEntry.java
@@ -1,8 +1,6 @@
/*
- This file is part of the OdinMS Maple Story Server
- Copyright (C) 2008 Patrick Huy
- Matthias Butz
- Jan Christian Meyer
+ This file is part of the HeavenMS MapleStory Server
+ Copyleft (L) 2016 - 2018 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
@@ -21,33 +19,210 @@
*/
package client;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import net.server.Server;
+import tools.DatabaseConnection;
+import tools.FilePrinter;
+import tools.MaplePacketCreator;
+import tools.Pair;
+
+/**
+ * @author Ubaware
+ */
+
public class MapleFamilyEntry {
- private int familyId;
- private int rank, reputation, totalReputation, todaysRep, totalJuniors, juniors, chrid;
- private String familyName;
+ private final int characterID;
+ private volatile MapleFamily family;
+ private volatile MapleCharacter character;
- public int getId() {
- return familyId;
+ private volatile MapleFamilyEntry senior;
+ private final MapleFamilyEntry[] juniors = new MapleFamilyEntry[2];
+ private final int[] entitlements = new int[11];
+ private volatile int reputation, totalReputation;
+ private volatile int todaysRep, repsToSenior; //both are daily values
+ private volatile int totalJuniors, totalSeniors;
+
+ private volatile int generation;
+
+ private volatile boolean repChanged; //used to ignore saving unchanged rep values
+
+ // cached values for offline players
+ private String charName;
+ private int level;
+ private MapleJob job;
+
+ public MapleFamilyEntry(MapleFamily family, int characterID, String charName, int level, MapleJob job) {
+ this.family = family;
+ this.characterID = characterID;
+ this.charName = charName;
+ this.level = level;
+ this.job = job;
}
- public void setFamilyId(int familyId) {
- this.familyId = familyId;
+ public MapleCharacter getChr() {
+ return character;
}
- public int getRank() {
- return rank;
+ public void setCharacter(MapleCharacter newCharacter) {
+ if(newCharacter == null) cacheOffline(newCharacter);
+ else newCharacter.setFamilyEntry(this);
+ this.character = newCharacter;
}
- public void setRank(int rank) {
- this.rank = rank;
+ private void cacheOffline(MapleCharacter chr) {
+ if(chr != null) {
+ charName = chr.getName();
+ level = chr.getLevel();
+ job = chr.getJob();
+ }
+ }
+
+ public synchronized void join(MapleFamilyEntry senior) {
+ if(senior == null || getSenior() != null) return;
+ MapleFamily oldFamily = getFamily();
+ MapleFamily newFamily = senior.getFamily();
+ setSenior(senior, false);
+ addSeniorCount(newFamily.getTotalGenerations(), newFamily); //count will be overwritten by doFullCount()
+ newFamily.getLeader().doFullCount(); //easier than keeping track of numbers
+ oldFamily.setMessage(null, true);
+ newFamily.addEntryTree(this);
+ Server.getInstance().getWorld(oldFamily.getWorld()).removeFamily(oldFamily.getID());
+
+ //db
+ try(Connection con = DatabaseConnection.getConnection()) {
+ con.setAutoCommit(false);
+ boolean success = updateDBChangeFamily(con, getChrId(), newFamily.getID(), senior.getChrId());
+ for(MapleFamilyEntry junior : juniors) { // better to duplicate this than the SQL code
+ if(junior != null) {
+ success = junior.updateNewFamilyDB(con); // recursively updates juniors in db
+ if(!success) break;
+ }
+ }
+ if(!success) {
+ con.rollback();
+ FilePrinter.printError(FilePrinter.FAMILY_ERROR, "Could not absorb " + oldFamily.getName() + " family into " + newFamily.getName() + " family. (SQL ERROR)");
+ }
+ con.setAutoCommit(true);
+ } catch(SQLException e) {
+ FilePrinter.printError(FilePrinter.FAMILY_ERROR, e, "Could not get connection to DB.");
+ e.printStackTrace();
+ }
+ }
+
+ public synchronized void fork() {
+ MapleFamily oldFamily = getFamily();
+ MapleFamilyEntry oldSenior = getSenior();
+ family = new MapleFamily(-1, oldFamily.getWorld());
+ Server.getInstance().getWorld(family.getWorld()).addFamily(family.getID(), family);
+ setSenior(null, false);
+ family.setLeader(this);
+ addSeniorCount(-getTotalSeniors(), family);
+ setTotalSeniors(0);
+ if(oldSenior != null) {
+ oldSenior.addJuniorCount(-getTotalJuniors());
+ oldSenior.removeJunior(this);
+ oldFamily.getLeader().doFullCount();
+ }
+ oldFamily.removeEntryBranch(this);
+ family.addEntryTree(this);
+ this.repsToSenior = 0;
+ this.repChanged = true;
+ family.setMessage("", true);
+ doFullCount(); //to make sure all counts are correct
+ // update db
+ try(Connection con = DatabaseConnection.getConnection()) {
+ con.setAutoCommit(false);
+
+ boolean success = updateDBChangeFamily(con, getChrId(), getFamily().getID(), 0);
+
+ for(MapleFamilyEntry junior : juniors) { // better to duplicate this than the SQL code
+ if(junior != null) {
+ success = junior.updateNewFamilyDB(con); // recursively updates juniors in db
+ if(!success) break;
+ }
+ }
+ if(!success) {
+ con.rollback();
+ FilePrinter.printError(FilePrinter.FAMILY_ERROR, "Could not fork family with new leader " + getName() + ". (Old senior : " + oldSenior.getName() + ", leader :" + oldFamily.getLeader().getName() + ")");
+ }
+ con.setAutoCommit(true);
+
+ } catch(SQLException e) {
+ FilePrinter.printError(FilePrinter.FAMILY_ERROR, e, "Could not get connection to DB.");
+ e.printStackTrace();
+ }
+ }
+
+ private synchronized boolean updateNewFamilyDB(Connection con) {
+ if(!updateFamilyEntryDB(con, getChrId(), getFamily().getID())) return false;
+ if(!updateCharacterFamilyDB(con, getChrId(), getFamily().getID(), true)) return false;
+
+ for(MapleFamilyEntry junior : juniors) {
+ if(junior != null) {
+ if(!junior.updateNewFamilyDB(con)) return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean updateFamilyEntryDB(Connection con, int cid, int familyid) {
+ try(PreparedStatement ps = con.prepareStatement("UPDATE family_character SET familyid = ? WHERE cid = ?")) {
+ ps.setInt(1, familyid);
+ ps.setInt(2, cid);
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ FilePrinter.printError(FilePrinter.FAMILY_ERROR, e, "Could not update family id in 'family_character' for character id " + cid + ". (fork)");
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ private synchronized void addSeniorCount(int seniorCount, MapleFamily newFamily) { // traverses tree and subtracts seniors and updates family
+ if(newFamily != null) this.family = newFamily;
+ setTotalSeniors(getTotalSeniors() + seniorCount);
+ this.generation += seniorCount;
+ for(MapleFamilyEntry junior : juniors) {
+ if(junior != null) junior.addSeniorCount(seniorCount, newFamily);
+ }
+ }
+
+ private synchronized void addJuniorCount(int juniorCount) { // climbs tree and adds junior count
+ setTotalJuniors(getTotalJuniors() + juniorCount);
+ MapleFamilyEntry senior = getSenior();
+ if(senior != null) senior.addJuniorCount(juniorCount);
+ }
+
+ public MapleFamily getFamily() {
+ return family;
}
public int getChrId() {
- return chrid;
+ return characterID;
}
- public void setChrId(int chrid) {
- this.chrid = chrid;
+ public String getName() {
+ MapleCharacter chr = character;
+ if(chr != null) return chr.getName();
+ else return charName;
+ }
+
+ public int getLevel() {
+ MapleCharacter chr = character;
+ if(chr != null) return chr.getLevel();
+ else return level;
+ }
+
+ public MapleJob getJob() {
+ MapleCharacter chr = character;
+ if(chr != null) return chr.getJob();
+ else return job;
}
public int getReputation() {
@@ -59,16 +234,182 @@ public class MapleFamilyEntry {
}
public void setReputation(int reputation) {
+ if(reputation != this.reputation) this.repChanged = true;
this.reputation = reputation;
}
public void setTodaysRep(int today) {
+ if(today != todaysRep) this.repChanged = true;
this.todaysRep = today;
}
-
- public void gainReputation(int gain) {
+
+ public int getRepsToSenior() {
+ return repsToSenior;
+ }
+
+ public void setRepsToSenior(int reputation) {
+ if(reputation != this.repsToSenior) this.repChanged = true;
+ this.repsToSenior = reputation;
+ }
+
+ public void gainReputation(int gain, boolean countTowardsTotal) {
+ gainReputation(gain, countTowardsTotal, this);
+ }
+
+ private void gainReputation(int gain, boolean countTowardsTotal, MapleFamilyEntry from) {
+ if(gain != 0) repChanged = true;
this.reputation += gain;
- this.totalReputation += gain;
+ this.todaysRep += gain;
+ if(gain > 0 && countTowardsTotal) {
+ this.totalReputation += gain;
+ }
+ MapleCharacter chr = getChr();
+ if(chr != null) chr.announce(MaplePacketCreator.sendGainRep(gain, from != null ? from.getName() : ""));
+ }
+
+ public void giveReputationToSenior(int gain, boolean includeSuperSenior) {
+ int actualGain = gain;
+ MapleFamilyEntry senior = getSenior();
+ if(senior != null && senior.getLevel() < getLevel() && gain > 0) actualGain /= 2; //don't halve negative values
+ if(senior != null) {
+ senior.gainReputation(actualGain, true, this);
+ if(actualGain > 0) {
+ this.repsToSenior += actualGain;
+ this.repChanged = true;
+ }
+ if(includeSuperSenior) {
+ senior = senior.getSenior();
+ if(senior != null) {
+ senior.gainReputation(actualGain, true, this);
+ }
+ }
+ }
+ }
+
+ public int getTotalReputation() {
+ return totalReputation;
+ }
+
+ public void setTotalReputation(int totalReputation) {
+ if(totalReputation != this.totalReputation) this.repChanged = true;
+ this.totalReputation = totalReputation;
+ }
+
+ public MapleFamilyEntry getSenior() {
+ return senior;
+ }
+
+ public synchronized boolean setSenior(MapleFamilyEntry senior, boolean save) {
+ if(this.senior == senior) return false;
+ MapleFamilyEntry oldSenior = this.senior;
+ this.senior = senior;
+ if(senior != null) {
+ if(senior.addJunior(this)) {
+ if(save) {
+ updateDBChangeFamily(getChrId(), senior.getFamily().getID(), senior.getChrId());
+ }
+ if(this.repsToSenior != 0) this.repChanged = true;
+ this.repsToSenior = 0;
+ this.addSeniorCount(1, null);
+ this.setTotalSeniors(senior.getTotalSeniors() + 1);
+ return true;
+ }
+ } else {
+ if(oldSenior != null) {
+ oldSenior.removeJunior(this);
+ }
+ }
+ return false;
+ }
+
+ private static boolean updateDBChangeFamily(int cid, int familyid, int seniorid) {
+ try(Connection con = DatabaseConnection.getConnection()) {
+ return updateDBChangeFamily(con, cid, familyid, seniorid);
+ } catch(SQLException e) {
+ FilePrinter.printError(FilePrinter.FAMILY_ERROR, e, "Could not get connection to DB.");
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ private static boolean updateDBChangeFamily(Connection con, int cid, int familyid, int seniorid) {
+ try(PreparedStatement ps = con.prepareStatement("UPDATE family_character SET familyid = ?, seniorid = ?, reptosenior = 0 WHERE cid = ?")) {
+ ps.setInt(1, familyid);
+ ps.setInt(2, seniorid);
+ ps.setInt(3, cid);
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ FilePrinter.printError(FilePrinter.FAMILY_ERROR, e, "Could not update seniorid in 'family_character' for character id " + cid + ".");
+ e.printStackTrace();
+ return false;
+ }
+ return updateCharacterFamilyDB(con, cid, familyid, false);
+ }
+
+ private static boolean updateCharacterFamilyDB(Connection con, int charid, int familyid, boolean fork) {
+ try(PreparedStatement ps = con.prepareStatement("UPDATE characters SET familyid = ? WHERE id = ?")) {
+ ps.setInt(1, familyid);
+ ps.setInt(2, charid);
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ FilePrinter.printError(FilePrinter.FAMILY_ERROR, e, "Could not update familyid in 'characters' for character id " + charid + " when changing family. " + (fork ? "(fork)" : ""));
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ public List getJuniors() {
+ return Collections.unmodifiableList(Arrays.asList(juniors));
+ }
+
+ public MapleFamilyEntry getOtherJunior(MapleFamilyEntry junior) {
+ if(juniors[0] == junior) return juniors[1];
+ else if(juniors[1] == junior) return juniors[0];
+ return null;
+ }
+
+ public int getJuniorCount() { //close enough to be relatively consistent to multiple threads (and the result is not vital)
+ int juniorCount = 0;
+ if(juniors[0] != null) juniorCount++;
+ if(juniors[1] != null) juniorCount++;
+ return juniorCount;
+ }
+
+ public synchronized boolean addJunior(MapleFamilyEntry newJunior) {
+ for(int i = 0; i < juniors.length; i++) {
+ if(juniors[i] == null) { // successfully add new junior to family
+ juniors[i] = newJunior;
+ addJuniorCount(1);
+ getFamily().addEntry(newJunior);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public synchronized boolean isJunior(MapleFamilyEntry entry) { //require locking since result accuracy is vital
+ if(juniors[0] == entry) return true;
+ else if(juniors[1] == entry) return true;
+ return false;
+ }
+
+ public synchronized boolean removeJunior(MapleFamilyEntry junior) {
+ for(int i = 0; i < juniors.length; i++) {
+ if(juniors[i] == junior) {
+ juniors[i] = null;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public int getTotalSeniors() {
+ return totalSeniors;
+ }
+
+ public void setTotalSeniors(int totalSeniors) {
+ this.totalSeniors = totalSeniors;
}
public int getTotalJuniors() {
@@ -78,28 +419,134 @@ public class MapleFamilyEntry {
public void setTotalJuniors(int totalJuniors) {
this.totalJuniors = totalJuniors;
}
-
- public int getJuniors() {
- return juniors;
+
+ public void announceToSenior(byte[] packet, boolean includeSuperSenior) {
+ MapleFamilyEntry senior = getSenior();
+ if(senior != null) {
+ MapleCharacter seniorChr = senior.getChr();
+ if(seniorChr != null) seniorChr.announce(packet);
+ senior = senior.getSenior();
+ if(includeSuperSenior && senior != null) {
+ seniorChr = senior.getChr();
+ if(seniorChr != null) seniorChr.announce(packet);
+ }
+ }
+ }
+
+ public void updateSeniorFamilyInfo(boolean includeSuperSenior) {
+ MapleFamilyEntry senior = getSenior();
+ if(senior != null) {
+ MapleCharacter seniorChr = senior.getChr();
+ if(seniorChr != null) seniorChr.announce(MaplePacketCreator.getFamilyInfo(senior));
+ senior = senior.getSenior();
+ if(includeSuperSenior && senior != null) {
+ seniorChr = senior.getChr();
+ if(seniorChr != null) seniorChr.announce(MaplePacketCreator.getFamilyInfo(senior));
+ }
+ }
}
- public void setJuniors(int juniors) {
- this.juniors = juniors;
+ /**
+ * Traverses entire family tree to update senior/junior counts. Call on leader.
+ */
+ public synchronized void doFullCount() {
+ Pair counts = this.traverseAndUpdateCounts(0);
+ getFamily().setTotalGenerations(counts.getLeft() + 1);
}
- public void setFamilyName(String familyName) {
- this.familyName = familyName;
+ private Pair traverseAndUpdateCounts(int seniors) { // recursion probably limits family size, but it should handle a depth of a few thousand
+ setTotalSeniors(seniors);
+ this.generation = seniors;
+ int juniorCount = 0;
+ int highestGeneration = this.generation;
+ for(MapleFamilyEntry entry : juniors) {
+ if(entry != null) {
+ Pair counts = entry.traverseAndUpdateCounts(seniors + 1);
+ juniorCount += counts.getRight(); //total juniors
+ if(counts.getLeft() > highestGeneration) highestGeneration = counts.getLeft();
+ }
+ }
+ setTotalJuniors(juniorCount);
+ return new Pair<>(highestGeneration, juniorCount); //creating new objects to return is a bit inefficient, but cleaner than packing into a long
}
- public String getFamilyName() {
- return familyName;
+ public boolean useEntitlement(MapleFamilyEntitlement entitlement) {
+ int id = entitlement.ordinal();
+ if(entitlements[id] >= 1) return false;
+ try(Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("INSERT INTO family_entitlement (entitlementid, charid, timestamp) VALUES (?, ?, ?)")) {
+ ps.setInt(1, id);
+ ps.setInt(2, getChrId());
+ ps.setLong(3, System.currentTimeMillis());
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ FilePrinter.printError(FilePrinter.FAMILY_ERROR, e, "Could not insert new row in 'family_entitlement' for character " + getName() + ".");
+ e.printStackTrace();
+ }
+ entitlements[id]++;
+ return true;
+ }
+
+ public boolean refundEntitlement(MapleFamilyEntitlement entitlement) {
+ int id = entitlement.ordinal();
+ try(Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("DELETE FROM family_entitlement WHERE entitlementid = ? AND charid = ?")) {
+ ps.setInt(1, id);
+ ps.setInt(2, getChrId());
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ FilePrinter.printError(FilePrinter.FAMILY_ERROR, e, "Could not refund family entitlement \"" + entitlement.getName() + "\" for character " + getName() + ".");
+ e.printStackTrace();
+ }
+ entitlements[id] = 0;
+ return true;
}
- public int getTotalReputation() {
- return totalReputation;
+ public boolean isEntitlementUsed(MapleFamilyEntitlement entitlement) {
+ return entitlements[entitlement.ordinal()] >= 1;
}
-
- public void setTotalReputation(int totalReputation) {
- this.totalReputation = totalReputation;
+
+ public int getEntitlementUsageCount(MapleFamilyEntitlement entitlement) {
+ return entitlements[entitlement.ordinal()];
+ }
+
+ public void setEntitlementUsed(int id) {
+ entitlements[id]++;
+ }
+
+ public void resetEntitlementUsages() {
+ for(MapleFamilyEntitlement entitlement : MapleFamilyEntitlement.values()) {
+ entitlements[entitlement.ordinal()] = 0;
+ }
+ }
+
+ public boolean saveReputation() {
+ if(!repChanged) return true;
+ try(Connection con = DatabaseConnection.getConnection()) {
+ return saveReputation(con);
+ } catch(SQLException e) {
+ FilePrinter.printError(FilePrinter.FAMILY_ERROR, e, "Could not get connection to DB.");
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ public boolean saveReputation(Connection con) {
+ if(!repChanged) return true;
+ try (PreparedStatement ps = con.prepareStatement("UPDATE family_character SET reputation = ?, todaysrep = ?, totalreputation = ?, reptosenior = ? WHERE cid = ?")) {
+ ps.setInt(1, getReputation());
+ ps.setInt(2, getTodaysRep());
+ ps.setInt(3, getTotalReputation());
+ ps.setInt(4, getRepsToSenior());
+ ps.setInt(5, getChrId());
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ FilePrinter.printError(FilePrinter.FAMILY_ERROR, e, "Failed to autosave rep to 'family_character' for charid " + getChrId());
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ public void savedSuccessfully() {
+ this.repChanged = false;
}
}
diff --git a/src/client/MapleMount.java b/src/client/MapleMount.java
index 41934014c1..864a54a279 100644
--- a/src/client/MapleMount.java
+++ b/src/client/MapleMount.java
@@ -107,6 +107,10 @@ public class MapleMount {
public void setItemId(int newitemid) {
this.itemid = newitemid;
}
+
+ public void setSkillId(int newskillid) {
+ this.skillid = newskillid;
+ }
public void setActive(boolean set) {
this.active = set;
diff --git a/src/client/MapleQuestStatus.java b/src/client/MapleQuestStatus.java
index 9e0ccc9dd1..e7ce741d57 100644
--- a/src/client/MapleQuestStatus.java
+++ b/src/client/MapleQuestStatus.java
@@ -151,14 +151,20 @@ public class MapleQuestStatus {
}
public boolean progress(int id) {
- if (progress.get(id) != null) {
- int current = Integer.parseInt(progress.get(id));
- String str = StringUtil.getLeftPaddedStr(Integer.toString(current + 1), '0', 3);
- progress.put(id, str);
- //this.setUpdated();
- return true;
+ String currentStr = progress.get(id);
+ if (currentStr == null) {
+ return false;
}
- return false;
+
+ int current = Integer.parseInt(currentStr);
+ if (current >= this.getQuest().getMobAmountNeeded(id)) {
+ return false;
+ }
+
+ String str = StringUtil.getLeftPaddedStr(Integer.toString(++current), '0', 3);
+ progress.put(id, str);
+ //this.setUpdated();
+ return true;
}
public void setProgress(int id, String pr) {
@@ -169,15 +175,14 @@ public class MapleQuestStatus {
public boolean madeProgress() {
return progress.size() > 0;
}
-
- public Integer getAnyProgressKey() {
- if (!progress.isEmpty()) return progress.entrySet().iterator().next().getKey();
- return 0;
- }
public String getProgress(int id) {
- if (progress.get(id) == null) return "";
- return progress.get(id);
+ String ret = progress.get(id);
+ if (ret == null) {
+ return "";
+ } else {
+ return ret;
+ }
}
public void resetProgress(int id) {
@@ -193,6 +198,27 @@ public class MapleQuestStatus {
public Map getProgress() {
return Collections.unmodifiableMap(progress);
}
+
+ public short getInfoNumber() {
+ MapleQuest q = this.getQuest();
+ Status s = this.getStatus();
+
+ return q.getInfoNumber(s);
+ }
+
+ public String getInfoEx(int index) {
+ MapleQuest q = this.getQuest();
+ Status s = this.getStatus();
+
+ return q.getInfoEx(s, index);
+ }
+
+ public List getInfoEx() {
+ MapleQuest q = this.getQuest();
+ Status s = this.getStatus();
+
+ return q.getInfoEx(s);
+ }
public long getCompletionTime() {
return completionTime;
@@ -217,18 +243,6 @@ public class MapleQuestStatus {
public int getCompleted() {
return completed;
}
-
- public String getInfo() {
- if(!progress.containsKey(0) && !getMedalMaps().isEmpty()) {
- return Integer.toString(getMedalProgress());
- }
- return getProgress(0);
- }
-
- public void setInfo(String newInfo) {
- progress.put(0, newInfo);
- //this.setUpdated();
- }
public void setForfeited(int forfeited) {
if (forfeited >= this.forfeited) {
@@ -254,11 +268,11 @@ public class MapleQuestStatus {
return customData;
}
- public String getQuestData() {
+ public String getProgressData() {
StringBuilder str = new StringBuilder();
for (String ps : progress.values()) {
str.append(ps);
}
return str.toString();
}
-}
\ No newline at end of file
+}
diff --git a/src/client/MonsterBook.java b/src/client/MonsterBook.java
index 1d2c6e41e3..235362d78f 100644
--- a/src/client/MonsterBook.java
+++ b/src/client/MonsterBook.java
@@ -29,6 +29,7 @@ import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.Semaphore;
@@ -46,10 +47,10 @@ public final class MonsterBook {
private Map cards = new LinkedHashMap<>();
private Lock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.BOOK);
- private Set> getCardSet() {
+ public Set> getCardSet() {
lock.lock();
try {
- return Collections.unmodifiableSet(cards.entrySet());
+ return new HashSet<>(cards.entrySet());
} finally {
lock.unlock();
}
@@ -82,7 +83,9 @@ public final class MonsterBook {
}
if(qty < 5) {
- calculateLevel(); // current leveling system only accounts unique cards...
+ if (qty == 0) { // leveling system only accounts unique cards
+ calculateLevel();
+ }
c.announce(MaplePacketCreator.addCard(false, cardid, qty + 1));
c.announce(MaplePacketCreator.showGainCard());
@@ -94,7 +97,15 @@ public final class MonsterBook {
private void calculateLevel() {
lock.lock();
try {
- bookLevel = (int) Math.max(1, Math.sqrt((normalCard + specialCard) / 5));
+ int collectionExp = (normalCard + specialCard);
+
+ int level = 0, expToNextlevel = 1;
+ do {
+ level++;
+ expToNextlevel += level * 10;
+ } while (collectionExp >= expToNextlevel);
+
+ bookLevel = level; // thanks IxianMace for noticing book level differing between book UI and character info UI
} finally {
lock.unlock();
}
@@ -232,4 +243,29 @@ public final class MonsterBook {
e.printStackTrace();
}
}
+
+ public static int[] getCardTierSize() {
+ try {
+ Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("SELECT COUNT(*) FROM monstercarddata GROUP BY floor(cardid / 1000);");
+ ResultSet rs = ps.executeQuery();
+
+ rs.last();
+ int[] tierSizes = new int[rs.getRow()];
+ rs.beforeFirst();
+
+ while (rs.next()) {
+ tierSizes[rs.getRow() - 1] = rs.getInt(1);
+ }
+
+ rs.close();
+ ps.close();
+ con.close();
+
+ return tierSizes;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ return new int[0];
+ }
+ }
}
diff --git a/src/client/SkillFactory.java b/src/client/SkillFactory.java
index 8e0e5398c4..7b542c0e2d 100644
--- a/src/client/SkillFactory.java
+++ b/src/client/SkillFactory.java
@@ -68,7 +68,7 @@ import constants.skills.Shadower;
import constants.skills.Sniper;
import constants.skills.Spearman;
import constants.skills.SuperGM;
-import constants.skills.Swordsman;
+import constants.skills.Warrior;
import constants.skills.ThunderBreaker;
import constants.skills.WhiteKnight;
import constants.skills.WindArcher;
@@ -180,6 +180,7 @@ public class SkillFactory {
case NightWalker.POISON_BOMB:
case NightWalker.VAMPIRE:
case ChiefBandit.CHAKRA:
+ case Aran.COMBAT_STEP:
case Evan.RECOVERY_AURA:
isBuff = false;
break;
@@ -188,7 +189,7 @@ public class SkillFactory {
case Beginner.MONSTER_RIDER:
case Beginner.ECHO_OF_HERO:
case Beginner.MAP_CHAIR:
- case Swordsman.IRON_BODY:
+ case Warrior.IRON_BODY:
case Fighter.AXE_BOOSTER:
case Fighter.POWER_GUARD:
case Fighter.RAGE:
diff --git a/src/client/SkillMacro.java b/src/client/SkillMacro.java
index 7f4e38c319..b129c5feee 100644
--- a/src/client/SkillMacro.java
+++ b/src/client/SkillMacro.java
@@ -49,6 +49,18 @@ public class SkillMacro {
public int getSkill3() {
return skill3;
}
+
+ public void setSkill1(int skill) {
+ skill1 = skill;
+ }
+
+ public void setSkill2(int skill) {
+ skill2 = skill;
+ }
+
+ public void setSkill3(int skill) {
+ skill3 = skill;
+ }
public String getName() {
return name;
diff --git a/src/client/autoban/AutobanFactory.java b/src/client/autoban/AutobanFactory.java
index 04f0f672c5..dbca257ea4 100644
--- a/src/client/autoban/AutobanFactory.java
+++ b/src/client/autoban/AutobanFactory.java
@@ -23,7 +23,7 @@ along with this program. If not, see .
package client.autoban;
import client.MapleCharacter;
-import constants.ServerConstants;
+import config.YamlConfig;
import net.server.Server;
import tools.FilePrinter;
import tools.MapleLogger;
@@ -84,19 +84,19 @@ public enum AutobanFactory {
}
public void alert(MapleCharacter chr, String reason) {
- if(ServerConstants.USE_AUTOBAN == true) {
+ if(YamlConfig.config.server.USE_AUTOBAN == true) {
if (chr != null && MapleLogger.ignored.contains(chr.getId())){
return;
}
Server.getInstance().broadcastGMMessage((chr != null ? chr.getWorld() : 0), MaplePacketCreator.sendYellowTip((chr != null ? MapleCharacter.makeMapleReadable(chr.getName()) : "") + " caused " + this.name() + " " + reason));
}
- if (ServerConstants.USE_AUTOBAN_LOG) {
+ if (YamlConfig.config.server.USE_AUTOBAN_LOG) {
FilePrinter.print(FilePrinter.AUTOBAN_WARNING, (chr != null ? MapleCharacter.makeMapleReadable(chr.getName()) : "") + " caused " + this.name() + " " + reason);
}
}
public void autoban(MapleCharacter chr, String value) {
- if(ServerConstants.USE_AUTOBAN == true) {
+ if(YamlConfig.config.server.USE_AUTOBAN == true) {
chr.autoban("Autobanned for (" + this.name() + ": " + value + ")");
//chr.sendPolice("You will be disconnected for (" + this.name() + ": " + value + ")");
}
diff --git a/src/client/autoban/AutobanManager.java b/src/client/autoban/AutobanManager.java
index 14d8f25370..1e46a0d6d7 100644
--- a/src/client/autoban/AutobanManager.java
+++ b/src/client/autoban/AutobanManager.java
@@ -6,7 +6,7 @@
package client.autoban;
import client.MapleCharacter;
-import constants.ServerConstants;
+import config.YamlConfig;
import java.util.HashMap;
import java.util.Map;
import net.server.Server;
@@ -33,10 +33,11 @@ public class AutobanManager {
}
public void addPoint(AutobanFactory fac, String reason) {
- if (chr.isGM() || chr.isBanned()){
- return;
- }
- if (ServerConstants.USE_AUTOBAN) {
+ if (YamlConfig.config.server.USE_AUTOBAN) {
+ if (chr.isGM() || chr.isBanned()){
+ return;
+ }
+
if (lastTime.containsKey(fac)) {
if (lastTime.get(fac) < (Server.getInstance().getCurrentTime() - fac.getExpire())) {
points.put(fac, points.get(fac) / 2); //So the points are not completely gone.
@@ -56,7 +57,7 @@ public class AutobanManager {
//chr.sendPolice("You have been blocked by #bMooplePolice for the HACK reason#k.");
}
}
- if (ServerConstants.USE_AUTOBAN_LOG) {
+ if (YamlConfig.config.server.USE_AUTOBAN_LOG) {
// Lets log every single point too.
FilePrinter.print(FilePrinter.AUTOBAN_WARNING, MapleCharacter.makeMapleReadable(chr.getName()) + " caused " + fac.name() + " " + reason);
}
@@ -113,7 +114,7 @@ public class AutobanManager {
if (this.timestamp[type] == time) {
this.timestampcounter[type]++;
if (this.timestampcounter[type] >= times) {
- if (ServerConstants.USE_AUTOBAN) {
+ if (YamlConfig.config.server.USE_AUTOBAN) {
chr.getClient().disconnect(false, false);
}
diff --git a/src/client/command/Command.java b/src/client/command/Command.java
index 7cd309e6af..fac0158ce1 100644
--- a/src/client/command/Command.java
+++ b/src/client/command/Command.java
@@ -27,6 +27,7 @@ import client.MapleClient;
public abstract class Command {
+ protected int rank;
protected String description;
public abstract void execute(MapleClient client, String[] params);
@@ -38,6 +39,14 @@ public abstract class Command {
protected void setDescription(String description) {
this.description = description;
}
+
+ public int getRank() {
+ return rank;
+ }
+
+ public void setRank(int rank) {
+ this.rank = rank;
+ }
protected String joinStringFrom(String arr[], int start) {
StringBuilder builder = new StringBuilder();
diff --git a/src/client/command/CommandsExecutor.java b/src/client/command/CommandsExecutor.java
index cc889cbfa1..e30c90adc2 100644
--- a/src/client/command/CommandsExecutor.java
+++ b/src/client/command/CommandsExecutor.java
@@ -62,7 +62,7 @@ public class CommandsExecutor {
return heading == USER_HEADING;
}
- private HashMap registeredCommands = new HashMap<>();
+ private HashMap registeredCommands = new HashMap<>();
private Pair
, List> levelCommandsCursor;
private List, List>> commandsNameDesc = new ArrayList<>();
@@ -94,7 +94,7 @@ public class CommandsExecutor {
private void handleInternal(MapleClient client, String message){
if (client.getPlayer().getMapId() == 300000012) {
- client.getPlayer().yellowMessage("You not have permission to use this command while in jail.");
+ client.getPlayer().yellowMessage("You do not have permission to use commands while in jail.");
return;
}
final String splitRegex = "[ ]";
@@ -107,13 +107,13 @@ public class CommandsExecutor {
final String commandName = splitedMessage[0].toLowerCase();
final String[] lowercaseParams = splitedMessage[1].toLowerCase().split(splitRegex);
- final RegisteredCommand command = registeredCommands.get(commandName);
+ final Command command = registeredCommands.get(commandName);
if (command == null){
client.getPlayer().yellowMessage("Command '" + commandName + "' is not available. See @commands for a list of available commands.");
return;
}
if (client.getPlayer().gmLevel() < command.getRank()){
- client.getPlayer().yellowMessage("You not have permission to use this command.");
+ client.getPlayer().yellowMessage("You do not have permission to use this command.");
return;
}
String[] params;
@@ -122,16 +122,9 @@ public class CommandsExecutor {
} else {
params = new String[]{};
}
- try {
- Command commandInstance = command.getCommandClass().newInstance();
- commandInstance.execute(client, params);
- writeLog(client, message);
- } catch (InstantiationException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- }
-
+
+ command.execute(client, params);
+ writeLog(client, message);
}
private void writeLog(MapleClient client, String command){
@@ -172,11 +165,19 @@ public class CommandsExecutor {
return;
}
- RegisteredCommand registeredCommand = new RegisteredCommand(commandClass, rank);
-
String commandName = syntax.toLowerCase();
addCommandInfo(commandName, commandClass);
- registeredCommands.put(commandName, registeredCommand);
+
+ try {
+ Command commandInstance = commandClass.newInstance(); // thanks Halcyon for noticing commands getting reinstanced every call
+ commandInstance.setRank(rank);
+
+ registeredCommands.put(commandName, commandInstance);
+ } catch (InstantiationException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
}
private void registerLv0Commands(){
@@ -253,6 +254,7 @@ public class CommandsExecutor {
addCommand("drop", 2, ItemDropCommand.class);
addCommand("level", 2, LevelCommand.class);
addCommand("levelpro", 2, LevelProCommand.class);
+ addCommand("setslot", 2, SetSlotCommand.class);
addCommand("setstat", 2, SetStatCommand.class);
addCommand("maxstat", 2, MaxStatCommand.class);
addCommand("maxskill", 2, MaxSkillCommand.class);
@@ -264,6 +266,7 @@ public class CommandsExecutor {
addCommand("unbug", 2, UnBugCommand.class);
addCommand("id", 2, IdCommand.class);
addCommand("gachalist", GachaListCommand.class);
+ addCommand("loot", LootCommand.class);
commandsNameDesc.add(levelCommandsCursor);
}
diff --git a/src/client/command/commands/gm0/BuyBackCommand.java b/src/client/command/commands/gm0/BuyBackCommand.java
index 67b0cd835f..3a8364d408 100644
--- a/src/client/command/commands/gm0/BuyBackCommand.java
+++ b/src/client/command/commands/gm0/BuyBackCommand.java
@@ -25,7 +25,7 @@ package client.command.commands.gm0;
import client.MapleClient;
import client.command.Command;
-import client.processor.BuybackProcessor;
+import client.processor.action.BuybackProcessor;
public class BuyBackCommand extends Command {
{
diff --git a/src/client/command/commands/gm0/DisposeCommand.java b/src/client/command/commands/gm0/DisposeCommand.java
index 01e2b7de68..16d08eddb2 100644
--- a/src/client/command/commands/gm0/DisposeCommand.java
+++ b/src/client/command/commands/gm0/DisposeCommand.java
@@ -26,6 +26,7 @@ package client.command.commands.gm0;
import client.command.Command;
import client.MapleClient;
import scripting.npc.NPCScriptManager;
+import scripting.quest.QuestScriptManager;
import tools.MaplePacketCreator;
public class DisposeCommand extends Command {
@@ -36,6 +37,7 @@ public class DisposeCommand extends Command {
@Override
public void execute(MapleClient c, String[] params) {
NPCScriptManager.getInstance().dispose(c);
+ QuestScriptManager.getInstance().dispose(c);
c.announce(MaplePacketCreator.enableActions());
c.removeClickedNPC();
c.getPlayer().message("You've been disposed.");
diff --git a/src/client/command/commands/gm0/DropLimitCommand.java b/src/client/command/commands/gm0/DropLimitCommand.java
index 1e579b93cc..efb5097a07 100644
--- a/src/client/command/commands/gm0/DropLimitCommand.java
+++ b/src/client/command/commands/gm0/DropLimitCommand.java
@@ -25,7 +25,7 @@ package client.command.commands.gm0;
import client.MapleClient;
import client.command.Command;
-import constants.ServerConstants;
+import config.YamlConfig;
public class DropLimitCommand extends Command {
{
@@ -35,10 +35,10 @@ public class DropLimitCommand extends Command {
@Override
public void execute(MapleClient c, String[] params) {
int dropCount = c.getPlayer().getMap().getDroppedItemCount();
- if(((float) dropCount) / ServerConstants.ITEM_LIMIT_ON_MAP < 0.75f) {
- c.getPlayer().showHint("Current drop count: #b" + dropCount + "#k / #e" + ServerConstants.ITEM_LIMIT_ON_MAP + "#n", 300);
+ if(((float) dropCount) / YamlConfig.config.server.ITEM_LIMIT_ON_MAP < 0.75f) {
+ c.getPlayer().showHint("Current drop count: #b" + dropCount + "#k / #e" + YamlConfig.config.server.ITEM_LIMIT_ON_MAP + "#n", 300);
} else {
- c.getPlayer().showHint("Current drop count: #r" + dropCount + "#k / #e" + ServerConstants.ITEM_LIMIT_ON_MAP + "#n", 300);
+ c.getPlayer().showHint("Current drop count: #r" + dropCount + "#k / #e" + YamlConfig.config.server.ITEM_LIMIT_ON_MAP + "#n", 300);
}
}
diff --git a/src/client/command/commands/gm0/EnableAuthCommand.java b/src/client/command/commands/gm0/EnableAuthCommand.java
index f8ed615b88..67659906c5 100644
--- a/src/client/command/commands/gm0/EnableAuthCommand.java
+++ b/src/client/command/commands/gm0/EnableAuthCommand.java
@@ -25,7 +25,7 @@ package client.command.commands.gm0;
import client.command.Command;
import client.MapleClient;
-import net.server.coordinator.MapleLoginBypassCoordinator;
+import net.server.coordinator.login.MapleLoginBypassCoordinator;
public class EnableAuthCommand extends Command {
{
diff --git a/src/client/command/commands/gm0/MapOwnerClaimCommand.java b/src/client/command/commands/gm0/MapOwnerClaimCommand.java
index 5818b1c5ff..5377217768 100644
--- a/src/client/command/commands/gm0/MapOwnerClaimCommand.java
+++ b/src/client/command/commands/gm0/MapOwnerClaimCommand.java
@@ -26,7 +26,8 @@ package client.command.commands.gm0;
import client.command.Command;
import client.MapleCharacter;
import client.MapleClient;
-import constants.ServerConstants;
+import config.YamlConfig;
+import server.maps.MapleMap;
public class MapOwnerClaimCommand extends Command {
{
@@ -39,14 +40,27 @@ public class MapOwnerClaimCommand extends Command {
try {
MapleCharacter chr = c.getPlayer();
- if (ServerConstants.USE_MAP_OWNERSHIP_SYSTEM) {
+ if (YamlConfig.config.server.USE_MAP_OWNERSHIP_SYSTEM) {
if (chr.getEventInstance() == null) {
- if (chr.getMap().unclaimOwnership(chr)) {
- chr.dropMessage(5, "This lawn is now free real estate.");
- } else if (chr.getMap().claimOwnership(chr)) {
- chr.dropMessage(5, "You have leased this lawn for a while, until you leave here or after 1 minute of inactivity.");
+ MapleMap map = chr.getMap();
+ if (map.countBosses() == 0) { // thanks Conrad for suggesting bosses prevent map leasing
+ MapleMap ownedMap = chr.getOwnedMap(); // thanks Conrad for suggesting not unlease a map as soon as player exits it
+ if (ownedMap != null) {
+ ownedMap.unclaimOwnership(chr);
+
+ if (map == ownedMap) {
+ chr.dropMessage(5, "This lawn is now free real estate.");
+ return;
+ }
+ }
+
+ if (map.claimOwnership(chr)) {
+ chr.dropMessage(5, "You have leased this lawn for a while, until you leave here or after 1 minute of inactivity.");
+ } else {
+ chr.dropMessage(5, "This lawn has already been leased by a player.");
+ }
} else {
- chr.dropMessage(5, "This lawn has already been leased by another player.");
+ chr.dropMessage(5, "This lawn is currently under a boss siege.");
}
} else {
chr.dropMessage(5, "This lawn cannot be leased.");
diff --git a/src/client/command/commands/gm0/RatesCommand.java b/src/client/command/commands/gm0/RatesCommand.java
index 8498efaa23..b297c99969 100644
--- a/src/client/command/commands/gm0/RatesCommand.java
+++ b/src/client/command/commands/gm0/RatesCommand.java
@@ -26,7 +26,7 @@ package client.command.commands.gm0;
import client.MapleCharacter;
import client.command.Command;
import client.MapleClient;
-import constants.ServerConstants;
+import config.YamlConfig;
public class RatesCommand extends Command {
{
@@ -43,7 +43,7 @@ public class RatesCommand extends Command {
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_ += "BOSS DROP Rate: #e#b" + player.getBossDropRate() + "x#k#n" + "\r\n";
- if(ServerConstants.USE_QUEST_RATE) showMsg_ += "QUEST Rate: #e#b" + c.getWorldServer().getQuestRate() + "x#k#n" + "\r\n";
+ if(YamlConfig.config.server.USE_QUEST_RATE) showMsg_ += "QUEST Rate: #e#b" + c.getWorldServer().getQuestRate() + "x#k#n" + "\r\n";
player.showHint(showMsg_, 300);
}
diff --git a/src/client/command/commands/gm0/ShowRatesCommand.java b/src/client/command/commands/gm0/ShowRatesCommand.java
index 9b7b95dfa1..7e4ce9eb54 100644
--- a/src/client/command/commands/gm0/ShowRatesCommand.java
+++ b/src/client/command/commands/gm0/ShowRatesCommand.java
@@ -26,7 +26,7 @@ package client.command.commands.gm0;
import client.MapleCharacter;
import client.command.Command;
import client.MapleClient;
-import constants.ServerConstants;
+import config.YamlConfig;
public class ShowRatesCommand extends Command {
{
@@ -60,7 +60,7 @@ public class ShowRatesCommand extends Command {
if(player.getCouponDropRate() != 1) showMsg += "Coupon DROP Rate: #k" + player.getCouponDropRate() + "x#k" + "\r\n";
showMsg += "BOSS DROP Rate: #e#b" + player.getBossDropRate() + "x#k#n" + "\r\n";
- if(ServerConstants.USE_QUEST_RATE) {
+ if(YamlConfig.config.server.USE_QUEST_RATE) {
showMsg += "\r\n" + "#eQUEST RATE#n" + "\r\n";
showMsg += "World QUEST Rate: #e#b" + c.getWorldServer().getQuestRate() + "x#k#n" + "\r\n";
}
diff --git a/src/client/command/commands/gm0/StatDexCommand.java b/src/client/command/commands/gm0/StatDexCommand.java
index 065d89fd92..ce3e1728ba 100644
--- a/src/client/command/commands/gm0/StatDexCommand.java
+++ b/src/client/command/commands/gm0/StatDexCommand.java
@@ -26,7 +26,7 @@ package client.command.commands.gm0;
import client.MapleCharacter;
import client.MapleClient;
import client.command.Command;
-import constants.ServerConstants;
+import config.YamlConfig;
public class StatDexCommand extends Command {
{
@@ -47,10 +47,10 @@ public class StatDexCommand extends Command {
return;
}
} else {
- amount = Math.min(remainingAp, ServerConstants.MAX_AP - player.getDex());
+ amount = Math.min(remainingAp, YamlConfig.config.server.MAX_AP - player.getDex());
}
if (!player.assignDex(Math.max(amount, 0))) {
- player.dropMessage("Please make sure your AP is not over " + ServerConstants.MAX_AP + " and you have enough to distribute.");
+ player.dropMessage("Please make sure your AP is not over " + YamlConfig.config.server.MAX_AP + " and you have enough to distribute.");
}
}
}
diff --git a/src/client/command/commands/gm0/StatIntCommand.java b/src/client/command/commands/gm0/StatIntCommand.java
index 6a39f4030c..1a69382e96 100644
--- a/src/client/command/commands/gm0/StatIntCommand.java
+++ b/src/client/command/commands/gm0/StatIntCommand.java
@@ -26,7 +26,7 @@ package client.command.commands.gm0;
import client.command.Command;
import client.MapleClient;
import client.MapleCharacter;
-import constants.ServerConstants;
+import config.YamlConfig;
public class StatIntCommand extends Command {
{
@@ -47,10 +47,10 @@ public class StatIntCommand extends Command {
return;
}
} else {
- amount = Math.min(remainingAp, ServerConstants.MAX_AP - player.getInt());
+ amount = Math.min(remainingAp, YamlConfig.config.server.MAX_AP - player.getInt());
}
if (!player.assignInt(Math.max(amount, 0))) {
- player.dropMessage("Please make sure your AP is not over " + ServerConstants.MAX_AP + " and you have enough to distribute.");
+ player.dropMessage("Please make sure your AP is not over " + YamlConfig.config.server.MAX_AP + " and you have enough to distribute.");
}
}
}
diff --git a/src/client/command/commands/gm0/StatLukCommand.java b/src/client/command/commands/gm0/StatLukCommand.java
index c5567febb8..8582c78587 100644
--- a/src/client/command/commands/gm0/StatLukCommand.java
+++ b/src/client/command/commands/gm0/StatLukCommand.java
@@ -26,7 +26,7 @@ package client.command.commands.gm0;
import client.MapleCharacter;
import client.MapleClient;
import client.command.Command;
-import constants.ServerConstants;
+import config.YamlConfig;
public class StatLukCommand extends Command {
{
@@ -47,10 +47,10 @@ public class StatLukCommand extends Command {
return;
}
} else {
- amount = Math.min(remainingAp, ServerConstants.MAX_AP - player.getLuk());
+ amount = Math.min(remainingAp, YamlConfig.config.server.MAX_AP - player.getLuk());
}
if (!player.assignLuk(Math.max(amount, 0))) {
- player.dropMessage("Please make sure your AP is not over " + ServerConstants.MAX_AP + " and you have enough to distribute.");
+ player.dropMessage("Please make sure your AP is not over " + YamlConfig.config.server.MAX_AP + " and you have enough to distribute.");
}
}
}
diff --git a/src/client/command/commands/gm0/StatStrCommand.java b/src/client/command/commands/gm0/StatStrCommand.java
index 1b7a782ba5..ad88a84a98 100644
--- a/src/client/command/commands/gm0/StatStrCommand.java
+++ b/src/client/command/commands/gm0/StatStrCommand.java
@@ -26,7 +26,7 @@ package client.command.commands.gm0;
import client.command.Command;
import client.MapleClient;
import client.MapleCharacter;
-import constants.ServerConstants;
+import config.YamlConfig;
public class StatStrCommand extends Command {
{
@@ -46,11 +46,11 @@ public class StatStrCommand extends Command {
return;
}
} else {
- amount = Math.min(remainingAp, ServerConstants.MAX_AP - player.getStr());
+ amount = Math.min(remainingAp, YamlConfig.config.server.MAX_AP - player.getStr());
}
if (!player.assignStr(Math.max(amount, 0))) {
- player.dropMessage("Please make sure your AP is not over " + ServerConstants.MAX_AP + " and you have enough to distribute.");
+ player.dropMessage("Please make sure your AP is not over " + YamlConfig.config.server.MAX_AP + " and you have enough to distribute.");
}
}
}
diff --git a/src/client/command/commands/gm0/TimeCommand.java b/src/client/command/commands/gm0/TimeCommand.java
index 9a9351c392..d91a3b8a01 100644
--- a/src/client/command/commands/gm0/TimeCommand.java
+++ b/src/client/command/commands/gm0/TimeCommand.java
@@ -25,7 +25,7 @@ package client.command.commands.gm0;
import client.MapleClient;
import client.command.Command;
-import constants.ServerConstants;
+import constants.net.ServerConstants;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
diff --git a/src/client/command/commands/gm1/GotoCommand.java b/src/client/command/commands/gm1/GotoCommand.java
index 95f2b66aa1..986bc279bf 100644
--- a/src/client/command/commands/gm1/GotoCommand.java
+++ b/src/client/command/commands/gm1/GotoCommand.java
@@ -26,14 +26,13 @@ package client.command.commands.gm1;
import client.MapleCharacter;
import client.command.Command;
import client.MapleClient;
-import constants.GameConstants;
+import constants.game.GameConstants;
import java.util.ArrayList;
import java.util.Collections;
-import net.server.Server;
-import server.MaplePortal;
+import server.maps.MaplePortal;
import server.maps.FieldLimit;
import server.maps.MapleMap;
-import server.maps.MapleMapManager;
+import server.maps.MapleMapFactory;
import server.maps.MapleMiniDungeonInfo;
import java.util.Comparator;
@@ -47,19 +46,28 @@ public class GotoCommand extends Command {
{
setDescription("");
- MapleMapManager mapManager = Server.getInstance().getWorlds().get(0).getChannels().get(0).getMapFactory();
-
List> towns = new ArrayList<>(GameConstants.GOTO_TOWNS.entrySet());
sortGotoEntries(towns);
- for (Map.Entry e : towns) {
- GOTO_TOWNS_INFO += ("'" + e.getKey() + "' - #b" + (mapManager.getMap(e.getValue()).getMapName()) + "#k\r\n");
+
+ try {
+ // thanks shavit for noticing goto areas getting loaded from wz needlessly, only for the name retrieval
+
+ for (Map.Entry e : towns) {
+ GOTO_TOWNS_INFO += ("'" + e.getKey() + "' - #b" + (MapleMapFactory.loadPlaceName(e.getValue())) + "#k\r\n");
+ }
+
+ List> areas = new ArrayList<>(GameConstants.GOTO_AREAS.entrySet());
+ sortGotoEntries(areas);
+ for (Map.Entry e : areas) {
+ GOTO_AREAS_INFO += ("'" + e.getKey() + "' - #b" + (MapleMapFactory.loadPlaceName(e.getValue())) + "#k\r\n");
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+
+ GOTO_TOWNS_INFO = "(none)";
+ GOTO_AREAS_INFO = "(none)";
}
- List> areas = new ArrayList<>(GameConstants.GOTO_AREAS.entrySet());
- sortGotoEntries(areas);
- for (Map.Entry e : areas) {
- GOTO_AREAS_INFO += ("'" + e.getKey() + "' - #b" + (mapManager.getMap(e.getValue()).getMapName()) + "#k\r\n");
- }
}
public static String GOTO_TOWNS_INFO = "";
@@ -105,7 +113,7 @@ public class GotoCommand extends Command {
gotomaps = new HashMap<>(GameConstants.GOTO_AREAS); // distinct map registry for GM/users suggested thanks to Vcoc
gotomaps.putAll(GameConstants.GOTO_TOWNS); // thanks Halcyon (UltimateMors) for pointing out duplicates on listed entries functionality
} else {
- gotomaps = new HashMap<>(GameConstants.GOTO_TOWNS);
+ gotomaps = GameConstants.GOTO_TOWNS;
}
if (gotomaps.containsKey(params[0])) {
diff --git a/src/client/command/commands/gm2/ApCommand.java b/src/client/command/commands/gm2/ApCommand.java
index d408e3cec6..baa72b0ad7 100644
--- a/src/client/command/commands/gm2/ApCommand.java
+++ b/src/client/command/commands/gm2/ApCommand.java
@@ -26,7 +26,7 @@ package client.command.commands.gm2;
import client.command.Command;
import client.MapleClient;
import client.MapleCharacter;
-import constants.ServerConstants;
+import config.YamlConfig;
public class ApCommand extends Command {
{
@@ -44,7 +44,7 @@ public class ApCommand extends Command {
if (params.length < 2) {
int newAp = Integer.parseInt(params[0]);
if (newAp < 0) newAp = 0;
- else if (newAp > ServerConstants.MAX_AP) newAp = ServerConstants.MAX_AP;
+ else if (newAp > YamlConfig.config.server.MAX_AP) newAp = YamlConfig.config.server.MAX_AP;
player.changeRemainingAp(newAp, false);
} else {
@@ -52,7 +52,7 @@ public class ApCommand extends Command {
if (victim != null) {
int newAp = Integer.parseInt(params[1]);
if (newAp < 0) newAp = 0;
- else if (newAp > ServerConstants.MAX_AP) newAp = ServerConstants.MAX_AP;
+ else if (newAp > YamlConfig.config.server.MAX_AP) newAp = YamlConfig.config.server.MAX_AP;
victim.changeRemainingAp(newAp, false);
} else {
diff --git a/src/client/command/commands/gm2/IdCommand.java b/src/client/command/commands/gm2/IdCommand.java
index 304f19c62a..d1153fc8ce 100644
--- a/src/client/command/commands/gm2/IdCommand.java
+++ b/src/client/command/commands/gm2/IdCommand.java
@@ -55,7 +55,7 @@ public class IdCommand extends Command {
}
sb.append(String.format("Results found: #r%d#k | Returned: #b%d#k/100 | Refine search query to improve time.", resultList.size(), count) + "\r\n");
- player.getClient().getAbstractPlayerInteraction().npcTalk(9010000, sb.toString());
+ player.getAbstractPlayerInteraction().npcTalk(9010000, sb.toString());
} else {
player.yellowMessage(String.format("Id not found for item: %s, of type: %s.", queryItem, params[0]));
}
diff --git a/src/client/command/commands/gm2/ItemCommand.java b/src/client/command/commands/gm2/ItemCommand.java
index e0e38a7b2e..e1ed732924 100644
--- a/src/client/command/commands/gm2/ItemCommand.java
+++ b/src/client/command/commands/gm2/ItemCommand.java
@@ -28,8 +28,8 @@ import client.MapleClient;
import client.MapleCharacter;
import client.inventory.MaplePet;
import client.inventory.manipulator.MapleInventoryManipulator;
-import constants.ItemConstants;
-import constants.ServerConstants;
+import config.YamlConfig;
+import constants.inventory.ItemConstants;
import server.MapleItemInformationProvider;
public class ItemCommand extends Command {
@@ -57,7 +57,7 @@ public class ItemCommand extends Command {
short quantity = 1;
if(params.length >= 2) quantity = Short.parseShort(params[1]);
- if (ServerConstants.BLOCK_GENERATE_CASH_ITEM && ii.isCash(itemId)) {
+ if (YamlConfig.config.server.BLOCK_GENERATE_CASH_ITEM && ii.isCash(itemId)) {
player.yellowMessage("You cannot create a cash item with this command.");
return;
}
@@ -77,12 +77,12 @@ public class ItemCommand extends Command {
}
}
- byte flag = 0;
+ short flag = 0;
if(player.gmLevel() < 3) {
flag |= ItemConstants.ACCOUNT_SHARING;
flag |= ItemConstants.UNTRADEABLE;
}
-
+
MapleInventoryManipulator.addById(c, itemId, quantity, player.getName(), -1, flag, -1);
}
}
diff --git a/src/client/command/commands/gm2/ItemDropCommand.java b/src/client/command/commands/gm2/ItemDropCommand.java
index 4a35be2207..d7b8bbb3c6 100644
--- a/src/client/command/commands/gm2/ItemDropCommand.java
+++ b/src/client/command/commands/gm2/ItemDropCommand.java
@@ -29,8 +29,8 @@ import client.MapleCharacter;
import client.inventory.Item;
import client.inventory.MapleInventoryType;
import client.inventory.MaplePet;
-import constants.ItemConstants;
-import constants.ServerConstants;
+import config.YamlConfig;
+import constants.inventory.ItemConstants;
import server.MapleItemInformationProvider;
public class ItemDropCommand extends Command {
@@ -58,7 +58,7 @@ public class ItemDropCommand extends Command {
short quantity = 1;
if(params.length >= 2) quantity = Short.parseShort(params[1]);
- if (ServerConstants.BLOCK_GENERATE_CASH_ITEM && ii.isCash(itemId)) {
+ if (YamlConfig.config.server.BLOCK_GENERATE_CASH_ITEM && ii.isCash(itemId)) {
player.yellowMessage("You cannot create a cash item with this command.");
return;
}
@@ -75,12 +75,12 @@ public class ItemDropCommand extends Command {
toDrop.setOwner("");
if(player.gmLevel() < 3) {
- byte b = toDrop.getFlag();
- b |= ItemConstants.ACCOUNT_SHARING;
- b |= ItemConstants.UNTRADEABLE;
- b |= ItemConstants.SANDBOX;
+ short f = toDrop.getFlag();
+ f |= ItemConstants.ACCOUNT_SHARING;
+ f |= ItemConstants.UNTRADEABLE;
+ f |= ItemConstants.SANDBOX;
- toDrop.setFlag(b);
+ toDrop.setFlag(f);
toDrop.setOwner("TRIAL-MODE");
}
@@ -102,12 +102,12 @@ public class ItemDropCommand extends Command {
toDrop.setOwner(player.getName());
if(player.gmLevel() < 3) {
- byte b = toDrop.getFlag();
- b |= ItemConstants.ACCOUNT_SHARING;
- b |= ItemConstants.UNTRADEABLE;
- b |= ItemConstants.SANDBOX;
+ short f = toDrop.getFlag();
+ f |= ItemConstants.ACCOUNT_SHARING;
+ f |= ItemConstants.UNTRADEABLE;
+ f |= ItemConstants.SANDBOX;
- toDrop.setFlag(b);
+ toDrop.setFlag(f);
toDrop.setOwner("TRIAL-MODE");
}
diff --git a/src/client/command/commands/gm2/JailCommand.java b/src/client/command/commands/gm2/JailCommand.java
index 122dc79c43..a159cfb599 100644
--- a/src/client/command/commands/gm2/JailCommand.java
+++ b/src/client/command/commands/gm2/JailCommand.java
@@ -26,7 +26,7 @@ package client.command.commands.gm2;
import client.command.Command;
import client.MapleClient;
import client.MapleCharacter;
-import server.MaplePortal;
+import server.maps.MaplePortal;
import server.maps.MapleMap;
public class JailCommand extends Command {
diff --git a/src/client/command/commands/gm2/LevelCommand.java b/src/client/command/commands/gm2/LevelCommand.java
index 5d1037652b..e532131880 100644
--- a/src/client/command/commands/gm2/LevelCommand.java
+++ b/src/client/command/commands/gm2/LevelCommand.java
@@ -26,7 +26,7 @@ package client.command.commands.gm2;
import client.command.Command;
import client.MapleClient;
import client.MapleCharacter;
-import constants.ServerConstants;
+import config.YamlConfig;
public class LevelCommand extends Command {
{
@@ -45,7 +45,7 @@ public class LevelCommand extends Command {
player.setLevel(Math.min(Integer.parseInt(params[0]), player.getMaxClassLevel()) - 1);
player.resetPlayerRates();
- if (ServerConstants.USE_ADD_RATES_BY_LEVEL) player.setPlayerRates();
+ if (YamlConfig.config.server.USE_ADD_RATES_BY_LEVEL) player.setPlayerRates();
player.setWorldRates();
player.levelUp(false);
diff --git a/src/client/command/commands/gm2/LootCommand.java b/src/client/command/commands/gm2/LootCommand.java
new file mode 100644
index 0000000000..fb43fac434
--- /dev/null
+++ b/src/client/command/commands/gm2/LootCommand.java
@@ -0,0 +1,51 @@
+/*
+ This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
+ Copyleft (L) 2016 - 2018 RonanLana
+
+ 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 .
+ */
+
+/*
+ @Author: Resinate
+*/
+package client.command.commands.gm2;
+
+import client.MapleClient;
+import client.command.Command;
+import java.util.Arrays;
+import java.util.List;
+import server.maps.MapleMapItem;
+import server.maps.MapleMapObject;
+import server.maps.MapleMapObjectType;
+
+public class LootCommand extends Command {
+
+ {
+ setDescription("Loots all items that belong to you.");
+ }
+
+ @Override
+ public void execute(MapleClient c, String[] params) {
+ List items = c.getPlayer().getMap().getMapObjectsInRange(c.getPlayer().getPosition(), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.ITEM));
+ for (MapleMapObject item : items) {
+ MapleMapItem mapItem = (MapleMapItem) item;
+ if (mapItem.getOwnerId() == c.getPlayer().getId() || mapItem.getOwnerId() == c.getPlayer().getPartyId()) {
+ c.getPlayer().pickupItem(mapItem);
+ }
+ }
+
+ }
+}
diff --git a/src/client/command/commands/gm2/MaxStatCommand.java b/src/client/command/commands/gm2/MaxStatCommand.java
index e7586c8f66..2b3dc1a492 100644
--- a/src/client/command/commands/gm2/MaxStatCommand.java
+++ b/src/client/command/commands/gm2/MaxStatCommand.java
@@ -27,7 +27,7 @@ import client.MapleStat;
import client.command.Command;
import client.MapleClient;
import client.MapleCharacter;
-import constants.ServerConstants;
+import config.YamlConfig;
public class MaxStatCommand extends Command {
{
@@ -40,7 +40,7 @@ public class MaxStatCommand extends Command {
player.loseExp(player.getExp(), false, false);
player.setLevel(255);
player.resetPlayerRates();
- if (ServerConstants.USE_ADD_RATES_BY_LEVEL) player.setPlayerRates();
+ if (YamlConfig.config.server.USE_ADD_RATES_BY_LEVEL) player.setPlayerRates();
player.setWorldRates();
player.updateStrDexIntLuk(Short.MAX_VALUE);
player.setFame(13337);
diff --git a/src/client/command/commands/gm2/RechargeCommand.java b/src/client/command/commands/gm2/RechargeCommand.java
index 56bb6c3b0d..d5a99a4ffd 100644
--- a/src/client/command/commands/gm2/RechargeCommand.java
+++ b/src/client/command/commands/gm2/RechargeCommand.java
@@ -28,7 +28,7 @@ import client.command.Command;
import client.MapleClient;
import client.inventory.Item;
import client.inventory.MapleInventoryType;
-import constants.ItemConstants;
+import constants.inventory.ItemConstants;
import server.MapleItemInformationProvider;
public class RechargeCommand extends Command {
diff --git a/scripts/quest/21728.js b/src/client/command/commands/gm2/SetSlotCommand.java
similarity index 53%
rename from scripts/quest/21728.js
rename to src/client/command/commands/gm2/SetSlotCommand.java
index d5ff8db4fd..06e4b46a17 100644
--- a/scripts/quest/21728.js
+++ b/src/client/command/commands/gm2/SetSlotCommand.java
@@ -1,5 +1,5 @@
/*
- This file is part of the HeavenMS MapleStory Server
+ This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
@@ -18,32 +18,37 @@
along with this program. If not, see .
*/
-var status = -1;
+/*
+ @Author: Ronan
+*/
+package client.command.commands.gm2;
-function end(mode, type, selection) {
- if (mode == -1) {
- qm.dispose();
- } else {
- if(mode == 0 && type > 0) {
- qm.dispose();
+import client.*;
+import client.command.Command;
+
+public class SetSlotCommand extends Command {
+ {
+ setDescription("");
+ }
+
+ @Override
+ public void execute(MapleClient c, String[] params) {
+ MapleCharacter player = c.getPlayer();
+ if (params.length < 1) {
+ player.yellowMessage("Syntax: !setslot ");
return;
}
- if (mode == 1)
- status++;
- else
- status--;
-
- if (status == 0) {
- if(qm.getQuestProgress(21728, 0) == 0) {
- qm.sendNext("You haven't found the #rPuppeteer's cave#k yet, did you?");
- } else {
- qm.sendNext("Hm, so the entrance is blocked by a powerful force? I see, gimme a time to think now...");
- qm.gainExp(200);
- qm.forceCompleteQuest();
+ int slots = (Integer.parseInt(params[0]) / 4) * 4;
+ for (int i = 1; i < 5; i++) {
+ int curSlots = player.getSlots(i);
+ if (slots <= -curSlots) {
+ continue;
}
- qm.dispose();
+ player.gainSlots(i, slots - curSlots, true);
}
+
+ player.yellowMessage("Slots updated.");
}
-}
\ No newline at end of file
+}
diff --git a/src/client/command/commands/gm2/SpCommand.java b/src/client/command/commands/gm2/SpCommand.java
index 57e9d2502e..18776dd01e 100644
--- a/src/client/command/commands/gm2/SpCommand.java
+++ b/src/client/command/commands/gm2/SpCommand.java
@@ -26,7 +26,7 @@ package client.command.commands.gm2;
import client.command.Command;
import client.MapleClient;
import client.MapleCharacter;
-import constants.ServerConstants;
+import config.YamlConfig;
public class SpCommand extends Command {
{
@@ -44,7 +44,7 @@ public class SpCommand extends Command {
if (params.length == 1) {
int newSp = Integer.parseInt(params[0]);
if (newSp < 0) newSp = 0;
- else if (newSp > ServerConstants.MAX_AP) newSp = ServerConstants.MAX_AP;
+ else if (newSp > YamlConfig.config.server.MAX_AP) newSp = YamlConfig.config.server.MAX_AP;
player.updateRemainingSp(newSp);
} else {
@@ -52,7 +52,7 @@ public class SpCommand extends Command {
if (victim != null) {
int newSp = Integer.parseInt(params[1]);
if (newSp < 0) newSp = 0;
- else if (newSp > ServerConstants.MAX_AP) newSp = ServerConstants.MAX_AP;
+ else if (newSp > YamlConfig.config.server.MAX_AP) newSp = YamlConfig.config.server.MAX_AP;
victim.updateRemainingSp(newSp);
diff --git a/src/client/command/commands/gm3/FaceCommand.java b/src/client/command/commands/gm3/FaceCommand.java
index 7b9496805f..018854b110 100644
--- a/src/client/command/commands/gm3/FaceCommand.java
+++ b/src/client/command/commands/gm3/FaceCommand.java
@@ -27,7 +27,7 @@ import client.MapleStat;
import client.command.Command;
import client.MapleClient;
import client.MapleCharacter;
-import constants.ItemConstants;
+import constants.inventory.ItemConstants;
import server.MapleItemInformationProvider;
public class FaceCommand extends Command {
diff --git a/src/client/command/commands/gm3/HairCommand.java b/src/client/command/commands/gm3/HairCommand.java
index 5d08e8dec9..187ad4db63 100644
--- a/src/client/command/commands/gm3/HairCommand.java
+++ b/src/client/command/commands/gm3/HairCommand.java
@@ -27,7 +27,7 @@ import client.MapleStat;
import client.command.Command;
import client.MapleClient;
import client.MapleCharacter;
-import constants.ItemConstants;
+import constants.inventory.ItemConstants;
import server.MapleItemInformationProvider;
public class HairCommand extends Command {
diff --git a/src/client/command/commands/gm3/MusicCommand.java b/src/client/command/commands/gm3/MusicCommand.java
index 2dc0cb4e12..acd71dd211 100644
--- a/src/client/command/commands/gm3/MusicCommand.java
+++ b/src/client/command/commands/gm3/MusicCommand.java
@@ -26,7 +26,7 @@ package client.command.commands.gm3;
import client.command.Command;
import client.MapleClient;
import client.MapleCharacter;
-import constants.GameConstants;
+import constants.game.GameConstants;
import tools.MaplePacketCreator;
public class MusicCommand extends Command {
diff --git a/src/client/command/commands/gm3/QuestCompleteCommand.java b/src/client/command/commands/gm3/QuestCompleteCommand.java
index b092d3fb20..8595b37b6e 100644
--- a/src/client/command/commands/gm3/QuestCompleteCommand.java
+++ b/src/client/command/commands/gm3/QuestCompleteCommand.java
@@ -46,13 +46,13 @@ public class QuestCompleteCommand extends Command {
if (player.getQuestStatus(questId) == 1) {
MapleQuest quest = MapleQuest.getInstance(questId);
- if (quest != null) {
- int npcid = quest.getNpcRequirement(true);
- quest.forceComplete(player, npcid);
- player.dropMessage(5, "QUEST " + questId + " completed.");
- } else { // should not occur
- player.dropMessage(5, "QUESTID " + questId + " is invalid.");
+ if (quest != null && quest.getNpcRequirement(true) != -1) {
+ c.getAbstractPlayerInteraction().forceCompleteQuest(questId, quest.getNpcRequirement(true));
+ } else {
+ c.getAbstractPlayerInteraction().forceCompleteQuest(questId);
}
+
+ player.dropMessage(5, "QUEST " + questId + " completed.");
} else {
player.dropMessage(5, "QUESTID " + questId + " not started or already completed.");
}
diff --git a/src/client/command/commands/gm3/QuestStartCommand.java b/src/client/command/commands/gm3/QuestStartCommand.java
index 4c0ad74cc3..5ad3caef31 100644
--- a/src/client/command/commands/gm3/QuestStartCommand.java
+++ b/src/client/command/commands/gm3/QuestStartCommand.java
@@ -46,13 +46,13 @@ public class QuestStartCommand extends Command {
if (player.getQuestStatus(questid) == 0) {
MapleQuest quest = MapleQuest.getInstance(questid);
- if (quest != null) {
- int npcid = quest.getNpcRequirement(false);
- quest.forceStart(player, npcid);
- player.dropMessage(5, "QUEST " + questid + " started.");
+ if (quest != null && quest.getNpcRequirement(false) != -1) {
+ c.getAbstractPlayerInteraction().forceStartQuest(questid, quest.getNpcRequirement(false));
} else {
- player.dropMessage(5, "QUESTID " + questid + " is invalid.");
+ c.getAbstractPlayerInteraction().forceStartQuest(questid);
}
+
+ player.dropMessage(5, "QUEST " + questid + " started.");
} else {
player.dropMessage(5, "QUESTID " + questid + " already started/completed.");
}
diff --git a/src/client/command/commands/gm4/PapCommand.java b/src/client/command/commands/gm4/PapCommand.java
index bbeed4e137..b6207ea9d8 100644
--- a/src/client/command/commands/gm4/PapCommand.java
+++ b/src/client/command/commands/gm4/PapCommand.java
@@ -36,6 +36,8 @@ public class PapCommand extends Command {
@Override
public void execute(MapleClient c, String[] params) {
MapleCharacter player = c.getPlayer();
- player.getMap().spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(8510000), player.getPosition());
+
+ // thanks Conrad for noticing mobid typo here
+ player.getMap().spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(8500001), player.getPosition());
}
}
diff --git a/src/client/command/commands/gm4/ProItemCommand.java b/src/client/command/commands/gm4/ProItemCommand.java
index 6c74f4d985..c1502da63f 100644
--- a/src/client/command/commands/gm4/ProItemCommand.java
+++ b/src/client/command/commands/gm4/ProItemCommand.java
@@ -30,7 +30,7 @@ import client.inventory.Equip;
import client.inventory.Item;
import client.inventory.MapleInventoryType;
import client.inventory.manipulator.MapleInventoryManipulator;
-import constants.ItemConstants;
+import constants.inventory.ItemConstants;
import server.MapleItemInformationProvider;
public class ProItemCommand extends Command {
@@ -84,7 +84,7 @@ public class ProItemCommand extends Command {
equip.setHp(stat);
equip.setMp(stat);
- byte flag = equip.getFlag();
+ short flag = equip.getFlag();
flag |= ItemConstants.UNTRADEABLE;
equip.setFlag(flag);
}
diff --git a/src/client/command/commands/gm4/SetEqStatCommand.java b/src/client/command/commands/gm4/SetEqStatCommand.java
index 7a3a0f562d..667f1848b1 100644
--- a/src/client/command/commands/gm4/SetEqStatCommand.java
+++ b/src/client/command/commands/gm4/SetEqStatCommand.java
@@ -29,7 +29,7 @@ import client.MapleCharacter;
import client.inventory.Equip;
import client.inventory.MapleInventory;
import client.inventory.MapleInventoryType;
-import constants.ItemConstants;
+import constants.inventory.ItemConstants;
public class SetEqStatCommand extends Command {
{
@@ -68,7 +68,7 @@ public class SetEqStatCommand extends Command {
eq.setStr(newStat);
eq.setLuk(newStat);
- byte flag = eq.getFlag();
+ short flag = eq.getFlag();
flag |= ItemConstants.UNTRADEABLE;
eq.setFlag(flag);
diff --git a/src/client/command/commands/gm5/DebugCommand.java b/src/client/command/commands/gm5/DebugCommand.java
index 4bfaaf7ca6..d062e63eb7 100644
--- a/src/client/command/commands/gm5/DebugCommand.java
+++ b/src/client/command/commands/gm5/DebugCommand.java
@@ -27,14 +27,13 @@ import client.command.Command;
import client.MapleClient;
import client.MapleCharacter;
import net.server.Server;
-import server.MaplePortal;
+import server.maps.MaplePortal;
import server.TimerManager;
import server.life.MapleMonster;
import server.life.SpawnPoint;
import server.maps.MapleMapObject;
import server.maps.MapleMapObjectType;
import server.maps.MapleReactor;
-import tools.MaplePacketCreator;
import java.awt.*;
import java.util.Arrays;
diff --git a/src/client/command/commands/gm5/IpListCommand.java b/src/client/command/commands/gm5/IpListCommand.java
index 65413d6370..081493e92c 100644
--- a/src/client/command/commands/gm5/IpListCommand.java
+++ b/src/client/command/commands/gm5/IpListCommand.java
@@ -23,7 +23,7 @@ import java.util.Collection;
import client.MapleClient;
import client.MapleCharacter;
import client.command.Command;
-import constants.GameConstants;
+import constants.game.GameConstants;
import net.server.Server;
import net.server.world.World;
diff --git a/src/client/command/commands/gm5/SetCommand.java b/src/client/command/commands/gm5/SetCommand.java
index 542093ce6a..a49408b1c5 100644
--- a/src/client/command/commands/gm5/SetCommand.java
+++ b/src/client/command/commands/gm5/SetCommand.java
@@ -25,7 +25,7 @@ package client.command.commands.gm5;
import client.command.Command;
import client.MapleClient;
-import constants.ServerConstants;
+import constants.net.ServerConstants;
public class SetCommand extends Command {
{
diff --git a/src/client/command/commands/gm5/ShowMoveLifeCommand.java b/src/client/command/commands/gm5/ShowMoveLifeCommand.java
index 92ec84358a..7e88b91dff 100644
--- a/src/client/command/commands/gm5/ShowMoveLifeCommand.java
+++ b/src/client/command/commands/gm5/ShowMoveLifeCommand.java
@@ -25,7 +25,7 @@ package client.command.commands.gm5;
import client.command.Command;
import client.MapleClient;
-import constants.ServerConstants;
+import config.YamlConfig;
public class ShowMoveLifeCommand extends Command {
{
@@ -34,6 +34,6 @@ public class ShowMoveLifeCommand extends Command {
@Override
public void execute(MapleClient c, String[] params) {
- ServerConstants.USE_DEBUG_SHOW_RCVD_MVLIFE = !ServerConstants.USE_DEBUG_SHOW_RCVD_MVLIFE;
+ YamlConfig.config.server.USE_DEBUG_SHOW_RCVD_MVLIFE = !YamlConfig.config.server.USE_DEBUG_SHOW_RCVD_MVLIFE;
}
}
diff --git a/src/client/command/commands/gm5/ShowPacketsCommand.java b/src/client/command/commands/gm5/ShowPacketsCommand.java
index 24bea650f9..25346e1468 100644
--- a/src/client/command/commands/gm5/ShowPacketsCommand.java
+++ b/src/client/command/commands/gm5/ShowPacketsCommand.java
@@ -25,7 +25,7 @@ package client.command.commands.gm5;
import client.command.Command;
import client.MapleClient;
-import constants.ServerConstants;
+import config.YamlConfig;
public class ShowPacketsCommand extends Command {
{
@@ -34,6 +34,6 @@ public class ShowPacketsCommand extends Command {
@Override
public void execute(MapleClient c, String[] params) {
- ServerConstants.USE_DEBUG_SHOW_RCVD_PACKET = !ServerConstants.USE_DEBUG_SHOW_RCVD_PACKET;
+ YamlConfig.config.server.USE_DEBUG_SHOW_RCVD_PACKET = !YamlConfig.config.server.USE_DEBUG_SHOW_RCVD_PACKET;
}
}
diff --git a/src/client/command/commands/gm5/ShowSessionsCommand.java b/src/client/command/commands/gm5/ShowSessionsCommand.java
index da853f3c9e..5ae15f609b 100644
--- a/src/client/command/commands/gm5/ShowSessionsCommand.java
+++ b/src/client/command/commands/gm5/ShowSessionsCommand.java
@@ -21,7 +21,7 @@ package client.command.commands.gm5;
import client.MapleClient;
import client.command.Command;
-import net.server.coordinator.MapleSessionCoordinator;
+import net.server.coordinator.session.MapleSessionCoordinator;
/**
*
diff --git a/src/client/command/commands/gm6/SupplyRateCouponCommand.java b/src/client/command/commands/gm6/SupplyRateCouponCommand.java
index 8e8e0a3ea9..e9742e8ea7 100644
--- a/src/client/command/commands/gm6/SupplyRateCouponCommand.java
+++ b/src/client/command/commands/gm6/SupplyRateCouponCommand.java
@@ -22,7 +22,7 @@ package client.command.commands.gm6;
import client.MapleCharacter;
import client.MapleClient;
import client.command.Command;
-import constants.ServerConstants;
+import config.YamlConfig;
public class SupplyRateCouponCommand extends Command {
{
@@ -37,7 +37,7 @@ public class SupplyRateCouponCommand extends Command {
return;
}
- ServerConstants.USE_SUPPLY_RATE_COUPONS = params[0].compareToIgnoreCase("no") != 0;
- player.dropMessage(5, "Rate coupons are now " + (ServerConstants.USE_SUPPLY_RATE_COUPONS ? "enabled" : "disabled") + " for purchase at the Cash Shop.");
+ YamlConfig.config.server.USE_SUPPLY_RATE_COUPONS = params[0].compareToIgnoreCase("no") != 0;
+ player.dropMessage(5, "Rate coupons are now " + (YamlConfig.config.server.USE_SUPPLY_RATE_COUPONS ? "enabled" : "disabled") + " for purchase at the Cash Shop.");
}
}
diff --git a/src/client/command/commands/gm6/WarpWorldCommand.java b/src/client/command/commands/gm6/WarpWorldCommand.java
index 2c5f9f0f9d..d760e2fbc8 100644
--- a/src/client/command/commands/gm6/WarpWorldCommand.java
+++ b/src/client/command/commands/gm6/WarpWorldCommand.java
@@ -52,7 +52,6 @@ public class WarpWorldCommand extends Command {
String[] socket = server.getInetSocket(worldb, c.getChannel());
c.getWorldServer().removePlayer(player);
player.getMap().removePlayer(player);//LOL FORGOT THIS ><
- c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
player.setSessionTransitionState();
player.setWorld(worldb);
player.saveCharToDB();//To set the new world :O (true because else 2 player instances are created, one in both worlds)
diff --git a/src/client/creator/CharacterFactory.java b/src/client/creator/CharacterFactory.java
index f155688ae5..fe65ab98b5 100644
--- a/src/client/creator/CharacterFactory.java
+++ b/src/client/creator/CharacterFactory.java
@@ -25,7 +25,7 @@ import client.MapleSkinColor;
import client.inventory.Item;
import client.inventory.MapleInventory;
import client.inventory.MapleInventoryType;
-import constants.ServerConstants;
+import config.YamlConfig;
import net.server.Server;
import server.MapleItemInformationProvider;
import tools.FilePrinter;
@@ -38,7 +38,7 @@ import tools.MaplePacketCreator;
public abstract class CharacterFactory {
protected synchronized static int createNewCharacter(MapleClient c, String name, int face, int hair, int skin, int gender, CharacterFactoryRecipe recipe) {
- if (ServerConstants.COLLECTIVE_CHARSLOT ? c.getAvailableCharacterSlots() <= 0 : c.getAvailableCharacterWorldSlots() <= 0) {
+ if (YamlConfig.config.server.COLLECTIVE_CHARSLOT ? c.getAvailableCharacterSlots() <= 0 : c.getAvailableCharacterWorldSlots() <= 0) {
return -3;
}
diff --git a/src/client/creator/CharacterFactoryRecipe.java b/src/client/creator/CharacterFactoryRecipe.java
index 74521f1478..7ce5ac9b61 100644
--- a/src/client/creator/CharacterFactoryRecipe.java
+++ b/src/client/creator/CharacterFactoryRecipe.java
@@ -23,6 +23,7 @@ import client.MapleJob;
import client.Skill;
import client.inventory.Item;
import client.inventory.MapleInventoryType;
+import config.YamlConfig;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.LinkedHashMap;
import java.util.LinkedList;
@@ -54,6 +55,15 @@ public class CharacterFactoryRecipe {
this.bottom = bottom;
this.shoes = shoes;
this.weapon = weapon;
+
+ if (!YamlConfig.config.server.USE_STARTING_AP_4) {
+ if (YamlConfig.config.server.USE_AUTOASSIGN_STARTERS_AP) {
+ str = 12;
+ dex = 5;
+ } else {
+ ap = 9;
+ }
+ }
}
public void setStr(int v) {
diff --git a/src/client/inventory/Equip.java b/src/client/inventory/Equip.java
index 71a600f547..91036d9287 100644
--- a/src/client/inventory/Equip.java
+++ b/src/client/inventory/Equip.java
@@ -22,9 +22,9 @@
package client.inventory;
import client.MapleClient;
-import constants.ServerConstants;
-import constants.ExpTable;
-import constants.ItemConstants;
+import config.YamlConfig;
+import constants.game.ExpTable;
+import constants.inventory.ItemConstants;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -64,7 +64,8 @@ public class Equip extends Item {
}
private byte upgradeSlots;
- private byte level, flag, itemLevel;
+ private byte level, itemLevel;
+ private short flag;
private short str, dex, _int, luk, hp, mp, watk, matk, wdef, mdef, acc, avoid, hands, speed, jump, vicious;
private float itemExp;
private int ringid = -1;
@@ -117,7 +118,7 @@ public class Equip extends Item {
}
@Override
- public byte getFlag() {
+ public short getFlag() {
return flag;
}
@@ -195,7 +196,7 @@ public class Equip extends Item {
}
@Override
- public void setFlag(byte flag) {
+ public void setFlag(short flag) {
this.flag = flag;
}
@@ -278,7 +279,7 @@ public class Equip extends Item {
private static int getStatModifier(boolean isAttribute) {
// each set of stat points grants a chance for a bonus stat point upgrade at equip level up.
- if(ServerConstants.USE_EQUIPMNT_LVLUP_POWER) {
+ if(YamlConfig.config.server.USE_EQUIPMNT_LVLUP_POWER) {
if(isAttribute) return 2;
else return 4;
}
@@ -289,7 +290,7 @@ public class Equip extends Item {
}
private static int randomizeStatUpgrade(int top) {
- int limit = Math.min(top, ServerConstants.MAX_EQUIPMNT_LVLUP_STAT_UP);
+ int limit = Math.min(top, YamlConfig.config.server.MAX_EQUIPMNT_LVLUP_STAT_UP);
int poolCount = (limit * (limit + 1) / 2) + limit;
int rnd = Randomizer.rand(0, poolCount);
@@ -382,7 +383,7 @@ public class Equip extends Item {
public Pair> gainStats(List> stats) {
boolean gotSlot = false, gotVicious = false;
String lvupStr = "";
- Integer statUp, maxStat = ServerConstants.MAX_EQUIPMNT_STAT;
+ Integer statUp, maxStat = YamlConfig.config.server.MAX_EQUIPMNT_STAT;
for (Pair stat : stats) {
switch (stat.getLeft()) {
case incDEX:
@@ -482,7 +483,7 @@ public class Equip extends Item {
}
if(!stats.isEmpty()) {
- if(ServerConstants.USE_EQUIPMNT_LVLUP_SLOTS) {
+ if(YamlConfig.config.server.USE_EQUIPMNT_LVLUP_SLOTS) {
if(vicious > 0) getUnitSlotUpgrade(stats, StatUpgrade.incVicious);
getUnitSlotUpgrade(stats, StatUpgrade.incSlot);
}
@@ -490,7 +491,7 @@ public class Equip extends Item {
isUpgradeable = false;
improveDefaultStats(stats);
- if(ServerConstants.USE_EQUIPMNT_LVLUP_SLOTS) {
+ if(YamlConfig.config.server.USE_EQUIPMNT_LVLUP_SLOTS) {
if(vicious > 0) getUnitSlotUpgrade(stats, StatUpgrade.incVicious);
getUnitSlotUpgrade(stats, StatUpgrade.incSlot);
}
@@ -498,7 +499,7 @@ public class Equip extends Item {
if(isUpgradeable) {
while(stats.isEmpty()) {
improveDefaultStats(stats);
- if(ServerConstants.USE_EQUIPMNT_LVLUP_SLOTS) {
+ if(YamlConfig.config.server.USE_EQUIPMNT_LVLUP_SLOTS) {
if(vicious > 0) getUnitSlotUpgrade(stats, StatUpgrade.incVicious);
getUnitSlotUpgrade(stats, StatUpgrade.incSlot);
}
@@ -562,14 +563,14 @@ public class Equip extends Item {
return;
}
- int equipMaxLevel = Math.min(30, Math.max(ii.getEquipLevel(this.getItemId(), true), ServerConstants.USE_EQUIPMNT_LVLUP));
+ int equipMaxLevel = Math.min(30, Math.max(ii.getEquipLevel(this.getItemId(), true), YamlConfig.config.server.USE_EQUIPMNT_LVLUP));
if (itemLevel >= equipMaxLevel) {
return;
}
int reqLevel = ii.getEquipLevelReq(this.getItemId());
- float masteryModifier = (float)(ServerConstants.EQUIP_EXP_RATE * ExpTable.getExpNeededForLevel(1)) / (float)normalizedMasteryExp(reqLevel);
+ float masteryModifier = (float)(YamlConfig.config.server.EQUIP_EXP_RATE * ExpTable.getExpNeededForLevel(1)) / (float)normalizedMasteryExp(reqLevel);
float elementModifier = (isElemental) ? 0.85f : 0.6f;
float baseExpGain = gain * elementModifier * masteryModifier;
@@ -577,7 +578,7 @@ public class Equip extends Item {
itemExp += baseExpGain;
int expNeeded = ExpTable.getEquipExpNeededForLevel(itemLevel);
- if(ServerConstants.USE_DEBUG_SHOW_INFO_EQPEXP) System.out.println("'" + ii.getName(this.getItemId()) + "' -> EXP Gain: " + gain + " Mastery: " + masteryModifier + " Base gain: " + baseExpGain + " exp: " + itemExp + " / " + expNeeded + ", Kills TNL: " + expNeeded / (baseExpGain / c.getPlayer().getExpRate()));
+ if(YamlConfig.config.server.USE_DEBUG_SHOW_INFO_EQPEXP) System.out.println("'" + ii.getName(this.getItemId()) + "' -> EXP Gain: " + gain + " Mastery: " + masteryModifier + " Base gain: " + baseExpGain + " exp: " + itemExp + " / " + expNeeded + ", Kills TNL: " + expNeeded / (baseExpGain / c.getPlayer().getExpRate()));
if (itemExp >= expNeeded) {
while(itemExp >= expNeeded) {
@@ -594,7 +595,7 @@ public class Equip extends Item {
}
c.getPlayer().forceUpdateItem(this);
- //if(ServerConstants.USE_DEBUG) c.getPlayer().dropMessage("'" + ii.getName(this.getItemId()) + "': " + itemExp + " / " + expNeeded);
+ //if(YamlConfig.config.server.USE_DEBUG) c.getPlayer().dropMessage("'" + ii.getName(this.getItemId()) + "': " + itemExp + " / " + expNeeded);
}
private boolean reachedMaxLevel() {
@@ -604,7 +605,7 @@ public class Equip extends Item {
}
}
- return itemLevel >= ServerConstants.USE_EQUIPMNT_LVLUP;
+ return itemLevel >= YamlConfig.config.server.USE_EQUIPMNT_LVLUP;
}
public String showEquipFeatures(MapleClient c) {
diff --git a/src/client/inventory/Item.java b/src/client/inventory/Item.java
index 74ca97932e..5da563f29d 100644
--- a/src/client/inventory/Item.java
+++ b/src/client/inventory/Item.java
@@ -21,7 +21,7 @@ along with this program. If not, see .
*/
package client.inventory;
-import constants.ItemConstants;
+import constants.inventory.ItemConstants;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
@@ -40,7 +40,7 @@ public class Item implements Comparable- {
private MaplePet pet = null;
private String owner = "";
protected List log;
- private byte flag;
+ private short flag;
private long expiration = -1;
private String giftFrom = "";
@@ -126,7 +126,7 @@ public class Item implements Comparable
- {
public int getPetId() {
return petid;
}
-
+
@Override
public int compareTo(Item other) {
if (this.id < other.getItemId()) {
@@ -146,11 +146,16 @@ public class Item implements Comparable
- {
return Collections.unmodifiableList(log);
}
- public byte getFlag() {
+ public short getFlag() {
return flag;
}
- public void setFlag(byte b) {
+ public void setFlag(short b) {
+ MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
+ if (ii.isAccountRestricted(id)) {
+ b |= ItemConstants.ACCOUNT_SHARING; // thanks Shinigami15 for noticing ACCOUNT_SHARING flag not being applied properly to items server-side
+ }
+
this.flag = b;
}
diff --git a/src/client/inventory/ItemFactory.java b/src/client/inventory/ItemFactory.java
index 4dab3c2a7b..7ece9b334b 100644
--- a/src/client/inventory/ItemFactory.java
+++ b/src/client/inventory/ItemFactory.java
@@ -97,7 +97,7 @@ public enum ItemFactory {
equip.setInt((short) rs.getInt("int"));
equip.setJump((short) rs.getInt("jump"));
equip.setVicious((short) rs.getInt("vicious"));
- equip.setFlag((byte) rs.getInt("flag"));
+ equip.setFlag((short) rs.getInt("flag"));
equip.setLuk((short) rs.getInt("luk"));
equip.setMatk((short) rs.getInt("matk"));
equip.setMdef((short) rs.getInt("mdef"));
@@ -173,11 +173,16 @@ public enum ItemFactory {
if (mit.equals(MapleInventoryType.EQUIP) || mit.equals(MapleInventoryType.EQUIPPED)) {
items.add(new Pair
- (loadEquipFromResultSet(rs), mit));
} else {
- Item item = new Item(rs.getInt("itemid"), (byte) rs.getInt("position"), (short) rs.getInt("quantity"), rs.getInt("petid"));
+ int petid = rs.getInt("petid");
+ if (rs.wasNull()) {
+ petid = -1;
+ }
+
+ Item item = new Item(rs.getInt("itemid"), (byte) rs.getInt("position"), (short) rs.getInt("quantity"), petid);
item.setOwner(rs.getString("owner"));
item.setExpiration(rs.getLong("expiration"));
item.setGiftFrom(rs.getString("giftFrom"));
- item.setFlag((byte) rs.getInt("flag"));
+ item.setFlag((short) rs.getInt("flag"));
items.add(new Pair<>(item, mit));
}
}
@@ -229,7 +234,7 @@ public enum ItemFactory {
ps.setInt(6, item.getPosition());
ps.setInt(7, item.getQuantity());
ps.setString(8, item.getOwner());
- ps.setInt(9, item.getPetId());
+ ps.setInt(9, item.getPetId()); // thanks Daddy Egg for alerting a case of unique petid constraint breach getting raised
ps.setInt(10, item.getFlag());
ps.setLong(11, item.getExpiration());
ps.setString(12, item.getGiftFrom());
@@ -329,11 +334,16 @@ public enum ItemFactory {
items.add(new Pair
- (loadEquipFromResultSet(rs), mit));
} else {
if(bundles > 0) {
- Item item = new Item(rs.getInt("itemid"), (byte) rs.getInt("position"), (short)(bundles * rs.getInt("quantity")), rs.getInt("petid"));
+ int petid = rs.getInt("petid");
+ if (rs.wasNull()) {
+ petid = -1;
+ }
+
+ Item item = new Item(rs.getInt("itemid"), (byte) rs.getInt("position"), (short)(bundles * rs.getInt("quantity")), petid);
item.setOwner(rs.getString("owner"));
item.setExpiration(rs.getLong("expiration"));
item.setGiftFrom(rs.getString("giftFrom"));
- item.setFlag((byte) rs.getInt("flag"));
+ item.setFlag((short) rs.getInt("flag"));
items.add(new Pair<>(item, mit));
}
}
diff --git a/src/client/inventory/MapleInventory.java b/src/client/inventory/MapleInventory.java
index 7255677ddc..a5d6529aed 100644
--- a/src/client/inventory/MapleInventory.java
+++ b/src/client/inventory/MapleInventory.java
@@ -37,7 +37,7 @@ import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
import tools.Pair;
import client.MapleCharacter;
import client.MapleClient;
-import constants.ItemConstants;
+import constants.inventory.ItemConstants;
import server.MapleItemInformationProvider;
import client.inventory.manipulator.MapleInventoryManipulator;
import tools.FilePrinter;
@@ -83,6 +83,19 @@ public class MapleInventory implements Iterable
- {
public void setSlotLimit(int newLimit) {
lock.lock();
try {
+ if (newLimit < slotLimit) {
+ List toRemove = new LinkedList<>();
+ for (Item it : list()) {
+ if (it.getPosition() > newLimit) {
+ toRemove.add(it.getPosition());
+ }
+ }
+
+ for (Short slot : toRemove) {
+ removeSlot(slot);
+ }
+ }
+
slotLimit = (byte) newLimit;
} finally {
lock.unlock();
diff --git a/src/client/inventory/MaplePet.java b/src/client/inventory/MaplePet.java
index acaa12c9bd..f26944c5fa 100644
--- a/src/client/inventory/MaplePet.java
+++ b/src/client/inventory/MaplePet.java
@@ -21,7 +21,7 @@
*/
package client.inventory;
-import constants.ExpTable;
+import constants.game.ExpTable;
import java.awt.Point;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@@ -98,75 +98,11 @@ public class MaplePet extends Item {
}
}
- private static void unreferenceMissingPetsFromInventoryDb() {
- PreparedStatement ps = null;
- Connection con = null;
- try {
- con = DatabaseConnection.getConnection();
-
- ps = con.prepareStatement("UPDATE inventoryitems SET petid = -1, expiration = 0 WHERE petid != -1 AND petid NOT IN (SELECT petid FROM pets)");
- ps.executeUpdate();
-
- ps.close();
- con.close();
- } catch(SQLException ex) {
- ex.printStackTrace();
- } finally {
- try {
- if(ps != null && !ps.isClosed()) {
- ps.close();
- }
- if(con != null && !con.isClosed()) {
- con.close();
- }
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
-
- private static void deleteMissingPetsFromDb() {
- PreparedStatement ps = null;
- Connection con = null;
- try {
- con = DatabaseConnection.getConnection();
-
- ps = con.prepareStatement("DELETE FROM pets WHERE petid NOT IN (SELECT petid FROM inventoryitems WHERE petid != -1)");
- ps.executeUpdate();
-
- ps.close();
- con.close();
- } catch(SQLException ex) {
- ex.printStackTrace();
- } finally {
- try {
- if(ps != null && !ps.isClosed()) {
- ps.close();
- }
- if(con != null && !con.isClosed()) {
- con.close();
- }
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
-
- public static void clearMissingPetsFromDb() {
- unreferenceMissingPetsFromInventoryDb();
- deleteMissingPetsFromDb();
- }
-
public static void deleteFromDb(MapleCharacter owner, int petid) {
try {
Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("DELETE FROM pets WHERE `petid` = ?");
- ps.setInt(1, petid);
- ps.executeUpdate();
- ps.close();
-
- ps = con.prepareStatement("DELETE FROM petignores WHERE `petid` = ?"); // thanks Vcoc for detecting petignores remaining after deletion
+ PreparedStatement ps = con.prepareStatement("DELETE FROM pets WHERE `petid` = ?"); // thanks Vcoc for detecting petignores remaining after deletion
ps.setInt(1, petid);
ps.executeUpdate();
ps.close();
diff --git a/src/client/inventory/manipulator/MapleCashidGenerator.java b/src/client/inventory/manipulator/MapleCashidGenerator.java
index 45af01f768..4345518d43 100644
--- a/src/client/inventory/manipulator/MapleCashidGenerator.java
+++ b/src/client/inventory/manipulator/MapleCashidGenerator.java
@@ -41,7 +41,10 @@ public class MapleCashidGenerator {
ResultSet rs = ps.executeQuery();
while (rs.next()) {
- existentCashids.add(rs.getInt(1));
+ int id = rs.getInt(1);
+ if (!rs.wasNull()) {
+ existentCashids.add(id);
+ }
}
rs.close();
diff --git a/src/client/inventory/manipulator/MapleInventoryManipulator.java b/src/client/inventory/manipulator/MapleInventoryManipulator.java
index d2f41d82a4..133b3a58b9 100644
--- a/src/client/inventory/manipulator/MapleInventoryManipulator.java
+++ b/src/client/inventory/manipulator/MapleInventoryManipulator.java
@@ -31,8 +31,8 @@ import client.inventory.MapleInventoryType;
import client.inventory.MaplePet;
import client.inventory.ModifyInventory;
import client.newyear.NewYearCardRecord;
-import constants.ItemConstants;
-import constants.ServerConstants;
+import config.YamlConfig;
+import constants.inventory.ItemConstants;
import java.awt.Point;
import java.util.ArrayList;
@@ -68,29 +68,20 @@ public class MapleInventoryManipulator {
return addById(c, itemId, quantity, owner, petid, (byte) 0, expiration);
}
- public static boolean addById(MapleClient c, int itemId, short quantity, String owner, int petid, byte flag, long expiration) {
+ public static boolean addById(MapleClient c, int itemId, short quantity, String owner, int petid, short flag, long expiration) {
MapleCharacter chr = c.getPlayer();
MapleInventoryType type = ItemConstants.getInventoryType(itemId);
- if (c.tryacquireClient()) {
- try {
- MapleInventory inv = chr.getInventory(type);
- inv.lockInventory();
- try {
- return addByIdInternal(c, chr, type, inv, itemId, quantity, owner, petid, flag, expiration);
- } finally {
- inv.unlockInventory();
- }
- } finally {
- c.releaseClient();
- }
- } else {
- c.announce(MaplePacketCreator.enableActions());
- return false;
+ MapleInventory inv = chr.getInventory(type);
+ inv.lockInventory();
+ try {
+ return addByIdInternal(c, chr, type, inv, itemId, quantity, owner, petid, flag, expiration);
+ } finally {
+ inv.unlockInventory();
}
}
- private static boolean addByIdInternal(MapleClient c, MapleCharacter chr, MapleInventoryType type, MapleInventory inv, int itemId, short quantity, String owner, int petid, byte flag, long expiration) {
+ private static boolean addByIdInternal(MapleClient c, MapleCharacter chr, MapleInventoryType type, MapleInventory inv, int itemId, short quantity, String owner, int petid, short flag, long expiration) {
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
if (!type.equals(MapleInventoryType.EQUIP)) {
short slotMax = ii.getSlotMax(c, itemId);
@@ -187,21 +178,12 @@ public class MapleInventoryManipulator {
MapleCharacter chr = c.getPlayer();
MapleInventoryType type = item.getInventoryType();
- if (c.tryacquireClient()) {
- try {
- MapleInventory inv = chr.getInventory(type);
- inv.lockInventory();
- try {
- return addFromDropInternal(c, chr, type, inv, item, show, petId);
- } finally {
- inv.unlockInventory();
- }
- } finally {
- c.releaseClient();
- }
- } else {
- c.announce(MaplePacketCreator.enableActions());
- return false;
+ MapleInventory inv = chr.getInventory(type);
+ inv.lockInventory();
+ try {
+ return addFromDropInternal(c, chr, type, inv, item, show, petId);
+ } finally {
+ inv.unlockInventory();
}
}
@@ -683,9 +665,27 @@ public class MapleInventoryManipulator {
c.announce(MaplePacketCreator.modifyInventory(true, Collections.singletonList(new ModifyInventory(2, source, src))));
chr.equipChanged();
}
+
+ private static boolean isDisappearingItemDrop(Item it) {
+ MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
+ if (ii.isDropRestricted(it.getItemId())) {
+ return true;
+ } else if (ii.isCash(it.getItemId())) {
+ if (YamlConfig.config.server.USE_ENFORCE_UNMERCHABLE_CASH) { // thanks Ari for noticing cash drops not available server-side
+ return true;
+ } else if (ItemConstants.isPet(it.getItemId()) && YamlConfig.config.server.USE_ENFORCE_UNMERCHABLE_PET) {
+ return true;
+ }
+ } else if (isDroppedItemRestricted(it)) {
+ return true;
+ } else if (ItemConstants.isWeddingRing(it.getItemId())) {
+ return true;
+ }
+
+ return false;
+ }
public static void drop(MapleClient c, MapleInventoryType type, short src, short quantity) {
- MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
if (src < 0) {
type = MapleInventoryType.EQUIPPED;
}
@@ -698,14 +698,21 @@ public class MapleInventoryManipulator {
return;
}
int itemId = source.getItemId();
- if (ItemConstants.isPet(itemId)) {
- return;
- }
MapleMap map = chr.getMap();
if ((!ItemConstants.isRechargeable(itemId) && source.getQuantity() < quantity) || quantity < 0) {
return;
}
+
+ int petid = source.getPetId();
+ if (petid > -1) {
+ int petIdx = chr.getPetIndex(petid);
+ if(petIdx > -1) {
+ MaplePet pet = chr.getPet(petIdx);
+ chr.unequipPet(pet, true);
+ }
+ }
+
Point dropPos = new Point(chr.getPosition());
if (quantity < source.getQuantity() && !ItemConstants.isRechargeable(itemId)) {
Item target = source.copy();
@@ -721,11 +728,9 @@ public class MapleInventoryManipulator {
NewYearCardRecord.removeAllNewYearCard(false, chr);
c.getAbstractPlayerInteraction().removeAll(4301000);
}
- } else if (ItemConstants.isWeddingRing(source.getItemId())) {
- map.disappearingItemDrop(chr, chr, target, dropPos);
}
- if (ii.isDropRestricted(target.getItemId()) || ii.isCash(target.getItemId()) || isDroppedItemRestricted(target)) {
+ if (isDisappearingItemDrop(target)) {
map.disappearingItemDrop(chr, chr, target, dropPos);
} else {
map.spawnItemDrop(chr, chr, target, dropPos, true, true);
@@ -754,11 +759,9 @@ public class MapleInventoryManipulator {
NewYearCardRecord.removeAllNewYearCard(false, chr);
c.getAbstractPlayerInteraction().removeAll(4301000);
}
- } else if (ItemConstants.isWeddingRing(source.getItemId())) {
- map.disappearingItemDrop(chr, chr, source, dropPos);
}
- if (ii.isDropRestricted(itemId) || ii.isCash(itemId) || isDroppedItemRestricted(source)) {
+ if (isDisappearingItemDrop(source)) {
map.disappearingItemDrop(chr, chr, source, dropPos);
} else {
map.spawnItemDrop(chr, chr, source, dropPos, true, true);
@@ -781,7 +784,7 @@ public class MapleInventoryManipulator {
}
private static boolean isDroppedItemRestricted(Item it) {
- return ServerConstants.USE_ERASE_UNTRADEABLE_DROP && it.isUntradeable();
+ return YamlConfig.config.server.USE_ERASE_UNTRADEABLE_DROP && it.isUntradeable();
}
public static boolean isSandboxItem(Item it) {
diff --git a/src/client/inventory/manipulator/MapleKarmaManipulator.java b/src/client/inventory/manipulator/MapleKarmaManipulator.java
index 92444187bc..c0cb0838d3 100644
--- a/src/client/inventory/manipulator/MapleKarmaManipulator.java
+++ b/src/client/inventory/manipulator/MapleKarmaManipulator.java
@@ -19,7 +19,7 @@
*/
package client.inventory.manipulator;
-import constants.ItemConstants;
+import constants.inventory.ItemConstants;
import client.inventory.Item;
/**
@@ -27,18 +27,18 @@ import client.inventory.Item;
* @author RonanLana
*/
public class MapleKarmaManipulator {
- private static int getKarmaFlag(Item item) {
+ private static short getKarmaFlag(Item item) {
return item.getItemType() == 1 ? ItemConstants.KARMA_EQP : ItemConstants.KARMA_USE;
}
public static boolean hasKarmaFlag(Item item) {
- int karmaFlag = getKarmaFlag(item);
+ short karmaFlag = getKarmaFlag(item);
return (item.getFlag() & karmaFlag) == karmaFlag;
}
public static void toggleKarmaFlagToUntradeable(Item item) {
- int karmaFlag = getKarmaFlag(item);
- int flag = item.getFlag();
+ short karmaFlag = getKarmaFlag(item);
+ short flag = item.getFlag();
if ((flag & karmaFlag) == karmaFlag) {
flag ^= karmaFlag;
@@ -49,8 +49,8 @@ public class MapleKarmaManipulator {
}
public static void setKarmaFlag(Item item) {
- int karmaFlag = getKarmaFlag(item);
- int flag = item.getFlag();
+ short karmaFlag = getKarmaFlag(item);
+ short flag = item.getFlag();
flag |= karmaFlag;
flag &= (0xFFFFFFFF ^ ItemConstants.UNTRADEABLE);
diff --git a/src/client/processor/BuybackProcessor.java b/src/client/processor/action/BuybackProcessor.java
similarity index 95%
rename from src/client/processor/BuybackProcessor.java
rename to src/client/processor/action/BuybackProcessor.java
index f031c9c9ea..cacd0067be 100644
--- a/src/client/processor/BuybackProcessor.java
+++ b/src/client/processor/action/BuybackProcessor.java
@@ -17,7 +17,7 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
-package client.processor;
+package client.processor.action; // thanks Alex for pointing out some package structures containing broad modules
import client.MapleClient;
import client.MapleCharacter;
diff --git a/src/client/processor/MakerProcessor.java b/src/client/processor/action/MakerProcessor.java
similarity index 70%
rename from src/client/processor/MakerProcessor.java
rename to src/client/processor/action/MakerProcessor.java
index 88f2694482..c9816ccbcf 100644
--- a/src/client/processor/MakerProcessor.java
+++ b/src/client/processor/action/MakerProcessor.java
@@ -17,22 +17,23 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
-package client.processor;
+package client.processor.action;
import client.MapleClient;
import client.MapleCharacter;
import client.inventory.Equip;
import client.inventory.Item;
import client.inventory.MapleInventoryType;
-import constants.ItemConstants;
-import constants.ServerConstants;
import client.inventory.manipulator.MapleInventoryManipulator;
-import constants.GameConstants;
+import config.YamlConfig;
+import constants.inventory.ItemConstants;
+import constants.game.GameConstants;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import server.MakerItemFactory;
+import server.MakerItemFactory.MakerItemCreateEntry;
import server.MapleItemInformationProvider;
import tools.FilePrinter;
import tools.MaplePacketCreator;
@@ -44,6 +45,7 @@ import tools.data.input.SeekableLittleEndianAccessor;
* @author Ronan
*/
public class MakerProcessor {
+
private static MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
public static void makerAction(SeekableLittleEndianAccessor slea, MapleClient c) {
@@ -54,7 +56,7 @@ public class MakerProcessor {
int toDisassemble = -1, pos = -1;
boolean makerSucceeded = true;
- MakerItemFactory.MakerItemCreateEntry recipe;
+ MakerItemCreateEntry recipe;
Map reagentids = new LinkedHashMap<>();
int stimulantid = -1;
@@ -62,29 +64,31 @@ public class MakerProcessor {
int fromLeftover = toCreate;
toCreate = ii.getMakerCrystalFromLeftover(toCreate);
if(toCreate == -1) {
- c.announce(MaplePacketCreator.serverNotice(1, ii.getName(toCreate) + " is unavailable for Monster Crystal conversion."));
+ c.announce(MaplePacketCreator.serverNotice(1, ii.getName(fromLeftover) + " is unavailable for Monster Crystal conversion."));
+ c.announce(MaplePacketCreator.makerEnableActions());
return;
}
-
- recipe = MakerItemFactory.generateLeftoverCrystalEntry(fromLeftover);
+
+ recipe = MakerItemFactory.generateLeftoverCrystalEntry(fromLeftover, toCreate);
} else if(type == 4) { // disassembling
slea.readInt(); // 1... probably inventory type
pos = slea.readInt();
Item it = c.getPlayer().getInventory(MapleInventoryType.EQUIP).getItem((short) pos);
if(it != null && it.getItemId() == toCreate) {
- Pair p;
-
- if((p = generateDisassemblyInfo(toCreate)) != null) {
- recipe = MakerItemFactory.generateDisassemblyCrystalEntry(p.getLeft(), p.getRight());
- toDisassemble = toCreate;
- toCreate = ii.getMakerCrystalFromEquip(toCreate);
+ toDisassemble = toCreate;
+
+ Pair>> p = generateDisassemblyInfo(toDisassemble);
+ if(p != null) {
+ recipe = MakerItemFactory.generateDisassemblyCrystalEntry(toDisassemble, p.getLeft(), p.getRight());
} else {
c.announce(MaplePacketCreator.serverNotice(1, ii.getName(toCreate) + " is unavailable for Monster Crystal disassembly."));
+ c.announce(MaplePacketCreator.makerEnableActions());
return;
}
} else {
c.announce(MaplePacketCreator.serverNotice(1, "An unknown error occurred when trying to apply that item for disassembly."));
+ c.announce(MaplePacketCreator.makerEnableActions());
return;
}
} else {
@@ -132,6 +136,7 @@ public class MakerProcessor {
if(!reagentids.isEmpty()) {
if(!removeOddMakerReagents(toCreate, reagentids)) {
c.announce(MaplePacketCreator.serverNotice(1, "You can only use WATK and MATK Strengthening Gems on weapon items."));
+ c.announce(MaplePacketCreator.makerEnableActions());
return;
}
}
@@ -146,65 +151,80 @@ public class MakerProcessor {
case -1:// non-available for Maker itemid has been tried to forge
FilePrinter.printError(FilePrinter.EXPLOITS, "Player " + c.getPlayer().getName() + " tried to craft itemid " + toCreate + " using the Maker skill.");
c.announce(MaplePacketCreator.serverNotice(1, "The requested item could not be crafted on this operation."));
+ c.announce(MaplePacketCreator.makerEnableActions());
break;
case 1: // no items
- c.announce(MaplePacketCreator.serverNotice(1, "You don't have all required items in your inventory to make " + recipe.getRewardAmount() + " " + ii.getName(toCreate) + "."));
+ c.announce(MaplePacketCreator.serverNotice(1, "You don't have all required items in your inventory to make " + ii.getName(toCreate) + "."));
+ c.announce(MaplePacketCreator.makerEnableActions());
break;
case 2: // no meso
c.announce(MaplePacketCreator.serverNotice(1, "You don't have enough mesos (" + GameConstants.numberWithCommas(recipe.getCost()) + ") to complete this operation."));
+ c.announce(MaplePacketCreator.makerEnableActions());
break;
case 3: // no req level
c.announce(MaplePacketCreator.serverNotice(1, "You don't have enough level to complete this operation."));
+ c.announce(MaplePacketCreator.makerEnableActions());
break;
case 4: // no req skill level
c.announce(MaplePacketCreator.serverNotice(1, "You don't have enough Maker level to complete this operation."));
+ c.announce(MaplePacketCreator.makerEnableActions());
+ break;
+
+ case 5: // inventory full
+ c.announce(MaplePacketCreator.serverNotice(1, "Your inventory is full."));
+ c.announce(MaplePacketCreator.makerEnableActions());
break;
default:
- if (MapleInventoryManipulator.checkSpace(c, toCreate, (short) recipe.getRewardAmount(), "")) {
+ if(toDisassemble != -1) {
+ MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.EQUIP, (short) pos, (short) 1, false);
+ } else {
for (Pair p : recipe.getReqItems()) {
- c.getAbstractPlayerInteraction().gainItem(p.getLeft(), (short) -p.getRight());
+ c.getAbstractPlayerInteraction().gainItem(p.getLeft(), (short) -p.getRight(), false);
}
+ }
- if(toDisassemble != -1) {
- MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.EQUIP, (short) pos, (short) 1, false);
- c.announce(MaplePacketCreator.getShowItemGain(toDisassemble, (short) -1, true));
- }
-
- int cost = recipe.getCost();
- if(stimulantid == -1 && reagentids.isEmpty()) {
- if(cost > 0) c.getPlayer().gainMeso(-cost);
-
+ int cost = recipe.getCost();
+ if(stimulantid == -1 && reagentids.isEmpty()) {
+ if(cost > 0) c.getPlayer().gainMeso(-cost, false);
+
+ for (Pair p : recipe.getGainItems()) {
c.getPlayer().setCS(true);
- c.getAbstractPlayerInteraction().gainItem(toCreate, (short) recipe.getRewardAmount());
+ c.getAbstractPlayerInteraction().gainItem(p.getLeft(), p.getRight().shortValue(), false);
c.getPlayer().setCS(false);
- } else {
- if(stimulantid != -1) c.getAbstractPlayerInteraction().gainItem(stimulantid, (short) -1);
- if(!reagentids.isEmpty()) {
- for(Map.Entry r : reagentids.entrySet()) {
- c.getAbstractPlayerInteraction().gainItem(r.getKey(), (short) (-1 * r.getValue()));
- }
- }
-
- if(cost > 0) c.getPlayer().gainMeso(-cost);
- makerSucceeded = addBoostedMakerItem(c, toCreate, stimulantid, reagentids);
- }
-
- if(makerSucceeded) c.announce(MaplePacketCreator.serverNotice(1, "You have successfully created " + recipe.getRewardAmount() + " " + ii.getName(toCreate) + "."));
- else c.getPlayer().dropMessage(5, "The Maker skill lights up, but the skill winds up as if nothing happened.");
-
- c.announce(MaplePacketCreator.showMakerEffect(makerSucceeded));
- c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showForeignMakerEffect(c.getPlayer().getId(), makerSucceeded), false);
-
- if(toCreate == 4260003 && type == 3 && c.getPlayer().getQuestStatus(6033) == 1) {
- c.getAbstractPlayerInteraction().setQuestProgress(6033, 1);
}
} else {
- c.announce(MaplePacketCreator.serverNotice(1, "Your inventory is full."));
+ toCreate = recipe.getGainItems().get(0).getLeft();
+
+ if(stimulantid != -1) c.getAbstractPlayerInteraction().gainItem(stimulantid, (short) -1, false);
+ if(!reagentids.isEmpty()) {
+ for(Map.Entry r : reagentids.entrySet()) {
+ c.getAbstractPlayerInteraction().gainItem(r.getKey(), (short) (-1 * r.getValue()), false);
+ }
+ }
+
+ if(cost > 0) c.getPlayer().gainMeso(-cost, false);
+ makerSucceeded = addBoostedMakerItem(c, toCreate, stimulantid, reagentids);
+ }
+
+ // thanks inhyuk for noticing missing MAKER_RESULT packets
+ if (type == 3) {
+ c.announce(MaplePacketCreator.makerResultCrystal(recipe.getGainItems().get(0).getLeft(), recipe.getReqItems().get(0).getLeft()));
+ } else if (type == 4) {
+ c.announce(MaplePacketCreator.makerResultDesynth(recipe.getReqItems().get(0).getLeft(), recipe.getCost(), recipe.getGainItems()));
+ } else {
+ c.announce(MaplePacketCreator.makerResult(makerSucceeded, recipe.getGainItems().get(0).getLeft(), recipe.getGainItems().get(0).getRight(), recipe.getCost(), recipe.getReqItems(), stimulantid, new LinkedList<>(reagentids.keySet())));
+ }
+
+ c.announce(MaplePacketCreator.showMakerEffect(makerSucceeded));
+ c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showForeignMakerEffect(c.getPlayer().getId(), makerSucceeded), false);
+
+ if(toCreate == 4260003 && type == 3 && c.getPlayer().getQuestStatus(6033) == 1) {
+ c.getAbstractPlayerInteraction().setQuestProgress(6033, 1);
}
}
} finally {
@@ -218,7 +238,7 @@ public class MakerProcessor {
Map reagentType = new LinkedHashMap<>();
List toRemove = new LinkedList<>();
- boolean isWeapon = ItemConstants.isWeapon(toCreate) || ServerConstants.USE_MAKER_PERMISSIVE_ATKUP; // thanks Vcoc for finding a case where a weapon wouldn't be counted as such due to a bounding on isWeapon
+ boolean isWeapon = ItemConstants.isWeapon(toCreate) || YamlConfig.config.server.USE_MAKER_PERMISSIVE_ATKUP; // thanks Vcoc for finding a case where a weapon wouldn't be counted as such due to a bounding on isWeapon
for(Map.Entry r : reagentids.entrySet()) {
int curRid = r.getKey();
@@ -271,12 +291,12 @@ public class MakerProcessor {
}
}
- private static Pair generateDisassemblyInfo(int itemId) {
+ private static Pair>> generateDisassemblyInfo(int itemId) {
int recvFee = ii.getMakerDisassembledFee(itemId);
if(recvFee > -1) {
- int recvQty = ii.getMakerDisassembledQuantity(itemId);
- if(recvQty > 0) {
- return new Pair<>(recvFee, recvQty);
+ List> gains = ii.getMakerDisassembledItems(itemId);
+ if(!gains.isEmpty()) {
+ return new Pair<>(recvFee, gains);
}
}
@@ -287,7 +307,7 @@ public class MakerProcessor {
return chr.getSkillLevel((chr.getJob().getId() / 1000) * 10000000 + 1007);
}
- private static short getCreateStatus(MapleClient c, MakerItemFactory.MakerItemCreateEntry recipe) {
+ private static short getCreateStatus(MapleClient c, MakerItemCreateEntry recipe) {
if(recipe == null) {
return -1;
}
@@ -308,10 +328,29 @@ public class MakerProcessor {
return 4;
}
+ List addItemids = new LinkedList<>();
+ List addQuantity = new LinkedList<>();
+ List rmvItemids = new LinkedList<>();
+ List rmvQuantity = new LinkedList<>();
+
+ for (Pair p : recipe.getReqItems()) {
+ rmvItemids.add(p.getLeft());
+ rmvQuantity.add(p.getRight());
+ }
+
+ for (Pair p : recipe.getGainItems()) {
+ addItemids.add(p.getLeft());
+ addQuantity.add(p.getRight());
+ }
+
+ if (!c.getAbstractPlayerInteraction().canHoldAllAfterRemoving(addItemids, addQuantity, rmvItemids, rmvQuantity)) {
+ return 5;
+ }
+
return 0;
}
- private static boolean hasItems(MapleClient c, MakerItemFactory.MakerItemCreateEntry recipe) {
+ private static boolean hasItems(MapleClient c, MakerItemCreateEntry recipe) {
for (Pair p : recipe.getReqItems()) {
int itemId = p.getLeft();
if (c.getPlayer().getInventory(ItemConstants.getInventoryType(itemId)).countById(itemId) < p.getRight()) {
@@ -332,8 +371,8 @@ public class MakerProcessor {
Equip eqp = (Equip)item;
if(ItemConstants.isAccessory(item.getItemId()) && eqp.getUpgradeSlots() <= 0) eqp.setUpgradeSlots(3);
- if(ServerConstants.USE_ENHANCED_CRAFTING == true) {
- if(!(c.getPlayer().isGM() && ServerConstants.USE_PERFECT_GM_SCROLL)) {
+ if(YamlConfig.config.server.USE_ENHANCED_CRAFTING == true) {
+ if(!(c.getPlayer().isGM() && YamlConfig.config.server.USE_PERFECT_GM_SCROLL)) {
eqp.setUpgradeSlots((byte)(eqp.getUpgradeSlots() + 1));
}
item = MapleItemInformationProvider.getInstance().scrollEquipWithId(eqp, 2049100, true, 2049100, c.getPlayer().isGM());
@@ -397,7 +436,6 @@ public class MakerProcessor {
}
MapleInventoryManipulator.addFromDrop(c, item, false, -1);
- c.announce(MaplePacketCreator.getShowItemGain(itemid, (short) 1, true));
return true;
}
}
diff --git a/src/client/processor/action/PetAutopotProcessor.java b/src/client/processor/action/PetAutopotProcessor.java
new file mode 100644
index 0000000000..0bb2c79c30
--- /dev/null
+++ b/src/client/processor/action/PetAutopotProcessor.java
@@ -0,0 +1,190 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 Patrick Huy
+ Matthias Butz
+ Jan Christian Meyer
+
+ Copyleft (L) 2016 - 2019 RonanLana (HeavenMS)
+
+ 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 client.processor.action;
+
+import client.MapleCharacter;
+import client.MapleClient;
+import client.inventory.Item;
+import client.inventory.MapleInventory;
+import client.inventory.MapleInventoryType;
+import client.inventory.manipulator.MapleInventoryManipulator;
+import config.YamlConfig;
+import java.util.List;
+import server.MapleItemInformationProvider;
+import server.MapleStatEffect;
+import tools.MaplePacketCreator;
+
+/**
+ *
+ * @author Ronan - multi-pot consumption feature
+ */
+public class PetAutopotProcessor {
+
+ private static class AutopotAction {
+
+ private MapleClient c;
+ private short slot;
+ private int itemId;
+
+ private Item toUse;
+ private List
- toUseList;
+
+ private boolean hasHpGain, hasMpGain;
+ private int maxHp, maxMp, curHp, curMp;
+ private double incHp, incMp;
+
+ private boolean cursorOnNextAvailablePot(MapleCharacter chr) {
+ if(toUseList == null) {
+ toUseList = chr.getInventory(MapleInventoryType.USE).linkedListById(itemId);
+ }
+
+ toUse = null;
+ while(!toUseList.isEmpty()) {
+ Item it = toUseList.remove(0);
+
+ if(it.getQuantity() > 0) {
+ toUse = it;
+ slot = it.getPosition();
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public AutopotAction(MapleClient c, short slot, int itemId) {
+ this.c = c;
+ this.slot = slot;
+ this.itemId = itemId;
+ }
+
+ public void run() {
+ MapleClient c = this.c;
+ MapleCharacter chr = c.getPlayer();
+ if (!chr.isAlive()) {
+ c.announce(MaplePacketCreator.enableActions());
+ return;
+ }
+
+ int useCount = 0, qtyCount = 0;
+ MapleStatEffect stat = null;
+
+ maxHp = chr.getCurrentMaxHp();
+ maxMp = chr.getCurrentMaxMp();
+
+ curHp = chr.getHp();
+ curMp = chr.getMp();
+
+ MapleInventory useInv = chr.getInventory(MapleInventoryType.USE);
+ useInv.lockInventory();
+ try {
+ toUse = useInv.getItem(slot);
+ if (toUse != null) {
+ if (toUse.getItemId() != itemId) {
+ c.announce(MaplePacketCreator.enableActions());
+ return;
+ }
+
+ toUseList = null;
+
+ // from now on, toUse becomes the "cursor" for the current pot being used
+ if (toUse.getQuantity() <= 0) {
+ if (!cursorOnNextAvailablePot(chr)) {
+ c.announce(MaplePacketCreator.enableActions());
+ return;
+ }
+ }
+
+ stat = MapleItemInformationProvider.getInstance().getItemEffect(toUse.getItemId());
+ hasHpGain = stat.getHp() > 0 || stat.getHpRate() > 0.0;
+ hasMpGain = stat.getMp() > 0 || stat.getMpRate() > 0.0;
+
+ incHp = stat.getHp();
+ if(incHp <= 0 && hasHpGain) incHp = Math.ceil(maxHp * stat.getHpRate());
+
+ incMp = stat.getMp();
+ if(incMp <= 0 && hasMpGain) incMp = Math.ceil(maxMp * stat.getMpRate());
+
+ if (YamlConfig.config.server.USE_COMPULSORY_AUTOPOT) {
+ if (hasHpGain) {
+ double hpRatio = (YamlConfig.config.server.PET_AUTOHP_RATIO * maxHp) - curHp;
+ if (hpRatio > 0.0) {
+ qtyCount = (int) Math.ceil(hpRatio / incHp);
+ }
+ }
+
+ if (hasMpGain) {
+ double mpRatio = ((YamlConfig.config.server.PET_AUTOMP_RATIO * maxMp) - curMp);
+ if (mpRatio > 0.0) {
+ qtyCount = Math.max(qtyCount, (int) Math.ceil(mpRatio / incMp));
+ }
+ }
+
+ if (qtyCount < 0) { // thanks Flint, Kevs for noticing an issue where negative counts were getting achieved
+ qtyCount = 0;
+ }
+ } else {
+ qtyCount = 1; // non-compulsory autopot concept thanks to marcuswoon
+ }
+
+ while (true) {
+ short qtyToUse = (short) Math.min(qtyCount, toUse.getQuantity());
+ MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.USE, slot, qtyToUse, false);
+
+ curHp += (incHp * qtyToUse);
+ curMp += (incMp * qtyToUse);
+
+ useCount += qtyToUse;
+ qtyCount -= qtyToUse;
+
+ if(toUse.getQuantity() == 0 && qtyCount > 0) {
+ // depleted out the current slot, fetch for more
+
+ if(!cursorOnNextAvailablePot(chr)) {
+ break; // no more pots available
+ }
+ } else {
+ break; // gracefully finished it's job, quit the loop
+ }
+ }
+ }
+ } finally {
+ useInv.unlockInventory();
+ }
+
+ if (stat != null) {
+ for (int i = 0; i < useCount; i++) {
+ stat.applyTo(chr);
+ }
+ }
+
+ chr.announce(MaplePacketCreator.enableActions());
+ }
+ }
+
+ public static void runAutopotAction(MapleClient c, short slot, int itemid) {
+ AutopotAction action = new AutopotAction(c, slot, itemid);
+ action.run();
+ }
+
+}
diff --git a/src/client/processor/SpawnPetProcessor.java b/src/client/processor/action/SpawnPetProcessor.java
similarity index 98%
rename from src/client/processor/SpawnPetProcessor.java
rename to src/client/processor/action/SpawnPetProcessor.java
index f3d12966c8..c8c74dcf86 100644
--- a/src/client/processor/SpawnPetProcessor.java
+++ b/src/client/processor/action/SpawnPetProcessor.java
@@ -17,7 +17,7 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
-package client.processor;
+package client.processor.action;
import client.MapleCharacter;
import java.awt.Point;
@@ -62,7 +62,7 @@ public class SpawnPetProcessor {
long expiration = chr.getInventory(MapleInventoryType.CASH).getItem(slot).getExpiration();
MapleInventoryManipulator.removeById(c, MapleInventoryType.CASH, petid, (short) 1, false, false);
MapleInventoryManipulator.addById(c, evolveid, (short) 1, null, petId, expiration);
- MaplePet.deleteFromDb(chr, petid);
+
c.announce(MaplePacketCreator.enableActions());
return;
}
diff --git a/src/client/processor/DueyProcessor.java b/src/client/processor/npc/DueyProcessor.java
similarity index 82%
rename from src/client/processor/DueyProcessor.java
rename to src/client/processor/npc/DueyProcessor.java
index 230e5927f6..0cc17d4636 100644
--- a/src/client/processor/DueyProcessor.java
+++ b/src/client/processor/npc/DueyProcessor.java
@@ -21,7 +21,7 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
-package client.processor;
+package client.processor.npc;
import client.MapleCharacter;
import client.MapleClient;
@@ -32,13 +32,14 @@ import client.inventory.MapleInventory;
import client.inventory.MapleInventoryType;
import client.inventory.manipulator.MapleInventoryManipulator;
import client.inventory.manipulator.MapleKarmaManipulator;
-import constants.ItemConstants;
-import constants.ServerConstants;
+import config.YamlConfig;
+import constants.inventory.ItemConstants;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
+import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Collections;
import java.util.LinkedList;
@@ -59,6 +60,7 @@ import tools.Pair;
public class DueyProcessor {
public enum Actions {
+ TOSERVER_RECV_ITEM(0x00),
TOSERVER_SEND_ITEM(0x02),
TOSERVER_CLAIM_PACKAGE(0x04),
TOSERVER_REMOVE_PACKAGE(0x05),
@@ -112,19 +114,6 @@ public class DueyProcessor {
return null;
}
- private static String getCurrentDate() {
- String date = "";
- Calendar cal = Calendar.getInstance();
- int day = cal.get(Calendar.DATE) - 1; // instant duey ?
- int month = cal.get(Calendar.MONTH) + 1; // its an array of months.
- int year = cal.get(Calendar.YEAR);
- date += day <= 9 ? "0" + day + "-" : "" + day + "-";
- date += month <= 9 ? "0" + month + "-" : "" + month + "-";
- date += year;
-
- return date;
- }
-
private static void showDueyNotification(MapleClient c, MapleCharacter player) {
Connection con = null;
PreparedStatement ps = null;
@@ -132,7 +121,7 @@ public class DueyProcessor {
ResultSet rs = null;
try {
con = DatabaseConnection.getConnection();
- ps = con.prepareStatement("SELECT Mesos FROM dueypackages WHERE ReceiverId = ? and Checked = 1");
+ ps = con.prepareStatement("SELECT SenderName, Type FROM dueypackages WHERE ReceiverId = ? AND Checked = 1 ORDER BY Type DESC");
ps.setInt(1, player.getId());
rs = ps.executeQuery();
if (rs.next()) {
@@ -143,11 +132,11 @@ public class DueyProcessor {
pss.executeUpdate();
pss.close();
con2.close();
+
+ c.announce(MaplePacketCreator.sendDueyParcelReceived(rs.getString("SenderName"), rs.getInt("Type") == 1));
} catch (SQLException e) {
e.printStackTrace();
}
-
- c.announce(MaplePacketCreator.sendDueyNotification(false));
}
} catch (SQLException e) {
e.printStackTrace();
@@ -207,7 +196,7 @@ public class DueyProcessor {
dueypack.setSender(rs.getString("SenderName"));
dueypack.setMesos(rs.getInt("Mesos"));
- dueypack.setSentTime(rs.getString("TimeStamp"));
+ dueypack.setSentTime(rs.getTimestamp("TimeStamp"), rs.getBoolean("Type"));
dueypack.setMessage(rs.getString("Message"));
return dueypack;
@@ -241,7 +230,7 @@ public class DueyProcessor {
return packages;
}
- private static int createPackage(int mesos, String message, String sender, int toCid) {
+ private static int createPackage(int mesos, String message, String sender, int toCid, boolean quick) {
try {
Connection con = null;
PreparedStatement ps = null;
@@ -249,16 +238,17 @@ public class DueyProcessor {
try {
con = DatabaseConnection.getConnection();
- ps = con.prepareStatement("INSERT INTO `dueypackages` (ReceiverId, SenderName, Mesos, TimeStamp, Message, Checked) VALUES (?, ?, ?, ?, ?, 1)", Statement.RETURN_GENERATED_KEYS);
+ ps = con.prepareStatement("INSERT INTO `dueypackages` (ReceiverId, SenderName, Mesos, TimeStamp, Message, Type, Checked) VALUES (?, ?, ?, ?, ?, ?, 1)", Statement.RETURN_GENERATED_KEYS);
ps.setInt(1, toCid);
ps.setString(2, sender);
ps.setInt(3, mesos);
- ps.setString(4, getCurrentDate());
+ ps.setTimestamp(4, new Timestamp(System.currentTimeMillis()));
ps.setString(5, message);
+ ps.setInt(6, quick ? 1 : 0);
int updateRows = ps.executeUpdate();
if (updateRows < 1) {
- FilePrinter.printError(FilePrinter.INSERT_CHAR, "Error trying to create package [mesos: " + mesos + ", " + sender + ", to CharacterId: " + toCid + "]");
+ FilePrinter.printError(FilePrinter.INSERT_CHAR, "Error trying to create package [mesos: " + mesos + ", " + sender + ", quick: " + quick + ", to CharacterId: " + toCid + "]");
return -1;
}
@@ -267,7 +257,7 @@ public class DueyProcessor {
if (rs.next()) {
packageId = rs.getInt(1);
} else {
- FilePrinter.printError(FilePrinter.INSERT_CHAR, "Failed inserting package [mesos: " + mesos + ", " + sender + ", to CharacterId: " + toCid + "]");
+ FilePrinter.printError(FilePrinter.INSERT_CHAR, "Failed inserting package [mesos: " + mesos + ", " + sender + ", quick: " + quick + ", to CharacterId: " + toCid + "]");
return -1;
}
@@ -348,10 +338,18 @@ public class DueyProcessor {
return 0;
}
- public static void dueySendItem(MapleClient c, byte invTypeId, short itemPos, short amount, int sendMesos, String sendMessage, String recipient) {
+ public static void dueySendItem(MapleClient c, byte invTypeId, short itemPos, short amount, int sendMesos, String sendMessage, String recipient, boolean quick) {
if (c.tryacquireClient()) {
try {
- final int fee = 5000 + MapleTrade.getFee(sendMesos);
+ int fee = MapleTrade.getFee(sendMesos);
+ if (!quick) {
+ fee += 5000;
+ } else if (!c.getPlayer().haveItem(5330000)) {
+ AutobanFactory.PACKET_EDIT.alert(c.getPlayer(), c.getPlayer().getName() + " tried to packet edit with Quick Delivery on duey.");
+ FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to use duey with Quick Delivery, mesos " + sendMesos + " and amount " + amount);
+ c.disconnect(true, false);
+ return;
+ }
long finalcost = (long) sendMesos + fee;
if (finalcost < 0 || finalcost > Integer.MAX_VALUE || (amount < 1 && sendMesos == 0)) {
@@ -385,7 +383,11 @@ public class DueyProcessor {
return;
}
- int packageId = createPackage(sendMesos, sendMessage, c.getPlayer().getName(), recipientCid);
+ if (quick) {
+ MapleInventoryManipulator.removeById(c, MapleInventoryType.CASH, 5330000, (short) 1, false, false);
+ }
+
+ int packageId = createPackage(sendMesos, sendMessage, c.getPlayer().getName(), recipientCid, quick);
if (packageId == -1) {
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_ENABLE_ACTIONS.getCode()));
return;
@@ -451,11 +453,16 @@ public class DueyProcessor {
}
con.close();
- if(dp == null) {
+ if (dp == null) {
c.announce(MaplePacketCreator.sendDueyMSG(Actions.TOCLIENT_RECV_UNKNOWN_ERROR.getCode()));
FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to receive package from duey with id " + packageId);
return;
}
+
+ if (dp.isDeliveringTime()) {
+ c.announce(MaplePacketCreator.sendDueyMSG(Actions.TOCLIENT_RECV_UNKNOWN_ERROR.getCode()));
+ return;
+ }
Item dpItem = dp.getItem();
if (dpItem != null) {
@@ -490,10 +497,21 @@ public class DueyProcessor {
}
}
- public static void dueySendTalk(MapleClient c) {
+ public static void dueySendTalk(MapleClient c, boolean quickDelivery) {
if (c.tryacquireClient()) {
try {
- c.announce(MaplePacketCreator.sendDuey((byte) 8, loadPackages(c.getPlayer())));
+ long timeNow = System.currentTimeMillis();
+ if(timeNow - c.getPlayer().getNpcCooldown() < YamlConfig.config.server.BLOCK_NPC_RACE_CONDT) {
+ c.announce(MaplePacketCreator.enableActions());
+ return;
+ }
+ c.getPlayer().setNpcCooldown(timeNow);
+
+ if (quickDelivery) {
+ c.announce(MaplePacketCreator.sendDuey(0x1A, null));
+ } else {
+ c.announce(MaplePacketCreator.sendDuey(0x8, loadPackages(c.getPlayer())));
+ }
} finally {
c.releaseClient();
}
@@ -501,9 +519,43 @@ public class DueyProcessor {
}
public static void dueyCreatePackage(Item item, int mesos, String sender, int recipientCid) {
- int packageId = createPackage(mesos, "", sender, recipientCid);
+ int packageId = createPackage(mesos, null, sender, recipientCid, false);
if (packageId != -1) {
insertPackageItem(packageId, item);
}
}
+
+ public static void runDueyExpireSchedule() {
+ try {
+ Calendar c = Calendar.getInstance();
+ c.add(Calendar.DATE, -30);
+
+ Timestamp ts = new Timestamp(c.getTime().getTime());
+
+ Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("SELECT `PackageId` FROM dueypackages WHERE `TimeStamp` < ?");
+ ps.setTimestamp(1, ts);
+
+ List toRemove = new LinkedList<>();
+ try (ResultSet rs = ps.executeQuery()) {
+ while (rs.next()) {
+ toRemove.add(rs.getInt("PackageId"));
+ }
+ }
+ ps.close();
+
+ for (Integer pid : toRemove) {
+ removePackageFromDB(pid);
+ }
+
+ ps = con.prepareStatement("DELETE FROM dueypackages WHERE `TimeStamp` < ?");
+ ps.setTimestamp(1, ts);
+ ps.executeUpdate();
+ ps.close();
+
+ con.close();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
}
diff --git a/src/client/processor/FredrickProcessor.java b/src/client/processor/npc/FredrickProcessor.java
similarity index 99%
rename from src/client/processor/FredrickProcessor.java
rename to src/client/processor/npc/FredrickProcessor.java
index e359949b6b..3b807b6552 100644
--- a/src/client/processor/FredrickProcessor.java
+++ b/src/client/processor/npc/FredrickProcessor.java
@@ -21,7 +21,7 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
-package client.processor;
+package client.processor.npc;
import client.MapleCharacter;
import client.MapleClient;
@@ -37,7 +37,6 @@ import java.sql.Timestamp;
import java.util.LinkedList;
import java.util.List;
import client.inventory.manipulator.MapleInventoryManipulator;
-import constants.ServerConstants;
import java.util.Collections;
import net.server.Server;
import net.server.world.World;
diff --git a/src/client/processor/StorageProcessor.java b/src/client/processor/npc/StorageProcessor.java
similarity index 85%
rename from src/client/processor/StorageProcessor.java
rename to src/client/processor/npc/StorageProcessor.java
index b2f5f4aa0e..8251c9791c 100644
--- a/src/client/processor/StorageProcessor.java
+++ b/src/client/processor/npc/StorageProcessor.java
@@ -19,7 +19,7 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
-package client.processor;
+package client.processor.npc;
import client.MapleClient;
import client.MapleCharacter;
@@ -28,8 +28,8 @@ import client.inventory.Item;
import client.inventory.MapleInventory;
import client.inventory.MapleInventoryType;
import client.inventory.manipulator.MapleKarmaManipulator;
-import constants.ItemConstants;
-import constants.ServerConstants;
+import config.YamlConfig;
+import constants.inventory.ItemConstants;
import client.inventory.manipulator.MapleInventoryManipulator;
import server.MapleItemInformationProvider;
import server.MapleStorage;
@@ -45,6 +45,7 @@ import tools.data.input.SeekableLittleEndianAccessor;
public class StorageProcessor {
public static void storageAction(SeekableLittleEndianAccessor slea, MapleClient c) {
+ MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
MapleCharacter chr = c.getPlayer();
MapleStorage storage = chr.getStorage();
byte mode = slea.readByte();
@@ -69,7 +70,7 @@ public class StorageProcessor {
slot = storage.getSlot(MapleInventoryType.getByType(type), slot);
Item item = storage.getItem(slot);
if (item != null) {
- if (MapleItemInformationProvider.getInstance().isPickupRestricted(item.getItemId()) && chr.haveItemWithId(item.getItemId(), true)) {
+ if (ii.isPickupRestricted(item.getItemId()) && chr.haveItemWithId(item.getItemId(), true)) {
c.announce(MaplePacketCreator.getStorageError((byte) 0x0C));
return;
}
@@ -83,13 +84,20 @@ public class StorageProcessor {
}
if (MapleInventoryManipulator.checkSpace(c, item.getItemId(), item.getQuantity(), item.getOwner())) {
- item = storage.takeOut(slot);//actually the same but idc
- String itemName = MapleItemInformationProvider.getInstance().getName(item.getItemId());
- FilePrinter.print(FilePrinter.STORAGE + c.getAccountName() + ".txt", c.getPlayer().getName() + " took out " + item.getQuantity() + " " + itemName + " (" + item.getItemId() + ")");
- chr.setUsedStorage();
- MapleKarmaManipulator.toggleKarmaFlagToUntradeable(item);
- MapleInventoryManipulator.addFromDrop(c, item, false);
- storage.sendTakenOut(c, item.getInventoryType());
+ if (storage.takeOut(item)) {
+ chr.setUsedStorage();
+
+ MapleKarmaManipulator.toggleKarmaFlagToUntradeable(item);
+ MapleInventoryManipulator.addFromDrop(c, item, false);
+
+ String itemName = ii.getName(item.getItemId());
+ FilePrinter.print(FilePrinter.STORAGE + c.getAccountName() + ".txt", c.getPlayer().getName() + " took out " + item.getQuantity() + " " + itemName + " (" + item.getItemId() + ")");
+
+ storage.sendTakenOut(c, item.getInventoryType());
+ } else {
+ c.announce(MaplePacketCreator.enableActions());
+ return;
+ }
} else {
c.announce(MaplePacketCreator.getStorageError((byte) 0x0A));
}
@@ -149,14 +157,17 @@ public class StorageProcessor {
MapleKarmaManipulator.toggleKarmaFlagToUntradeable(item);
item.setQuantity(quantity);
- storage.store(item);
- storage.sendStored(c, ItemConstants.getInventoryType(itemId));
- String itemName = MapleItemInformationProvider.getInstance().getName(item.getItemId());
- FilePrinter.print(FilePrinter.STORAGE + c.getAccountName() + ".txt", c.getPlayer().getName() + " stored " + item.getQuantity() + " " + itemName + " (" + item.getItemId() + ")");
+
+ storage.store(item); // inside a critical section, "!(storage.isFull())" is still in effect...
chr.setUsedStorage();
+
+ String itemName = ii.getName(item.getItemId());
+ FilePrinter.print(FilePrinter.STORAGE + c.getAccountName() + ".txt", c.getPlayer().getName() + " stored " + item.getQuantity() + " " + itemName + " (" + item.getItemId() + ")");
+
+ storage.sendStored(c, ItemConstants.getInventoryType(itemId));
}
} else if (mode == 6) { // arrange items
- if(ServerConstants.USE_STORAGE_ITEM_SORT) storage.arrangeItems(c);
+ if(YamlConfig.config.server.USE_STORAGE_ITEM_SORT) storage.arrangeItems(c);
c.announce(MaplePacketCreator.enableActions());
} else if (mode == 7) { // meso
int meso = slea.readInt();
@@ -178,14 +189,14 @@ public class StorageProcessor {
}
storage.setMeso(storageMesos - meso);
chr.gainMeso(meso, false, true, false);
- FilePrinter.print(FilePrinter.STORAGE + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + (meso > 0 ? " took out " : " stored ") + Math.abs(meso) + " mesos");
chr.setUsedStorage();
+ FilePrinter.print(FilePrinter.STORAGE + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + (meso > 0 ? " took out " : " stored ") + Math.abs(meso) + " mesos");
+ storage.sendMeso(c);
} else {
c.announce(MaplePacketCreator.enableActions());
return;
}
- storage.sendMeso(c);
- } else if (mode == 8) {// close
+ } else if (mode == 8) {// close... unless the player decides to enter cash shop!
storage.close();
}
} finally {
diff --git a/src/client/processor/AssignAPProcessor.java b/src/client/processor/stat/AssignAPProcessor.java
similarity index 91%
rename from src/client/processor/AssignAPProcessor.java
rename to src/client/processor/stat/AssignAPProcessor.java
index 74390eb1bc..3c2edb6fd8 100644
--- a/src/client/processor/AssignAPProcessor.java
+++ b/src/client/processor/stat/AssignAPProcessor.java
@@ -21,7 +21,7 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
-package client.processor;
+package client.processor.stat;
import client.MapleCharacter;
import client.MapleClient;
@@ -33,11 +33,12 @@ import client.autoban.AutobanFactory;
import client.inventory.Equip;
import client.inventory.Item;
import client.inventory.MapleInventoryType;
-import constants.ServerConstants;
+import config.YamlConfig;
import constants.skills.BlazeWizard;
import constants.skills.Brawler;
import constants.skills.DawnWarrior;
import constants.skills.Magician;
+import constants.skills.ThunderBreaker;
import constants.skills.Warrior;
import java.util.ArrayList;
import java.util.Collection;
@@ -69,7 +70,7 @@ public class AssignAPProcessor {
int remainingAp = chr.getRemainingAp();
slea.skip(8);
- if(ServerConstants.USE_SERVER_AUTOASSIGNER) {
+ if(YamlConfig.config.server.USE_SERVER_AUTOASSIGNER) {
// --------- Ronan Lana's AUTOASSIGNER ---------
// This method excels for assigning APs in such a way to cover all equipments AP requirements.
byte opt = slea.readByte(); // useful for pirate autoassigning
@@ -134,7 +135,7 @@ public class AssignAPProcessor {
luk = scStat;
str = 0; dex = 0;
- if(ServerConstants.USE_AUTOASSIGN_SECONDARY_CAP && luk + chr.getLuk() > CAP) {
+ if(YamlConfig.config.server.USE_AUTOASSIGN_SECONDARY_CAP && luk + chr.getLuk() > CAP) {
temp = luk + chr.getLuk() - CAP;
scStat -= temp;
prStat += temp;
@@ -160,7 +161,7 @@ public class AssignAPProcessor {
str = scStat;
int_ = 0; luk = 0;
- if(ServerConstants.USE_AUTOASSIGN_SECONDARY_CAP && str + chr.getStr() > CAP) {
+ if(YamlConfig.config.server.USE_AUTOASSIGN_SECONDARY_CAP && str + chr.getStr() > CAP) {
temp = str + chr.getStr() - CAP;
scStat -= temp;
prStat += temp;
@@ -186,7 +187,7 @@ public class AssignAPProcessor {
str = scStat;
int_ = 0; luk = 0;
- if(ServerConstants.USE_AUTOASSIGN_SECONDARY_CAP && str + chr.getStr() > CAP) {
+ if(YamlConfig.config.server.USE_AUTOASSIGN_SECONDARY_CAP && str + chr.getStr() > CAP) {
temp = str + chr.getStr() - CAP;
scStat -= temp;
prStat += temp;
@@ -240,12 +241,12 @@ public class AssignAPProcessor {
str = trStat;
int_ = 0;
- if(ServerConstants.USE_AUTOASSIGN_SECONDARY_CAP && dex + chr.getDex() > CAP) {
+ if(YamlConfig.config.server.USE_AUTOASSIGN_SECONDARY_CAP && dex + chr.getDex() > CAP) {
temp = dex + chr.getDex() - CAP;
scStat -= temp;
prStat += temp;
}
- if(ServerConstants.USE_AUTOASSIGN_SECONDARY_CAP && str + chr.getStr() > CAP) {
+ if(YamlConfig.config.server.USE_AUTOASSIGN_SECONDARY_CAP && str + chr.getStr() > CAP) {
temp = str + chr.getStr() - CAP;
trStat -= temp;
prStat += temp;
@@ -312,7 +313,7 @@ public class AssignAPProcessor {
dex = scStat;
int_ = 0; luk = 0;
- if(ServerConstants.USE_AUTOASSIGN_SECONDARY_CAP && dex + chr.getDex() > CAP) {
+ if(YamlConfig.config.server.USE_AUTOASSIGN_SECONDARY_CAP && dex + chr.getDex() > CAP) {
temp = dex + chr.getDex() - CAP;
scStat -= temp;
prStat += temp;
@@ -347,14 +348,7 @@ public class AssignAPProcessor {
if(slea.available() < 16) {
AutobanFactory.PACKET_EDIT.alert(chr, "Didn't send full packet for Auto Assign.");
- final MapleClient client = c;
- ThreadManager.getInstance().newTask(new Runnable() {
- @Override
- public void run() {
- client.disconnect(false, false);
- }
- });
-
+ c.disconnect(true, false);
return;
}
@@ -386,44 +380,44 @@ public class AssignAPProcessor {
int newVal = 0;
if (type.equals(MapleStat.STR)) {
newVal = statUpdate[0] + gain;
- if (newVal > ServerConstants.MAX_AP) {
- statGain[0] += (gain - (newVal - ServerConstants.MAX_AP));
- statUpdate[0] = ServerConstants.MAX_AP;
+ if (newVal > YamlConfig.config.server.MAX_AP) {
+ statGain[0] += (gain - (newVal - YamlConfig.config.server.MAX_AP));
+ statUpdate[0] = YamlConfig.config.server.MAX_AP;
} else {
statGain[0] += gain;
statUpdate[0] = newVal;
}
} else if (type.equals(MapleStat.INT)) {
newVal = statUpdate[3] + gain;
- if (newVal > ServerConstants.MAX_AP) {
- statGain[3] += (gain - (newVal - ServerConstants.MAX_AP));
- statUpdate[3] = ServerConstants.MAX_AP;
+ if (newVal > YamlConfig.config.server.MAX_AP) {
+ statGain[3] += (gain - (newVal - YamlConfig.config.server.MAX_AP));
+ statUpdate[3] = YamlConfig.config.server.MAX_AP;
} else {
statGain[3] += gain;
statUpdate[3] = newVal;
}
} else if (type.equals(MapleStat.LUK)) {
newVal = statUpdate[2] + gain;
- if (newVal > ServerConstants.MAX_AP) {
- statGain[2] += (gain - (newVal - ServerConstants.MAX_AP));
- statUpdate[2] = ServerConstants.MAX_AP;
+ if (newVal > YamlConfig.config.server.MAX_AP) {
+ statGain[2] += (gain - (newVal - YamlConfig.config.server.MAX_AP));
+ statUpdate[2] = YamlConfig.config.server.MAX_AP;
} else {
statGain[2] += gain;
statUpdate[2] = newVal;
}
} else if (type.equals(MapleStat.DEX)) {
newVal = statUpdate[1] + gain;
- if (newVal > ServerConstants.MAX_AP) {
- statGain[1] += (gain - (newVal - ServerConstants.MAX_AP));
- statUpdate[1] = ServerConstants.MAX_AP;
+ if (newVal > YamlConfig.config.server.MAX_AP) {
+ statGain[1] += (gain - (newVal - YamlConfig.config.server.MAX_AP));
+ statUpdate[1] = YamlConfig.config.server.MAX_AP;
} else {
statGain[1] += gain;
statUpdate[1] = newVal;
}
}
- if (newVal > ServerConstants.MAX_AP) {
- return newVal - ServerConstants.MAX_AP;
+ if (newVal > YamlConfig.config.server.MAX_AP) {
+ return newVal - YamlConfig.config.server.MAX_AP;
}
return 0;
}
@@ -488,7 +482,7 @@ public class AssignAPProcessor {
}
break;
case 2048: // HP
- if(ServerConstants.USE_ENFORCE_HPMP_SWAP) {
+ if(YamlConfig.config.server.USE_ENFORCE_HPMP_SWAP) {
if (APTo != 8192) {
player.message("You can only swap HP ability points to MP.");
c.announce(MaplePacketCreator.enableActions());
@@ -513,13 +507,13 @@ public class AssignAPProcessor {
int curHp = player.getHp();
int hplose = -takeHp(player.getJob());
player.assignHP(hplose, -1);
- if (!ServerConstants.USE_FIXED_RATIO_HPMP_UPDATE) {
+ if (!YamlConfig.config.server.USE_FIXED_RATIO_HPMP_UPDATE) {
player.updateHp(Math.max(1, curHp + hplose));
}
break;
case 8192: // MP
- if(ServerConstants.USE_ENFORCE_HPMP_SWAP) {
+ if(YamlConfig.config.server.USE_ENFORCE_HPMP_SWAP) {
if (APTo != 2048) {
player.message("You can only swap MP ability points to HP.");
c.announce(MaplePacketCreator.enableActions());
@@ -557,7 +551,7 @@ public class AssignAPProcessor {
int curMp = player.getMp();
int mplose = -takeMp(job);
player.assignMP(mplose, -1);
- if (!ServerConstants.USE_FIXED_RATIO_HPMP_UPDATE) {
+ if (!YamlConfig.config.server.USE_FIXED_RATIO_HPMP_UPDATE) {
player.updateMp(Math.max(0, curMp + mplose));
}
break;
@@ -646,7 +640,7 @@ public class AssignAPProcessor {
MaxHP += increaseHP.getEffect(sLvl).getY();
}
- if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
+ if(YamlConfig.config.server.USE_RANDOMIZE_HPMP_GAIN) {
if (usedAPReset) {
MaxHP += 20;
} else {
@@ -656,7 +650,7 @@ public class AssignAPProcessor {
MaxHP += 20;
}
} else if(job.isA(MapleJob.ARAN1)) {
- if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
+ if(YamlConfig.config.server.USE_RANDOMIZE_HPMP_GAIN) {
if (usedAPReset) {
MaxHP += 20;
} else {
@@ -666,7 +660,7 @@ public class AssignAPProcessor {
MaxHP += 28;
}
} else if (job.isA(MapleJob.MAGICIAN) || job.isA(MapleJob.BLAZEWIZARD1)) {
- if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
+ if(YamlConfig.config.server.USE_RANDOMIZE_HPMP_GAIN) {
if (usedAPReset) {
MaxHP += 6;
} else {
@@ -676,7 +670,7 @@ public class AssignAPProcessor {
MaxHP += 6;
}
} else if (job.isA(MapleJob.THIEF) || job.isA(MapleJob.NIGHTWALKER1)) {
- if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
+ if(YamlConfig.config.server.USE_RANDOMIZE_HPMP_GAIN) {
if (usedAPReset) {
MaxHP += 16;
} else {
@@ -686,7 +680,7 @@ public class AssignAPProcessor {
MaxHP += 16;
}
} else if(job.isA(MapleJob.BOWMAN) || job.isA(MapleJob.WINDARCHER1)) {
- if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
+ if(YamlConfig.config.server.USE_RANDOMIZE_HPMP_GAIN) {
if (usedAPReset) {
MaxHP += 16;
} else {
@@ -697,14 +691,14 @@ public class AssignAPProcessor {
}
} else if (job.isA(MapleJob.PIRATE) || job.isA(MapleJob.THUNDERBREAKER1)) {
if(!usedAPReset) {
- Skill increaseHP = SkillFactory.getSkill(Brawler.IMPROVE_MAX_HP);
+ Skill increaseHP = SkillFactory.getSkill(job.isA(MapleJob.PIRATE) ? Brawler.IMPROVE_MAX_HP : ThunderBreaker.IMPROVE_MAX_HP);
int sLvl = player.getSkillLevel(increaseHP);
if(sLvl > 0)
MaxHP += increaseHP.getEffect(sLvl).getY();
}
- if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
+ if(YamlConfig.config.server.USE_RANDOMIZE_HPMP_GAIN) {
if (usedAPReset) {
MaxHP += 18;
} else {
@@ -716,7 +710,7 @@ public class AssignAPProcessor {
} else if (usedAPReset) {
MaxHP += 8;
} else {
- if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
+ if(YamlConfig.config.server.USE_RANDOMIZE_HPMP_GAIN) {
MaxHP += Randomizer.rand(8, 12);
} else {
MaxHP += 10;
@@ -731,7 +725,7 @@ public class AssignAPProcessor {
int MaxMP = 0;
if (job.isA(MapleJob.WARRIOR) || job.isA(MapleJob.DAWNWARRIOR1) || job.isA(MapleJob.ARAN1)) {
- if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
+ if(YamlConfig.config.server.USE_RANDOMIZE_HPMP_GAIN) {
if(!usedAPReset) {
MaxMP += (Randomizer.rand(2, 4) + (player.getInt() / 10));
} else {
@@ -749,7 +743,7 @@ public class AssignAPProcessor {
MaxMP += increaseMP.getEffect(sLvl).getY();
}
- if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
+ if(YamlConfig.config.server.USE_RANDOMIZE_HPMP_GAIN) {
if(!usedAPReset) {
MaxMP += (Randomizer.rand(12, 16) + (player.getInt() / 20));
} else {
@@ -759,7 +753,7 @@ public class AssignAPProcessor {
MaxMP += 18;
}
} else if (job.isA(MapleJob.BOWMAN) || job.isA(MapleJob.WINDARCHER1)) {
- if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
+ if(YamlConfig.config.server.USE_RANDOMIZE_HPMP_GAIN) {
if(!usedAPReset) {
MaxMP += (Randomizer.rand(6, 8) + (player.getInt() / 10));
} else {
@@ -769,7 +763,7 @@ public class AssignAPProcessor {
MaxMP += 10;
}
} else if(job.isA(MapleJob.THIEF) || job.isA(MapleJob.NIGHTWALKER1)) {
- if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
+ if(YamlConfig.config.server.USE_RANDOMIZE_HPMP_GAIN) {
if(!usedAPReset) {
MaxMP += (Randomizer.rand(6, 8) + (player.getInt() / 10));
} else {
@@ -779,7 +773,7 @@ public class AssignAPProcessor {
MaxMP += 10;
}
} else if (job.isA(MapleJob.PIRATE) || job.isA(MapleJob.THUNDERBREAKER1)) {
- if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
+ if(YamlConfig.config.server.USE_RANDOMIZE_HPMP_GAIN) {
if(!usedAPReset) {
MaxMP += (Randomizer.rand(7, 9) + (player.getInt() / 10));
} else {
@@ -789,7 +783,7 @@ public class AssignAPProcessor {
MaxMP += 14;
}
} else {
- if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
+ if(YamlConfig.config.server.USE_RANDOMIZE_HPMP_GAIN) {
if(!usedAPReset) {
MaxMP += (Randomizer.rand(4, 6) + (player.getInt() / 10));
} else {
diff --git a/src/client/processor/AssignSPProcessor.java b/src/client/processor/stat/AssignSPProcessor.java
similarity index 77%
rename from src/client/processor/AssignSPProcessor.java
rename to src/client/processor/stat/AssignSPProcessor.java
index b209cad6a5..fc1cf37870 100644
--- a/src/client/processor/AssignSPProcessor.java
+++ b/src/client/processor/stat/AssignSPProcessor.java
@@ -21,14 +21,14 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
-package client.processor;
+package client.processor.stat;
import client.MapleCharacter;
import client.MapleClient;
import client.Skill;
import client.SkillFactory;
import client.autoban.AutobanFactory;
-import constants.GameConstants;
+import constants.game.GameConstants;
import constants.skills.Aran;
import server.ThreadManager;
import tools.FilePrinter;
@@ -40,31 +40,35 @@ import tools.MaplePacketCreator;
*/
public class AssignSPProcessor {
+ public static boolean canSPAssign(MapleClient c, int skillid) {
+ if (skillid == Aran.HIDDEN_FULL_DOUBLE || skillid == Aran.HIDDEN_FULL_TRIPLE || skillid == Aran.HIDDEN_OVER_DOUBLE || skillid == Aran.HIDDEN_OVER_TRIPLE) {
+ c.announce(MaplePacketCreator.enableActions());
+ return false;
+ }
+
+ MapleCharacter player = c.getPlayer();
+ if ((!GameConstants.isPqSkillMap(player.getMapId()) && GameConstants.isPqSkill(skillid)) || (!player.isGM() && GameConstants.isGMSkills(skillid)) || (!GameConstants.isInJobTree(skillid, player.getJob().getId()) && !player.isGM())) {
+ AutobanFactory.PACKET_EDIT.alert(player, "tried to packet edit in distributing sp.");
+ FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to use skill " + skillid + " without it being in their job.");
+
+ c.disconnect(true, false);
+ return false;
+ }
+
+ return true;
+ }
+
public static void SPAssignAction(MapleClient c, int skillid) {
c.lockClient();
try {
- if (skillid == Aran.HIDDEN_FULL_DOUBLE || skillid == Aran.HIDDEN_FULL_TRIPLE || skillid == Aran.HIDDEN_OVER_DOUBLE || skillid == Aran.HIDDEN_OVER_TRIPLE) {
- c.announce(MaplePacketCreator.enableActions());
+ if (!canSPAssign(c, skillid)) {
return;
}
-
+
MapleCharacter player = c.getPlayer();
int remainingSp = player.getRemainingSps()[GameConstants.getSkillBook(skillid/10000)];
boolean isBeginnerSkill = false;
- if ((!GameConstants.isPqSkillMap(player.getMapId()) && GameConstants.isPqSkill(skillid)) || (!player.isGM() && GameConstants.isGMSkills(skillid)) || (!GameConstants.isInJobTree(skillid, player.getJob().getId()) && !player.isGM())) {
- AutobanFactory.PACKET_EDIT.alert(player, "tried to packet edit in distributing sp.");
- FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to use skill " + skillid + " without it being in their job.");
-
- final MapleClient client = c;
- ThreadManager.getInstance().newTask(new Runnable() {
- @Override
- public void run() {
- client.disconnect(true, false);
- }
- });
-
- return;
- }
+
if (skillid % 10000000 > 999 && skillid % 10000000 < 1003) {
int total = 0;
for (int i = 0; i < 3; i++) {
diff --git a/src/config/ServerConfig.java b/src/config/ServerConfig.java
new file mode 100644
index 0000000000..ea40b0b2ad
--- /dev/null
+++ b/src/config/ServerConfig.java
@@ -0,0 +1,304 @@
+package config;
+
+public class ServerConfig {
+ //Thread Tracker Configuration
+ public boolean USE_THREAD_TRACKER;
+
+ //Database Configuration
+ public String DB_URL;
+ public String DB_USER;
+ public String DB_PASS;
+ public boolean DB_CONNECTION_POOL;
+
+ //Login Configuration
+ public int WORLDS;
+ public int WLDLIST_SIZE;
+ public int CHANNEL_SIZE;
+ public int CHANNEL_LOAD;
+ public int CHANNEL_LOCKS;
+
+ public long RESPAWN_INTERVAL;
+ public long PURGING_INTERVAL;
+ public long RANKING_INTERVAL;
+ public long COUPON_INTERVAL;
+ public long UPDATE_INTERVAL;
+
+ public boolean ENABLE_PIC;
+ public boolean ENABLE_PIN;
+
+ public int BYPASS_PIC_EXPIRATION;
+ public int BYPASS_PIN_EXPIRATION;
+
+ public boolean AUTOMATIC_REGISTER;
+ public boolean BCRYPT_MIGRATION;
+ public boolean COLLECTIVE_CHARSLOT;
+ public boolean DETERRED_MULTICLIENT;
+
+ //Besides blocking logging in with several client sessions on the same machine, this also blocks suspicious login attempts for players that tries to login on an account using several diferent remote addresses.
+
+ //Multiclient Coordinator Configuration
+ public int MAX_ALLOWED_ACCOUNT_HWID;
+ public int MAX_ACCOUNT_LOGIN_ATTEMPT;
+ public int LOGIN_ATTEMPT_DURATION;
+
+ //Ip Configuration
+ public String HOST;
+ public boolean LOCALSERVER;
+ public boolean GMSERVER;
+
+ //Other configuration
+ public boolean SHUTDOWNHOOK;
+
+ //Server Flags
+ public boolean USE_CUSTOM_KEYSET;
+ public boolean USE_DEBUG;
+ public boolean USE_DEBUG_SHOW_INFO_EQPEXP;
+ public boolean USE_DEBUG_SHOW_RCVD_PACKET;
+ public boolean USE_DEBUG_SHOW_RCVD_MVLIFE;
+ public boolean USE_DEBUG_SHOW_PACKET;
+ public boolean USE_SUPPLY_RATE_COUPONS;
+ public boolean USE_IP_VALIDATION;
+ public boolean USE_CHARACTER_ACCOUNT_CHECK;
+
+ public boolean USE_MAXRANGE;
+ public boolean USE_MAXRANGE_ECHO_OF_HERO;
+ public boolean USE_MTS;
+ public boolean USE_CPQ;
+ public boolean USE_AUTOHIDE_GM;
+ public boolean USE_BUYBACK_SYSTEM;
+ public boolean USE_FIXED_RATIO_HPMP_UPDATE;
+ public boolean USE_FAMILY_SYSTEM;
+ public boolean USE_DUEY;
+ public boolean USE_RANDOMIZE_HPMP_GAIN;
+ public boolean USE_STORAGE_ITEM_SORT;
+ public boolean USE_ITEM_SORT;
+ public boolean USE_ITEM_SORT_BY_NAME;
+ public boolean USE_PARTY_FOR_STARTERS;
+ public boolean USE_AUTOASSIGN_STARTERS_AP;
+ public boolean USE_AUTOASSIGN_SECONDARY_CAP;
+ public boolean USE_STARTING_AP_4;
+ public boolean USE_AUTOBAN;
+ public boolean USE_AUTOBAN_LOG;
+ public boolean USE_AUTOSAVE;
+ public boolean USE_SERVER_AUTOASSIGNER;
+ public boolean USE_REFRESH_RANK_MOVE;
+ public boolean USE_ENFORCE_ADMIN_ACCOUNT;
+ public boolean USE_ENFORCE_NOVICE_EXPRATE;
+ public boolean USE_ENFORCE_HPMP_SWAP;
+ public boolean USE_ENFORCE_MOB_LEVEL_RANGE;
+ public boolean USE_ENFORCE_JOB_LEVEL_RANGE;
+ public boolean USE_ENFORCE_JOB_SP_RANGE;
+ public boolean USE_ENFORCE_ITEM_SUGGESTION;
+ public boolean USE_ENFORCE_UNMERCHABLE_CASH;
+ public boolean USE_ENFORCE_UNMERCHABLE_PET;
+ public boolean USE_ENFORCE_MERCHANT_SAVE;
+ public boolean USE_ENFORCE_MDOOR_POSITION;
+ public boolean USE_SPAWN_CLEAN_MDOOR;
+ public boolean USE_SPAWN_LOOT_ON_ANIMATION;
+ public boolean USE_SPAWN_RELEVANT_LOOT;
+ public boolean USE_ERASE_PERMIT_ON_OPENSHOP;
+ public boolean USE_ERASE_UNTRADEABLE_DROP;
+ public boolean USE_ERASE_PET_ON_EXPIRATION;
+ public boolean USE_BUFF_MOST_SIGNIFICANT;
+ public boolean USE_BUFF_EVERLASTING;
+ public boolean USE_MULTIPLE_SAME_EQUIP_DROP;
+ public boolean USE_BANISHABLE_TOWN_SCROLL;
+ public boolean USE_ENABLE_FULL_RESPAWN;
+ public boolean USE_ENABLE_CHAT_LOG;
+ public boolean USE_REBIRTH_SYSTEM;
+ public boolean USE_MAP_OWNERSHIP_SYSTEM;
+ public boolean USE_FISHING_SYSTEM;
+ public boolean USE_NPCS_SCRIPTABLE;
+
+ //Events/PQs Configuration
+ public boolean USE_OLD_GMS_STYLED_PQ_NPCS;
+ public boolean USE_ENABLE_SOLO_EXPEDITIONS;
+ public boolean USE_ENABLE_DAILY_EXPEDITIONS;
+ public boolean USE_ENABLE_RECALL_EVENT;
+
+ //Announcement Configuration
+ public boolean USE_ANNOUNCE_SHOPITEMSOLD;
+ public boolean USE_ANNOUNCE_CHANGEJOB;
+
+ //Cash Shop Configuration
+ public boolean USE_JOINT_CASHSHOP_INVENTORY;
+ public boolean USE_CLEAR_OUTDATED_COUPONS;
+ public boolean ALLOW_CASHSHOP_NAME_CHANGE;
+ public boolean ALLOW_CASHSHOP_WORLD_TRANSFER;//Allows players to buy world transfers in the cash shop.
+
+ //Maker Configuration
+ public boolean USE_MAKER_PERMISSIVE_ATKUP;
+ public boolean USE_MAKER_FEE_HEURISTICS;
+
+ //Custom Configuration
+ public boolean USE_ENABLE_CUSTOM_NPC_SCRIPT;
+ public boolean USE_STARTER_MERGE;
+
+ //Commands Configuration
+ public boolean BLOCK_GENERATE_CASH_ITEM;
+ public boolean USE_WHOLE_SERVER_RANKING;
+
+ public double EQUIP_EXP_RATE;
+ public double PQ_BONUS_EXP_RATE;
+
+ public byte EXP_SPLIT_LEVEL_INTERVAL;
+ public byte EXP_SPLIT_LEECH_INTERVAL;
+ public float EXP_SPLIT_MVP_MOD;
+ public float EXP_SPLIT_COMMON_MOD;
+ public float PARTY_BONUS_EXP_RATE;
+
+ //Miscellaneous Configuration
+ public String TIMEZONE;
+ public boolean USE_DISPLAY_NUMBERS_WITH_COMMA;
+ public boolean USE_UNITPRICE_WITH_COMMA;
+ public byte MAX_MONITORED_BUFFSTATS;
+ public int MAX_AP;
+ public int MAX_EVENT_LEVELS;
+ public long BLOCK_NPC_RACE_CONDT;
+ public int TOT_MOB_QUEST_REQUIREMENT;
+ public int MOB_REACTOR_REFRESH_TIME;
+ public int PARTY_SEARCH_REENTRY_LIMIT;
+ public long NAME_CHANGE_COOLDOWN;
+ public long WORLD_TRANSFER_COOLDOWN=NAME_CHANGE_COOLDOWN;//Cooldown for world tranfers, default is same as name change (30 days).
+ public boolean INSTANT_NAME_CHANGE;
+
+ //Dangling Items/Locks Configuration
+ public int ITEM_EXPIRE_TIME ;
+ public int KITE_EXPIRE_TIME ;
+ public int ITEM_MONITOR_TIME;
+ public int LOCK_MONITOR_TIME;
+
+ //Map Monitor Configuration
+ public int ITEM_EXPIRE_CHECK;
+ public int ITEM_LIMIT_ON_MAP;
+ public int MAP_VISITED_SIZE;
+ public int MAP_DAMAGE_OVERTIME_INTERVAL;
+
+ //Channel Mob Disease Monitor Configuration
+ public int MOB_STATUS_MONITOR_PROC;
+ public int MOB_STATUS_MONITOR_LIFE;
+ public int MOB_STATUS_AGGRO_PERSISTENCE;
+ public int MOB_STATUS_AGGRO_INTERVAL;
+
+ //Some Gameplay Enhancing Configurations
+ //Scroll Configuration
+ public boolean USE_PERFECT_GM_SCROLL;
+ public boolean USE_PERFECT_SCROLLING;
+ public boolean USE_ENHANCED_CHSCROLL;
+ public boolean USE_ENHANCED_CRAFTING;
+ public boolean USE_ENHANCED_CLNSLATE;
+ public int SCROLL_CHANCE_ROLLS;
+ public int CHSCROLL_STAT_RATE;
+ public int CHSCROLL_STAT_RANGE;
+
+ //Beginner Skills Configuration
+ public boolean USE_ULTRA_NIMBLE_FEET;
+ public boolean USE_ULTRA_RECOVERY;
+ public boolean USE_ULTRA_THREE_SNAILS;
+
+ //Other Skills Configuration
+ public boolean USE_FULL_ARAN_SKILLSET;
+ public boolean USE_FAST_REUSE_HERO_WILL;
+ public boolean USE_ANTI_IMMUNITY_CRASH;
+ public boolean USE_UNDISPEL_HOLY_SHIELD;
+ public boolean USE_FULL_HOLY_SYMBOL;
+
+ //Character Configuration
+ public boolean USE_ADD_SLOTS_BY_LEVEL;
+ public boolean USE_ADD_RATES_BY_LEVEL;
+ public boolean USE_STACK_COUPON_RATES;
+ public boolean USE_PERFECT_PITCH;
+
+ //Quest Configuration
+ public boolean USE_QUEST_RATE;
+
+ //Quest Points Configuration
+ public int QUEST_POINT_REPEATABLE_INTERVAL;
+ public int QUEST_POINT_REQUIREMENT;
+ public int QUEST_POINT_PER_QUEST_COMPLETE;
+ public int QUEST_POINT_PER_EVENT_CLEAR;
+
+ //Guild Configuration
+ public int CREATE_GUILD_MIN_PARTNERS;
+ public int CREATE_GUILD_COST;
+ public int CHANGE_EMBLEM_COST;
+ public int EXPAND_GUILD_BASE_COST;
+ public int EXPAND_GUILD_TIER_COST;
+ public int EXPAND_GUILD_MAX_COST;
+
+ //Family Configuration
+ public int FAMILY_REP_PER_KILL;
+ public int FAMILY_REP_PER_BOSS_KILL;
+ public int FAMILY_REP_PER_LEVELUP;
+ public int FAMILY_MAX_GENERATIONS;
+
+ //Equipment Configuration
+ public boolean USE_EQUIPMNT_LVLUP_SLOTS;
+ public boolean USE_EQUIPMNT_LVLUP_POWER;
+ public boolean USE_EQUIPMNT_LVLUP_CASH;
+ public boolean USE_SPIKES_AVOID_BANISH;
+ public int MAX_EQUIPMNT_LVLUP_STAT_UP;
+ public int MAX_EQUIPMNT_STAT;
+ public int USE_EQUIPMNT_LVLUP;
+
+ //Map-Chair Configuration
+ public boolean USE_CHAIR_EXTRAHEAL;
+ public byte CHAIR_EXTRA_HEAL_MULTIPLIER;
+ public int CHAIR_EXTRA_HEAL_MAX_DELAY;
+
+ //Player NPC Configuration
+ public int PLAYERNPC_INITIAL_X;
+ public int PLAYERNPC_INITIAL_Y;
+ public int PLAYERNPC_AREA_X;
+ public int PLAYERNPC_AREA_Y;
+ public int PLAYERNPC_AREA_STEPS;
+ public boolean PLAYERNPC_ORGANIZE_AREA;
+ public boolean PLAYERNPC_AUTODEPLOY;
+
+ //Pet Auto-Pot Configuration
+ public boolean USE_COMPULSORY_AUTOPOT;
+ public boolean USE_EQUIPS_ON_AUTOPOT;
+ public double PET_AUTOHP_RATIO;
+ public double PET_AUTOMP_RATIO;
+
+ //Pet & Mount Configuration
+ public byte PET_EXHAUST_COUNT;
+ public byte MOUNT_EXHAUST_COUNT;
+
+ //Pet Hunger Configuration
+ public boolean PETS_NEVER_HUNGRY;
+ public boolean GM_PETS_NEVER_HUNGRY;
+
+ //Event Configuration
+ public int EVENT_MAX_GUILD_QUEUE;
+ public long EVENT_LOBBY_DELAY;
+
+ //Dojo Configuration
+ public boolean USE_FAST_DOJO_UPGRADE;
+ public boolean USE_DEADLY_DOJO;
+ public int DOJO_ENERGY_ATK;
+ public int DOJO_ENERGY_DMG;
+
+ //Wedding Configuration
+ public int WEDDING_RESERVATION_DELAY;
+ public int WEDDING_RESERVATION_TIMEOUT;
+ public int WEDDING_RESERVATION_INTERVAL;
+ public int WEDDING_BLESS_EXP;
+ public int WEDDING_GIFT_LIMIT;
+ public boolean WEDDING_BLESSER_SHOWFX;
+
+ //Buyback Configuration
+ public boolean USE_BUYBACK_WITH_MESOS;
+ public float BUYBACK_FEE;
+ public float BUYBACK_LEVEL_STACK_FEE;
+ public int BUYBACK_MESO_MULTIPLIER;
+ public int BUYBACK_RETURN_MINUTES;
+ public int BUYBACK_COOLDOWN_MINUTES;
+
+ // Login timeout by shavit
+ public long TIMEOUT_DURATION;
+
+ //Event End Timestamp
+ public long EVENT_END_TIMESTAMP;
+
+}
diff --git a/src/config/WorldConfig.java b/src/config/WorldConfig.java
new file mode 100644
index 0000000000..075282bf50
--- /dev/null
+++ b/src/config/WorldConfig.java
@@ -0,0 +1,16 @@
+package config;
+
+public class WorldConfig {
+ public int flag = 0;
+ public String server_message = "Welcome!";
+ public String event_message = "";
+ public String why_am_i_recommended = "";
+ public int channels = 1;
+ public int exp_rate = 1;
+ public int meso_rate = 1;
+ public int drop_rate = 1;
+ public int boss_drop_rate = 1;
+ public int quest_rate = 1;
+ public int travel_rate = 1;
+ public int fishing_rate = 1;
+}
diff --git a/src/config/YamlConfig.java b/src/config/YamlConfig.java
new file mode 100644
index 0000000000..c8adc338d1
--- /dev/null
+++ b/src/config/YamlConfig.java
@@ -0,0 +1,32 @@
+package config;
+
+import com.esotericsoftware.yamlbeans.YamlReader;
+
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.List;
+
+
+public class YamlConfig {
+
+ public static final YamlConfig config = fromFile("config.yaml");
+
+ public List worlds;
+ public ServerConfig server;
+
+ public static YamlConfig fromFile(String filename) {
+ try {
+ YamlReader reader = new YamlReader(new FileReader(filename));
+ YamlConfig config = reader.read(YamlConfig.class);
+ reader.close();
+ return config;
+ } catch (FileNotFoundException e) {
+ String message = "Could not read config file " + filename + ": " + e.getMessage();
+ throw new RuntimeException(message);
+ } catch (IOException e) {
+ String message = "Could not successfully parse config file " + filename + ": " + e.getMessage();
+ throw new RuntimeException(message);
+ }
+ }
+}
diff --git a/src/constants/ServerConstants.java b/src/constants/ServerConstants.java
deleted file mode 100644
index 8147fa1ffe..0000000000
--- a/src/constants/ServerConstants.java
+++ /dev/null
@@ -1,331 +0,0 @@
-package constants;
-
-import java.io.FileInputStream;
-import java.util.Properties;
-
-public class ServerConstants {
- //Thread Tracker Configuration
- public static final boolean USE_THREAD_TRACKER = true; //[SEVERE] This deadlock auditing thing will bloat the memory as fast as the time frame one takes to lose track of a raindrop on a tempesting day. Only for debugging purposes.
-
- //Database Configuration
- public static String DB_URL = "";
- public static String DB_USER = "";
- public static String DB_PASS = "";
- public static final boolean DB_CONNECTION_POOL = true; //Installs a connection pool to hub DB connections. Set false to default.
-
- //Server Version
- public static short VERSION = 83;
-
- //Login Configuration
- public static final int WLDLIST_SIZE = 21; //Max possible worlds on the server.
- public static final int CHANNEL_SIZE = 20; //Max possible channels per world (which is 20, based on the channel list on login phase).
- public static final int CHANNEL_LOAD = 100; //Max players per channel (limit actually used to calculate the World server capacity).
- public static final int CHANNEL_LOCKS = 20; //Total number of structure management locks each channel has.
-
- public static final long RESPAWN_INTERVAL = 10 * 1000; //10 seconds, 10000.
- public static final long PURGING_INTERVAL = 5 * 60 * 1000;
- public static final long RANKING_INTERVAL = 60 * 60 * 1000; //60 minutes, 3600000.
- public static final long COUPON_INTERVAL = 60 * 60 * 1000; //60 minutes, 3600000.
- public static final long UPDATE_INTERVAL = 777; //Dictates the frequency on which the "centralized server time" is updated.
-
- public static final boolean ENABLE_PIC = false; //Pick true/false to enable or disable Pic. Delete character requires PIC available.
- public static final boolean ENABLE_PIN = false; //Pick true/false to enable or disable Pin.
-
- public static final int BYPASS_PIC_EXPIRATION = 20; //Enables PIC bypass, which will remain active for that account by that client machine for N minutes. Set 0 to disable.
- public static final int BYPASS_PIN_EXPIRATION = 15; //Enables PIN bypass, which will remain active for that account by that client machine for N minutes. Set 0 to disable.
-
- public static final boolean AUTOMATIC_REGISTER = true; //Automatically register players when they login with a nonexistent username.
- public static final boolean BCRYPT_MIGRATION = true; //Performs a migration from old SHA-1 and SHA-512 password to bcrypt.
- public static final boolean COLLECTIVE_CHARSLOT = false; //Available character slots are contabilized globally rather than per world server.
- public static final boolean DETERRED_MULTICLIENT = false; //Enables detection of multi-client and suspicious remote IP on the login system.
-
- //Besides blocking logging in with several client sessions on the same machine, this also blocks suspicious login attempts for players that tries to login on an account using several diferent remote addresses.
-
- //Multiclient Coordinator Configuration
- public static final int MAX_ALLOWED_ACCOUNT_HWID = 4; //Allows up to N concurrent HWID's for an account. HWID's remains linked to an account longer the more times it's used to login.
- public static final int MAX_ACCOUNT_LOGIN_ATTEMPT = 15; //After N tries on an account, login on that account gets disabled for a short period.
- public static final int LOGIN_ATTEMPT_DURATION = 120; //Period in seconds the login attempt remains registered on the system.
-
- //Ip Configuration
- public static String HOST;
- public static boolean LOCALSERVER;
-
- //Other Configuration
- public static boolean JAVA_8;
- public static boolean SHUTDOWNHOOK;
- // JAVA_8: every static function in AbstractPlayerInteraction are to be made non-static, and code comment sections uncommented after enabling this functionality.
-
-
- //Server Flags
- public static final boolean USE_CUSTOM_KEYSET = true; //Enables auto-setup of the HeavenMS's custom keybindings when creating characters.
- public static final boolean USE_DEBUG = false; //Will enable some text prints on the client, oriented for debugging purposes.
- public static final boolean USE_DEBUG_SHOW_INFO_EQPEXP = false; //Prints on the cmd all equip exp gain info.
- public static boolean USE_DEBUG_SHOW_RCVD_PACKET = false; //Prints on the cmd all received packet ids.
- public static boolean USE_DEBUG_SHOW_RCVD_MVLIFE = false; //Prints on the cmd all received move life content.
- public static final boolean USE_DEBUG_SHOW_PACKET = false;
- public static boolean USE_SUPPLY_RATE_COUPONS = true; //Allows rate coupons to be sold through the Cash Shop.
- public static final boolean USE_IP_VALIDATION = true; //Enables IP checking when logging in.
-
- public static final boolean USE_MAXRANGE = true; //Will send and receive packets from all events on a map, rather than those of only view range.
- public static final boolean USE_MAXRANGE_ECHO_OF_HERO = true;
- public static final boolean USE_MTS = false;
- public static final boolean USE_CPQ = true; //Renders the CPQ available or not.
- public static final boolean USE_AUTOHIDE_GM = false; //When enabled, GMs are automatically hidden when joining. Thanks to Steven Deblois (steven1152).
- public static final boolean USE_BUYBACK_SYSTEM = true; //Enables the HeavenMS-builtin buyback system, dead players can use it by clicking the MTS button.
- public static final boolean USE_FIXED_RATIO_HPMP_UPDATE = true; //Enables the HeavenMS-builtin HPMP update based on the current pool to max pool ratio.
- public static final boolean USE_FAMILY_SYSTEM = false;
- public static final boolean USE_DUEY = true;
- public static final boolean USE_RANDOMIZE_HPMP_GAIN = true; //Enables randomizing on MaxHP/MaxMP gains and INT accounting for the MaxMP gain on level up.
- public static final boolean USE_STORAGE_ITEM_SORT = true; //Enables storage "Arrange Items" feature.
- public static final boolean USE_ITEM_SORT = true; //Enables inventory "Item Sort/Merge" feature.
- public static final boolean USE_ITEM_SORT_BY_NAME = false; //Item sorting based on name rather than id.
- public static final boolean USE_PARTY_FOR_STARTERS = true; //Players level 10 or below can create/invite other players on the given level range.
- public static final boolean USE_AUTOASSIGN_STARTERS_AP = false; //Beginners level 10 or below have their AP autoassigned (they can't choose to levelup a stat). Set true ONLY if the localhost doesn't support AP assigning for beginners level 10 or below.
- public static final boolean USE_AUTOASSIGN_SECONDARY_CAP = true;//Prevents AP autoassign from spending on secondary stats after the player class' cap (defined on the autoassign handler) has been reached.
- public static final boolean USE_AUTOBAN = false; //Commands the server to detect infractors automatically.
- public static final boolean USE_AUTOBAN_LOG = true; //Log autoban related messages. Still logs even with USE_AUTOBAN disabled.
- public static final boolean USE_AUTOSAVE = true; //Enables server autosaving feature (saves characters to DB each 1 hour).
- public static final boolean USE_SERVER_AUTOASSIGNER = true; //HeavenMS-builtin autoassigner, uses algorithm based on distributing AP accordingly with required secondary stat on equipments.
- public static final boolean USE_REFRESH_RANK_MOVE = true;
- public static final boolean USE_ENFORCE_ADMIN_ACCOUNT = false; //Forces accounts having GM characters to be treated as a "GM account" by the client (localhost). Some of the GM account perks is the ability to FLY, but unable to TRADE.
- public static final boolean USE_ENFORCE_NOVICE_EXPRATE = false; //Hardsets experience rate 1x for beginners level 10 or under. Ideal for roaming on novice areas without caring too much about losing some stats.
- public static final boolean USE_ENFORCE_HPMP_SWAP = false; //Forces players to reuse stats (via AP Resetting) located on HP/MP pool only inside the HP/MP stats.
- public static final boolean USE_ENFORCE_MOB_LEVEL_RANGE = true; //Players N levels below the killed mob will gain no experience from defeating it.
- public static final boolean USE_ENFORCE_JOB_LEVEL_RANGE = false;//Caps the player level on the minimum required to advance their current jobs.
- public static final boolean USE_ENFORCE_JOB_SP_RANGE = false; //Caps the player SP level on the total obtainable by their current jobs. After changing jobs, missing SP will be retrieved.
- public static final boolean USE_ENFORCE_ITEM_SUGGESTION = false;//Forces the Owl of Minerva and the Cash Shop to always display the defined item array instead of those featured from players.
- public static final boolean USE_ENFORCE_UNMERCHABLE_CASH = false;//Forces players to not sell CASH items via merchants.
- public static final boolean USE_ENFORCE_UNMERCHABLE_PET = false; //Forces players to not sell pets via merchants. (since non-named pets gets dirty name and other possible DB-related issues)
- public static final boolean USE_ENFORCE_MERCHANT_SAVE = true; //Forces automatic DB save on merchant owners, at every item movement on shop.
- public static final boolean USE_ENFORCE_MDOOR_POSITION = false; //Forces mystic door to be spawned near spawnpoints.
- public static final boolean USE_SPAWN_CLEAN_MDOOR = false; //Makes mystic doors to be spawned without deploy animation. This clears disconnecting issues that may happen when trying to cancel doors a couple seconds after deployment.
- public static final boolean USE_SPAWN_LOOT_ON_ANIMATION = false;//Makes loot appear some time after the mob has been killed (following the mob death animation, instead of instantly).
- public static final boolean USE_SPAWN_RELEVANT_LOOT = true; //Forces to only spawn loots that are collectable by the player or any of their party members.
- public static final boolean USE_ERASE_PERMIT_ON_OPENSHOP = true;//Forces "shop permit" item to be consumed when player deploy his/her player shop.
- public static final boolean USE_ERASE_UNTRADEABLE_DROP = true; //Forces flagged untradeable items to disappear when dropped.
- public static final boolean USE_ERASE_PET_ON_EXPIRATION = false;//Forces pets to be removed from inventory when expire time comes, rather than converting it to a doll.
- public static final boolean USE_BUFF_MOST_SIGNIFICANT = true; //When applying buffs, the player will stick with the highest stat boost among the listed, rather than overwriting stats.
- public static final boolean USE_BUFF_EVERLASTING = false; //Every applied buff on players holds expiration time so high it'd be considered permanent. Thanks Vcoc for this suggestion.
- public static final boolean USE_MULTIPLE_SAME_EQUIP_DROP = true;//Enables multiple drops by mobs of the same equipment, number of possible drops based on the quantities provided at the drop data.
- public static final boolean USE_BANISHABLE_TOWN_SCROLL = true; //Enables town scrolls to act as if it's a "player banish", rendering the antibanish scroll effect available.
- public static final boolean USE_ENABLE_FULL_RESPAWN = true; //At respawn task, always respawn missing mobs when they're available. Spawn count doesn't depend on how many players are currently there.
- public static final boolean USE_ENABLE_CHAT_LOG = false; //Write in-game chat to log
- public static final boolean USE_REBIRTH_SYSTEM = false; //Flag to enable/disable rebirth system
- public static final boolean USE_MAP_OWNERSHIP_SYSTEM = true; //Flag to enable/disable map ownership system
- public static final boolean USE_FISHING_SYSTEM = true; //Flag to enable/disable fishing system
- public static final boolean USE_NPCS_SCRIPTABLE = true; //Flag to enable/disable serverside predefined script NPCs.
-
- //Events/PQs Configuration
- public static final boolean USE_OLD_GMS_STYLED_PQ_NPCS = true; //Enables PQ NPCs with similar behaviour to old GMS style, that skips info about the PQs and immediately tries to register the party in.
- public static final boolean USE_ENABLE_SOLO_EXPEDITIONS = true; //Enables start expeditions with any number of players. This will also bypass all the Zakum prequest.
- public static final boolean USE_ENABLE_RECALL_EVENT = true; //Enables a disconnected player to reaccess the last event instance they were in before logging out. Recall only works if the event isn't cleared or disposed yet. Suggestion thanks to Alisson (Goukken).
-
- //Announcement Configuration
- public static final boolean USE_ANNOUNCE_SHOPITEMSOLD = false; //Automatic message sent to owner when an item from the Player Shop or Hired Merchant is sold.
- public static final boolean USE_ANNOUNCE_CHANGEJOB = false; //Automatic message sent to acquantainces when changing jobs.
-
- //Cash Shop Configuration
- public static final boolean USE_JOINT_CASHSHOP_INVENTORY = true;//Enables usage of a same cash shop inventory for explorers, cygnus and legends. Items from exclusive cash shop inventories won't show up on the shared inventory, though.
- public static final boolean USE_CLEAR_OUTDATED_COUPONS = true; //Enables deletion of older code coupon registry from the DB, freeing so-long irrelevant data.
-
- //Maker Configuration
- public static final boolean USE_MAKER_PERMISSIVE_ATKUP = true; //Allows players to use attack-based strengthening gems on non-weapon items.
- public static final boolean USE_MAKER_FEE_HEURISTICS = true; //Apply compiled values for stimulants and reagents into the Maker fee calculations (max error revolves around 50k mesos). Set false to use basic constant values instead (results are never higher than the client-side requests).
-
- //Custom Configuration
- public static final boolean USE_ENABLE_CUSTOM_NPC_SCRIPT = true;//Enables usage of custom HeavenMS NPC scripts (Agent E, Coco, etc). Will not disable Abdula (it's actually useful for the gameplay), quests or NPC shops.
- public static final boolean USE_STARTER_MERGE = false; //Allows any players to use the Equipment Merge custom mechanic (as opposed to the high-level, Maker lv3 requisites).
-
- //Commands Configuration
- public static final boolean BLOCK_GENERATE_CASH_ITEM = false; //Prevents creation of cash items with the item/drop command.
- public static final boolean USE_WHOLE_SERVER_RANKING = false; //Enables a ranking pool made from every character registered on the server for the "ranks" command, instead of split by worlds.
-
- //Server Rates And Experience
- public static final int EXP_RATE = 10; //NOTE: World-specific rates within "world.ini" OVERRIDES the default rates from here.
- public static final int MESO_RATE = 10;
- public static final int DROP_RATE = 10;
- public static final int BOSS_DROP_RATE = 10; //NOTE: Boss drop rate OVERRIDES common drop rate, for bosses-only.
- public static final int QUEST_RATE = 5; //Multiplier for Exp & Meso gains when completing a quest. Only available when USE_QUEST_RATE is true. Stacks with server Exp & Meso rates.
- public static final int FISHING_RATE = 10; //Multiplier for success likelihood on meso thrown during fishing.
- public static final int TRAVEL_RATE = 10; //Means of transportation rides/departs using 1/N of the default time.
-
- public static final double EQUIP_EXP_RATE = 1.0; //Rate for equipment exp gain, 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_RATE = 0.5; //Rate for the PQ exp reward.
-
- public static final byte EXP_SPLIT_LEVEL_INTERVAL = 5; //Non-contributing players must be within N level between the mob to receive EXP.
- public static final byte EXP_SPLIT_LEECH_INTERVAL = 5; //Non-contributing players must be within N level between any contributing party member to receive EXP.
- public static final float EXP_SPLIT_MVP_MOD = 0.2f;
- public static final float EXP_SPLIT_COMMON_MOD = 0.8f;
- public static final float PARTY_BONUS_EXP_RATE = 1.0f; //Rate for the party exp bonus reward.
-
- //Miscellaneous Configuration
- public static String TIMEZONE = "GMT-3";
- public static boolean USE_DISPLAY_NUMBERS_WITH_COMMA = true; //Enforce comma on displayed strings (use this when USE_UNITPRICE_WITH_COMMA is active and you still want to display comma-separated values).
- public static boolean USE_UNITPRICE_WITH_COMMA = true; //Set this accordingly with the layout of the unitPrices on Item.wz XML's, whether it's using commas or dots to represent fractions.
- public static final byte MAX_MONITORED_BUFFSTATS = 5; //Limits accounting for "dormant" buff effects, that should take place when stronger stat buffs expires.
- 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.
- public static final int TOT_MOB_QUEST_REQUIREMENT = 77; //Overwrites old 999-mobs requirement for the ToT questline with new requirement value, set 0 for default.
- public static final int MOB_REACTOR_REFRESH_TIME = 30 * 1000; //Overwrites refresh time for those reactors oriented to inflict damage to bosses (Ice Queen, Riche), set 0 for default.
- public static final int PARTY_SEARCH_REENTRY_LIMIT = 10; //Max amount of times a party leader is allowed to persist on the Party Search before entry expiration (thus needing to manually restart the Party Search to be able to search for members).
-
- //Dangling Items/Locks 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 KITE_EXPIRE_TIME = 60 * 60 * 1000; //Time before kites (cash item) disappears.
- public static final int ITEM_MONITOR_TIME = 5 * 60 * 1000; //Interval between item monitoring tasks on maps, which checks for dangling (null) item objects on the map item history.
- public static final int LOCK_MONITOR_TIME = 30 * 1000; //Waiting time for a lock to be released. If it reaches timeout, a critical server deadlock has made present.
-
- //Map Monitor Configuration
- public static final int ITEM_EXPIRE_CHECK = 10 * 1000; //Interval between item expiring tasks on maps, which checks and makes disappear expired items.
- public static final int ITEM_LIMIT_ON_MAP = 200; //Max number of items allowed on a map.
- public static final int MAP_VISITED_SIZE = 5; //Max length for last mapids a player visits. This is used to recover and update drops on these maps accordingly with player actions.
- public static final int MAP_DAMAGE_OVERTIME_INTERVAL = 5000;//Interval in milliseconds between map environment damage (e.g. El Nath and Aqua Road surrondings).
-
- //Channel Mob Disease Monitor Configuration
- public static final int MOB_STATUS_MONITOR_PROC = 200; //Frequency in milliseconds between each proc on the mob disease monitor schedule.
- public static final int MOB_STATUS_MONITOR_LIFE = 84; //Idle proc count the mob disease monitor is allowed to be there before closing it due to inactivity.
- public static final int MOB_STATUS_AGGRO_PERSISTENCE = 2; //Idle proc count on aggro update for a mob to keep following the current controller, given him/her is the leading damage dealer.
- public static final int MOB_STATUS_AGGRO_INTERVAL = 5000; //Interval in milliseconds between aggro logistics update.
-
- //Some Gameplay Enhancing Configurations
- //Scroll Configuration
- public static final boolean USE_PERFECT_GM_SCROLL = true; //Scrolls from GMs never uses up slots nor fails.
- public static final boolean USE_PERFECT_SCROLLING = true; //Scrolls doesn't use slots upon failure.
- public static final boolean USE_ENHANCED_CHSCROLL = true; //Equips even more powerful with chaos upgrade.
- public static final boolean USE_ENHANCED_CRAFTING = true; //Apply chaos scroll on every equip crafted.
- public static final boolean USE_ENHANCED_CLNSLATE = true; //Clean slates can be applied to recover successfully used slots as well.
- public static final int SCROLL_CHANCE_RATE = 10; //Number of rolls for success on a scroll, set 1 for default.
- public static final int CHSCROLL_STAT_RATE = 3; //Number of rolls of stat upgrade on a successfully applied chaos scroll, set 1 for default.
- public static final int CHSCROLL_STAT_RANGE = 6; //Stat upgrade range (-N, N) on chaos scrolls.
-
- //Beginner Skills Configuration
- public static final boolean USE_ULTRA_NIMBLE_FEET = true; //Massive speed & jump upgrade.
- public static final boolean USE_ULTRA_RECOVERY = true; //Massive recovery amounts overtime.
- public static final boolean USE_ULTRA_THREE_SNAILS = true; //Massive damage on shell toss.
-
- //Other Skills Configuration
- public static final boolean USE_FULL_ARAN_SKILLSET = false; //Enables starter availability to all Aran job skills. Thanks Masterrulax for this suggestion.
- public static final boolean USE_FAST_REUSE_HERO_WILL = true;//Greatly reduce cooldown on Hero's Will.
- public static final boolean USE_ANTI_IMMUNITY_CRASH = true; //Crash skills additionally removes the mob's invincibility buffs. Thanks Celestial for this suggestion.
- public static final boolean USE_UNDISPEL_HOLY_SHIELD = true;//Holy shield buff also prevents players from suffering dispel from mobs.
-
- //Character Configuration
- public static final boolean USE_ADD_SLOTS_BY_LEVEL = true; //Slots are added each 20 levels.
- public static final boolean USE_ADD_RATES_BY_LEVEL = true; //Rates are added each 20 levels.
- public static final boolean USE_STACK_COUPON_RATES = false; //Multiple coupons effects builds up together.
- public static final boolean USE_PERFECT_PITCH = true; //For lvl 30 or above, each lvlup grants player 1 perfect pitch.
-
- //Quest Configuration
- public static final boolean USE_QUEST_RATE = false; //Exp/Meso gain by quests uses fixed server exp/meso rate times quest rate as multiplier, instead of player rates.
-
- //Quest Points Configuration
- public static final int QUEST_POINT_REPEATABLE_INTERVAL = 24;//Minimum interval between repeatable quest completions for quest points to be awarded.
- public static final int QUEST_POINT_REQUIREMENT = 16; //Exchange factor between N quest points to +1 fame, set 0 to disable the entire quest point mechanism.
- public static final int QUEST_POINT_PER_QUEST_COMPLETE = 4; //Each completed quest awards N quest points, set 0 to disable.
- public static final int QUEST_POINT_PER_EVENT_CLEAR = 1; //Each completed event instance awards N quest points, set 0 to disable.
-
- //Guild Configuration
- public static final int CREATE_GUILD_MIN_PARTNERS = 6; //Minimum number of members on Guild Headquarters to establish a new guild.
- public static final int CREATE_GUILD_COST = 1500000;
- public static final int CHANGE_EMBLEM_COST = 5000000;
- public static final int EXPAND_GUILD_BASE_COST = 500000;
- public static final int EXPAND_GUILD_TIER_COST = 1000000;
- public static final int EXPAND_GUILD_MAX_COST = 5000000;
-
- //Equipment Configuration
- public static final boolean USE_EQUIPMNT_LVLUP_SLOTS = true;//Equips can upgrade slots at level up.
- public static final boolean USE_EQUIPMNT_LVLUP_POWER = true;//Enable more powerful stat upgrades at equip level up.
- public static final boolean USE_EQUIPMNT_LVLUP_CASH = true; //Enable equip leveling up on cash equipments as well.
- public static final boolean USE_SPIKES_AVOID_BANISH = true; //Shoes equipped with spikes prevents mobs from banishing wearer.
- public static final int MAX_EQUIPMNT_LVLUP_STAT_UP = 10000; //Max stat upgrade an equipment can have on a levelup.
- public static final int MAX_EQUIPMNT_STAT = 32767; //Max stat on an equipment by leveling up.
- public static final int USE_EQUIPMNT_LVLUP = 7; //All equips lvlup at max level of N, set 1 to disable.
-
- //Map-Chair Configuration
- public static final boolean USE_CHAIR_EXTRAHEAL = true; //Enable map chairs to further recover player's HP and MP (player must have the Chair Mastery skill).
- public static final byte CHAIR_EXTRA_HEAL_MULTIPLIER = 10; //Due to only being able to be send up-to-255 heal values, values being actually updated is the one displayed times this.
- public static final int CHAIR_EXTRA_HEAL_MAX_DELAY = 21; //Players are expected to recover fully after using this skill for N seconds.
-
- //Player NPC Configuration
- public static final int PLAYERNPC_INITIAL_X = 262; //Map frame width for putting PlayerNPCs.
- public static final int PLAYERNPC_INITIAL_Y = 262; //Map frame height for putting PlayerNPCs.
- public static final int PLAYERNPC_AREA_X = 320; //Initial width gap between PlayerNPCs.
- public static final int PLAYERNPC_AREA_Y = 160; //Initial height gap between PlayerNPCs.
- public static final int PLAYERNPC_AREA_STEPS = 4; //Max number of times gap is shortened to comport PlayerNPCs.
- public static final boolean PLAYERNPC_ORGANIZE_AREA = true; //Automatically rearranges PlayerNPCs on the map if there is no space set the new NPC. Current distance gap between NPCs is decreased to solve this issue.
- public static final boolean PLAYERNPC_AUTODEPLOY = true; //Makes PlayerNPC automatically deployed on the Hall of Fame at the instant one reaches max level. If false, eligible players must talk to 1st job instructor to deploy a NPC.
-
- //Pet Auto-Pot Configuration
- public static final boolean USE_COMPULSORY_AUTOPOT = true; //Pets will consume as many potions as needed to fulfill the AUTOHP/MP ratio threshold.
- public static final boolean USE_EQUIPS_ON_AUTOPOT = true; //Player MaxHP and MaxMP check values on autopot handler will change according to HP/MP bonuses on equipped items.
- 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.
-
- //Pet Hunger Configuration
- public static final boolean PETS_NEVER_HUNGRY = false; //If true, pets and mounts will never grow hungry.
- public static final boolean GM_PETS_NEVER_HUNGRY = true; //If true, pets and mounts own by GMs will never grow hungry.
-
- //Event Configuration
- public static final int EVENT_MAX_GUILD_QUEUE = 10; //Max number of guilds in queue for GPQ.
- public static final long EVENT_LOBBY_DELAY = 10; //Cooldown duration in seconds before reopening an event lobby.
-
- //Dojo Configuration
- public static final boolean USE_FAST_DOJO_UPGRADE = true; //Reduced Dojo training points amount required for a belt upgrade.
- public static final boolean USE_DEADLY_DOJO = false; //Should bosses really use 1HP,1MP attacks in dojo?
- public static final int DOJO_ENERGY_ATK = 100; //Dojo energy gain when deal attack
- public static final int DOJO_ENERGY_DMG = 20; //Dojo energy gain when recv attack
-
- //Wedding Configuration
- public static final int WEDDING_RESERVATION_DELAY = 3; //Minimum idle slots before processing a wedding reservation.
- public static final int WEDDING_RESERVATION_TIMEOUT = 10; //Limit time in minutes for the couple to show up before cancelling the wedding reservation.
- public static final int WEDDING_RESERVATION_INTERVAL = 60; //Time between wedding starts in minutes.
- public static final int WEDDING_BLESS_EXP = 30000; //Exp gained per bless count.
- public static final int WEDDING_GIFT_LIMIT = 1; //Max number of gifts per person to same wishlist on marriage instances.
- public static final boolean WEDDING_BLESSER_SHOWFX = true; //Pops bubble sprite effect on players blessing the couple. Setting this false shows the blessing effect on the couple instead.
-
- //Buyback Configuration
- public static final boolean USE_BUYBACK_WITH_MESOS = true; //Enables usage of either mesos or NX for the buyback fee.
- public static final float BUYBACK_FEE = 77.70f; //Sets the base amount needed to buyback (level 30 or under will use the base value).
- public static final float BUYBACK_LEVEL_STACK_FEE = 85.47f; //Sets the level-stacking portion of the amount needed to buyback (fee will sum up linearly until level 120, when it reaches the peak).
- public static final int BUYBACK_MESO_MULTIPLIER = 1000; //Sets a multiplier for the fee when using meso as the charge unit.
- public static final int BUYBACK_RETURN_MINUTES = 1; //Sets the maximum amount of time the player can wait before decide to buyback.
- public static final int BUYBACK_COOLDOWN_MINUTES = 7; //Sets the time the player must wait before using buyback again.
-
- //Event End Timestamp
- public static final long EVENT_END_TIMESTAMP = 1428897600000L;
-
- //Debug Variables
- public static int DEBUG_VALUES[] = new int[10]; // Field designed for packet testing purposes
-
- //Properties
- static {
- Properties p = new Properties();
- try {
- p.load(new FileInputStream("configuration.ini"));
-
- //Server Host
- ServerConstants.HOST = p.getProperty("HOST");
- ServerConstants.LOCALSERVER = ServerConstants.HOST.startsWith("127.") || ServerConstants.HOST.startsWith("localhost");
-
- //Sql Database
- ServerConstants.DB_URL = p.getProperty("URL");
- ServerConstants.DB_USER = p.getProperty("DB_USER");
- ServerConstants.DB_PASS = p.getProperty("DB_PASS");
-
- //java8 And Shutdownhook
- ServerConstants.JAVA_8 = p.getProperty("JAVA8").equalsIgnoreCase("TRUE");
- ServerConstants.SHUTDOWNHOOK = p.getProperty("SHUTDOWNHOOK").equalsIgnoreCase("true");
-
- } catch (Exception e) {
- e.printStackTrace();
- System.out.println("Failed to load configuration.ini.");
- System.exit(0);
- }
- }
-}
diff --git a/src/constants/ExpTable.java b/src/constants/game/ExpTable.java
similarity index 99%
rename from src/constants/ExpTable.java
rename to src/constants/game/ExpTable.java
index a7b4d2f22d..1b963bf68c 100644
--- a/src/constants/ExpTable.java
+++ b/src/constants/game/ExpTable.java
@@ -19,7 +19,7 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
-package constants;
+package constants.game;
public final class ExpTable {
private static final int[] exp = {15, 15, 34, 57, 92, 135, 372, 560, 840, 1144, 1242, 1573, 2144, 2800, 3640, 4700, 5893, 7360, 9144, 11120, 13477, 16268, 19320, 22880, 27008, 31477, 36600, 42444, 48720, 55813, 63800, 86784, 98208, 110932, 124432, 139372, 155865, 173280, 192400, 213345, 235372, 259392, 285532, 312928, 342624, 374760, 408336, 445544, 483532, 524160, 567772, 598886, 631704, 666321, 702836, 741351, 781976, 824828, 870028, 917625, 967995, 1021041, 1076994, 1136013, 1198266, 1263930, 1333194, 1406252, 1483314, 1564600, 1650340, 1740778, 1836173, 1936794, 2042930, 2154882, 2272970, 2397528, 2528912, 2667496, 2813674, 2967863, 3130502, 3302053, 3483005, 3673873, 3875201, 4087562, 4311559, 4547832, 4797053, 5059931, 5337215, 5629694, 5938202, 6263614, 6606860, 6968915, 7350811, 7753635, 8178534, 8626718, 9099462, 9598112, 10124088, 10678888, 11264090, 11881362, 12532461, 13219239, 13943653, 14707765, 15513750, 16363902, 17260644, 18206527, 19204245, 20256637, 21366700, 22537594, 23772654, 25075395, 26449526, 27898960, 29427822, 31040466, 32741483, 34535716, 36428273, 38424542, 40530206, 42751262, 45094030, 47565183, 50171755, 52921167, 55821246, 58880250, 62106888, 65510344, 69100311, 72887008, 76881216, 81094306, 85594273, 90225770, 95170142, 100385466, 105886589, 111689174, 117809740, 124265714, 131075474, 138258410, 145834970, 153826726, 162256430, 171148082, 180526997, 190419876, 200854885, 211861732, 223471711, 223471711, 248635353, 262260570, 276632449, 291791906, 307782102, 324648562, 342439302, 361204976, 380999008, 401877754, 423900654, 447130410, 471633156, 497478653, 524740482, 553496261, 583827855, 615821622, 649568646, 685165008, 722712050, 762316670, 804091623, 848155844, 894634784, 943660770, 995373379, 1049919840, 1107455447, 1168144006, 1232158297, 1299680571, 1370903066, 1446028554, 1525246918, 1608855764, 1697021059};
diff --git a/src/constants/GameConstants.java b/src/constants/game/GameConstants.java
similarity index 93%
rename from src/constants/GameConstants.java
rename to src/constants/game/GameConstants.java
index 5575e2169c..929a63a460 100644
--- a/src/constants/GameConstants.java
+++ b/src/constants/game/GameConstants.java
@@ -1,4 +1,4 @@
-package constants;
+package constants.game;
import client.MapleDisease;
import java.util.ArrayList;
@@ -6,10 +6,18 @@ import java.util.List;
import java.util.HashMap;
import java.util.Map;
import client.MapleJob;
+import config.YamlConfig;
import constants.skills.Aran;
+import java.io.File;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Locale;
+import provider.MapleData;
+import provider.MapleDataDirectoryEntry;
+import provider.MapleDataFileEntry;
+import provider.MapleDataProvider;
+import provider.MapleDataProviderFactory;
+import provider.MapleDataTool;
import server.maps.MapleMap;
import server.maps.FieldLimit;
import server.quest.MapleQuest;
@@ -33,11 +41,13 @@ public class GameConstants {
private static final int[] jobUpgradeSpUp = {0, 1, 2, 3, 6};
private final static Map jobNames = new HashMap<>();
private final static NumberFormat nfFormatter = new DecimalFormat("#,###,###,###");
- private final static NumberFormat nfParser = NumberFormat.getInstance(ServerConstants.USE_UNITPRICE_WITH_COMMA ? Locale.FRANCE : Locale.UK);
+ private final static NumberFormat nfParser = NumberFormat.getInstance(YamlConfig.config.server.USE_UNITPRICE_WITH_COMMA ? Locale.FRANCE : Locale.UK);
public static final MapleDisease[] CPQ_DISEASES = {MapleDisease.SLOW, MapleDisease.SEDUCE, MapleDisease.STUN, MapleDisease.POISON,
MapleDisease.SEAL, MapleDisease.DARKNESS, MapleDisease.WEAKEN, MapleDisease.CURSE};
+ public static final int MAX_FIELD_MOB_DAMAGE = getMaxObstacleMobDamageFromWz() * 2;
+
public static int getPlayerBonusDropRate(int slot) {
return(DROP_RATE_GAIN[slot]);
}
@@ -480,18 +490,6 @@ public class GameConstants {
}
}
- public static int getHiddenSkill(final int skill) {
- switch (skill) {
- case Aran.HIDDEN_FULL_DOUBLE:
- case Aran.HIDDEN_FULL_TRIPLE:
- return Aran.FULL_SWING;
- case Aran.HIDDEN_OVER_DOUBLE:
- case Aran.HIDDEN_OVER_TRIPLE:
- return Aran.OVER_SWING;
- }
- return skill;
- }
-
public static int getSkillBook(final int job) {
if (job >= 2210 && job <= 2218) {
return job - 2209;
@@ -563,7 +561,7 @@ public class GameConstants {
}
public static boolean isFreeMarketRoom(int mapid) {
- return mapid > 910000000 && mapid < 910000023;
+ return mapid / 1000000 == 910 && mapid > 910000000; // FM rooms subset, thanks to shavit
}
public static boolean isMerchantLocked(MapleMap map) {
@@ -657,7 +655,7 @@ public class GameConstants {
}
public synchronized static String numberWithCommas(int i) {
- if(!ServerConstants.USE_DISPLAY_NUMBERS_WITH_COMMA) {
+ if(!YamlConfig.config.server.USE_DISPLAY_NUMBERS_WITH_COMMA) {
return nfFormatter.format(i); // will display number on whatever locale is currently assigned on NumberFormat
} else {
return NumberFormat.getNumberInstance(Locale.UK).format(i);
@@ -672,4 +670,32 @@ public class GameConstants {
return 0.0f;
}
}
+
+ private static int getMaxObstacleMobDamageFromWz() {
+ MapleDataProvider mapSource = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Map.wz"));
+ int maxMobDmg = 0;
+
+ MapleDataDirectoryEntry root = mapSource.getRoot();
+ for (MapleDataDirectoryEntry objData : root.getSubdirectories()) {
+ if (!objData.getName().contentEquals("Obj")) {
+ continue;
+ }
+
+ for (MapleDataFileEntry obj : objData.getFiles()) {
+ for (MapleData l0 : mapSource.getData(objData.getName() + "/" + obj.getName()).getChildren()) {
+ for (MapleData l1 : l0.getChildren()) {
+ for (MapleData l2 : l1.getChildren()) {
+ int objDmg = MapleDataTool.getIntConvert("s1/mobdamage", l2, 0);
+ if (maxMobDmg < objDmg) {
+ maxMobDmg = objDmg;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return maxMobDmg;
+ }
+
}
diff --git a/src/constants/ScriptableNPCConstants.java b/src/constants/game/ScriptableNPCConstants.java
similarity index 78%
rename from src/constants/ScriptableNPCConstants.java
rename to src/constants/game/ScriptableNPCConstants.java
index cfddd8563b..df8a255cf9 100644
--- a/src/constants/ScriptableNPCConstants.java
+++ b/src/constants/game/ScriptableNPCConstants.java
@@ -1,4 +1,4 @@
-package constants;
+package constants.game;
/**
* @brief ScriptableNPCConstants
@@ -16,7 +16,8 @@ import tools.Pair;
public class ScriptableNPCConstants {
public static final Set> SCRIPTABLE_NPCS = new HashSet>(){{
- add(new Pair<>(9200000, "Cody"));
+ //add(new Pair<>(9200000, "Cody"));
+ add(new Pair<>(9001105, "Grandpa Moon Bunny"));
}};
}
diff --git a/src/constants/EquipSlot.java b/src/constants/inventory/EquipSlot.java
similarity index 98%
rename from src/constants/EquipSlot.java
rename to src/constants/inventory/EquipSlot.java
index 178759d1d3..63c7f7b3a9 100644
--- a/src/constants/EquipSlot.java
+++ b/src/constants/inventory/EquipSlot.java
@@ -1,4 +1,4 @@
-package constants;
+package constants.inventory;
/**
*
diff --git a/src/constants/EquipType.java b/src/constants/inventory/EquipType.java
similarity index 98%
rename from src/constants/EquipType.java
rename to src/constants/inventory/EquipType.java
index f1c6b5045d..afcc627420 100644
--- a/src/constants/EquipType.java
+++ b/src/constants/inventory/EquipType.java
@@ -17,7 +17,7 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
-package constants;
+package constants.inventory;
import java.util.HashMap;
import java.util.Map;
diff --git a/src/constants/ItemConstants.java b/src/constants/inventory/ItemConstants.java
similarity index 85%
rename from src/constants/ItemConstants.java
rename to src/constants/inventory/ItemConstants.java
index fbbbfc900b..dae6df6b89 100644
--- a/src/constants/ItemConstants.java
+++ b/src/constants/inventory/ItemConstants.java
@@ -19,9 +19,12 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
-package constants;
+package constants.inventory;
+import constants.net.ServerConstants;
import client.inventory.MapleInventoryType;
+import config.YamlConfig;
+
import java.util.HashSet;
import java.util.Set;
import java.util.HashMap;
@@ -35,16 +38,16 @@ import java.util.Map;
public final class ItemConstants {
protected static Map inventoryTypeCache = new HashMap<>();
- public final static int LOCK = 0x01;
- public final static int SPIKES = 0x02;
- public final static int KARMA_USE = 0x02;
- public final static int COLD = 0x04;
- public final static int UNTRADEABLE = 0x08;
- public final static int KARMA_EQP = 0x10;
- public final static int SANDBOX = 0x40; // let 0x40 until it's proven something uses this
- public final static int PET_COME = 0x80;
- public final static int ACCOUNT_SHARING = 0x100;
- public final static int MERGE_UNTRADEABLE = 0x200;
+ public final static short LOCK = 0x01;
+ public final static short SPIKES = 0x02;
+ public final static short KARMA_USE = 0x02;
+ public final static short COLD = 0x04;
+ public final static short UNTRADEABLE = 0x08;
+ public final static short KARMA_EQP = 0x10;
+ public final static short SANDBOX = 0x40; // let 0x40 until it's proven something uses this
+ public final static short PET_COME = 0x80;
+ public final static short ACCOUNT_SHARING = 0x100;
+ public final static short MERGE_UNTRADEABLE = 0x200;
public final static boolean EXPIRING_ITEMS = true;
public final static Set permanentItemids = new HashSet<>();
@@ -107,7 +110,7 @@ public final class ItemConstants {
}
public static boolean isExpirablePet(int itemId) {
- return ServerConstants.USE_ERASE_PET_ON_EXPIRATION || itemId == 5000054;
+ return YamlConfig.config.server.USE_ERASE_PET_ON_EXPIRATION || itemId == 5000054;
}
public static boolean isPermanentItem(int itemId) {
@@ -147,7 +150,7 @@ public final class ItemConstants {
return scrollId == 2040727 || scrollId == 2041058;
}
- public static boolean isFlagModifier(int scrollId, byte flag) {
+ public static boolean isFlagModifier(int scrollId, short flag) {
if(scrollId == 2041058 && ((flag & ItemConstants.COLD) == ItemConstants.COLD)) return true;
if(scrollId == 2040727 && ((flag & ItemConstants.SPIKES) == ItemConstants.SPIKES)) return true;
return false;
@@ -167,11 +170,11 @@ public final class ItemConstants {
}
public static boolean isPartyItem(int itemId) {
- return itemId >= 2022430 && itemId <= 2022433;
+ return itemId >= 2022430 && itemId <= 2022433 || itemId >= 2022160 && itemId <= 2022163;
}
public static boolean isPartyAllcure(int itemId) {
- return itemId == 2022433;
+ return itemId == 2022433 || itemId == 2022163;
}
public static boolean isHiredMerchant(int itemId) {
@@ -247,4 +250,12 @@ public final class ItemConstants {
public static boolean isHair(int itemId) {
return itemId >= 30000 && itemId < 35000;
}
+
+ public static boolean isFaceExpression(int itemId) {
+ return itemId / 10000 == 516;
+ }
+
+ public static boolean isChair(int itemId) {
+ return itemId / 10000 == 301;
+ }
}
diff --git a/src/constants/OpcodeConstants.java b/src/constants/net/OpcodeConstants.java
similarity index 98%
rename from src/constants/OpcodeConstants.java
rename to src/constants/net/OpcodeConstants.java
index 114b9339ba..d37bff7331 100644
--- a/src/constants/OpcodeConstants.java
+++ b/src/constants/net/OpcodeConstants.java
@@ -17,7 +17,7 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
-package constants;
+package constants.net;
import java.util.Map;
import java.util.HashMap;
diff --git a/src/constants/net/ServerConstants.java b/src/constants/net/ServerConstants.java
new file mode 100644
index 0000000000..869a135f5d
--- /dev/null
+++ b/src/constants/net/ServerConstants.java
@@ -0,0 +1,35 @@
+package constants.net;
+
+public class ServerConstants {
+
+ //Server Version
+ public static short VERSION = 83;
+
+ //Java Configuration
+ public static final boolean JAVA_8 = getJavaVersion() >= 8; //Max amount of times a party leader is allowed to persist on the Party Search before entry expiration (thus needing to manually restart the Party Search to be able to search for members).
+
+ //Debug Variables
+ public static int DEBUG_VALUES[] = new int[10]; // Field designed for packet testing purposes
+
+ // https://github.com/openstreetmap/josm/blob/a3a6e8a6b657cf4c5b4c64ea14d6e87be6280d65/src/org/openstreetmap/josm/tools/Utils.java#L1566-L1585
+ /**
+ * Returns the Java version as an int value.
+ * @return the Java version as an int value (8, 9, etc.)
+ * @since 12130
+ */
+ public static int getJavaVersion() {
+ String version = System.getProperty("java.version");
+ if (version.startsWith("1.")) {
+ version = version.substring(2);
+ }
+ // Allow these formats:
+ // 1.8.0_72-ea
+ // 9-ea
+ // 9
+ // 9.0.1
+ int dotPos = version.indexOf('.');
+ int dashPos = version.indexOf('-');
+ return Integer.parseInt(version.substring(0,
+ dotPos > -1 ? dotPos : dashPos > -1 ? dashPos : 1));
+ }
+}
diff --git a/src/constants/skills/Aran.java b/src/constants/skills/Aran.java
index 75a857c2bb..7a78c8ff69 100644
--- a/src/constants/skills/Aran.java
+++ b/src/constants/skills/Aran.java
@@ -29,11 +29,13 @@ public class Aran {
public static final int DOUBLE_SWING = 21000002;
public static final int TRIPLE_SWING = 21100001;
public static final int COMBO_ABILITY = 21000000;
+ public static final int COMBAT_STEP = 21001001;
public static final int POLEARM_BOOSTER = 21001003;
public static final int MAPLE_WARRIOR = 21121000;
public static final int FREEZE_STANDING = 21121003;
public static final int SNOW_CHARGE = 21111005;
public static final int HEROS_WILL = 21121008;
+ public static final int HIGH_DEFENSE = 21120004;
public static final int BODY_PRESSURE = 21101003;
public static final int COMBO_DRAIN = 21100005;
public static final int COMBO_SMASH = 21100004;
diff --git a/src/constants/skills/FPWizard.java b/src/constants/skills/FPWizard.java
index 2025c05924..b62b90208c 100644
--- a/src/constants/skills/FPWizard.java
+++ b/src/constants/skills/FPWizard.java
@@ -29,5 +29,6 @@ public class FPWizard {
public static final int MP_EATER = 2100000;
public static final int MEDITATION = 2101001;
public static final int SLOW = 2101003;
+ public static final int FIRE_ARROW = 2101004;
public static final int POISON_BREATH = 2101005;
}
diff --git a/src/constants/skills/Warrior.java b/src/constants/skills/Warrior.java
index 050f8a4f15..7bb463fa70 100644
--- a/src/constants/skills/Warrior.java
+++ b/src/constants/skills/Warrior.java
@@ -11,4 +11,5 @@ package constants.skills;
public class Warrior {
public static final int IMPROVED_HPREC = 1000000;
public static final int IMPROVED_MAXHP = 1000001;
+ public static final int IRON_BODY = 1000003;
}
diff --git a/src/constants/CharsetConstants.java b/src/constants/string/CharsetConstants.java
similarity index 97%
rename from src/constants/CharsetConstants.java
rename to src/constants/string/CharsetConstants.java
index a00bc90bd2..45c9c6ce4e 100644
--- a/src/constants/CharsetConstants.java
+++ b/src/constants/string/CharsetConstants.java
@@ -4,7 +4,7 @@
* and open the template in the editor.
*/
-package constants;
+package constants.string;
/*
* Thanks to GabrielSin (EllinMS) - gabrielsin@playellin.net
diff --git a/src/constants/LanguageConstants.java b/src/constants/string/LanguageConstants.java
similarity index 99%
rename from src/constants/LanguageConstants.java
rename to src/constants/string/LanguageConstants.java
index 152fd78509..2170961aad 100644
--- a/src/constants/LanguageConstants.java
+++ b/src/constants/string/LanguageConstants.java
@@ -1,4 +1,4 @@
-package constants;
+package constants.string;
import client.MapleCharacter;
diff --git a/src/net/MapleServerHandler.java b/src/net/MapleServerHandler.java
index 58a43e75ed..3922c847c8 100644
--- a/src/net/MapleServerHandler.java
+++ b/src/net/MapleServerHandler.java
@@ -28,19 +28,20 @@ import java.util.HashSet;
import java.util.Calendar;
import java.util.concurrent.atomic.AtomicLong;
+import config.YamlConfig;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import client.MapleClient;
-import constants.ServerConstants;
+import constants.net.ServerConstants;
import java.net.InetSocketAddress;
import net.server.Server;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReentrantLock;
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
-import net.server.coordinator.MapleSessionCoordinator;
+import net.server.coordinator.session.MapleSessionCoordinator;
import tools.FilePrinter;
import tools.MapleAESOFB;
@@ -188,7 +189,7 @@ public class MapleServerHandler extends IoHandlerAdapter {
short packetId = slea.readShort();
MapleClient client = (MapleClient) session.getAttribute(MapleClient.CLIENT_KEY);
- if(ServerConstants.USE_DEBUG_SHOW_RCVD_PACKET && !ignoredDebugRecvPackets.contains(packetId)) System.out.println("Received packet id " + packetId);
+ if(YamlConfig.config.server.USE_DEBUG_SHOW_RCVD_PACKET && !ignoredDebugRecvPackets.contains(packetId)) System.out.println("Received packet id " + packetId);
final MaplePacketHandler packetHandler = processor.getHandler(packetId);
if (packetHandler != null && packetHandler.validateState(client)) {
try {
@@ -198,6 +199,7 @@ public class MapleServerHandler extends IoHandlerAdapter {
FilePrinter.printError(FilePrinter.PACKET_HANDLER + packetHandler.getClass().getName() + ".txt", t, "Error for " + (client.getPlayer() == null ? "" : "player ; " + client.getPlayer() + " on map ; " + client.getPlayer().getMapId() + " - ") + "account ; " + client.getAccountName() + "\r\n" + slea.toString());
//client.announce(MaplePacketCreator.enableActions());//bugs sometimes
}
+ client.updateLastPacket();
}
}
@@ -240,14 +242,14 @@ public class MapleServerHandler extends IoHandlerAdapter {
long timeNow = Server.getInstance().getCurrentTime();
long timeThen = timeNow - 15000;
+ Set pingClients = new HashSet<>();
idleLock.lock();
try {
for(Entry mc : idleSessions.entrySet()) {
if(timeNow - mc.getValue() >= 15000) {
- mc.getKey().testPing(timeThen);
+ pingClients.add(mc.getKey());
}
}
-
idleSessions.clear();
if(!tempIdleSessions.isEmpty()) {
@@ -265,6 +267,10 @@ public class MapleServerHandler extends IoHandlerAdapter {
} finally {
idleLock.unlock();
}
+
+ for(MapleClient c : pingClients) {
+ c.testPing(timeThen);
+ }
}
private void idleManagerTask() {
diff --git a/src/net/PacketProcessor.java b/src/net/PacketProcessor.java
index 0e03f0d0e7..ad7dade738 100644
--- a/src/net/PacketProcessor.java
+++ b/src/net/PacketProcessor.java
@@ -163,6 +163,7 @@ public final class PacketProcessor {
registerHandler(RecvOpcode.CANCEL_BUFF, new CancelBuffHandler());
registerHandler(RecvOpcode.CANCEL_ITEM_EFFECT, new CancelItemEffectHandler());
registerHandler(RecvOpcode.PLAYER_INTERACTION, new PlayerInteractionHandler());
+ registerHandler(RecvOpcode.RPS_ACTION, new RPSActionHandler());
registerHandler(RecvOpcode.DISTRIBUTE_AP, new DistributeAPHandler());
registerHandler(RecvOpcode.DISTRIBUTE_SP, new DistributeSPHandler());
registerHandler(RecvOpcode.CHANGE_KEYMAP, new KeymapChangeHandler());
@@ -222,8 +223,14 @@ public final class PacketProcessor {
registerHandler(RecvOpcode.MONSTER_BOOK_COVER, new MonsterBookCoverHandler());
registerHandler(RecvOpcode.AUTO_DISTRIBUTE_AP, new AutoAssignHandler());
registerHandler(RecvOpcode.MAKER_SKILL, new MakerSkillHandler());
+ registerHandler(RecvOpcode.OPEN_FAMILY_PEDIGREE, new OpenFamilyPedigreeHandler());
+ registerHandler(RecvOpcode.OPEN_FAMILY, new OpenFamilyHandler());
registerHandler(RecvOpcode.ADD_FAMILY, new FamilyAddHandler());
+ registerHandler(RecvOpcode.SEPARATE_FAMILY_BY_SENIOR, new FamilySeparateHandler());
+ registerHandler(RecvOpcode.SEPARATE_FAMILY_BY_JUNIOR, new FamilySeparateHandler());
registerHandler(RecvOpcode.USE_FAMILY, new FamilyUseHandler());
+ registerHandler(RecvOpcode.CHANGE_FAMILY_MESSAGE, new FamilyPreceptsHandler());
+ registerHandler(RecvOpcode.FAMILY_SUMMON_RESPONSE, new FamilySummonResponseHandler());
registerHandler(RecvOpcode.USE_HAMMER, new UseHammerHandler());
registerHandler(RecvOpcode.SCRIPTED_ITEM, new ScriptedItemHandler());
registerHandler(RecvOpcode.TOUCHING_REACTOR, new TouchReactorHandler());
@@ -244,6 +251,7 @@ public final class PacketProcessor {
registerHandler(RecvOpcode.PLAYER_MAP_TRANSFER, new PlayerMapTransitionHandler());
registerHandler(RecvOpcode.USE_MAPLELIFE, new UseMapleLifeHandler());
registerHandler(RecvOpcode.USE_CATCH_ITEM, new UseCatchItemHandler());
+ registerHandler(RecvOpcode.FIELD_DAMAGE_MOB, new FieldDamageMobHandler());
registerHandler(RecvOpcode.MOB_DAMAGE_MOB_FRIENDLY, new MobDamageMobFriendlyHandler());
registerHandler(RecvOpcode.PARTY_SEARCH_REGISTER, new PartySearchRegisterHandler());
registerHandler(RecvOpcode.PARTY_SEARCH_START, new PartySearchStartHandler());
diff --git a/src/net/mina/MaplePacketDecoder.java b/src/net/mina/MaplePacketDecoder.java
index 782406ba62..30695ab3f8 100644
--- a/src/net/mina/MaplePacketDecoder.java
+++ b/src/net/mina/MaplePacketDecoder.java
@@ -21,10 +21,10 @@
*/
package net.mina;
-import constants.ServerConstants;
+import config.YamlConfig;
import client.MapleClient;
-import constants.OpcodeConstants;
-import net.server.coordinator.MapleSessionCoordinator;
+import constants.net.OpcodeConstants;
+import net.server.coordinator.session.MapleSessionCoordinator;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
@@ -33,7 +33,6 @@ import tools.HexTool;
import tools.MapleAESOFB;
import tools.data.input.ByteArrayByteStream;
import tools.data.input.GenericLittleEndianAccessor;
-import net.opcodes.RecvOpcode;
import tools.FilePrinter;
public class MaplePacketDecoder extends CumulativeProtocolDecoder {
@@ -75,7 +74,7 @@ public class MaplePacketDecoder extends CumulativeProtocolDecoder {
rcvdCrypto.crypt(decryptedPacket);
MapleCustomEncryption.decryptData(decryptedPacket);
out.write(decryptedPacket);
- if (ServerConstants.USE_DEBUG_SHOW_PACKET){ // Atoot's idea: packet traffic log, applied using auto-identation thanks to lrenex
+ if (YamlConfig.config.server.USE_DEBUG_SHOW_PACKET){ // packet traffic log: Atoot's idea, applied using auto-identation thanks to lrenex
int packetLen = decryptedPacket.length;
int pHeader = readFirstShort(decryptedPacket);
String pHeaderStr = Integer.toHexString(pHeader).toUpperCase();
diff --git a/src/net/mina/MaplePacketEncoder.java b/src/net/mina/MaplePacketEncoder.java
index 9887244c1d..2bd7fda9b4 100644
--- a/src/net/mina/MaplePacketEncoder.java
+++ b/src/net/mina/MaplePacketEncoder.java
@@ -21,11 +21,10 @@ along with this program. If not, see .
*/
package net.mina;
-import constants.ServerConstants;
+import config.YamlConfig;
import client.MapleClient;
-import constants.OpcodeConstants;
-import net.opcodes.SendOpcode;
-import net.server.coordinator.MapleSessionCoordinator;
+import constants.net.OpcodeConstants;
+import net.server.coordinator.session.MapleSessionCoordinator;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoder;
@@ -43,40 +42,41 @@ public class MaplePacketEncoder implements ProtocolEncoder {
final MapleClient client = (MapleClient) session.getAttribute(MapleClient.CLIENT_KEY);
try {
- client.lockEncoder();
- try {
- final MapleAESOFB send_crypto = client.getSendCrypto();
- final byte[] input = (byte[]) message;
- if (ServerConstants.USE_DEBUG_SHOW_PACKET) {
- int packetLen = input.length;
- int pHeader = readFirstShort(input);
- String pHeaderStr = Integer.toHexString(pHeader).toUpperCase();
- String op = lookupRecv(pHeader);
- String Recv = "ServerSend:" + op + " [" + pHeaderStr + "] (" + packetLen + ")\r\n";
- if (packetLen <= 50000) {
- String RecvTo = Recv + HexTool.toString(input) + "\r\n" + HexTool.toStringFromAscii(input);
- System.out.println(RecvTo);
- if (op == null) {
- System.out.println("UnknownPacket:" + RecvTo);
+ if (client.tryacquireEncoder()) {
+ try {
+ final MapleAESOFB send_crypto = client.getSendCrypto();
+ final byte[] input = (byte[]) message;
+ if (YamlConfig.config.server.USE_DEBUG_SHOW_PACKET) {
+ int packetLen = input.length;
+ int pHeader = readFirstShort(input);
+ String pHeaderStr = Integer.toHexString(pHeader).toUpperCase();
+ String op = lookupRecv(pHeader);
+ String Recv = "ServerSend:" + op + " [" + pHeaderStr + "] (" + packetLen + ")\r\n";
+ if (packetLen <= 50000) {
+ String RecvTo = Recv + HexTool.toString(input) + "\r\n" + HexTool.toStringFromAscii(input);
+ System.out.println(RecvTo);
+ if (op == null) {
+ System.out.println("UnknownPacket:" + RecvTo);
+ }
+ } else {
+ FilePrinter.print(FilePrinter.PACKET_STREAM + MapleSessionCoordinator.getSessionRemoteAddress(session) + ".txt", HexTool.toString(new byte[]{input[0], input[1]}) + " ...");
}
- } else {
- FilePrinter.print(FilePrinter.PACKET_STREAM + MapleSessionCoordinator.getSessionRemoteAddress(session) + ".txt", HexTool.toString(new byte[]{input[0], input[1]}) + " ...");
}
+
+ final byte[] unencrypted = new byte[input.length];
+ System.arraycopy(input, 0, unencrypted, 0, input.length);
+ final byte[] ret = new byte[unencrypted.length + 4];
+ final byte[] header = send_crypto.getPacketHeader(unencrypted.length);
+ MapleCustomEncryption.encryptData(unencrypted);
+
+ send_crypto.crypt(unencrypted);
+ System.arraycopy(header, 0, ret, 0, 4);
+ System.arraycopy(unencrypted, 0, ret, 4, unencrypted.length);
+
+ out.write(IoBuffer.wrap(ret));
+ } finally {
+ client.unlockEncoder();
}
-
- final byte[] unencrypted = new byte[input.length];
- System.arraycopy(input, 0, unencrypted, 0, input.length);
- final byte[] ret = new byte[unencrypted.length + 4];
- final byte[] header = send_crypto.getPacketHeader(unencrypted.length);
- MapleCustomEncryption.encryptData(unencrypted);
-
- send_crypto.crypt(unencrypted);
- System.arraycopy(header, 0, ret, 0, 4);
- System.arraycopy(unencrypted, 0, ret, 4, unencrypted.length);
-
- out.write(IoBuffer.wrap(ret));
- } finally {
- client.unlockEncoder();
}
// System.arraycopy(unencrypted, 0, ret, 4, unencrypted.length);
// out.write(ByteBuffer.wrap(ret));
diff --git a/src/net/opcodes/RecvOpcode.java b/src/net/opcodes/RecvOpcode.java
index 3d1a942f09..98fab2ed94 100644
--- a/src/net/opcodes/RecvOpcode.java
+++ b/src/net/opcodes/RecvOpcode.java
@@ -145,10 +145,15 @@ public enum RecvOpcode {
WEDDING_TALK_MORE(0x8B),
ALLIANCE_OPERATION(0x8F),
DENY_ALLIANCE_REQUEST(0x90),
+ OPEN_FAMILY_PEDIGREE(0x91),
OPEN_FAMILY(0x92),
ADD_FAMILY(0x93),
+ SEPARATE_FAMILY_BY_SENIOR(0x94),
+ SEPARATE_FAMILY_BY_JUNIOR(0x95),
ACCEPT_FAMILY(0x96),
USE_FAMILY(0x97),
+ CHANGE_FAMILY_MESSAGE(0x98),
+ FAMILY_SUMMON_RESPONSE(0x99),
BBS_OPERATION(0x9B),
ENTER_MTS(0x9C),
USE_SOLOMON_ITEM(0x9D),
@@ -170,6 +175,7 @@ public enum RecvOpcode {
MOVE_DRAGON(0xB5),
MOVE_LIFE(0xBC),
AUTO_AGGRO(0xBD),
+ FIELD_DAMAGE_MOB(0xBF),
MOB_DAMAGE_MOB_FRIENDLY(0xC0),
MONSTER_BOMB(0xC1),
MOB_DAMAGE_MOB(0xC2),
diff --git a/src/net/opcodes/SendOpcode.java b/src/net/opcodes/SendOpcode.java
index 42e14c9b8f..bcbeb2eb19 100644
--- a/src/net/opcodes/SendOpcode.java
+++ b/src/net/opcodes/SendOpcode.java
@@ -124,7 +124,7 @@ public enum SendOpcode {
FAMILY_JOIN_REQUEST_RESULT(0x62),
FAMILY_JOIN_ACCEPTED(0x63),
FAMILY_PRIVILEGE_LIST(0x64),
- FAMILY_FAMOUS_POINT_INC_RESULT(0x65),
+ FAMILY_REP_GAIN(0x65),
FAMILY_NOTIFY_LOGIN_OR_LOGOUT(0x66), //? is logged in. LOLWUT
FAMILY_SET_PRIVILEGE(0x67),
FAMILY_SUMMON_REQUEST(0x68),
@@ -182,7 +182,7 @@ public enum SendOpcode {
CONTI_STATE(0x95),
SET_QUEST_CLEAR(0x96),
SET_QUEST_TIME(0x97),
- WARN_MESSAGE(0x98),
+ ARIANT_RESULT(0x98), // thanks lrenex
SET_OBJECT_STATE(0x99),
STOP_CLOCK(0x9A),
ARIANT_ARENA_SHOW_RESULT(0x9B),
@@ -239,6 +239,7 @@ public enum SendOpcode {
MESO_BAG_MESSAGE(0xD2),
UPDATE_QUEST_INFO(0xD3),
PLAYER_HINT(0xD6),
+ MAKER_RESULT(0xD9),
KOREAN_EVENT(0xDB),
OPEN_UI(0xDC),
LOCK_UI(0xDD),
@@ -301,7 +302,7 @@ public enum SendOpcode {
ARIANT_ARENA_USER_SCORE(0x129),
SHEEP_RANCH_INFO(0x12B),
SHEEP_RANCH_CLOTHES(0x12C),
- ARIANT_SCORE(0x12D),
+ WITCH_TOWER_SCORE_UPDATE(0x12D), // thanks lrenex
HORNTAIL_CAVE(0x12E),
ZAKUM_SHRINE(0x12F),
NPC_TALK(0x130),
diff --git a/src/net/server/PlayerStorage.java b/src/net/server/PlayerStorage.java
index 2db15fc0e2..9576cad510 100644
--- a/src/net/server/PlayerStorage.java
+++ b/src/net/server/PlayerStorage.java
@@ -28,18 +28,19 @@ import java.util.Collection;
import java.util.List;
import java.util.LinkedHashMap;
import java.util.Map;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
import net.server.audit.locks.MonitoredLockType;
+import net.server.audit.locks.MonitoredReadLock;
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
+import net.server.audit.locks.MonitoredWriteLock;
+import net.server.audit.locks.factory.MonitoredReadLockFactory;
+import net.server.audit.locks.factory.MonitoredWriteLockFactory;
public class PlayerStorage {
- private final ReentrantReadWriteLock locks = new MonitoredReentrantReadWriteLock(MonitoredLockType.PLAYER_STORAGE, true);
+ private final MonitoredReentrantReadWriteLock locks = new MonitoredReentrantReadWriteLock(MonitoredLockType.PLAYER_STORAGE, true);
private final Map storage = new LinkedHashMap<>();
private final Map nameStorage = new LinkedHashMap<>();
- private ReadLock rlock = locks.readLock();
- private WriteLock wlock = locks.writeLock();
+ private MonitoredReadLock rlock = MonitoredReadLockFactory.createLock(locks);
+ private MonitoredWriteLock wlock = MonitoredWriteLockFactory.createLock(locks);
public void addPlayer(MapleCharacter chr) {
wlock.lock();
diff --git a/src/net/server/Server.java b/src/net/server/Server.java
index b32e2d12ca..b8f0e62a50 100644
--- a/src/net/server/Server.java
+++ b/src/net/server/Server.java
@@ -21,7 +21,6 @@
*/
package net.server;
-import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.security.Security;
@@ -42,31 +41,36 @@ import java.util.Properties;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
+import config.YamlConfig;
import net.server.audit.ThreadTracker;
import net.server.audit.locks.MonitoredLockType;
+import net.server.audit.locks.MonitoredReadLock;
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
+import net.server.audit.locks.MonitoredWriteLock;
+import net.server.audit.locks.factory.MonitoredReadLockFactory;
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
+import net.server.audit.locks.factory.MonitoredWriteLockFactory;
import net.MapleServerHandler;
import net.mina.MapleCodecFactory;
import net.server.channel.Channel;
+import net.server.coordinator.session.MapleSessionCoordinator;
import net.server.guild.MapleAlliance;
import net.server.guild.MapleGuild;
import net.server.guild.MapleGuildCharacter;
-import net.server.worker.CharacterDiseaseWorker;
-import net.server.worker.CouponWorker;
-import net.server.worker.EventRecallCoordinatorWorker;
-import net.server.worker.FredrickWorker;
-import net.server.worker.InvitationWorker;
-import net.server.worker.LoginCoordinatorWorker;
-import net.server.worker.LoginStorageWorker;
-import net.server.worker.RankingCommandWorker;
-import net.server.worker.RankingLoginWorker;
-import net.server.worker.ReleaseLockWorker;
+import net.server.task.BossLogTask;
+import net.server.task.CharacterDiseaseTask;
+import net.server.task.CouponTask;
+import net.server.task.EventRecallCoordinatorTask;
+import net.server.task.DueyFredrickTask;
+import net.server.task.InvitationTask;
+import net.server.task.LoginCoordinatorTask;
+import net.server.task.LoginStorageTask;
+import net.server.task.RankingCommandTask;
+import net.server.task.RankingLoginTask;
+import net.server.task.ReleaseLockTask;
+import net.server.task.RespawnTask;
import net.server.world.World;
import org.apache.mina.core.buffer.IoBuffer;
@@ -78,30 +82,30 @@ import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import client.MapleClient;
+import client.MapleFamily;
import client.MapleCharacter;
import client.SkillFactory;
import client.command.CommandsExecutor;
import client.inventory.Item;
import client.inventory.ItemFactory;
-import client.inventory.MaplePet;
import client.inventory.manipulator.MapleCashidGenerator;
import client.newyear.NewYearCardRecord;
-import constants.ItemConstants;
-import constants.GameConstants;
-import constants.OpcodeConstants;
-import constants.ServerConstants;
+import constants.inventory.ItemConstants;
+import constants.game.GameConstants;
+import constants.net.OpcodeConstants;
+import constants.net.ServerConstants;
import java.util.TimeZone;
-import net.server.coordinator.MapleSessionCoordinator;
import server.CashShop.CashItemFactory;
import server.MapleSkillbookInformationProvider;
import server.ThreadManager;
import server.TimerManager;
+import server.expeditions.MapleExpeditionBossLog;
import server.life.MaplePlayerNPCFactory;
import server.quest.MapleQuest;
import tools.AutoJCE;
import tools.DatabaseConnection;
+import tools.FilePrinter;
import tools.Pair;
-import org.apache.mina.core.session.IoSession;
public class Server {
@@ -141,13 +145,13 @@ public class Server {
private final Lock srvLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.SERVER);
private final Lock disLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.SERVER_DISEASES);
- private final ReentrantReadWriteLock wldLock = new MonitoredReentrantReadWriteLock(MonitoredLockType.SERVER_WORLDS, true);
- private final ReadLock wldRLock = wldLock.readLock();
- private final WriteLock wldWLock = wldLock.writeLock();
+ private final MonitoredReentrantReadWriteLock wldLock = new MonitoredReentrantReadWriteLock(MonitoredLockType.SERVER_WORLDS, true);
+ private final MonitoredReadLock wldRLock = MonitoredReadLockFactory.createLock(wldLock);
+ private final MonitoredWriteLock wldWLock = MonitoredWriteLockFactory.createLock(wldLock);
- private final ReentrantReadWriteLock lgnLock = new MonitoredReentrantReadWriteLock(MonitoredLockType.SERVER_LOGIN, true);
- private final ReadLock lgnRLock = lgnLock.readLock();
- private final WriteLock lgnWLock = lgnLock.writeLock();
+ private final MonitoredReentrantReadWriteLock lgnLock = new MonitoredReentrantReadWriteLock(MonitoredLockType.SERVER_LOGIN, true);
+ private final MonitoredReadLock lgnRLock = MonitoredReadLockFactory.createLock(lgnLock);
+ private final MonitoredWriteLock lgnWLock = MonitoredWriteLockFactory.createLock(lgnLock);
private final AtomicLong currentTime = new AtomicLong(0);
private long serverCurrentTime = 0;
@@ -165,7 +169,7 @@ public class Server {
}
public void updateCurrentTime() {
- serverCurrentTime = currentTime.addAndGet(ServerConstants.UPDATE_INTERVAL);
+ serverCurrentTime = currentTime.addAndGet(YamlConfig.config.server.UPDATE_INTERVAL);
}
public long forceUpdateCurrentTime() {
@@ -337,18 +341,13 @@ public class Server {
if(worldChannels == null) return -3;
int channelid = worldChannels.size();
- if(channelid >= ServerConstants.CHANNEL_SIZE) return -2;
-
- Properties p = loadWorldINI();
- if(p == null) {
- return -1;
- }
+ if(channelid >= YamlConfig.config.server.CHANNEL_SIZE) return -2;
channelid++;
World world = this.getWorld(worldid);
Channel channel = new Channel(worldid, channelid, getCurrentTime());
-
- channel.setServerMessage(p.getProperty("whyamirecommended" + worldid));
+
+ channel.setServerMessage(YamlConfig.config.worlds.get(worldid).why_am_i_recommended);
world.addChannel(channel);
worldChannels.put(channelid, channel.getIP());
@@ -360,10 +359,7 @@ public class Server {
}
public int addWorld() {
- Properties p = loadWorldINI();
- if(p == null) return -2;
-
- int newWorld = initWorld(p);
+ int newWorld = initWorld();
if(newWorld > -1) {
installWorldPlayerRanking(newWorld);
@@ -383,40 +379,40 @@ public class Server {
return newWorld;
}
- private static int getWorldProperty(Properties p, String property, int wid, int defaultValue) {
- String content = p.getProperty(property + wid);
- return content != null ? Integer.parseInt(content) : defaultValue;
- }
-
- private int initWorld(Properties p) {
+ private int initWorld() {
wldWLock.lock();
try {
int i = worlds.size();
- if(i >= ServerConstants.WLDLIST_SIZE) {
+ if(i >= YamlConfig.config.server.WLDLIST_SIZE) {
return -1;
}
System.out.println("Starting world " + i);
- int exprate = getWorldProperty(p, "exprate", i, ServerConstants.EXP_RATE);
- int mesorate = getWorldProperty(p, "mesorate", i, ServerConstants.MESO_RATE);
- int droprate = getWorldProperty(p, "droprate", i, ServerConstants.DROP_RATE);
- int bossdroprate = getWorldProperty(p, "bossdroprate", i, ServerConstants.BOSS_DROP_RATE);
- int questrate = getWorldProperty(p, "questrate", i, ServerConstants.QUEST_RATE);
- int travelrate = getWorldProperty(p, "travelrate", i, ServerConstants.TRAVEL_RATE);
- int fishingrate = getWorldProperty(p, "fishrate", i, ServerConstants.FISHING_RATE);
+
+ int exprate = YamlConfig.config.worlds.get(i).exp_rate;
+ int mesorate = YamlConfig.config.worlds.get(i).meso_rate;
+ int droprate = YamlConfig.config.worlds.get(i).drop_rate;
+ int bossdroprate = YamlConfig.config.worlds.get(i).boss_drop_rate;
+ int questrate = YamlConfig.config.worlds.get(i).quest_rate;
+ int travelrate = YamlConfig.config.worlds.get(i).travel_rate;
+ int fishingrate = YamlConfig.config.worlds.get(i).fishing_rate;
+
+ int flag = YamlConfig.config.worlds.get(i).flag;
+ String event_message = YamlConfig.config.worlds.get(i).event_message;
+ String why_am_i_recommended = YamlConfig.config.worlds.get(i).why_am_i_recommended;
World world = new World(i,
- Integer.parseInt(p.getProperty("flag" + i)),
- p.getProperty("eventmessage" + i),
+ flag,
+ event_message,
exprate, droprate, bossdroprate, mesorate, questrate, travelrate, fishingrate);
- worldRecommendedList.add(new Pair<>(i, p.getProperty("whyamirecommended" + i)));
+ worldRecommendedList.add(new Pair<>(i, why_am_i_recommended));
worlds.add(world);
Map channelInfo = new HashMap<>();
long bootTime = getCurrentTime();
- for (int j = 1; j <= Integer.parseInt(p.getProperty("channels" + i)); j++) {
+ for (int j = 1; j <= YamlConfig.config.worlds.get(i).channels; j++) {
int channelid = j;
Channel channel = new Channel(i, channelid, bootTime);
@@ -426,7 +422,7 @@ public class Server {
channels.add(i, channelInfo);
- world.setServerMessage(p.getProperty("servermessage" + i));
+ world.setServerMessage(YamlConfig.config.worlds.get(i).server_message);
System.out.println("Finished loading world " + i + "\r\n");
return i;
@@ -506,18 +502,6 @@ public class Server {
}
}
- public static Properties loadWorldINI() {
- Properties p = new Properties();
- try {
- p.load(new FileInputStream("world.ini"));
- return p;
- } catch (Exception e) {
- e.printStackTrace();
- System.out.println("[SEVERE] Could not find/open 'world.ini'.");
- return null;
- }
- }
-
private static long getTimeLeftForNextHour() {
Calendar nextHour = Calendar.getInstance();
nextHour.add(Calendar.HOUR, 1);
@@ -527,12 +511,22 @@ public class Server {
return Math.max(0, nextHour.getTimeInMillis() - System.currentTimeMillis());
}
+ public static long getTimeLeftForNextDay() {
+ Calendar nextDay = Calendar.getInstance();
+ nextDay.add(Calendar.DAY_OF_MONTH, 1);
+ nextDay.set(Calendar.HOUR_OF_DAY, 0);
+ nextDay.set(Calendar.MINUTE, 0);
+ nextDay.set(Calendar.SECOND, 0);
+
+ return Math.max(0, nextDay.getTimeInMillis() - System.currentTimeMillis());
+ }
+
public Map getCouponRates() {
return couponRates;
}
public static void cleanNxcodeCoupons(Connection con) throws SQLException {
- if (!ServerConstants.USE_CLEAR_OUTDATED_COUPONS) return;
+ if (!YamlConfig.config.server.USE_CLEAR_OUTDATED_COUPONS) return;
long timeClear = System.currentTimeMillis() - 14 * 24 * 60 * 60 * 1000;
@@ -662,6 +656,7 @@ public class Server {
MapleCharacter player = c.getPlayer();
if(player != null && player.isLoggedinWorld()) {
player.announceDiseases();
+ player.collectDiseases();
}
}
@@ -689,7 +684,7 @@ public class Server {
public List> getWorldPlayerRanking(int worldid) {
wldRLock.lock();
try {
- return new ArrayList<>(playerRanking.get(!ServerConstants.USE_WHOLE_SERVER_RANKING ? worldid : 0));
+ return new ArrayList<>(playerRanking.get(!YamlConfig.config.server.USE_WHOLE_SERVER_RANKING ? worldid : 0));
} finally {
wldRLock.unlock();
}
@@ -700,7 +695,7 @@ public class Server {
if(!ranking.isEmpty()) {
wldWLock.lock();
try {
- if (!ServerConstants.USE_WHOLE_SERVER_RANKING) {
+ if (!YamlConfig.config.server.USE_WHOLE_SERVER_RANKING) {
for(int i = playerRanking.size(); i <= worldid; i++) {
playerRanking.add(new ArrayList>(0));
}
@@ -716,7 +711,7 @@ public class Server {
}
private void removeWorldPlayerRanking() {
- if (!ServerConstants.USE_WHOLE_SERVER_RANKING) {
+ if (!YamlConfig.config.server.USE_WHOLE_SERVER_RANKING) {
wldWLock.lock();
try {
if(playerRanking.size() < this.getWorldsSize()) {
@@ -744,7 +739,7 @@ public class Server {
if(!rankUpdates.isEmpty()) {
wldWLock.lock();
try {
- if (!ServerConstants.USE_WHOLE_SERVER_RANKING) {
+ if (!YamlConfig.config.server.USE_WHOLE_SERVER_RANKING) {
for(int i = playerRanking.size(); i <= rankUpdates.get(rankUpdates.size() - 1).getLeft(); i++) {
playerRanking.add(new ArrayList>(0));
}
@@ -762,7 +757,7 @@ public class Server {
}
private void initWorldPlayerRanking() {
- if (ServerConstants.USE_WHOLE_SERVER_RANKING) {
+ if (YamlConfig.config.server.USE_WHOLE_SERVER_RANKING) {
playerRanking.add(new ArrayList>(0));
}
updateWorldPlayerRanking();
@@ -779,7 +774,7 @@ public class Server {
con = DatabaseConnection.getConnection();
String worldQuery;
- if (!ServerConstants.USE_WHOLE_SERVER_RANKING) {
+ if (!YamlConfig.config.server.USE_WHOLE_SERVER_RANKING) {
if(worldid >= 0) {
worldQuery = (" AND `characters`.`world` = " + worldid);
} else {
@@ -789,10 +784,10 @@ public class Server {
worldQuery = (" AND `characters`.`world` >= 0 AND `characters`.`world` <= " + Math.abs(worldid));
}
- ps = con.prepareStatement("SELECT `characters`.`name`, `characters`.`level`, `characters`.`world` FROM `characters` LEFT JOIN accounts ON accounts.id = characters.accountid WHERE `characters`.`gm` < 2 AND `accounts`.`banned` = '0'" + worldQuery + " ORDER BY " + (!ServerConstants.USE_WHOLE_SERVER_RANKING ? "world, " : "") + "level DESC, exp DESC, lastExpGainTime ASC LIMIT 50");
+ ps = con.prepareStatement("SELECT `characters`.`name`, `characters`.`level`, `characters`.`world` FROM `characters` LEFT JOIN accounts ON accounts.id = characters.accountid WHERE `characters`.`gm` < 2 AND `accounts`.`banned` = '0'" + worldQuery + " ORDER BY " + (!YamlConfig.config.server.USE_WHOLE_SERVER_RANKING ? "world, " : "") + "level DESC, exp DESC, lastExpGainTime ASC LIMIT 50");
rs = ps.executeQuery();
- if (!ServerConstants.USE_WHOLE_SERVER_RANKING) {
+ if (!YamlConfig.config.server.USE_WHOLE_SERVER_RANKING) {
int currentWorld = -1;
while(rs.next()) {
int rsWorld = rs.getInt("world");
@@ -838,17 +833,12 @@ public class Server {
}
public void init() {
- Properties p = loadWorldINI();
- if(p == null) {
- System.exit(0);
- }
-
System.out.println("HeavenMS v" + ServerConstants.VERSION + " starting up.\r\n");
- if(ServerConstants.SHUTDOWNHOOK)
+ if(YamlConfig.config.server.SHUTDOWNHOOK)
Runtime.getRuntime().addShutdownHook(new Thread(shutdown(false)));
- TimeZone.setDefault(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
+ TimeZone.setDefault(TimeZone.getTimeZone(YamlConfig.config.server.TIMEZONE));
Connection c = null;
try {
@@ -868,8 +858,9 @@ public class Server {
} catch (SQLException sqle) {
sqle.printStackTrace();
}
-
- MaplePet.clearMissingPetsFromDb();
+ applyAllNameChanges(); //name changes can be missed by INSTANT_NAME_CHANGE
+ applyAllWorldTransfers();
+ //MaplePet.clearMissingPetsFromDb(); // thanks Optimist for noticing this taking too long to run
MapleCashidGenerator.loadExistentCashIdsFromDb();
IoBuffer.setUseDirectBuffer(false);
@@ -880,20 +871,25 @@ public class Server {
ThreadManager.getInstance().start();
TimerManager tMan = TimerManager.getInstance();
tMan.start();
- tMan.register(tMan.purge(), ServerConstants.PURGING_INTERVAL);//Purging ftw...
+ tMan.register(tMan.purge(), YamlConfig.config.server.PURGING_INTERVAL);//Purging ftw...
disconnectIdlesOnLoginTask();
long timeLeft = getTimeLeftForNextHour();
- tMan.register(new CharacterDiseaseWorker(), ServerConstants.UPDATE_INTERVAL, ServerConstants.UPDATE_INTERVAL);
- tMan.register(new ReleaseLockWorker(), 2 * 60 * 1000, 2 * 60 * 1000);
- tMan.register(new CouponWorker(), ServerConstants.COUPON_INTERVAL, timeLeft);
- tMan.register(new RankingCommandWorker(), 5 * 60 * 1000, 5 * 60 * 1000);
- tMan.register(new RankingLoginWorker(), ServerConstants.RANKING_INTERVAL, timeLeft);
- tMan.register(new LoginCoordinatorWorker(), 60 * 60 * 1000, timeLeft);
- tMan.register(new EventRecallCoordinatorWorker(), 60 * 60 * 1000, timeLeft);
- tMan.register(new LoginStorageWorker(), 2 * 60 * 1000, 2 * 60 * 1000);
- tMan.register(new FredrickWorker(), 60 * 60 * 1000, 60 * 60 * 1000);
- tMan.register(new InvitationWorker(), 30 * 1000, 30 * 1000);
+ tMan.register(new CharacterDiseaseTask(), YamlConfig.config.server.UPDATE_INTERVAL, YamlConfig.config.server.UPDATE_INTERVAL);
+ tMan.register(new ReleaseLockTask(), 2 * 60 * 1000, 2 * 60 * 1000);
+ tMan.register(new CouponTask(), YamlConfig.config.server.COUPON_INTERVAL, timeLeft);
+ tMan.register(new RankingCommandTask(), 5 * 60 * 1000, 5 * 60 * 1000);
+ tMan.register(new RankingLoginTask(), YamlConfig.config.server.RANKING_INTERVAL, timeLeft);
+ tMan.register(new LoginCoordinatorTask(), 60 * 60 * 1000, timeLeft);
+ tMan.register(new EventRecallCoordinatorTask(), 60 * 60 * 1000, timeLeft);
+ tMan.register(new LoginStorageTask(), 2 * 60 * 1000, 2 * 60 * 1000);
+ tMan.register(new DueyFredrickTask(), 60 * 60 * 1000, timeLeft);
+ tMan.register(new InvitationTask(), 30 * 1000, 30 * 1000);
+ tMan.register(new RespawnTask(), YamlConfig.config.server.RESPAWN_INTERVAL, YamlConfig.config.server.RESPAWN_INTERVAL);
+
+ timeLeft = getTimeLeftForNextDay();
+ MapleExpeditionBossLog.resetBossLogTable();
+ tMan.register(new BossLogTask(), 24 * 60 * 60 * 1000, timeLeft);
long timeToTake = System.currentTimeMillis();
SkillFactory.loadAllSkills();
@@ -910,13 +906,13 @@ public class Server {
NewYearCardRecord.startPendingNewYearCardRequests();
- if(ServerConstants.USE_THREAD_TRACKER) ThreadTracker.getInstance().registerThreadTrackerTask();
+ if(YamlConfig.config.server.USE_THREAD_TRACKER) ThreadTracker.getInstance().registerThreadTrackerTask();
try {
- Integer worldCount = Math.min(GameConstants.WORLD_NAMES.length, Integer.parseInt(p.getProperty("worlds")));
+ Integer worldCount = Math.min(GameConstants.WORLD_NAMES.length, YamlConfig.config.server.WORLDS);
for (int i = 0; i < worldCount; i++) {
- initWorld(p);
+ initWorld();
}
initWorldPlayerRanking();
@@ -927,7 +923,17 @@ public class Server {
System.out.println("[SEVERE] Syntax error in 'world.ini'.");
System.exit(0);
}
-
+
+ System.out.println();
+
+ if(YamlConfig.config.server.USE_FAMILY_SYSTEM) {
+ timeToTake = System.currentTimeMillis();
+ MapleFamily.loadAllFamilies();
+ System.out.println("Families loaded in " + ((System.currentTimeMillis() - timeToTake) / 1000.0) + " seconds\r\n");
+ }
+
+ System.out.println();
+
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 30);
acceptor.setHandler(new MapleServerHandler());
try {
@@ -937,13 +943,17 @@ public class Server {
}
System.out.println("Listening on port 8484\r\n\r\n");
-
+
System.out.println("HeavenMS is now online.\r\n");
online = true;
MapleSkillbookInformationProvider.getInstance();
OpcodeConstants.generateOpcodeNames();
CommandsExecutor.getInstance();
+
+ for (Channel ch : this.getAllChannels()) {
+ ch.reloadEventScriptManager();
+ }
}
public static void main(String args[]) {
@@ -1080,18 +1090,25 @@ public class Server {
public MapleGuild getGuild(int id, int world, MapleCharacter mc) {
synchronized (guilds) {
- if (guilds.get(id) != null) {
- return guilds.get(id);
+ MapleGuild g = guilds.get(id);
+ if (g != null) {
+ return g;
}
- MapleGuild g = new MapleGuild(id, world);
+
+ g = new MapleGuild(id, world);
if (g.getId() == -1) {
return null;
}
if(mc != null) {
- mc.setMGC(g.getMGC(mc.getId()));
- if(g.getMGC(mc.getId()) == null) System.out.println("null for " + mc.getName() + " when loading guild " + id);
- g.getMGC(mc.getId()).setCharacter(mc);
+ MapleGuildCharacter mgc = g.getMGC(mc.getId());
+ if (mgc != null) {
+ mc.setMGC(mgc);
+ mgc.setCharacter(mc);
+ } else {
+ FilePrinter.printError(FilePrinter.GUILD_CHAR_ERROR, "Could not find " + mc.getName() + " when loading guild " + id + ".");
+ }
+
g.setOnline(mc.getId(), true, mc.getClient().getChannel());
}
@@ -1419,6 +1436,11 @@ public class Server {
} finally {
lgnWLock.unlock();
}
+
+ for (World wserv : this.getWorlds()) {
+ wserv.clearAccountCharacterView(accountid);
+ wserv.unregisterAccountStorage(accountid);
+ }
}
*/
@@ -1536,6 +1558,82 @@ public class Server {
}
}
+ private static void applyAllNameChanges() {
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("SELECT * FROM namechanges WHERE completionTime IS NULL")) {
+ ResultSet rs = ps.executeQuery();
+ List> changedNames = new LinkedList>(); //logging only
+ while(rs.next()) {
+ con.setAutoCommit(false);
+ int nameChangeId = rs.getInt("id");
+ int characterId = rs.getInt("characterId");
+ String oldName = rs.getString("old");
+ String newName = rs.getString("new");
+ boolean success = MapleCharacter.doNameChange(con, characterId, oldName, newName, nameChangeId);
+ if(!success) con.rollback(); //discard changes
+ else changedNames.add(new Pair(oldName, newName));
+ con.setAutoCommit(true);
+ }
+ //log
+ for(Pair namePair : changedNames) {
+ FilePrinter.print(FilePrinter.CHANGE_CHARACTER_NAME, "Name change applied : from \"" + namePair.getLeft() + "\" to \"" + namePair.getRight() + "\" at " + Calendar.getInstance().getTime().toString());
+ }
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Failed to retrieve list of pending name changes.");
+ }
+ }
+
+ private static void applyAllWorldTransfers() {
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("SELECT * FROM worldtransfers WHERE completionTime IS NULL")) {
+ ResultSet rs = ps.executeQuery();
+ List removedTransfers = new LinkedList();
+ while(rs.next()) {
+ int nameChangeId = rs.getInt("id");
+ int characterId = rs.getInt("characterId");
+ int oldWorld = rs.getInt("from");
+ int newWorld = rs.getInt("to");
+ String reason = MapleCharacter.checkWorldTransferEligibility(con, characterId, oldWorld, newWorld); //check if character is still eligible
+ if(reason != null) {
+ removedTransfers.add(nameChangeId);
+ FilePrinter.print(FilePrinter.WORLD_TRANSFER, "World transfer cancelled : Character ID " + characterId + " at " + Calendar.getInstance().getTime().toString() + ", Reason : " + reason);
+ try (PreparedStatement delPs = con.prepareStatement("DELETE FROM worldtransfers WHERE id = ?")) {
+ delPs.setInt(1, nameChangeId);
+ delPs.executeUpdate();
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.WORLD_TRANSFER, e, "Failed to delete world transfer for character ID " + characterId);
+ }
+ }
+ }
+ rs.beforeFirst();
+ List>> worldTransfers = new LinkedList>>(); //logging only >
+ while(rs.next()) {
+ con.setAutoCommit(false);
+ int nameChangeId = rs.getInt("id");
+ if(removedTransfers.contains(nameChangeId)) continue;
+ int characterId = rs.getInt("characterId");
+ int oldWorld = rs.getInt("from");
+ int newWorld = rs.getInt("to");
+ boolean success = MapleCharacter.doWorldTransfer(con, characterId, oldWorld, newWorld, nameChangeId);
+ if(!success) con.rollback();
+ else worldTransfers.add(new Pair>(characterId, new Pair(oldWorld, newWorld)));
+ con.setAutoCommit(true);
+ }
+ //log
+ for(Pair> worldTransferPair : worldTransfers) {
+ int charId = worldTransferPair.getLeft();
+ int oldWorld = worldTransferPair.getRight().getLeft();
+ int newWorld = worldTransferPair.getRight().getRight();
+ FilePrinter.print(FilePrinter.WORLD_TRANSFER, "World transfer applied : Character ID " + charId + " from World " + oldWorld + " to World " + newWorld + " at " + Calendar.getInstance().getTime().toString());
+ }
+ } catch(SQLException e) {
+ e.printStackTrace();
+ FilePrinter.printError(FilePrinter.WORLD_TRANSFER, e, "Failed to retrieve list of pending world transfers.");
+ }
+ }
+
public void loadAccountCharacters(MapleClient c) {
Integer accId = c.getAccID();
if (!isFirstAccountLogin(accId)) {
@@ -1605,12 +1703,38 @@ public class Server {
return gmLevel;
}
- private static String getRemoteIp(IoSession session) {
- return MapleSessionCoordinator.getSessionRemoteAddress(session);
+ public void loadAccountStorages(MapleClient c) {
+ int accountId = c.getAccID();
+ Set accWorlds = new HashSet<>();
+ lgnWLock.lock();
+ try {
+ Set chars = accountChars.get(accountId);
+
+ for (Integer cid : chars) {
+ Integer worldid = worldChars.get(cid);
+ if (worldid != null) {
+ accWorlds.add(worldid);
+ }
+ }
+ } finally {
+ lgnWLock.unlock();
+ }
+
+ List worldList = this.getWorlds();
+ for (Integer worldid : accWorlds) {
+ if (worldid < worldList.size()) {
+ World wserv = worldList.get(worldid);
+ wserv.registerAccountStorage(accountId);
+ }
+ }
}
- public void setCharacteridInTransition(IoSession session, int charId) {
- String remoteIp = getRemoteIp(session);
+ private static String getRemoteHost(MapleClient client) {
+ return MapleSessionCoordinator.getSessionRemoteHost(client.getSession());
+ }
+
+ public void setCharacteridInTransition(MapleClient client, int charId) {
+ String remoteIp = getRemoteHost(client);
lgnWLock.lock();
try {
@@ -1620,12 +1744,12 @@ public class Server {
}
}
- public boolean validateCharacteridInTransition(IoSession session, int charId) {
- if (!ServerConstants.USE_IP_VALIDATION) {
+ public boolean validateCharacteridInTransition(MapleClient client, int charId) {
+ if (!YamlConfig.config.server.USE_IP_VALIDATION) {
return true;
}
- String remoteIp = getRemoteIp(session);
+ String remoteIp = getRemoteHost(client);
lgnWLock.lock();
try {
@@ -1636,12 +1760,12 @@ public class Server {
}
}
- public Integer freeCharacteridInTransition(IoSession session) {
- if (!ServerConstants.USE_IP_VALIDATION) {
+ public Integer freeCharacteridInTransition(MapleClient client) {
+ if (!YamlConfig.config.server.USE_IP_VALIDATION) {
return null;
}
- String remoteIp = getRemoteIp(session);
+ String remoteIp = getRemoteHost(client);
lgnWLock.lock();
try {
@@ -1651,13 +1775,13 @@ public class Server {
}
}
- public boolean hasCharacteridInTransition(IoSession session) {
- if (!ServerConstants.USE_IP_VALIDATION) {
+ public boolean hasCharacteridInTransition(MapleClient client) {
+ if (!YamlConfig.config.server.USE_IP_VALIDATION) {
return true;
}
- String remoteIp = getRemoteIp(session);
-
+ String remoteIp = getRemoteHost(client);
+
lgnRLock.lock();
try {
return transitioningChars.containsKey(remoteIp);
@@ -1759,7 +1883,7 @@ public class Server {
List allChannels = getAllChannels();
- if(ServerConstants.USE_THREAD_TRACKER) ThreadTracker.getInstance().cancelThreadTrackerTask();
+ if(YamlConfig.config.server.USE_THREAD_TRACKER) ThreadTracker.getInstance().cancelThreadTrackerTask();
for (Channel ch : allChannels) {
while (!ch.finishedShutdown()) {
@@ -1771,13 +1895,13 @@ public class Server {
}
}
}
-
+
resetServerWorlds();
-
+
ThreadManager.getInstance().stop();
TimerManager.getInstance().purge();
TimerManager.getInstance().stop();
-
+
System.out.println("Worlds + Channels are offline.");
acceptor.unbind();
acceptor = null;
diff --git a/src/net/server/audit/locks/MonitoredLockType.java b/src/net/server/audit/locks/MonitoredLockType.java
index 8aa3eb773c..53d78f062f 100644
--- a/src/net/server/audit/locks/MonitoredLockType.java
+++ b/src/net/server/audit/locks/MonitoredLockType.java
@@ -35,7 +35,9 @@ public enum MonitoredLockType {
CHARACTER_EVT,
CHARACTER_STA,
CLIENT,
+ CLIENT_ANNOUNCER,
CLIENT_ENCODER,
+ CLIENT_SESSION,
CLIENT_LOGIN,
BOOK,
ITEM,
@@ -76,6 +78,7 @@ public enum MonitoredLockType {
WORLD_PSHOPS,
WORLD_MERCHS,
WORLD_MAPOBJS,
+ WORLD_SAVECHARS,
WORLD_SUGGEST,
EIM,
EIM_PARTY,
diff --git a/src/net/server/audit/locks/active/TrackerReadLock.java b/src/net/server/audit/locks/active/TrackerReadLock.java
index 732cba27e1..fbdb6c7b3c 100644
--- a/src/net/server/audit/locks/active/TrackerReadLock.java
+++ b/src/net/server/audit/locks/active/TrackerReadLock.java
@@ -19,7 +19,7 @@
*/
package net.server.audit.locks.active;
-import constants.ServerConstants;
+import config.YamlConfig;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -59,7 +59,7 @@ public class TrackerReadLock extends ReentrantReadWriteLock.ReadLock implements
@Override
public void lock() {
- if(ServerConstants.USE_THREAD_TRACKER) {
+ if(YamlConfig.config.server.USE_THREAD_TRACKER) {
if(deadlockedState != null) {
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getDefault());
@@ -77,7 +77,7 @@ public class TrackerReadLock extends ReentrantReadWriteLock.ReadLock implements
@Override
public void unlock() {
- if(ServerConstants.USE_THREAD_TRACKER) {
+ if(YamlConfig.config.server.USE_THREAD_TRACKER) {
unregisterLocking();
}
@@ -87,7 +87,7 @@ public class TrackerReadLock extends ReentrantReadWriteLock.ReadLock implements
@Override
public boolean tryLock() {
if(super.tryLock()) {
- if(ServerConstants.USE_THREAD_TRACKER) {
+ if(YamlConfig.config.server.USE_THREAD_TRACKER) {
if(deadlockedState != null) {
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState));
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
@@ -114,7 +114,7 @@ public class TrackerReadLock extends ReentrantReadWriteLock.ReadLock implements
public void run() {
issueDeadlock(t);
}
- }, ServerConstants.LOCK_MONITOR_TIME);
+ }, YamlConfig.config.server.LOCK_MONITOR_TIME);
}
} finally {
state.unlock();
diff --git a/src/net/server/audit/locks/active/TrackerReentrantLock.java b/src/net/server/audit/locks/active/TrackerReentrantLock.java
index 09bf1f75b9..6d87a8739c 100644
--- a/src/net/server/audit/locks/active/TrackerReentrantLock.java
+++ b/src/net/server/audit/locks/active/TrackerReentrantLock.java
@@ -23,7 +23,8 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.ScheduledFuture;
-import constants.ServerConstants;
+
+import config.YamlConfig;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -61,7 +62,7 @@ public class TrackerReentrantLock extends ReentrantLock implements MonitoredReen
@Override
public void lock() {
- if(ServerConstants.USE_THREAD_TRACKER) {
+ if(YamlConfig.config.server.USE_THREAD_TRACKER) {
if(deadlockedState != null) {
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getDefault());
@@ -79,7 +80,7 @@ public class TrackerReentrantLock extends ReentrantLock implements MonitoredReen
@Override
public void unlock() {
- if(ServerConstants.USE_THREAD_TRACKER) {
+ if(YamlConfig.config.server.USE_THREAD_TRACKER) {
unregisterLocking();
}
@@ -89,7 +90,7 @@ public class TrackerReentrantLock extends ReentrantLock implements MonitoredReen
@Override
public boolean tryLock() {
if(super.tryLock()) {
- if(ServerConstants.USE_THREAD_TRACKER) {
+ if(YamlConfig.config.server.USE_THREAD_TRACKER) {
if(deadlockedState != null) {
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState));
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
@@ -116,7 +117,7 @@ public class TrackerReentrantLock extends ReentrantLock implements MonitoredReen
public void run() {
issueDeadlock(t);
}
- }, ServerConstants.LOCK_MONITOR_TIME);
+ }, YamlConfig.config.server.LOCK_MONITOR_TIME);
}
} finally {
state.unlock();
diff --git a/src/net/server/audit/locks/active/TrackerWriteLock.java b/src/net/server/audit/locks/active/TrackerWriteLock.java
index ac45afa3a7..3bf895a3f1 100644
--- a/src/net/server/audit/locks/active/TrackerWriteLock.java
+++ b/src/net/server/audit/locks/active/TrackerWriteLock.java
@@ -19,7 +19,7 @@
*/
package net.server.audit.locks.active;
-import constants.ServerConstants;
+import config.YamlConfig;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -57,7 +57,7 @@ public class TrackerWriteLock extends ReentrantReadWriteLock.WriteLock implement
@Override
public void lock() {
- if(ServerConstants.USE_THREAD_TRACKER) {
+ if(YamlConfig.config.server.USE_THREAD_TRACKER) {
if(deadlockedState != null) {
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getDefault());
@@ -75,7 +75,7 @@ public class TrackerWriteLock extends ReentrantReadWriteLock.WriteLock implement
@Override
public void unlock() {
- if(ServerConstants.USE_THREAD_TRACKER) {
+ if(YamlConfig.config.server.USE_THREAD_TRACKER) {
unregisterLocking();
}
@@ -85,7 +85,7 @@ public class TrackerWriteLock extends ReentrantReadWriteLock.WriteLock implement
@Override
public boolean tryLock() {
if(super.tryLock()) {
- if(ServerConstants.USE_THREAD_TRACKER) {
+ if(YamlConfig.config.server.USE_THREAD_TRACKER) {
if(deadlockedState != null) {
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState));
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
@@ -112,7 +112,7 @@ public class TrackerWriteLock extends ReentrantReadWriteLock.WriteLock implement
public void run() {
issueDeadlock(t);
}
- }, ServerConstants.LOCK_MONITOR_TIME);
+ }, YamlConfig.config.server.LOCK_MONITOR_TIME);
}
} finally {
state.unlock();
diff --git a/src/net/server/audit/locks/empty/EmptyReadLock.java b/src/net/server/audit/locks/empty/EmptyReadLock.java
index 6eafbce887..b0a0cb78df 100644
--- a/src/net/server/audit/locks/empty/EmptyReadLock.java
+++ b/src/net/server/audit/locks/empty/EmptyReadLock.java
@@ -19,7 +19,7 @@
*/
package net.server.audit.locks.empty;
-import constants.ServerConstants;
+import constants.net.ServerConstants;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
diff --git a/src/net/server/audit/locks/empty/EmptyReentrantLock.java b/src/net/server/audit/locks/empty/EmptyReentrantLock.java
index 64be5f9c1e..eda1e527c8 100644
--- a/src/net/server/audit/locks/empty/EmptyReentrantLock.java
+++ b/src/net/server/audit/locks/empty/EmptyReentrantLock.java
@@ -19,7 +19,7 @@
*/
package net.server.audit.locks.empty;
-import constants.ServerConstants;
+import constants.net.ServerConstants;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
diff --git a/src/net/server/audit/locks/empty/EmptyWriteLock.java b/src/net/server/audit/locks/empty/EmptyWriteLock.java
index b4343fc4e6..36a8ed8d59 100644
--- a/src/net/server/audit/locks/empty/EmptyWriteLock.java
+++ b/src/net/server/audit/locks/empty/EmptyWriteLock.java
@@ -19,7 +19,7 @@
*/
package net.server.audit.locks.empty;
-import constants.ServerConstants;
+import constants.net.ServerConstants;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
diff --git a/src/net/server/channel/Channel.java b/src/net/server/channel/Channel.java
index 17ffdc03a7..df6b7440f0 100644
--- a/src/net/server/channel/Channel.java
+++ b/src/net/server/channel/Channel.java
@@ -34,9 +34,13 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
+
+import net.server.audit.locks.MonitoredReadLock;
+import net.server.audit.locks.MonitoredWriteLock;
+import net.server.audit.locks.factory.MonitoredReadLockFactory;
+import net.server.audit.locks.factory.MonitoredWriteLockFactory;
+
+import config.YamlConfig;
import net.server.audit.LockCollector;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReentrantLock;
@@ -48,7 +52,6 @@ import net.mina.MapleCodecFactory;
import net.server.PlayerStorage;
import net.server.Server;
-import net.server.channel.worker.*;
import net.server.world.World;
import net.server.world.MapleParty;
@@ -63,6 +66,10 @@ import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.transport.socket.SocketSessionConfig;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
+import client.MapleCharacter;
+import net.server.services.ServicesManager;
+import net.server.services.BaseService;
+import net.server.services.type.ChannelServices;
import scripting.event.EventScriptManager;
import server.TimerManager;
import server.events.gm.MapleEvent;
@@ -72,12 +79,9 @@ import server.maps.MapleHiredMerchant;
import server.maps.MapleMap;
import server.maps.MapleMapManager;
import server.maps.MapleMiniDungeon;
+import server.maps.MapleMiniDungeonInfo;
import tools.MaplePacketCreator;
import tools.Pair;
-import client.MapleCharacter;
-import client.status.MonsterStatusEffect;
-import constants.ServerConstants;
-import server.maps.MapleMiniDungeonInfo;
public final class Channel {
@@ -88,13 +92,7 @@ public final class Channel {
private String ip, serverMessage;
private MapleMapManager mapManager;
private EventScriptManager eventSM;
- private MobStatusScheduler mobStatusSchedulers[] = new MobStatusScheduler[ServerConstants.CHANNEL_LOCKS];
- private MobAnimationScheduler mobAnimationSchedulers[] = new MobAnimationScheduler[ServerConstants.CHANNEL_LOCKS];
- private MobClearSkillScheduler mobClearSkillSchedulers[] = new MobClearSkillScheduler[ServerConstants.CHANNEL_LOCKS];
- private MobMistScheduler mobMistSchedulers[] = new MobMistScheduler[ServerConstants.CHANNEL_LOCKS];
- private FaceExpressionScheduler faceExpressionSchedulers[] = new FaceExpressionScheduler[ServerConstants.CHANNEL_LOCKS];
- private EventScheduler eventSchedulers[] = new EventScheduler[ServerConstants.CHANNEL_LOCKS];
- private OverallScheduler channelSchedulers[] = new OverallScheduler[ServerConstants.CHANNEL_LOCKS];
+ private ServicesManager services;
private Map hiredMerchants = new HashMap<>();
private final Map storedVars = new HashMap<>();
private Set playersAway = new HashSet<>();
@@ -125,11 +123,11 @@ public final class Channel {
private Set ongoingCathedralGuests = null;
private long ongoingStartTime;
- private ReentrantReadWriteLock merchantLock = new MonitoredReentrantReadWriteLock(MonitoredLockType.MERCHANT, true);
- private ReadLock merchRlock = merchantLock.readLock();
- private WriteLock merchWlock = merchantLock.writeLock();
+ private MonitoredReentrantReadWriteLock merchantLock = new MonitoredReentrantReadWriteLock(MonitoredLockType.MERCHANT, true);
+ private MonitoredReadLock merchRlock = MonitoredReadLockFactory.createLock(merchantLock);
+ private MonitoredWriteLock merchWlock = MonitoredWriteLockFactory.createLock(merchantLock);
- private MonitoredReentrantLock faceLock[] = new MonitoredReentrantLock[ServerConstants.CHANNEL_LOCKS];
+ private MonitoredReentrantLock faceLock[] = new MonitoredReentrantLock[YamlConfig.config.server.CHANNEL_LOCKS];
private MonitoredReentrantLock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHANNEL, true);
@@ -140,10 +138,9 @@ public final class Channel {
this.ongoingStartTime = startTime + 10000; // rude approach to a world's last channel boot time, placeholder for the 1st wedding reservation ever
this.mapManager = new MapleMapManager(null, world, channel);
try {
- eventSM = new EventScriptManager(this, getEvents());
port = 7575 + this.channel - 1;
port += (world * 100);
- ip = ServerConstants.HOST + ":" + port;
+ ip = YamlConfig.config.server.HOST + ":" + port;
IoBuffer.setUseDirectBuffer(false);
IoBuffer.setAllocator(new SimpleBufferAllocator());
acceptor = new NioSocketAcceptor();
@@ -155,7 +152,14 @@ public final class Channel {
for (MapleExpeditionType exped : MapleExpeditionType.values()) {
expedType.add(exped);
}
- eventSM.init();
+
+ if (Server.getInstance().isOnline()) { // postpone event loading to improve boot time... thanks Riizade, daronhudson for noticing slow startup times
+ eventSM = new EventScriptManager(this, getEvents());
+ eventSM.init();
+ } else {
+ String[] ev = {"0_EXAMPLE"};
+ eventSM = new EventScriptManager(this, ev);
+ }
dojoStage = new int[20];
dojoFinishTime = new long[20];
@@ -166,17 +170,7 @@ public final class Channel {
dojoTask[i] = null;
}
- for(int i = 0; i < ServerConstants.CHANNEL_LOCKS; i++) {
- faceLock[i] = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHANNEL_FACEEXPRS, true);
-
- mobStatusSchedulers[i] = new MobStatusScheduler();
- mobAnimationSchedulers[i] = new MobAnimationScheduler();
- mobClearSkillSchedulers[i] = new MobClearSkillScheduler();
- mobMistSchedulers[i] = new MobMistScheduler();
- faceExpressionSchedulers[i] = new FaceExpressionScheduler(faceLock[i]);
- eventSchedulers[i] = new EventScheduler();
- channelSchedulers[i] = new OverallScheduler();
- }
+ services = new ServicesManager(ChannelServices.OVERALL);
System.out.println(" Channel " + getId() + ": Listening on port " + port);
} catch (Exception e) {
@@ -184,27 +178,34 @@ public final class Channel {
}
}
- public void reloadEventScriptManager(){
- eventSM.cancel();
+ public synchronized void reloadEventScriptManager(){
+ if (finishedShutdown) {
+ return;
+ }
+
+ eventSM.cancel();
eventSM = null;
eventSM = new EventScriptManager(this, getEvents());
- eventSM.init();
}
- public final void shutdown() {
+ public final synchronized void shutdown() {
try {
+ if (finishedShutdown) {
+ return;
+ }
+
System.out.println("Shutting down Channel " + channel + " on World " + world);
closeAllMerchants();
disconnectAwayPlayers();
players.disconnectAll();
+ eventSM.dispose();
+ eventSM = null;
+
mapManager.dispose();
mapManager = null;
- eventSM.cancel();
- eventSM = null;
-
closeChannelSchedules();
players = null;
@@ -220,6 +221,10 @@ public final class Channel {
}
}
+ private void closeChannelServices() {
+ services.shutdown();
+ }
+
private void closeChannelSchedules() {
for(int i = 0; i < 20; i++) {
if(dojoTask[i] != null) {
@@ -227,44 +232,8 @@ public final class Channel {
dojoTask[i] = null;
}
}
-
- for(int i = 0; i < ServerConstants.CHANNEL_LOCKS; i++) {
- if(mobStatusSchedulers[i] != null) {
- mobStatusSchedulers[i].dispose();
- mobStatusSchedulers[i] = null;
- }
-
- if(mobAnimationSchedulers[i] != null) {
- mobAnimationSchedulers[i].dispose();
- mobAnimationSchedulers[i] = null;
- }
-
- if(mobClearSkillSchedulers[i] != null) {
- mobClearSkillSchedulers[i].dispose();
- mobClearSkillSchedulers[i] = null;
- }
-
- if(mobMistSchedulers[i] != null) {
- mobMistSchedulers[i].dispose();
- mobMistSchedulers[i] = null;
- }
-
- if(faceExpressionSchedulers[i] != null) {
- faceExpressionSchedulers[i].dispose();
- faceExpressionSchedulers[i] = null;
- }
-
- if(eventSchedulers[i] != null) {
- eventSchedulers[i].dispose();
- eventSchedulers[i] = null;
- }
-
- if(channelSchedulers[i] != null) {
- channelSchedulers[i].dispose();
- channelSchedulers[i] = null;
- }
- }
+ closeChannelServices();
disposeLocks();
}
@@ -278,7 +247,7 @@ public final class Channel {
}
private void emptyLocks() {
- for(int i = 0; i < ServerConstants.CHANNEL_LOCKS; i++) {
+ for(int i = 0; i < YamlConfig.config.server.CHANNEL_LOCKS; i++) {
faceLock[i] = faceLock[i].dispose();
}
@@ -308,7 +277,11 @@ public final class Channel {
public MapleMapManager getMapFactory() {
return mapManager;
}
-
+
+ public BaseService getServiceAccess(ChannelServices sv) {
+ return services.getAccess(sv).getService();
+ }
+
public int getWorld() {
return world;
}
@@ -335,7 +308,7 @@ public final class Channel {
}
public int getChannelCapacity() {
- return (int)(Math.ceil(((float) players.getAllCharacters().size() / ServerConstants.CHANNEL_LOAD) * 800));
+ return (int)(Math.ceil(((float) players.getAllCharacters().size() / YamlConfig.config.server.CHANNEL_LOAD) * 800));
}
public void broadcastPacket(final byte[] data) {
@@ -402,7 +375,7 @@ public final class Channel {
for (Integer cid : playersAway) {
MapleCharacter chr = wserv.getPlayerStorage().getCharacterById(cid);
if (chr != null && chr.isLoggedin()) {
- chr.getClient().disconnect(true, false);
+ chr.getClient().forceDisconnect();
}
}
}
@@ -460,6 +433,7 @@ public final class Channel {
}
expeditions.put(exped.getType(), exped);
+ exped.beginRegistration(); // thanks Conrad for noticing leader still receiving packets on failure-to-register cases
return true;
}
}
@@ -484,6 +458,11 @@ public final class Channel {
return getPlayerStorage().getCharacterByName(name) != null;
}
+ public boolean isActive() {
+ EventScriptManager esm = this.getEventSM();
+ return esm != null && esm.isActive();
+ }
+
public boolean finishedShutdown() {
return finishedShutdown;
}
@@ -683,7 +662,7 @@ public final class Channel {
if(dungeons.containsKey(dungeonid)) return false;
MapleMiniDungeonInfo mmdi = MapleMiniDungeonInfo.getDungeon(dungeonid);
- MapleMiniDungeon mmd = new MapleMiniDungeon(mmdi.getBase(), 30); // all minidungeons timeout on 30 mins
+ MapleMiniDungeon mmd = new MapleMiniDungeon(mmdi.getBase(), this.getMapFactory().getMap(mmdi.getDungeonId()).getTimeLimit()); // thanks Conrad for noticing hardcoded time limit for minidungeons
dungeons.put(dungeonid, mmd);
return true;
@@ -785,7 +764,7 @@ public final class Channel {
try {
List weddingReservationQueue = (cathedral ? cathedralReservationQueue : chapelReservationQueue);
- int delay = ServerConstants.WEDDING_RESERVATION_DELAY - 1 - weddingReservationQueue.size();
+ int delay = YamlConfig.config.server.WEDDING_RESERVATION_DELAY - 1 - weddingReservationQueue.size();
for(int i = 0; i < delay; i++) {
weddingReservationQueue.add(null); // push empty slots to fill the waiting time
}
@@ -868,7 +847,7 @@ public final class Channel {
public void run() {
closeOngoingWedding(cathedral);
}
- }, ServerConstants.WEDDING_RESERVATION_TIMEOUT * 60 * 1000);
+ }, YamlConfig.config.server.WEDDING_RESERVATION_TIMEOUT * 60 * 1000);
if(cathedral) {
cathedralReservationTask = weddingTask;
@@ -932,7 +911,7 @@ public final class Channel {
}
public static long getRelativeWeddingTicketExpireTime(int resSlot) {
- return (resSlot * ServerConstants.WEDDING_RESERVATION_INTERVAL * 60 * 1000);
+ return (resSlot * YamlConfig.config.server.WEDDING_RESERVATION_INTERVAL * 60 * 1000);
}
public String getWeddingReservationTimeLeft(Integer weddingId) {
@@ -958,7 +937,7 @@ public final class Channel {
return venue + " - RIGHT NOW";
}
- return venue + " - " + getTimeLeft(ongoingStartTime + (resStatus * ServerConstants.WEDDING_RESERVATION_INTERVAL * 60 * 1000)) + " from now";
+ return venue + " - " + getTimeLeft(ongoingStartTime + (resStatus * YamlConfig.config.server.WEDDING_RESERVATION_INTERVAL * 60 * 1000)) + " from now";
} finally {
lock.unlock();
}
@@ -1017,84 +996,6 @@ public final class Channel {
return !usedMC.contains(getMonsterCarnivalRoom(cpq1, field));
}
- private static int getChannelSchedulerIndex(int mapid) {
- int section = 1000000000 / ServerConstants.CHANNEL_LOCKS;
- return mapid / section;
- }
-
- public void registerMobStatus(int mapid, MonsterStatusEffect mse, Runnable cancelAction, long duration) {
- registerMobStatus(mapid, mse, cancelAction, duration, null, -1);
- }
-
- public void registerMobStatus(int mapid, MonsterStatusEffect mse, Runnable cancelAction, long duration, Runnable overtimeAction, int overtimeDelay) {
- mobStatusSchedulers[getChannelSchedulerIndex(mapid)].registerMobStatus(mse, cancelAction, duration, overtimeAction, overtimeDelay);
- }
-
- public void interruptMobStatus(int mapid, MonsterStatusEffect mse) {
- mobStatusSchedulers[getChannelSchedulerIndex(mapid)].interruptMobStatus(mse);
- }
-
- public boolean registerMobOnAnimationEffect(int mapid, int mobHash, long delay) {
- return mobAnimationSchedulers[getChannelSchedulerIndex(mapid)].registerAnimationMode(mobHash, delay);
- }
-
- public void registerMobClearSkillAction(int mapid, Runnable runAction, long delay) {
- mobClearSkillSchedulers[getChannelSchedulerIndex(mapid)].registerClearSkillAction(runAction, delay);
- }
-
- public void registerMobMistCancelAction(int mapid, Runnable runAction, long delay) {
- mobMistSchedulers[getChannelSchedulerIndex(mapid)].registerMistCancelAction(runAction, delay);
- }
-
- public void registerEventAction(int mapid, Runnable runAction, long delay) {
- eventSchedulers[getChannelSchedulerIndex(mapid)].registerDelayedAction(runAction, delay);
- }
-
- public void registerOverallAction(int mapid, Runnable runAction, long delay) {
- channelSchedulers[getChannelSchedulerIndex(mapid)].registerDelayedAction(runAction, delay);
- }
-
- public void forceRunOverallAction(int mapid, Runnable runAction) {
- channelSchedulers[getChannelSchedulerIndex(mapid)].forceRunDelayedAction(runAction);
- }
-
- public void registerFaceExpression(final MapleMap map, final MapleCharacter chr, int emote) {
- int lockid = getChannelSchedulerIndex(map.getId());
-
- Runnable cancelAction = new Runnable() {
- @Override
- public void run() {
- if(chr.isLoggedinWorld()) {
- map.broadcastMessage(chr, MaplePacketCreator.facialExpression(chr, 0), false);
- }
- }
- };
-
- faceLock[lockid].lock();
- try {
- if(!chr.isLoggedinWorld()) {
- return;
- }
-
- faceExpressionSchedulers[lockid].registerFaceExpression(chr.getId(), cancelAction);
- } finally {
- faceLock[lockid].unlock();
- }
-
- map.broadcastMessage(chr, MaplePacketCreator.facialExpression(chr, emote), false);
- }
-
- public void unregisterFaceExpression(int mapid, MapleCharacter chr) {
- int lockid = getChannelSchedulerIndex(mapid);
-
- faceLock[lockid].lock();
- try {
- faceExpressionSchedulers[lockid].unregisterFaceExpression(chr.getId());
- } finally {
- faceLock[lockid].unlock();
- }
- }
-
public void debugMarriageStatus() {
System.out.println(" ----- WORLD DATA -----");
getWorldServer().debugMarriageStatus();
diff --git a/src/net/server/channel/handlers/AbstractDealDamageHandler.java b/src/net/server/channel/handlers/AbstractDealDamageHandler.java
index 38ab0d1218..d0455c3c99 100644
--- a/src/net/server/channel/handlers/AbstractDealDamageHandler.java
+++ b/src/net/server/channel/handlers/AbstractDealDamageHandler.java
@@ -28,6 +28,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import config.YamlConfig;
import net.AbstractMaplePacketHandler;
import server.MapleStatEffect;
import server.TimerManager;
@@ -49,14 +50,13 @@ import tools.data.input.LittleEndianAccessor;
import client.MapleBuffStat;
import client.MapleCharacter;
import client.MapleJob;
-import client.MapleStat;
import client.Skill;
import client.SkillFactory;
import client.autoban.AutobanFactory;
import client.status.MonsterStatus;
import client.status.MonsterStatusEffect;
-import constants.GameConstants;
-import constants.ServerConstants;
+import constants.game.GameConstants;
+import constants.net.ServerConstants;
import constants.skills.Aran;
import constants.skills.Assassin;
import constants.skills.Bandit;
@@ -113,10 +113,11 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
public boolean ranged, magic;
public int speed = 4;
public Point position = new Point();
+
public MapleStatEffect getAttackEffect(MapleCharacter chr, Skill theSkill) {
Skill mySkill = theSkill;
if (mySkill == null) {
- mySkill = SkillFactory.getSkill(GameConstants.getHiddenSkill(skill));
+ mySkill = SkillFactory.getSkill(skill);
}
int skillLevel = chr.getSkillLevel(mySkill);
@@ -135,8 +136,9 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
}
}
- protected synchronized void applyAttack(AttackInfo attack, final MapleCharacter player, int attackCount) {
- if (player.getMap().isOwnershipRestricted(player)) {
+ protected void applyAttack(AttackInfo attack, final MapleCharacter player, int attackCount) {
+ final MapleMap map = player.getMap();
+ if (map.isOwnershipRestricted(player)) {
return;
}
@@ -148,10 +150,10 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
return;
}
if (attack.skill != 0) {
- theSkill = SkillFactory.getSkill(GameConstants.getHiddenSkill(attack.skill)); //returns back the skill id if its not a hidden skill so we are gucci
- attackEffect = attack.getAttackEffect(player, theSkill);
+ theSkill = SkillFactory.getSkill(attack.skill); // thanks Conrad for noticing some Aran skills not consuming MP
+ attackEffect = attack.getAttackEffect(player, theSkill); //returns back the player's attack effect so we are gucci
if (attackEffect == null) {
- player.getClient().announce(MaplePacketCreator.enableActions());
+ player.announce(MaplePacketCreator.enableActions());
return;
}
@@ -162,9 +164,11 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
int mobCount = attackEffect.getMobCount();
if (attack.skill != Cleric.HEAL) {
if (player.isAlive()) {
- if(attack.skill == NightWalker.POISON_BOMB) {// Poison Bomb
+ if(attack.skill == Aran.BODY_PRESSURE || attack.skill == Marauder.ENERGY_CHARGE || attack.skill == ThunderBreaker.ENERGY_CHARGE) { // thanks IxianMace for noticing Energy Charge skills refreshing on touch, leading to misleading buff applies
+ // prevent touch dmg skills refreshing
+ } else if(attack.skill == NightWalker.POISON_BOMB) {// Poison Bomb
attackEffect.applyTo(player, new Point(attack.position.x, attack.position.y));
- } else if(attack.skill != Aran.BODY_PRESSURE) {// prevent BP refreshing
+ } else {
attackEffect.applyTo(player);
if (attack.skill == DawnWarrior.FINAL_ATTACK || attack.skill == Page.FINAL_ATTACK_BW || attack.skill == Page.FINAL_ATTACK_SWORD || attack.skill == Fighter.FINAL_ATTACK_SWORD
@@ -177,7 +181,7 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
}
}
} else {
- player.getClient().announce(MaplePacketCreator.enableActions());
+ player.announce(MaplePacketCreator.enableActions());
}
}
@@ -196,7 +200,6 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
}*/
int totDamage = 0;
- final MapleMap map = player.getMap();
if (attack.skill == ChiefBandit.MESO_EXPLOSION) {
int delay = 0;
@@ -309,7 +312,7 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
TimerManager.getInstance().schedule(new Runnable() {
@Override
public void run() {
- player.getMap().spawnMesoDrop(Math.min((int) Math.max(((double) eachdf / (double) 20000) * (double) maxmeso, (double) 1), maxmeso), new Point((int) (monster.getPosition().getX() + Randomizer.nextInt(100) - 50), (int) (monster.getPosition().getY())), monster, player, true, (byte) 2);
+ map.spawnMesoDrop(Math.min((int) Math.max(((double) eachdf / (double) 20000) * (double) maxmeso, (double) 1), maxmeso), new Point((int) (monster.getPosition().getX() + Randomizer.nextInt(100) - 50), (int) (monster.getPosition().getY())), monster, player, true, (byte) 2);
}
}, delay);
delay += 100;
@@ -322,8 +325,9 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
Skill steal = SkillFactory.getSkill(Bandit.STEAL);
if (monster.getStolen().size() < 1) { // One steal per mob <3
if (steal.getEffect(player.getSkillLevel(steal)).makeChanceResult()) {
- MapleMonsterInformationProvider mi = MapleMonsterInformationProvider.getInstance();
+ monster.addStolen(0);
+ MapleMonsterInformationProvider mi = MapleMonsterInformationProvider.getInstance();
List dropPool = mi.retrieveDropPool(monster.getId());
if(!dropPool.isEmpty()) {
Integer rndPool = (int) Math.floor(Math.random() * dropPool.get(dropPool.size() - 1));
@@ -334,7 +338,7 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
List toSteal = new ArrayList<>();
toSteal.add(mi.retrieveDrop(monster.getId()).get(i));
- player.getMap().dropItemsFromMonster(toSteal, player, monster);
+ map.dropItemsFromMonster(toSteal, player, monster);
monster.addStolen(toSteal.get(0).itemId);
}
}
@@ -442,11 +446,13 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
} else {
mortalBlow = SkillFactory.getSkill(Sniper.MORTAL_BLOW);
}
- if (player.getSkillLevel(mortalBlow) > 0) {
- MapleStatEffect mortal = mortalBlow.getEffect(player.getSkillLevel(mortalBlow));
+
+ int skillLevel = player.getSkillLevel(mortalBlow);
+ if (skillLevel > 0) {
+ MapleStatEffect mortal = mortalBlow.getEffect(skillLevel);
if (monster.getHp() <= (monster.getStats().getHp() * mortal.getX()) / 100) {
if (Randomizer.rand(1, 100) <= mortal.getY()) {
- monster.getMap().killMonster(monster, player, true);
+ map.damageMonster(player, monster, Integer.MAX_VALUE); // thanks Conrad for noticing reduced EXP gain from skill kill
}
}
}
@@ -460,7 +466,7 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
int threeSnailsId = player.getJobType() * 10000000 + 1000;
if(attack.skill == threeSnailsId) {
- if(ServerConstants.USE_ULTRA_THREE_SNAILS) {
+ if(YamlConfig.config.server.USE_ULTRA_THREE_SNAILS) {
int skillLv = player.getSkillLevel(threeSnailsId);
if(skillLv > 0) {
@@ -522,7 +528,7 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
map.damageMonster(player, monster, totDamageToOneMonster);
}
- if (monster.isBuffed(MonsterStatus.WEAPON_REFLECT)) {
+ if (monster.isBuffed(MonsterStatus.WEAPON_REFLECT) && !attack.magic) {
List> mobSkills = monster.getSkills();
for (Pair ms : mobSkills) {
@@ -533,13 +539,14 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
}
}
}
- if (monster.isBuffed(MonsterStatus.MAGIC_REFLECT)) {
+ if (monster.isBuffed(MonsterStatus.MAGIC_REFLECT) && attack.magic) {
List> mobSkills = monster.getSkills();
for (Pair ms : mobSkills) {
if (ms.left == 145) {
MobSkill toUse = MobSkillFactory.getMobSkill(ms.left, ms.right);
- player.addMP(-toUse.getY());
+ player.addHP(-toUse.getY());
+ map.broadcastMessage(player, MaplePacketCreator.damagePlayer(0, monster.getId(), player.getId(), toUse.getY(), 0, 0, false, 0, true, monster.getObjectId(), 0, 0), true);
}
}
}
@@ -650,16 +657,16 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
// Find the base damage to base futher calculations on.
// Several skills have their own formula in this section.
- int calcDmgMax = 0;
+ long calcDmgMax;
- if(magic && ret.skill != 0) {
- calcDmgMax = (chr.getTotalMagic() * chr.getTotalMagic() / 1000 + chr.getTotalMagic()) / 30 + chr.getTotalInt() / 200;
+ if(magic && ret.skill != 0) { // thanks onechord for noticing a few false positives stemming from maxdmg as 0
+ calcDmgMax = (long) (Math.ceil((chr.getTotalMagic() * Math.ceil(chr.getTotalMagic() / 1000.0) + chr.getTotalMagic()) / 30.0) + Math.ceil(chr.getTotalInt() / 200.0));
} else if(ret.skill == 4001344 || ret.skill == NightWalker.LUCKY_SEVEN || ret.skill == NightLord.TRIPLE_THROW) {
- calcDmgMax = (chr.getTotalLuk() * 5) * chr.getTotalWatk() / 100;
+ calcDmgMax = (long) ((chr.getTotalLuk() * 5) * Math.ceil(chr.getTotalWatk() / 100.0));
} else if(ret.skill == DragonKnight.DRAGON_ROAR) {
- calcDmgMax = (chr.getTotalStr() * 4 + chr.getTotalDex()) * chr.getTotalWatk() / 100;
+ calcDmgMax = (long) ((chr.getTotalStr() * 4 + chr.getTotalDex()) * Math.ceil(chr.getTotalWatk() / 100.0));
} else if(ret.skill == NightLord.VENOMOUS_STAR || ret.skill == Shadower.VENOMOUS_STAB) {
- calcDmgMax = (int) (18.5 * (chr.getTotalStr() + chr.getTotalLuk()) + chr.getTotalDex() * 2) / 100 * chr.calculateMaxBaseDamage(chr.getTotalWatk());
+ calcDmgMax = (long) (Math.ceil((18.5 * (chr.getTotalStr() + chr.getTotalLuk()) + chr.getTotalDex() * 2) / 100.0) * chr.calculateMaxBaseDamage(chr.getTotalWatk()));
} else {
calcDmgMax = chr.calculateMaxBaseDamage(chr.getTotalWatk());
}
@@ -714,7 +721,7 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
if(comboBuff > 6) {
// Advanced Combo
MapleStatEffect ceffect = SkillFactory.getSkill(advcomboid).getEffect(chr.getSkillLevel(advcomboid));
- calcDmgMax = (int) Math.floor(calcDmgMax * (ceffect.getDamage() + 50) / 100 + 0.20 + (comboBuff - 5) * 0.04);
+ calcDmgMax = (long) Math.floor(calcDmgMax * (ceffect.getDamage() + 50) / 100 + 0.20 + (comboBuff - 5) * 0.04);
} else {
// Normal Combo
int skillLv = chr.getSkillLevel(oid);
@@ -722,7 +729,7 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
if(skillLv > 0) {
MapleStatEffect ceffect = SkillFactory.getSkill(oid).getEffect(skillLv);
- calcDmgMax = (int) Math.floor(calcDmgMax * (ceffect.getDamage() + 50) / 100 + Math.floor((comboBuff - 1) * (skillLv / 6)) / 100);
+ calcDmgMax = (long) Math.floor(calcDmgMax * (ceffect.getDamage() + 50) / 100 + Math.floor((comboBuff - 1) * (skillLv / 6)) / 100);
}
}
@@ -840,7 +847,7 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
}
} else if (ret.skill == Aran.BODY_PRESSURE) {
if (monster != null) {
- int bodyPressureDmg = monster.getMaxHp() * SkillFactory.getSkill(Aran.BODY_PRESSURE).getEffect(ret.skilllevel).getDamage() / 100;
+ int bodyPressureDmg = (int) Math.ceil(monster.getMaxHp() * SkillFactory.getSkill(Aran.BODY_PRESSURE).getEffect(ret.skilllevel).getDamage() / 100.0);
if (bodyPressureDmg > calcDmgMax) {
calcDmgMax = bodyPressureDmg;
}
@@ -850,7 +857,7 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
for (int j = 0; j < ret.numDamage; j++) {
int damage = lea.readInt();
- int hitDmgMax = calcDmgMax;
+ long hitDmgMax = calcDmgMax;
if(ret.skill == Buccaneer.BARRAGE || ret.skill == ThunderBreaker.BARRAGE) {
if(j > 3)
hitDmgMax *= Math.pow(2, (j - 3));
@@ -870,7 +877,7 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
hitDmgMax = 82569000; // 30% of Max HP of strongest Dojo boss
}
- int maxWithCrit = hitDmgMax;
+ long maxWithCrit = hitDmgMax;
if(canCrit) // They can crit, so up the max.
maxWithCrit *= 2;
diff --git a/src/net/server/channel/handlers/AbstractMovementPacketHandler.java b/src/net/server/channel/handlers/AbstractMovementPacketHandler.java
index 47f2852c60..2c56a360da 100644
--- a/src/net/server/channel/handlers/AbstractMovementPacketHandler.java
+++ b/src/net/server/channel/handlers/AbstractMovementPacketHandler.java
@@ -30,17 +30,18 @@ import server.maps.AnimatedMapleMapObject;
import server.movement.AbsoluteLifeMovement;
import server.movement.ChangeEquip;
import server.movement.JumpDownMovement;
-import server.movement.LifeMovement;
import server.movement.LifeMovementFragment;
import server.movement.RelativeLifeMovement;
import server.movement.TeleportMovement;
import tools.data.input.LittleEndianAccessor;
+import tools.exceptions.EmptyMovementException;
public abstract class AbstractMovementPacketHandler extends AbstractMaplePacketHandler {
- protected List parseMovement(LittleEndianAccessor lea) {
+ protected List parseMovement(LittleEndianAccessor lea) throws EmptyMovementException {
List res = new ArrayList<>();
byte numCommands = lea.readByte();
+ if (numCommands < 1) throw new EmptyMovementException(lea);
for (byte i = 0; i < numCommands; i++) {
byte command = lea.readByte();
switch (command) {
@@ -139,21 +140,104 @@ public abstract class AbstractMovementPacketHandler extends AbstractMaplePacketH
}
default:
System.out.println("Unhandled Case:" + command);
- return null;
+ throw new EmptyMovementException(lea);
}
}
+
+ if (res.isEmpty()) {
+ throw new EmptyMovementException(lea);
+ }
return res;
}
-
- protected void updatePosition(List movement, AnimatedMapleMapObject target, int yoffset) {
- for (LifeMovementFragment move : movement) {
- if (move instanceof LifeMovement) {
- if (move instanceof AbsoluteLifeMovement) {
- Point position = ((LifeMovement) move).getPosition();
- position.y += yoffset;
- target.setPosition(position);
+
+ protected void updatePosition(LittleEndianAccessor lea, AnimatedMapleMapObject target, int yOffset) throws EmptyMovementException {
+
+ byte numCommands = lea.readByte();
+ if (numCommands < 1) throw new EmptyMovementException(lea);
+ for (byte i = 0; i < numCommands; i++) {
+ byte command = lea.readByte();
+ switch (command) {
+ case 0: // normal move
+ case 5:
+ case 17: { // Float
+ //Absolute movement - only this is important for the server, other movement can be passed to the client
+ short xpos = lea.readShort(); //is signed fine here?
+ short ypos = lea.readShort();
+ target.setPosition(new Point(xpos, ypos + yOffset));
+ lea.skip(6); //xwobble = lea.readShort(); ywobble = lea.readShort(); fh = lea.readShort();
+ byte newstate = lea.readByte();
+ target.setStance(newstate);
+ lea.readShort(); //duration
+ break;
}
- target.setStance(((LifeMovement) move).getNewstate());
+ case 1:
+ case 2:
+ case 6: // fj
+ case 12:
+ case 13: // Shot-jump-back thing
+ case 16: // Float
+ case 18:
+ case 19: // Springs on maps
+ case 20: // Aran Combat Step
+ case 22: {
+ //Relative movement - server only cares about stance
+ lea.skip(4); //xpos = lea.readShort(); ypos = lea.readShort();
+ byte newstate = lea.readByte();
+ target.setStance(newstate);
+ lea.readShort(); //duration
+ break;
+ }
+ case 3:
+ case 4: // tele... -.-
+ case 7: // assaulter
+ case 8: // assassinate
+ case 9: // rush
+ case 11: //chair
+ {
+// case 14: {
+ //Teleport movement - same as above
+ lea.skip(8); //xpos = lea.readShort(); ypos = lea.readShort(); xwobble = lea.readShort(); ywobble = lea.readShort();
+ byte newstate = lea.readByte();
+ target.setStance(newstate);
+ break;
+ }
+ case 14:
+ lea.skip(9); // jump down (?)
+ break;
+ case 10: // Change Equip
+ //ignored by server
+ lea.readByte();
+ break;
+ /*case 11: { // Chair
+ short xpos = lea.readShort();
+ short ypos = lea.readShort();
+ short fh = lea.readShort();
+ byte newstate = lea.readByte();
+ short duration = lea.readShort();
+ ChairMovement cm = new ChairMovement(command, new Point(xpos, ypos), duration, newstate);
+ cm.setFh(fh);
+ res.add(cm);
+ break;
+ }*/
+ case 15: {
+ //Jump down movement - stance only
+ lea.skip(12); //short xpos = lea.readShort(); ypos = lea.readShort(); xwobble = lea.readShort(); ywobble = lea.readShort(); fh = lea.readShort(); ofh = lea.readShort();
+ byte newstate = lea.readByte();
+ target.setStance(newstate);
+ lea.readShort(); // duration
+ break;
+ }
+ case 21: {//Causes aran to do weird stuff when attacking o.o
+ /*byte newstate = lea.readByte();
+ short unk = lea.readShort();
+ AranMovement am = new AranMovement(command, null, unk, newstate);
+ res.add(am);*/
+ lea.skip(3);
+ break;
+ }
+ default:
+ System.out.println("Unhandled Case:" + command);
+ throw new EmptyMovementException(lea);
}
}
}
diff --git a/src/net/server/channel/handlers/AcceptFamilyHandler.java b/src/net/server/channel/handlers/AcceptFamilyHandler.java
index b87b124ad6..ebe120fb11 100644
--- a/src/net/server/channel/handlers/AcceptFamilyHandler.java
+++ b/src/net/server/channel/handlers/AcceptFamilyHandler.java
@@ -21,31 +21,133 @@
*/
package net.server.channel.handlers;
-import constants.ServerConstants;
+import config.YamlConfig;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
import client.MapleCharacter;
import client.MapleClient;
+import client.MapleFamily;
+import client.MapleFamilyEntry;
import net.AbstractMaplePacketHandler;
+import net.server.coordinator.world.MapleInviteCoordinator;
+import net.server.coordinator.world.MapleInviteCoordinator.InviteResult;
+import net.server.coordinator.world.MapleInviteCoordinator.InviteType;
+import net.server.coordinator.world.MapleInviteCoordinator.MapleInviteResult;
+import tools.DatabaseConnection;
+import tools.FilePrinter;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author Jay Estrella
+ * @author Ubaware
*/
public final class AcceptFamilyHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
- if (!ServerConstants.USE_FAMILY_SYSTEM){
- return;
- }
- //System.out.println(slea.toString());
+ if(!YamlConfig.config.server.USE_FAMILY_SYSTEM) {
+ return;
+ }
+ MapleCharacter chr = c.getPlayer();
int inviterId = slea.readInt();
- //String inviterName = slea.readMapleAsciiString();
+ slea.readMapleAsciiString();
+ boolean accept = slea.readByte() != 0;
+ // String inviterName = slea.readMapleAsciiString();
MapleCharacter inviter = c.getWorldServer().getPlayerStorage().getCharacterById(inviterId);
- if (inviter != null) {
- inviter.getClient().announce(MaplePacketCreator.sendFamilyJoinResponse(true, c.getPlayer().getName()));
+ if(inviter != null) {
+ MapleInviteResult inviteResult = MapleInviteCoordinator.answerInvite(InviteType.FAMILY, c.getPlayer().getId(), c.getPlayer(), accept);
+ if(inviteResult.result == InviteResult.NOT_FOUND) return; //was never invited. (or expired on server only somehow?)
+ if(accept) {
+ if(inviter.getFamily() != null) {
+ if(chr.getFamily() == null) {
+ MapleFamilyEntry newEntry = new MapleFamilyEntry(inviter.getFamily(), chr.getId(), chr.getName(), chr.getLevel(), chr.getJob());
+ newEntry.setCharacter(chr);
+ if(!newEntry.setSenior(inviter.getFamilyEntry(), true)) {
+ inviter.announce(MaplePacketCreator.sendFamilyMessage(1, 0));
+ return;
+ } else {
+ // save
+ inviter.getFamily().addEntry(newEntry);
+ insertNewFamilyRecord(chr.getId(), inviter.getFamily().getID(), inviter.getId(), false);
+ }
+ } else { //absorb target family
+ MapleFamilyEntry targetEntry = chr.getFamilyEntry();
+ MapleFamily targetFamily = targetEntry.getFamily();
+ if(targetFamily.getLeader() != targetEntry) return;
+ if(inviter.getFamily().getTotalGenerations() + targetFamily.getTotalGenerations() <= YamlConfig.config.server.FAMILY_MAX_GENERATIONS) {
+ targetEntry.join(inviter.getFamilyEntry());
+ } else {
+ inviter.announce(MaplePacketCreator.sendFamilyMessage(76, 0));
+ chr.announce(MaplePacketCreator.sendFamilyMessage(76, 0));
+ return;
+ }
+ }
+ } else { // create new family
+ if(chr.getFamily() != null && inviter.getFamily() != null && chr.getFamily().getTotalGenerations() + inviter.getFamily().getTotalGenerations() >= YamlConfig.config.server.FAMILY_MAX_GENERATIONS) {
+ inviter.announce(MaplePacketCreator.sendFamilyMessage(76, 0));
+ chr.announce(MaplePacketCreator.sendFamilyMessage(76, 0));
+ return;
+ }
+ MapleFamily newFamily = new MapleFamily(-1, c.getWorld());
+ c.getWorldServer().addFamily(newFamily.getID(), newFamily);
+ MapleFamilyEntry inviterEntry = new MapleFamilyEntry(newFamily, inviter.getId(), inviter.getName(), inviter.getLevel(), inviter.getJob());
+ inviterEntry.setCharacter(inviter);
+ newFamily.setLeader(inviter.getFamilyEntry());
+ newFamily.addEntry(inviterEntry);
+ if(chr.getFamily() == null) { //completely new family
+ MapleFamilyEntry newEntry = new MapleFamilyEntry(newFamily, chr.getId(), chr.getName(), chr.getLevel(), chr.getJob());
+ newEntry.setCharacter(chr);
+ newEntry.setSenior(inviterEntry, true);
+ // save new family
+ insertNewFamilyRecord(inviter.getId(), newFamily.getID(), 0, true);
+ insertNewFamilyRecord(chr.getId(), newFamily.getID(), inviter.getId(), false); // char was already saved by setSenior() above
+ newFamily.setMessage("", true);
+ } else { //new family for inviter, absorb invitee family
+ insertNewFamilyRecord(inviter.getId(), newFamily.getID(), 0 , true);
+ newFamily.setMessage("", true);
+ chr.getFamilyEntry().join(inviterEntry);
+ }
+ }
+ c.getPlayer().getFamily().broadcast(MaplePacketCreator.sendFamilyJoinResponse(true, c.getPlayer().getName()), c.getPlayer().getId());
+ c.announce(MaplePacketCreator.getSeniorMessage(inviter.getName()));
+ c.announce(MaplePacketCreator.getFamilyInfo(chr.getFamilyEntry()));
+ chr.getFamilyEntry().updateSeniorFamilyInfo(true);
+ } else {
+ inviter.announce(MaplePacketCreator.sendFamilyJoinResponse(false, c.getPlayer().getName()));
+ }
}
c.announce(MaplePacketCreator.sendFamilyMessage(0, 0));
}
+
+ private static void insertNewFamilyRecord(int characterID, int familyID, int seniorID, boolean updateChar) {
+ try(Connection con = DatabaseConnection.getConnection()) {
+ try(PreparedStatement ps = con.prepareStatement("INSERT INTO family_character (cid, familyid, seniorid) VALUES (?, ?, ?)")) {
+ ps.setInt(1, characterID);
+ ps.setInt(2, familyID);
+ ps.setInt(3, seniorID);
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ FilePrinter.printError(FilePrinter.FAMILY_ERROR, e, "Could not save new family record for char id " + characterID + ".");
+ e.printStackTrace();
+ }
+ if(updateChar) {
+ try(PreparedStatement ps = con.prepareStatement("UPDATE characters SET familyid = ? WHERE id = ?")) {
+ ps.setInt(1, familyID);
+ ps.setInt(2, characterID);
+ ps.executeUpdate();
+ } catch(SQLException e) {
+ FilePrinter.printError(FilePrinter.FAMILY_ERROR, e, "Could not update 'characters' 'familyid' record for char id " + characterID + ".");
+ e.printStackTrace();
+ }
+ }
+ } catch(SQLException e) {
+ FilePrinter.printError(FilePrinter.FAMILY_ERROR, e, "Could not get connection to DB.");
+ e.printStackTrace();
+ }
+ }
}
diff --git a/src/net/server/channel/handlers/AdminChatHandler.java b/src/net/server/channel/handlers/AdminChatHandler.java
index a27edfa2d0..40acfc9259 100644
--- a/src/net/server/channel/handlers/AdminChatHandler.java
+++ b/src/net/server/channel/handlers/AdminChatHandler.java
@@ -1,7 +1,7 @@
package net.server.channel.handlers;
import client.MapleClient;
-import constants.ServerConstants;
+import config.YamlConfig;
import net.AbstractMaplePacketHandler;
import tools.LogHelper;
import tools.MaplePacketCreator;
@@ -25,19 +25,19 @@ public class AdminChatHandler extends AbstractMaplePacketHandler {
switch (mode) {
case 0:// /alertall, /noticeall, /slideall
c.getWorldServer().broadcastPacket(packet);
- if (ServerConstants.USE_ENABLE_CHAT_LOG) {
+ if (YamlConfig.config.server.USE_ENABLE_CHAT_LOG) {
LogHelper.logChat(c, "Alert All", message);
}
break;
case 1:// /alertch, /noticech, /slidech
c.getChannelServer().broadcastPacket(packet);
- if (ServerConstants.USE_ENABLE_CHAT_LOG) {
+ if (YamlConfig.config.server.USE_ENABLE_CHAT_LOG) {
LogHelper.logChat(c, "Alert Ch", message);
}
break;
case 2:// /alertm /alertmap, /noticem /noticemap, /slidem /slidemap
c.getPlayer().getMap().broadcastMessage(packet);
- if (ServerConstants.USE_ENABLE_CHAT_LOG) {
+ if (YamlConfig.config.server.USE_ENABLE_CHAT_LOG) {
LogHelper.logChat(c, "Alert Map", message);
}
break;
diff --git a/src/net/server/channel/handlers/AllianceOperationHandler.java b/src/net/server/channel/handlers/AllianceOperationHandler.java
index 0c74c76142..f24956088e 100644
--- a/src/net/server/channel/handlers/AllianceOperationHandler.java
+++ b/src/net/server/channel/handlers/AllianceOperationHandler.java
@@ -124,7 +124,11 @@ public final class AllianceOperationHandler extends AbstractMaplePacketHandler {
Server.getInstance().resetAllianceGuildPlayersRank(guildid);
chr.getMGC().setAllianceRank(2);
- Server.getInstance().getGuild(chr.getGuildId()).getMGC(chr.getId()).setAllianceRank(2);
+ MapleGuild g = Server.getInstance().getGuild(chr.getGuildId());
+ if (g != null) {
+ g.getMGC(chr.getId()).setAllianceRank(2);
+ }
+
chr.saveGuildStatus();
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.addGuildToAlliance(alliance, guildid, c), -1, -1);
diff --git a/src/net/server/channel/handlers/AranComboHandler.java b/src/net/server/channel/handlers/AranComboHandler.java
index 5490843b6a..1f5de34084 100644
--- a/src/net/server/channel/handlers/AranComboHandler.java
+++ b/src/net/server/channel/handlers/AranComboHandler.java
@@ -24,7 +24,7 @@ package net.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import client.SkillFactory;
-import constants.GameConstants;
+import constants.game.GameConstants;
import constants.skills.Aran;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
diff --git a/src/net/server/channel/handlers/AutoAssignHandler.java b/src/net/server/channel/handlers/AutoAssignHandler.java
index b9e2717c4f..41b5582263 100644
--- a/src/net/server/channel/handlers/AutoAssignHandler.java
+++ b/src/net/server/channel/handlers/AutoAssignHandler.java
@@ -22,7 +22,7 @@
package net.server.channel.handlers;
import client.MapleClient;
-import client.processor.AssignAPProcessor;
+import client.processor.stat.AssignAPProcessor;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
diff --git a/src/net/server/channel/handlers/BBSOperationHandler.java b/src/net/server/channel/handlers/BBSOperationHandler.java
index 153ec2423c..6f97a56e92 100644
--- a/src/net/server/channel/handlers/BBSOperationHandler.java
+++ b/src/net/server/channel/handlers/BBSOperationHandler.java
@@ -56,7 +56,7 @@ public final class BBSOperationHandler extends AbstractMaplePacketHandler {
String text = correctLength(slea.readMapleAsciiString(), 600);
int icon = slea.readInt();
if (icon >= 0x64 && icon <= 0x6a) {
- if (c.getPlayer().haveItemWithId(5290000 + icon - 0x64, false)) {
+ if (!c.getPlayer().haveItemWithId(5290000 + icon - 0x64, false)) {
return;
}
} else if (icon < 0 || icon > 3) {
@@ -149,8 +149,8 @@ public final class BBSOperationHandler extends AbstractMaplePacketHandler {
}
private static void editBBSThread(MapleClient client, String title, String text, int icon, int localthreadid) {
- MapleCharacter c = client.getPlayer();
- if (c.getGuildId() < 1) {
+ MapleCharacter chr = client.getPlayer();
+ if (chr.getGuildId() < 1) {
return;
}
try {
@@ -160,10 +160,10 @@ public final class BBSOperationHandler extends AbstractMaplePacketHandler {
ps.setLong(2, currentServerTime());
ps.setInt(3, icon);
ps.setString(4, text);
- ps.setInt(5, c.getGuildId());
+ ps.setInt(5, chr.getGuildId());
ps.setInt(6, localthreadid);
- ps.setInt(7, c.getId());
- ps.setBoolean(8, c.getGuildRank() < 3);
+ ps.setInt(7, chr.getId());
+ ps.setBoolean(8, chr.getGuildRank() < 3);
ps.execute();
}
con.close();
@@ -174,8 +174,8 @@ public final class BBSOperationHandler extends AbstractMaplePacketHandler {
}
private static void newBBSThread(MapleClient client, String title, String text, int icon, boolean bNotice) {
- MapleCharacter c = client.getPlayer();
- if (c.getGuildId() <= 0) {
+ MapleCharacter chr = client.getPlayer();
+ if (chr.getGuildId() <= 0) {
return;
}
int nextId = 0;
@@ -184,7 +184,7 @@ public final class BBSOperationHandler extends AbstractMaplePacketHandler {
PreparedStatement ps;
if (!bNotice) {
ps = con.prepareStatement("SELECT MAX(localthreadid) AS lastLocalId FROM bbs_threads WHERE guildid = ?");
- ps.setInt(1, c.getGuildId());
+ ps.setInt(1, chr.getGuildId());
try (ResultSet rs = ps.executeQuery()) {
rs.next();
nextId = rs.getInt("lastLocalId") + 1;
@@ -192,12 +192,12 @@ public final class BBSOperationHandler extends AbstractMaplePacketHandler {
ps.close();
}
ps = con.prepareStatement("INSERT INTO bbs_threads " + "(`postercid`, `name`, `timestamp`, `icon`, `startpost`, " + "`guildid`, `localthreadid`) " + "VALUES(?, ?, ?, ?, ?, ?, ?)");
- ps.setInt(1, c.getId());
+ ps.setInt(1, chr.getId());
ps.setString(2, title);
ps.setLong(3, currentServerTime());
ps.setInt(4, icon);
ps.setString(5, text);
- ps.setInt(6, c.getGuildId());
+ ps.setInt(6, chr.getGuildId());
ps.setInt(7, nextId);
ps.execute();
ps.close();
diff --git a/src/net/server/channel/handlers/CancelChairHandler.java b/src/net/server/channel/handlers/CancelChairHandler.java
index 0b6693be51..74a4cdbae9 100644
--- a/src/net/server/channel/handlers/CancelChairHandler.java
+++ b/src/net/server/channel/handlers/CancelChairHandler.java
@@ -32,8 +32,17 @@ public final class CancelChairHandler extends AbstractMaplePacketHandler {
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
int id = slea.readShort();
MapleCharacter mc = c.getPlayer();
- if(!mc.isLoggedinWorld()) return;
- mc.sitChair(id == -1 ? 0 : id);
+ if (id >= mc.getMap().getSeats()) {
+ return;
+ }
+
+ if (c.tryacquireClient()) {
+ try {
+ mc.sitChair(id);
+ } finally {
+ c.releaseClient();
+ }
+ }
}
}
diff --git a/src/net/server/channel/handlers/CashOperationHandler.java b/src/net/server/channel/handlers/CashOperationHandler.java
index 9ebb36ccb6..ea776e240e 100644
--- a/src/net/server/channel/handlers/CashOperationHandler.java
+++ b/src/net/server/channel/handlers/CashOperationHandler.java
@@ -28,17 +28,18 @@ import client.inventory.Equip;
import client.inventory.Item;
import client.inventory.MapleInventory;
import client.inventory.MapleInventoryType;
-import constants.ItemConstants;
+import config.YamlConfig;
+import constants.inventory.ItemConstants;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import net.AbstractMaplePacketHandler;
+import net.server.Server;
import server.CashShop;
import server.CashShop.CashItem;
import server.CashShop.CashItemFactory;
import client.inventory.manipulator.MapleInventoryManipulator;
-import constants.ServerConstants;
import server.MapleItemInformationProvider;
import tools.FilePrinter;
import tools.MaplePacketCreator;
@@ -75,7 +76,7 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
if (ItemConstants.isCashStore(cItem.getItemId()) && chr.getLevel() < 16) {
c.enableCSActions();
return;
- } else if (ItemConstants.isRateCoupon(cItem.getItemId()) && !ServerConstants.USE_SUPPLY_RATE_COUPONS) {
+ } else if (ItemConstants.isRateCoupon(cItem.getItemId()) && !YamlConfig.config.server.USE_SUPPLY_RATE_COUPONS) {
chr.dropMessage(1, "Rate coupons are currently unavailable to purchase.");
c.enableCSActions();
return;
@@ -343,7 +344,7 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
slea.readByte();
MapleCharacter partner = c.getChannelServer().getPlayerStorage().getCharacterByName(sentTo);
if (partner == null) {
- chr.dropMessage(5, "The partner you specified cannot be found. Please make sure your partner is online and in the same channel.");
+ c.announce(MaplePacketCreator.showCashShopMessage((byte)0xBE));
} else {
// Need to check to make sure its actually an equip and the right SN...
if(itemRing.toItem() instanceof Equip) {
@@ -351,7 +352,7 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
Pair rings = MapleRing.createRing(itemRing.getItemId(), chr, partner);
eqp.setRingId(rings.getLeft());
cs.addToInventory(eqp);
- c.announce(MaplePacketCreator.showBoughtCashItem(eqp, c.getAccID()));
+ c.announce(MaplePacketCreator.showBoughtCashRing(eqp, partner.getName(), c.getAccID()));
cs.gift(partner.getId(), chr.getName(), text, eqp.getSN(), rings.getRight());
cs.gainCash(payment, -itemRing.getPrice());
chr.addFriendshipRing(MapleRing.loadFromDb(rings.getLeft()));
@@ -368,6 +369,65 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
}
c.announce(MaplePacketCreator.showCash(c.getPlayer()));
+ } else if (action == 0x2E) { //name change
+ CashItem cItem = CashItemFactory.getItem(slea.readInt());
+ if (cItem == null || !canBuy(chr, cItem, cs.getCash(4))) {
+ c.announce(MaplePacketCreator.showCashShopMessage((byte)0));
+ c.enableCSActions();
+ return;
+ }
+ if(cItem.getSN() == 50600000 && YamlConfig.config.server.ALLOW_CASHSHOP_NAME_CHANGE) {
+ slea.readMapleAsciiString(); //old name
+ String newName = slea.readMapleAsciiString();
+ if(!MapleCharacter.canCreateChar(newName) || chr.getLevel() < 10) { //(longest ban duration isn't tracked currently)
+ c.announce(MaplePacketCreator.showCashShopMessage((byte)0));
+ c.enableCSActions();
+ return;
+ } else if(c.getTempBanCalendar() != null && c.getTempBanCalendar().getTimeInMillis() + (30*24*60*60*1000) > Calendar.getInstance().getTimeInMillis()) {
+ c.announce(MaplePacketCreator.showCashShopMessage((byte)0));
+ c.enableCSActions();
+ return;
+ }
+ if(chr.registerNameChange(newName)) { //success
+ Item item = cItem.toItem();
+ c.announce(MaplePacketCreator.showNameChangeSuccess(item, c.getAccID()));
+ cs.addToInventory(item);
+ cs.gainCash(4, cItem, chr.getWorld());
+ } else {
+ c.announce(MaplePacketCreator.showCashShopMessage((byte)0));
+ }
+ }
+ c.enableCSActions();
+ } else if(action == 0x31) { //world transfer
+ CashItem cItem = CashItemFactory.getItem(slea.readInt());
+ if (cItem == null || !canBuy(chr, cItem, cs.getCash(4))) {
+ c.announce(MaplePacketCreator.showCashShopMessage((byte)0));
+ c.enableCSActions();
+ return;
+ }
+ if(cItem.getSN() == 50600001 && YamlConfig.config.server.ALLOW_CASHSHOP_WORLD_TRANSFER) {
+ int newWorldSelection = slea.readInt();
+
+ int worldTransferError = chr.checkWorldTransferEligibility();
+ if(worldTransferError != 0 || newWorldSelection >= Server.getInstance().getWorldsSize() || Server.getInstance().getWorldsSize() <= 1) {
+ c.announce(MaplePacketCreator.showCashShopMessage((byte)0));
+ return;
+ } else if(newWorldSelection == c.getWorld()) {
+ c.announce(MaplePacketCreator.showCashShopMessage((byte)0xDC));
+ return;
+ } else if(c.getAvailableCharacterWorldSlots(newWorldSelection) < 1 || Server.getInstance().getAccountWorldCharacterCount(c.getAccID(), newWorldSelection) >= 3) {
+ c.announce(MaplePacketCreator.showCashShopMessage((byte)0xDF));
+ return;
+ } else if(chr.registerWorldTransfer(newWorldSelection)) {
+ Item item = cItem.toItem();
+ c.announce(MaplePacketCreator.showWorldTransferSuccess(item, c.getAccID()));
+ cs.addToInventory(item);
+ cs.gainCash(4, cItem, chr.getWorld());
+ } else {
+ c.announce(MaplePacketCreator.showCashShopMessage((byte)0));
+ }
+ }
+ c.enableCSActions();
} else {
System.out.println("Unhandled action: " + action + "\n" + slea);
}
diff --git a/src/net/server/channel/handlers/CashShopSurpriseHandler.java b/src/net/server/channel/handlers/CashShopSurpriseHandler.java
index 2b625377da..f5df6a4699 100644
--- a/src/net/server/channel/handlers/CashShopSurpriseHandler.java
+++ b/src/net/server/channel/handlers/CashShopSurpriseHandler.java
@@ -40,12 +40,10 @@ public class CashShopSurpriseHandler extends AbstractMaplePacketHandler {
Pair
- cssResult = cs.openCashShopSurprise();
if(cssResult != null) {
- //Item cssItem = cssResult.getLeft(), cssBox = cssResult.getRight();
- //c.announce(MaplePacketCreator.onCashGachaponOpenSuccess(c.getAccID(), cssBox.getSN(), cssBox.getQuantity(), cssItem, cssItem.getItemId(), cssItem.getQuantity(), true));
- c.announce(MaplePacketCreator.showCashShopMessage((byte) 0xA4));
+ Item cssItem = cssResult.getLeft(), cssBox = cssResult.getRight();
+ c.announce(MaplePacketCreator.onCashGachaponOpenSuccess(c.getAccID(), cssBox.getSN(), cssBox.getQuantity(), cssItem, cssItem.getItemId(), cssItem.getQuantity(), true));
} else {
- //c.announce(MaplePacketCreator.onCashItemGachaponOpenFailed());
- c.announce(MaplePacketCreator.showCashShopMessage((byte) 0x00));
+ c.announce(MaplePacketCreator.onCashItemGachaponOpenFailed());
}
}
}
diff --git a/src/net/server/channel/handlers/ChangeMapHandler.java b/src/net/server/channel/handlers/ChangeMapHandler.java
index 206b86594a..d3be7548ab 100644
--- a/src/net/server/channel/handlers/ChangeMapHandler.java
+++ b/src/net/server/channel/handlers/ChangeMapHandler.java
@@ -30,7 +30,7 @@ import client.MapleCharacter;
import client.MapleClient;
import client.inventory.MapleInventoryType;
import client.inventory.manipulator.MapleInventoryManipulator;
-import server.MaplePortal;
+import server.maps.MaplePortal;
import server.MapleTrade;
import server.maps.MapleMap;
import tools.FilePrinter;
@@ -62,7 +62,6 @@ public final class ChangeMapHandler extends AbstractMaplePacketHandler {
String[] socket = c.getChannelServer().getIP().split(":");
chr.getCashShop().open(false);
- c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
chr.setSessionTransitionState();
try {
c.announce(MaplePacketCreator.getChannelChange(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1])));
diff --git a/src/net/server/channel/handlers/ChangeMapSpecialHandler.java b/src/net/server/channel/handlers/ChangeMapSpecialHandler.java
index fdafc0d709..1c1f6368df 100644
--- a/src/net/server/channel/handlers/ChangeMapSpecialHandler.java
+++ b/src/net/server/channel/handlers/ChangeMapSpecialHandler.java
@@ -23,7 +23,7 @@ package net.server.channel.handlers;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
-import server.MaplePortal;
+import server.maps.MaplePortal;
import server.MapleTrade;
import server.MapleTrade.TradeResult;
import tools.MaplePacketCreator;
diff --git a/src/net/server/channel/handlers/CloseRangeDamageHandler.java b/src/net/server/channel/handlers/CloseRangeDamageHandler.java
index 00dc153da2..d7792beec8 100644
--- a/src/net/server/channel/handlers/CloseRangeDamageHandler.java
+++ b/src/net/server/channel/handlers/CloseRangeDamageHandler.java
@@ -25,19 +25,14 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
-import server.MapleStatEffect;
-import tools.MaplePacketCreator;
-import tools.Pair;
-import tools.data.input.SeekableLittleEndianAccessor;
+import config.YamlConfig;
import client.MapleBuffStat;
import client.MapleCharacter;
import client.MapleClient;
import client.MapleJob;
-import client.MapleStat;
import client.Skill;
import client.SkillFactory;
-import constants.GameConstants;
-import constants.ServerConstants;
+import constants.game.GameConstants;
import constants.skills.Crusader;
import constants.skills.DawnWarrior;
import constants.skills.DragonKnight;
@@ -45,12 +40,16 @@ import constants.skills.Hero;
import constants.skills.NightWalker;
import constants.skills.Rogue;
import constants.skills.WindArcher;
+import server.MapleStatEffect;
+import tools.MaplePacketCreator;
+import tools.Pair;
+import tools.data.input.SeekableLittleEndianAccessor;
public final class CloseRangeDamageHandler extends AbstractDealDamageHandler {
+
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
- //chr.setPetLootCd(currentServerTime());
/*long timeElapsed = currentServerTime() - chr.getAutobanManager().getLastSpam(8);
if(timeElapsed < 300) {
@@ -70,7 +69,7 @@ public final class CloseRangeDamageHandler extends AbstractDealDamageHandler {
if (chr.getDojoEnergy() < 10000 && (attack.skill == 1009 || attack.skill == 10001009 || attack.skill == 20001009)) // PE hacking or maybe just lagging
return;
if (chr.getMap().isDojoMap() && attack.numAttacked > 0) {
- chr.setDojoEnergy(chr.getDojoEnergy() + ServerConstants.DOJO_ENERGY_ATK);
+ chr.setDojoEnergy(chr.getDojoEnergy() + YamlConfig.config.server.DOJO_ENERGY_ATK);
c.announce(MaplePacketCreator.getEnergy("energy", chr.getDojoEnergy()));
}
diff --git a/src/net/server/channel/handlers/CouponCodeHandler.java b/src/net/server/channel/handlers/CouponCodeHandler.java
index 35b3ee6c5b..2dfb6f86e4 100644
--- a/src/net/server/channel/handlers/CouponCodeHandler.java
+++ b/src/net/server/channel/handlers/CouponCodeHandler.java
@@ -31,6 +31,7 @@ import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -63,7 +64,6 @@ public final class CouponCodeHandler extends AbstractMaplePacketHandler {
ResultSet rs = ps.executeQuery();
while (rs.next()) {
int type = rs.getInt("type"), quantity = rs.getInt("quantity");
-
if (type < 5) {
Integer i = couponPoints.get(type);
if (i != null) {
@@ -195,8 +195,13 @@ public final class CouponCodeHandler extends AbstractMaplePacketHandler {
if (type < 0) {
c.announce(MaplePacketCreator.showCashShopMessage((byte) parseCouponResult(type)));
} else {
- List
- couponPackage = new LinkedList<>();
-
+ List
- cashItems = new LinkedList
- ();
+ List> items = new LinkedList>();
+ int nxCredit = 0;
+ int maplePoints = 0;
+ int nxPrepaid = 0;
+ int mesos = 0;
+
for (Pair> p : codeRes.getRight()) {
type = p.getLeft();
int quantity = p.getRight().getRight();
@@ -204,18 +209,26 @@ public final class CouponCodeHandler extends AbstractMaplePacketHandler {
CashShop cs = c.getPlayer().getCashShop();
switch (type) {
case 0:
+ c.getPlayer().gainMeso(quantity, false); //mesos
+ mesos += quantity;
+ break;
case 4:
cs.gainCash(1, quantity); //nxCredit
+ nxCredit += quantity;
break;
case 1:
cs.gainCash(2, quantity); //maplePoint
+ maplePoints += quantity;
break;
case 2:
cs.gainCash(4, quantity); //nxPrepaid
+ nxPrepaid += quantity;
break;
case 3:
cs.gainCash(1, quantity);
+ nxCredit += quantity;
cs.gainCash(4, (quantity / 5000));
+ nxPrepaid += quantity / 5000;
break;
default:
@@ -234,22 +247,28 @@ public final class CouponCodeHandler extends AbstractMaplePacketHandler {
Item it = CashShop.generateCouponItem(item, qty);
cs.addToInventory(it);
- couponPackage.add(it);
+ cashItems.add(it);
} else {
MapleInventoryManipulator.addById(c, item, qty, "", -1);
+ items.add(new Pair((int)qty, item));
}
-
- //c.announce(MaplePacketCreator.showCouponRedeemedItem(item));
break;
}
}
-
- if (!couponPackage.isEmpty()) {
- c.announce(MaplePacketCreator.showBoughtCashPackage(couponPackage, c.getAccID()));
- } else {
- c.announce(MaplePacketCreator.showBoughtQuestItem(0));
+ if(cashItems.size() > 255) {
+ List
- oldList = cashItems;
+ cashItems = Arrays.asList(new Item[255]);
+ int index = 0;
+ for(Item item : oldList) {
+ cashItems.set(index, item);
+ index++;
+ }
+ }
+ if (nxCredit != 0 || nxPrepaid != 0) { //coupon packet can only show maple points (afaik)
+ c.announce(MaplePacketCreator.showBoughtQuestItem(0));
+ } else {
+ c.announce(MaplePacketCreator.showCouponRedeemedItems(c.getAccID(), maplePoints, mesos, cashItems, items));
}
-
c.enableCSActions();
}
} finally {
diff --git a/src/net/server/channel/handlers/DenyPartyRequestHandler.java b/src/net/server/channel/handlers/DenyPartyRequestHandler.java
index b6f12b4b71..748804377d 100644
--- a/src/net/server/channel/handlers/DenyPartyRequestHandler.java
+++ b/src/net/server/channel/handlers/DenyPartyRequestHandler.java
@@ -24,9 +24,9 @@ package net.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
-import net.server.coordinator.MapleInviteCoordinator;
-import net.server.coordinator.MapleInviteCoordinator.InviteResult;
-import net.server.coordinator.MapleInviteCoordinator.InviteType;
+import net.server.coordinator.world.MapleInviteCoordinator;
+import net.server.coordinator.world.MapleInviteCoordinator.InviteResult;
+import net.server.coordinator.world.MapleInviteCoordinator.InviteType;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
@@ -41,7 +41,7 @@ public final class DenyPartyRequestHandler extends AbstractMaplePacketHandler {
if (cfrom != null) {
MapleCharacter chr = c.getPlayer();
- if (MapleInviteCoordinator.answerInvite(InviteType.PARTY, chr.getId(), cfrom.getPartyId(), false).getLeft() == InviteResult.DENIED) {
+ if (MapleInviteCoordinator.answerInvite(InviteType.PARTY, chr.getId(), cfrom.getPartyId(), false).result == InviteResult.DENIED) {
chr.updatePartySearchAvailability(chr.getParty() == null);
cfrom.getClient().announce(MaplePacketCreator.partyStatusMessage(23, chr.getName()));
}
diff --git a/src/net/server/channel/handlers/DistributeAPHandler.java b/src/net/server/channel/handlers/DistributeAPHandler.java
index 3831a15e5d..c83c64158b 100644
--- a/src/net/server/channel/handlers/DistributeAPHandler.java
+++ b/src/net/server/channel/handlers/DistributeAPHandler.java
@@ -22,7 +22,7 @@
package net.server.channel.handlers;
import client.MapleClient;
-import client.processor.AssignAPProcessor;
+import client.processor.stat.AssignAPProcessor;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
diff --git a/src/net/server/channel/handlers/DistributeSPHandler.java b/src/net/server/channel/handlers/DistributeSPHandler.java
index 8e1e570c03..22b6042445 100644
--- a/src/net/server/channel/handlers/DistributeSPHandler.java
+++ b/src/net/server/channel/handlers/DistributeSPHandler.java
@@ -22,7 +22,7 @@
package net.server.channel.handlers;
import client.MapleClient;
-import client.processor.AssignSPProcessor;
+import client.processor.stat.AssignSPProcessor;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
diff --git a/src/net/server/channel/handlers/DueyHandler.java b/src/net/server/channel/handlers/DueyHandler.java
index ae2fc17a6e..0e67dc43e7 100644
--- a/src/net/server/channel/handlers/DueyHandler.java
+++ b/src/net/server/channel/handlers/DueyHandler.java
@@ -22,8 +22,8 @@
package net.server.channel.handlers;
import client.MapleClient;
-import client.processor.DueyProcessor;
-import constants.ServerConstants;
+import client.processor.npc.DueyProcessor;
+import config.YamlConfig;
import net.AbstractMaplePacketHandler;
import tools.MaplePacketCreator;
@@ -33,20 +33,24 @@ public final class DueyHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
- if (!ServerConstants.USE_DUEY){
+ if (!YamlConfig.config.server.USE_DUEY){
c.announce(MaplePacketCreator.enableActions());
return;
}
-
+
byte operation = slea.readByte();
- if (operation == DueyProcessor.Actions.TOSERVER_SEND_ITEM.getCode()) {
+ if (operation == DueyProcessor.Actions.TOSERVER_RECV_ITEM.getCode()) { // on click 'O' Button, thanks inhyuk
+ DueyProcessor.dueySendTalk(c, false);
+ } else if (operation == DueyProcessor.Actions.TOSERVER_SEND_ITEM.getCode()) {
byte inventId = slea.readByte();
short itemPos = slea.readShort();
short amount = slea.readShort();
int mesos = slea.readInt();
String recipient = slea.readMapleAsciiString();
- String message = slea.readByte() != 0 ? slea.readMapleAsciiString() : "";
- DueyProcessor.dueySendItem(c, inventId, itemPos, amount, mesos, message, recipient);
+ boolean quick = slea.readByte() != 0;
+ String message = quick ? slea.readMapleAsciiString() : null;
+
+ DueyProcessor.dueySendItem(c, inventId, itemPos, amount, mesos, message, recipient, quick);
} else if (operation == DueyProcessor.Actions.TOSERVER_REMOVE_PACKAGE.getCode()) {
int packageid = slea.readInt();
@@ -55,6 +59,8 @@ public final class DueyHandler extends AbstractMaplePacketHandler {
int packageid = slea.readInt();
DueyProcessor.dueyClaimPackage(c, packageid);
+ } else if (operation == DueyProcessor.Actions.TOSERVER_CLAIM_PACKAGE.getCode()) {
+ DueyProcessor.dueySendTalk(c, false);
}
}
}
diff --git a/src/net/server/channel/handlers/EnterMTSHandler.java b/src/net/server/channel/handlers/EnterMTSHandler.java
index b62781026e..402e84ead9 100644
--- a/src/net/server/channel/handlers/EnterMTSHandler.java
+++ b/src/net/server/channel/handlers/EnterMTSHandler.java
@@ -28,12 +28,12 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
-import constants.ServerConstants;
+import config.YamlConfig;
import client.MapleCharacter;
import client.MapleClient;
import client.inventory.Equip;
import client.inventory.Item;
-import client.processor.BuybackProcessor;
+import client.processor.action.BuybackProcessor;
import net.AbstractMaplePacketHandler;
import net.server.Server;
import server.MTSItemInfo;
@@ -49,11 +49,11 @@ public final class EnterMTSHandler extends AbstractMaplePacketHandler {
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
- if(!chr.isAlive() && ServerConstants.USE_BUYBACK_SYSTEM) {
+ if(!chr.isAlive() && YamlConfig.config.server.USE_BUYBACK_SYSTEM) {
BuybackProcessor.processBuyback(c);
c.announce(MaplePacketCreator.enableActions());
} else {
- if (!ServerConstants.USE_MTS) {
+ if (!YamlConfig.config.server.USE_MTS) {
c.announce(MaplePacketCreator.enableActions());
return;
}
@@ -141,7 +141,7 @@ public final class EnterMTSHandler extends AbstractMaplePacketHandler {
equip.setInt((short) rs.getInt("int"));
equip.setJump((short) rs.getInt("jump"));
equip.setVicious((short) rs.getInt("vicious"));
- equip.setFlag((byte) rs.getInt("flag"));
+ equip.setFlag((short) rs.getInt("flag"));
equip.setLuk((short) rs.getInt("luk"));
equip.setMatk((short) rs.getInt("matk"));
equip.setMdef((short) rs.getInt("mdef"));
@@ -152,6 +152,12 @@ public final class EnterMTSHandler extends AbstractMaplePacketHandler {
equip.setWdef((short) rs.getInt("wdef"));
equip.setUpgradeSlots((byte) rs.getInt("upgradeslots"));
equip.setLevel((byte) rs.getInt("level"));
+ equip.setItemLevel(rs.getByte("itemlevel"));
+ equip.setItemExp(rs.getInt("itemexp"));
+ equip.setRingId(rs.getInt("ringid"));
+ equip.setExpiration(rs.getLong("expiration"));
+ equip.setGiftFrom(rs.getString("giftFrom"));
+
items.add(new MTSItemInfo((Item) equip, rs.getInt("price") + 100 + (int) (rs.getInt("price") * 0.1), rs.getInt("id"), rs.getInt("seller"), rs.getString("sellername"), rs.getString("sell_ends")));
}
}
@@ -209,7 +215,12 @@ public final class EnterMTSHandler extends AbstractMaplePacketHandler {
equip.setWdef((short) rs.getInt("wdef"));
equip.setUpgradeSlots((byte) rs.getInt("upgradeslots"));
equip.setLevel((byte) rs.getInt("level"));
- equip.setFlag((byte) rs.getInt("flag"));
+ equip.setItemLevel(rs.getByte("itemlevel"));
+ equip.setItemExp(rs.getInt("itemexp"));
+ equip.setRingId(rs.getInt("ringid"));
+ equip.setFlag((short) rs.getInt("flag"));
+ equip.setExpiration(rs.getLong("expiration"));
+ equip.setGiftFrom(rs.getString("giftFrom"));
items.add(new MTSItemInfo((Item) equip, rs.getInt("price"), rs.getInt("id"), rs.getInt("seller"), rs.getString("sellername"), rs.getString("sell_ends")));
}
}
@@ -256,7 +267,12 @@ public final class EnterMTSHandler extends AbstractMaplePacketHandler {
equip.setWdef((short) rs.getInt("wdef"));
equip.setUpgradeSlots((byte) rs.getInt("upgradeslots"));
equip.setLevel((byte) rs.getInt("level"));
- equip.setFlag((byte) rs.getInt("flag"));
+ equip.setItemLevel(rs.getByte("itemlevel"));
+ equip.setItemExp(rs.getInt("itemexp"));
+ equip.setRingId(rs.getInt("ringid"));
+ equip.setFlag((short) rs.getInt("flag"));
+ equip.setExpiration(rs.getLong("expiration"));
+ equip.setGiftFrom(rs.getString("giftFrom"));
items.add(new MTSItemInfo((Item) equip, rs.getInt("price"), rs.getInt("id"), rs.getInt("seller"), rs.getString("sellername"), rs.getString("sell_ends")));
}
}
diff --git a/src/net/server/channel/handlers/FaceExpressionHandler.java b/src/net/server/channel/handlers/FaceExpressionHandler.java
index dd6d0cb577..6a463dd726 100644
--- a/src/net/server/channel/handlers/FaceExpressionHandler.java
+++ b/src/net/server/channel/handlers/FaceExpressionHandler.java
@@ -23,7 +23,7 @@ package net.server.channel.handlers;
import client.MapleClient;
import client.MapleCharacter;
-import constants.ItemConstants;
+import constants.inventory.ItemConstants;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
@@ -34,15 +34,17 @@ public final class FaceExpressionHandler extends AbstractMaplePacketHandler {
int emote = slea.readInt();
if (emote > 7) {
- int emoteid = 5159992 + emote;
- if (chr.getInventory(ItemConstants.getInventoryType(emoteid)).findById(emoteid) == null) {
+ int itemid = 5159992 + emote; // thanks Rajan (Darter) for reporting unchecked emote itemid
+ if (!ItemConstants.isFaceExpression(itemid) || chr.getInventory(ItemConstants.getInventoryType(itemid)).findById(itemid) == null) {
return;
}
+ } else if (emote < 1) {
+ return;
}
if(c.tryacquireClient()) {
try { // expecting players never intends to wear the emote 0 (default face, that changes back after 5sec timeout)
- if (emote != 0 && chr.isLoggedinWorld()) {
+ if (chr.isLoggedinWorld()) {
chr.changeFaceExpression(emote);
}
} finally {
diff --git a/src/net/server/channel/handlers/FamilyAddHandler.java b/src/net/server/channel/handlers/FamilyAddHandler.java
index cbbf17d308..6c9e0d7fcd 100644
--- a/src/net/server/channel/handlers/FamilyAddHandler.java
+++ b/src/net/server/channel/handlers/FamilyAddHandler.java
@@ -21,33 +21,50 @@
*/
package net.server.channel.handlers;
-import constants.ServerConstants;
+import config.YamlConfig;
import client.MapleCharacter;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
+import net.server.coordinator.world.MapleInviteCoordinator;
+import net.server.coordinator.world.MapleInviteCoordinator.InviteType;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author Jay Estrella
+ * @author Ubaware
*/
public final class FamilyAddHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
- if (!ServerConstants.USE_FAMILY_SYSTEM){
- return;
- }
- System.out.println(slea.toString());
+ if(!YamlConfig.config.server.USE_FAMILY_SYSTEM) {
+ return;
+ }
String toAdd = slea.readMapleAsciiString();
MapleCharacter addChr = c.getChannelServer().getPlayerStorage().getCharacterByName(toAdd);
- if (addChr != null) {
- addChr.getClient().announce(MaplePacketCreator.sendFamilyInvite(c.getPlayer().getId(), toAdd));
- c.getPlayer().dropMessage("The invite has been sent.");
+ MapleCharacter chr = c.getPlayer();
+ if(addChr == null) {
+ c.announce(MaplePacketCreator.sendFamilyMessage(65, 0));
+ } else if(addChr == chr) { //only possible through packet editing/client editing i think?
+ c.announce(MaplePacketCreator.enableActions());
+ } else if(addChr.getMap() != chr.getMap() || (addChr.isHidden()) && chr.gmLevel() < addChr.gmLevel()) {
+ c.announce(MaplePacketCreator.sendFamilyMessage(69, 0));
+ } else if(addChr.getLevel() <= 10) {
+ c.announce(MaplePacketCreator.sendFamilyMessage(77, 0));
+ } else if(Math.abs(addChr.getLevel() - chr.getLevel()) > 20) {
+ c.announce(MaplePacketCreator.sendFamilyMessage(72, 0));
+ } else if(addChr.getFamily() != null && addChr.getFamily() == chr.getFamily()) { //same family
+ c.announce(MaplePacketCreator.enableActions());
+ } else if(MapleInviteCoordinator.hasInvite(InviteType.FAMILY, addChr.getId())) {
+ c.announce(MaplePacketCreator.sendFamilyMessage(73, 0));
+ } else if(chr.getFamily() != null && addChr.getFamily() != null && addChr.getFamily().getTotalGenerations() + chr.getFamily().getTotalGenerations() > YamlConfig.config.server.FAMILY_MAX_GENERATIONS) {
+ c.announce(MaplePacketCreator.sendFamilyMessage(76, 0));
} else {
- c.getPlayer().dropMessage("The player cannot be found!");
+ MapleInviteCoordinator.createInvite(InviteType.FAMILY, chr, addChr, addChr.getId());
+ addChr.getClient().announce(MaplePacketCreator.sendFamilyInvite(chr.getId(), chr.getName()));
+ chr.dropMessage("The invite has been sent.");
+ c.announce(MaplePacketCreator.enableActions());
}
- c.announce(MaplePacketCreator.enableActions());
}
}
-
diff --git a/src/net/server/channel/handlers/FamilyPreceptsHandler.java b/src/net/server/channel/handlers/FamilyPreceptsHandler.java
new file mode 100644
index 0000000000..7da34c29f2
--- /dev/null
+++ b/src/net/server/channel/handlers/FamilyPreceptsHandler.java
@@ -0,0 +1,23 @@
+package net.server.channel.handlers;
+
+import client.MapleClient;
+import client.MapleFamily;
+import net.AbstractMaplePacketHandler;
+import tools.MaplePacketCreator;
+import tools.data.input.SeekableLittleEndianAccessor;
+
+public class FamilyPreceptsHandler extends AbstractMaplePacketHandler {
+
+ @Override
+ public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
+ MapleFamily family = c.getPlayer().getFamily();
+ if(family == null) return;
+ if(family.getLeader().getChr() != c.getPlayer()) return; //only the leader can set the precepts
+ String newPrecepts = slea.readMapleAsciiString();
+ if(newPrecepts.length() > 200) return;
+ family.setMessage(newPrecepts, true);
+ //family.broadcastFamilyInfoUpdate(); //probably don't need to broadcast for this?
+ c.announce(MaplePacketCreator.getFamilyInfo(c.getPlayer().getFamilyEntry()));
+ }
+
+}
diff --git a/src/net/server/channel/handlers/FamilySeparateHandler.java b/src/net/server/channel/handlers/FamilySeparateHandler.java
new file mode 100644
index 0000000000..93597f53d1
--- /dev/null
+++ b/src/net/server/channel/handlers/FamilySeparateHandler.java
@@ -0,0 +1,78 @@
+/*
+ This file is part of the HeavenMS MapleStory Server
+ Copyleft (L) 2016 - 2018 RonanLana
+
+ 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.channel.handlers;
+
+import client.MapleClient;
+import client.MapleFamily;
+import client.MapleFamilyEntry;
+import config.YamlConfig;
+import net.AbstractMaplePacketHandler;
+import tools.MaplePacketCreator;
+import tools.data.input.SeekableLittleEndianAccessor;
+
+public class FamilySeparateHandler extends AbstractMaplePacketHandler {
+
+ @Override
+ public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
+ if(!YamlConfig.config.server.USE_FAMILY_SYSTEM) return;
+ MapleFamily oldFamily = c.getPlayer().getFamily();
+ if(oldFamily == null) return;
+ MapleFamilyEntry forkOn = null;
+ boolean isSenior;
+ if(slea.available() > 0) { //packet 0x95 doesn't send id, since there is only one senior
+ forkOn = c.getPlayer().getFamily().getEntryByID(slea.readInt());
+ if(!c.getPlayer().getFamilyEntry().isJunior(forkOn)) return; //packet editing?
+ isSenior = true;
+ } else {
+ forkOn = c.getPlayer().getFamilyEntry();
+ isSenior = false;
+ }
+ if(forkOn == null) return;
+
+ MapleFamilyEntry senior = forkOn.getSenior();
+ if(senior == null) return;
+ int levelDiff = Math.abs(c.getPlayer().getLevel() - senior.getLevel());
+ int cost = 2500 * levelDiff;
+ cost += levelDiff * levelDiff;
+ if(c.getPlayer().getMeso() < cost) {
+ c.announce(MaplePacketCreator.sendFamilyMessage(isSenior ? 81 : 80, cost));
+ return;
+ }
+ c.getPlayer().gainMeso(-cost);
+ int repCost = separateRepCost(forkOn);
+ senior.gainReputation(-repCost, false);
+ if(senior.getSenior() != null) senior.getSenior().gainReputation(-(repCost/2), false);
+ forkOn.announceToSenior(MaplePacketCreator.serverNotice(5, forkOn.getName() + " has left the family."), true);
+ forkOn.fork();
+ c.announce(MaplePacketCreator.getFamilyInfo(forkOn)); //pedigree info will be requested by the client if the window is open
+ forkOn.updateSeniorFamilyInfo(true);
+ c.announce(MaplePacketCreator.sendFamilyMessage(1, 0));
+ }
+
+
+ private static int separateRepCost(MapleFamilyEntry junior) {
+ int level = junior.getLevel();
+ int ret = level / 20;
+ ret += 10;
+ ret *= level;
+ ret *= 2;
+ return ret;
+ }
+}
diff --git a/src/net/server/channel/handlers/FamilySummonResponseHandler.java b/src/net/server/channel/handlers/FamilySummonResponseHandler.java
new file mode 100644
index 0000000000..9f39b745f8
--- /dev/null
+++ b/src/net/server/channel/handlers/FamilySummonResponseHandler.java
@@ -0,0 +1,40 @@
+package net.server.channel.handlers;
+
+import client.MapleCharacter;
+import client.MapleClient;
+import client.MapleFamilyEntitlement;
+import client.MapleFamilyEntry;
+import config.YamlConfig;
+import net.AbstractMaplePacketHandler;
+import net.server.coordinator.world.MapleInviteCoordinator;
+import net.server.coordinator.world.MapleInviteCoordinator.InviteResult;
+import net.server.coordinator.world.MapleInviteCoordinator.InviteType;
+import net.server.coordinator.world.MapleInviteCoordinator.MapleInviteResult;
+import server.maps.MapleMap;
+import tools.MaplePacketCreator;
+import tools.data.input.SeekableLittleEndianAccessor;
+
+public class FamilySummonResponseHandler extends AbstractMaplePacketHandler {
+
+ @Override
+ public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
+ if(!YamlConfig.config.server.USE_FAMILY_SYSTEM) return;
+ slea.readMapleAsciiString(); //family name
+ boolean accept = slea.readByte() != 0;
+ MapleInviteResult inviteResult = MapleInviteCoordinator.answerInvite(InviteType.FAMILY_SUMMON, c.getPlayer().getId(), c.getPlayer(), accept);
+ if(inviteResult.result == InviteResult.NOT_FOUND) return;
+ MapleCharacter inviter = inviteResult.from;
+ MapleFamilyEntry inviterEntry = inviter.getFamilyEntry();
+ if(inviterEntry == null) return;
+ MapleMap map = (MapleMap) inviteResult.params[0];
+ if(accept && inviter.getMap() == map) { //cancel if inviter has changed maps
+ c.getPlayer().changeMap(map, map.getPortal(0));
+ } else {
+ inviterEntry.refundEntitlement(MapleFamilyEntitlement.SUMMON_FAMILY);
+ inviterEntry.gainReputation(MapleFamilyEntitlement.SUMMON_FAMILY.getRepCost(), false); //refund rep cost if declined
+ inviter.announce(MaplePacketCreator.getFamilyInfo(inviterEntry));
+ inviter.dropMessage(5, c.getPlayer().getName() + " has denied the summon request.");
+ }
+ }
+
+}
diff --git a/src/net/server/channel/handlers/FamilyUseHandler.java b/src/net/server/channel/handlers/FamilyUseHandler.java
index 38af1f49da..344f8b541d 100644
--- a/src/net/server/channel/handlers/FamilyUseHandler.java
+++ b/src/net/server/channel/handlers/FamilyUseHandler.java
@@ -21,82 +21,121 @@
*/
package net.server.channel.handlers;
-import constants.ServerConstants;
import client.MapleCharacter;
import client.MapleClient;
+import client.MapleFamilyEntitlement;
+import client.MapleFamilyEntry;
+import config.YamlConfig;
import net.AbstractMaplePacketHandler;
-import net.opcodes.SendOpcode;
+import net.server.coordinator.world.MapleInviteCoordinator;
+import net.server.coordinator.world.MapleInviteCoordinator.InviteType;
+import server.maps.FieldLimit;
+import server.maps.MapleMap;
+import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
-import tools.data.output.MaplePacketLittleEndianWriter;
/**
*
* @author Moogra
+ * @author Ubaware
*/
public final class FamilyUseHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
- if (!ServerConstants.USE_FAMILY_SYSTEM){
- return;
- }
- int[] repCost = {3, 5, 7, 8, 10, 12, 15, 20, 25, 40, 50};
- final int type = slea.readInt();
+ if(!YamlConfig.config.server.USE_FAMILY_SYSTEM) {
+ return;
+ }
+ MapleFamilyEntitlement type = MapleFamilyEntitlement.values()[slea.readInt()];
+ int cost = type.getRepCost();
+ MapleFamilyEntry entry = c.getPlayer().getFamilyEntry();
+ if(entry.getReputation() < cost || entry.isEntitlementUsed(type)) {
+ return; // shouldn't even be able to request it
+ }
+ c.announce(MaplePacketCreator.getFamilyInfo(entry));
MapleCharacter victim;
- if (type == 0 || type == 1) {
+ if(type == MapleFamilyEntitlement.FAMILY_REUINION || type == MapleFamilyEntitlement.SUMMON_FAMILY) {
victim = c.getChannelServer().getPlayerStorage().getCharacterByName(slea.readMapleAsciiString());
- if (victim != null) {
- if (type == 0) {
- c.getPlayer().changeMap(victim.getMap(), victim.getMap().getPortal(0));
+ if(victim != null && victim != c.getPlayer()) {
+ if(victim.getFamily() == c.getPlayer().getFamily()) {
+ MapleMap targetMap = victim.getMap();
+ MapleMap ownMap = c.getPlayer().getMap();
+ if(targetMap != null) {
+ if(type == MapleFamilyEntitlement.FAMILY_REUINION) {
+ if(!FieldLimit.CANNOTMIGRATE.check(ownMap.getFieldLimit()) && !FieldLimit.CANNOTVIPROCK.check(targetMap.getFieldLimit())
+ && (targetMap.getForcedReturnId() == 999999999 || targetMap.getId() < 100000000) && targetMap.getEventInstance() == null) {
+
+ c.getPlayer().changeMap(victim.getMap(), victim.getMap().getPortal(0));
+ useEntitlement(entry, type);
+ } else {
+ c.announce(MaplePacketCreator.sendFamilyMessage(75, 0)); // wrong message, but close enough. (client should check this first anyway)
+ return;
+ }
+ } else {
+ if(!FieldLimit.CANNOTMIGRATE.check(targetMap.getFieldLimit()) && !FieldLimit.CANNOTVIPROCK.check(ownMap.getFieldLimit())
+ && (ownMap.getForcedReturnId() == 999999999 || ownMap.getId() < 100000000) && ownMap.getEventInstance() == null) {
+
+ if(MapleInviteCoordinator.hasInvite(InviteType.FAMILY_SUMMON, victim.getId())) {
+ c.announce(MaplePacketCreator.sendFamilyMessage(74, 0));
+ return;
+ }
+ MapleInviteCoordinator.createInvite(InviteType.FAMILY_SUMMON, c.getPlayer(), victim, victim.getId(), c.getPlayer().getMap());
+ victim.announce(MaplePacketCreator.sendFamilySummonRequest(c.getPlayer().getFamily().getName(), c.getPlayer().getName()));
+ useEntitlement(entry, type);
+ } else {
+ c.announce(MaplePacketCreator.sendFamilyMessage(75, 0));
+ return;
+ }
+ }
+ }
} else {
- victim.changeMap(c.getPlayer().getMap(), c.getPlayer().getMap().getPortal(0));
+ c.announce(MaplePacketCreator.sendFamilyMessage(67, 0));
}
- } else {
- return;
}
+ } else if(type == MapleFamilyEntitlement.FAMILY_BONDING) {
+ //not implemented
} else {
- int erate = type == 3 ? 150 : (type == 4 || type == 6 || type == 8 || type == 10 ? 200 : 100);
- int drate = type == 2 ? 150 : (type == 4 || type == 5 || type == 7 || type == 9 ? 200 : 100);
- if (type > 8) {
- } else {
- c.announce(useRep(drate == 100 ? 2 : (erate == 100 ? 3 : 4), type, erate, drate, ((type > 5 || type == 4) ? 2 : 1) * 15 * 60 * 1000));
- }
+ boolean party = false;
+ boolean isExp = false;
+ float rate = 1.5f;
+ int duration = 15;
+ do {
+ switch(type) {
+ case PARTY_EXP_2_30MIN:
+ party = true;
+ isExp = true;
+ type = MapleFamilyEntitlement.SELF_EXP_2_30MIN;
+ continue;
+ case PARTY_DROP_2_30MIN:
+ party = true;
+ type = MapleFamilyEntitlement.SELF_DROP_2_30MIN;
+ continue;
+ case SELF_DROP_2_30MIN:
+ duration = 30;
+ case SELF_DROP_2:
+ rate = 2.0f;
+ case SELF_DROP_1_5:
+ break;
+ case SELF_EXP_2_30MIN:
+ duration = 30;
+ case SELF_EXP_2:
+ rate = 2.0f;
+ case SELF_EXP_1_5:
+ isExp = true;
+ default:
+ break;
+ }
+ break;
+ } while(true);
+ //not implemented
}
- c.getPlayer().getFamily().getMember(c.getPlayer().getId()).gainReputation(repCost[type]);
}
-
- /**
- * [65 00][02][08 00 00 00][C8 00 00 00][00 00 00 00][00][40 77 1B 00]
- */
- private static byte[] useRep(int mode, int type, int erate, int drate, int time) {
- MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
- mplew.writeShort(0x60);//noty
- mplew.write(mode);
- mplew.writeInt(type);
- if (mode < 4) {
- mplew.writeInt(erate);
- mplew.writeInt(drate);
+
+ private boolean useEntitlement(MapleFamilyEntry entry, MapleFamilyEntitlement entitlement) {
+ if(entry.useEntitlement(entitlement)) {
+ entry.gainReputation(-entitlement.getRepCost(), false);
+ entry.getChr().announce(MaplePacketCreator.getFamilyInfo(entry));
+ return true;
}
- mplew.write(0);
- mplew.writeInt(time);
- return mplew.getPacket();
- }
-
- //20 00
- //00 00 00 00
- //00 00 00 00 00 00 00 00
- //80 01
- //00 00 28 00
- //8C 93 3E 00
- //40 0D
- //03 00 14 00
- //8C 93 3E 00
- //40 0D 03 00 00 00 00 00 02
- private static byte[] giveBuff() {
- MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
- mplew.writeShort(SendOpcode.GIVE_BUFF.getValue());
- mplew.writeInt(0);
- mplew.writeLong(0);
-
- return null;
+ return false;
}
}
diff --git a/src/net/server/channel/handlers/FieldDamageMobHandler.java b/src/net/server/channel/handlers/FieldDamageMobHandler.java
new file mode 100644
index 0000000000..0a6942319d
--- /dev/null
+++ b/src/net/server/channel/handlers/FieldDamageMobHandler.java
@@ -0,0 +1,59 @@
+/*
+ This file is part of the HeavenMS MapleStory Server
+ Copyleft (L) 2016 - 2018 RonanLana
+
+ 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.channel.handlers;
+
+import client.MapleCharacter;
+import client.MapleClient;
+import constants.game.GameConstants;
+import net.AbstractMaplePacketHandler;
+import server.life.MapleMonster;
+import server.life.MapleMonsterInformationProvider;
+import server.maps.MapleMap;
+import tools.FilePrinter;
+import tools.MaplePacketCreator;
+import tools.data.input.SeekableLittleEndianAccessor;
+
+public class FieldDamageMobHandler extends AbstractMaplePacketHandler {
+
+ @Override
+ public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
+ int mobOid = slea.readInt(); // packet structure found thanks to Darter (Rajan)
+ int dmg = slea.readInt();
+
+ MapleCharacter chr = c.getPlayer();
+ MapleMap map = chr.getMap();
+
+ if (map.getEnvironment().isEmpty()) { // no environment objects activated to actually hit the mob
+ FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to use an obstacle on mapid " + map.getId() + " to attack.");
+ return;
+ }
+
+ MapleMonster mob = map.getMonsterByOid(mobOid);
+ if (mob != null) {
+ if (dmg < 0 || dmg > GameConstants.MAX_FIELD_MOB_DAMAGE) {
+ FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to use an obstacle on mapid " + map.getId() + " to attack " + MapleMonsterInformationProvider.getInstance().getMobNameFromId(mob.getId()) + " with damage " + dmg);
+ return;
+ }
+
+ map.broadcastMessage(chr, MaplePacketCreator.damageMonster(mobOid, dmg), true);
+ map.damageMonster(chr, mob, dmg);
+ }
+ }
+}
diff --git a/src/net/server/channel/handlers/FredrickHandler.java b/src/net/server/channel/handlers/FredrickHandler.java
index ef516098a0..1e035ded11 100644
--- a/src/net/server/channel/handlers/FredrickHandler.java
+++ b/src/net/server/channel/handlers/FredrickHandler.java
@@ -23,7 +23,7 @@ package net.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
-import client.processor.FredrickProcessor;
+import client.processor.npc.FredrickProcessor;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
diff --git a/src/net/server/channel/handlers/GeneralChatHandler.java b/src/net/server/channel/handlers/GeneralChatHandler.java
index 5fbea4eb43..6f56b1a16b 100644
--- a/src/net/server/channel/handlers/GeneralChatHandler.java
+++ b/src/net/server/channel/handlers/GeneralChatHandler.java
@@ -25,7 +25,7 @@ import client.MapleCharacter;
import client.MapleClient;
import client.autoban.AutobanFactory;
import client.command.CommandsExecutor;
-import constants.ServerConstants;
+import config.YamlConfig;
import net.AbstractMaplePacketHandler;
import tools.FilePrinter;
import tools.LogHelper;
@@ -59,12 +59,12 @@ public final class GeneralChatHandler extends AbstractMaplePacketHandler {
if (!chr.isHidden()) {
chr.getMap().broadcastMessage(MaplePacketCreator.getChatText(chr.getId(), s, chr.getWhiteChat(), show));
- if (ServerConstants.USE_ENABLE_CHAT_LOG) {
+ if (YamlConfig.config.server.USE_ENABLE_CHAT_LOG) {
LogHelper.logChat(c, "General", s);
}
} else {
chr.getMap().broadcastGMMessage(MaplePacketCreator.getChatText(chr.getId(), s, chr.getWhiteChat(), show));
- if (ServerConstants.USE_ENABLE_CHAT_LOG) {
+ if (YamlConfig.config.server.USE_ENABLE_CHAT_LOG) {
LogHelper.logChat(c, "GM General", s);
}
}
diff --git a/src/net/server/channel/handlers/GuildOperationHandler.java b/src/net/server/channel/handlers/GuildOperationHandler.java
index cb1a41e189..92991f4269 100644
--- a/src/net/server/channel/handlers/GuildOperationHandler.java
+++ b/src/net/server/channel/handlers/GuildOperationHandler.java
@@ -21,10 +21,11 @@
*/
package net.server.channel.handlers;
+import config.YamlConfig;
import net.server.guild.MapleGuildResponse;
import net.server.guild.MapleGuild;
-import constants.GameConstants;
-import constants.ServerConstants;
+import constants.game.GameConstants;
+import constants.net.ServerConstants;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
@@ -65,8 +66,8 @@ public final class GuildOperationHandler extends AbstractMaplePacketHandler {
mc.dropMessage(1, "You cannot create a new Guild while in one.");
return;
}
- if (mc.getMeso() < ServerConstants.CREATE_GUILD_COST) {
- mc.dropMessage(1, "You do not have " + GameConstants.numberWithCommas(ServerConstants.CREATE_GUILD_COST) + " mesos to create a Guild.");
+ if (mc.getMeso() < YamlConfig.config.server.CREATE_GUILD_COST) {
+ mc.dropMessage(1, "You do not have " + GameConstants.numberWithCommas(YamlConfig.config.server.CREATE_GUILD_COST) + " mesos to create a Guild.");
return;
}
String guildName = slea.readMapleAsciiString();
@@ -76,8 +77,8 @@ public final class GuildOperationHandler extends AbstractMaplePacketHandler {
}
Set eligibleMembers = new HashSet<>(MapleGuild.getEligiblePlayersForGuild(mc));
- if (eligibleMembers.size() < ServerConstants.CREATE_GUILD_MIN_PARTNERS) {
- if (mc.getMap().getAllPlayers().size() < ServerConstants.CREATE_GUILD_MIN_PARTNERS) {
+ if (eligibleMembers.size() < YamlConfig.config.server.CREATE_GUILD_MIN_PARTNERS) {
+ if (mc.getMap().getAllPlayers().size() < YamlConfig.config.server.CREATE_GUILD_MIN_PARTNERS) {
// thanks NovaStory for noticing message in need of smoother info
mc.dropMessage(1, "Your Guild doesn't have enough cofounders present here and therefore cannot be created at this time.");
} else {
@@ -211,8 +212,8 @@ public final class GuildOperationHandler extends AbstractMaplePacketHandler {
System.out.println("[Hack] " + mc.getName() + " tried to change guild emblem without being the guild leader.");
return;
}
- if (mc.getMeso() < ServerConstants.CHANGE_EMBLEM_COST) {
- c.announce(MaplePacketCreator.serverNotice(1, "You do not have " + GameConstants.numberWithCommas(ServerConstants.CHANGE_EMBLEM_COST) + " mesos to change the Guild emblem."));
+ if (mc.getMeso() < YamlConfig.config.server.CHANGE_EMBLEM_COST) {
+ c.announce(MaplePacketCreator.serverNotice(1, "You do not have " + GameConstants.numberWithCommas(YamlConfig.config.server.CHANGE_EMBLEM_COST) + " mesos to change the Guild emblem."));
return;
}
short bg = slea.readShort();
@@ -226,7 +227,7 @@ public final class GuildOperationHandler extends AbstractMaplePacketHandler {
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.getGuildAlliances(alliance, c.getWorld()), -1, -1);
}
- mc.gainMeso(-ServerConstants.CHANGE_EMBLEM_COST, true, false, true);
+ mc.gainMeso(-YamlConfig.config.server.CHANGE_EMBLEM_COST, true, false, true);
mc.getGuild().broadcastNameChanged();
mc.getGuild().broadcastEmblemChanged();
break;
diff --git a/src/net/server/channel/handlers/HealOvertimeHandler.java b/src/net/server/channel/handlers/HealOvertimeHandler.java
index 70c5157c48..35ab9233d0 100644
--- a/src/net/server/channel/handlers/HealOvertimeHandler.java
+++ b/src/net/server/channel/handlers/HealOvertimeHandler.java
@@ -27,7 +27,7 @@ import client.autoban.AutobanFactory;
import client.autoban.AutobanManager;
import net.AbstractMaplePacketHandler;
import net.server.Server;
-import server.maps.MapleMapFactory;
+import server.maps.MapleMap;
import tools.data.input.SeekableLittleEndianAccessor;
import tools.MaplePacketCreator;
@@ -46,7 +46,8 @@ public final class HealOvertimeHandler extends AbstractMaplePacketHandler {
abm.setTimestamp(8, timestamp, 28); // thanks Vcoc & Thora for pointing out d/c happening here
if ((abm.getLastSpam(0) + 1500) > timestamp) AutobanFactory.FAST_HP_HEALING.addPoint(abm, "Fast hp healing");
- int abHeal = 120 + (int)(20 * MapleMapFactory.getMapRecoveryRate(chr.getMapId())); // Sleepywood sauna and showa spa...
+ MapleMap map = chr.getMap();
+ int abHeal = (int)(77 * map.getRecovery() * 1.5); // thanks Ari for noticing players not getting healed in sauna in certain cases
if (healHP > abHeal) {
AutobanFactory.HIGH_HP_HEALING.autoban(chr, "Healing: " + healHP + "; Max is " + abHeal + ".");
return;
@@ -59,7 +60,10 @@ public final class HealOvertimeHandler extends AbstractMaplePacketHandler {
short healMP = slea.readShort();
if (healMP != 0 && healMP < 1000) {
abm.setTimestamp(9, timestamp, 28);
- if ((abm.getLastSpam(1) + 1500) > timestamp) AutobanFactory.FAST_MP_HEALING.addPoint(abm, "Fast mp healing");
+ if ((abm.getLastSpam(1) + 1500) > timestamp) {
+ AutobanFactory.FAST_MP_HEALING.addPoint(abm, "Fast mp healing");
+ return; // thanks resinate for noticing mp being gained even after detection
+ }
chr.addMP(healMP);
abm.spam(1, timestamp);
}
diff --git a/src/net/server/channel/handlers/HiredMerchantRequest.java b/src/net/server/channel/handlers/HiredMerchantRequest.java
index 29fe4a2b48..160cdfff0d 100644
--- a/src/net/server/channel/handlers/HiredMerchantRequest.java
+++ b/src/net/server/channel/handlers/HiredMerchantRequest.java
@@ -26,9 +26,13 @@ import client.MapleCharacter;
import java.sql.SQLException;
import java.util.Arrays;
import client.MapleClient;
-import constants.GameConstants;
+import constants.game.GameConstants;
+import java.awt.Point;
import net.AbstractMaplePacketHandler;
+import server.maps.MaplePortal;
+import server.maps.MapleMapObject;
import server.maps.MapleMapObjectType;
+import server.maps.MaplePlayerShop;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
@@ -40,7 +44,34 @@ public final class HiredMerchantRequest extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
- if (chr.getMap().getMapObjectsInRange(chr.getPosition(), 23000, Arrays.asList(MapleMapObjectType.HIRED_MERCHANT)).isEmpty() && (GameConstants.isFreeMarketRoom(chr.getMapId()))) {
+
+ try {
+ for (MapleMapObject mmo : chr.getMap().getMapObjectsInRange(chr.getPosition(), 23000, Arrays.asList(MapleMapObjectType.HIRED_MERCHANT, MapleMapObjectType.PLAYER))) {
+ if (mmo instanceof MapleCharacter) {
+ MapleCharacter mc = (MapleCharacter) mmo;
+
+ MaplePlayerShop shop = mc.getPlayerShop();
+ if (shop != null && shop.isOwner(mc)) {
+ chr.announce(MaplePacketCreator.getMiniRoomError(13));
+ return;
+ }
+ } else {
+ chr.announce(MaplePacketCreator.getMiniRoomError(13));
+ return;
+ }
+ }
+
+ Point cpos = chr.getPosition();
+ MaplePortal portal = chr.getMap().findClosestTeleportPortal(cpos);
+ if (portal != null && portal.getPosition().distance(cpos) < 120.0) {
+ chr.announce(MaplePacketCreator.getMiniRoomError(10));
+ return;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ if (GameConstants.isFreeMarketRoom(chr.getMapId())) {
if (!chr.hasMerchant()) {
try {
if (ItemFactory.MERCHANT.loadItems(chr.getId(), false).isEmpty() && chr.getMerchantMeso() == 0) {
diff --git a/src/net/server/channel/handlers/InventoryMergeHandler.java b/src/net/server/channel/handlers/InventoryMergeHandler.java
index 43ec9f437e..ae8c2feb3b 100644
--- a/src/net/server/channel/handlers/InventoryMergeHandler.java
+++ b/src/net/server/channel/handlers/InventoryMergeHandler.java
@@ -21,7 +21,7 @@
*/
package net.server.channel.handlers;
-import constants.ServerConstants;
+import config.YamlConfig;
import net.AbstractMaplePacketHandler;
import client.inventory.manipulator.MapleInventoryManipulator;
import tools.MaplePacketCreator;
@@ -42,7 +42,7 @@ public final class InventoryMergeHandler extends AbstractMaplePacketHandler {
slea.readInt();
chr.getAutobanManager().setTimestamp(2, Server.getInstance().getCurrentTimestamp(), 4);
- if(!ServerConstants.USE_ITEM_SORT) {
+ if(!YamlConfig.config.server.USE_ITEM_SORT) {
c.announce(MaplePacketCreator.enableActions());
return;
}
diff --git a/src/net/server/channel/handlers/InventorySortHandler.java b/src/net/server/channel/handlers/InventorySortHandler.java
index c48a8d9390..d7510405f8 100644
--- a/src/net/server/channel/handlers/InventorySortHandler.java
+++ b/src/net/server/channel/handlers/InventorySortHandler.java
@@ -24,6 +24,7 @@ package net.server.channel.handlers;
import java.util.ArrayList;
import java.util.List;
+import config.YamlConfig;
import net.AbstractMaplePacketHandler;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
@@ -34,7 +35,7 @@ import client.inventory.Equip;
import client.inventory.MapleInventory;
import client.inventory.MapleInventoryType;
import client.inventory.ModifyInventory;
-import constants.ServerConstants;
+import constants.net.ServerConstants;
import server.MapleItemInformationProvider;
import net.server.Server;
@@ -265,7 +266,7 @@ public final class InventorySortHandler extends AbstractMaplePacketHandler {
slea.readInt();
chr.getAutobanManager().setTimestamp(3, Server.getInstance().getCurrentTimestamp(), 4);
- if(!ServerConstants.USE_ITEM_SORT) {
+ if(!YamlConfig.config.server.USE_ITEM_SORT) {
c.announce(MaplePacketCreator.enableActions());
return;
}
@@ -295,7 +296,7 @@ public final class InventorySortHandler extends AbstractMaplePacketHandler {
}
int invTypeCriteria = (MapleInventoryType.getByType(invType) == MapleInventoryType.EQUIP) ? 3 : 1;
- int sortCriteria = (ServerConstants.USE_ITEM_SORT_BY_NAME == true) ? 2 : 0;
+ int sortCriteria = (YamlConfig.config.server.USE_ITEM_SORT_BY_NAME == true) ? 2 : 0;
PairedQuicksort pq = new PairedQuicksort(itemarray, sortCriteria, invTypeCriteria);
for (Item item : itemarray) {
diff --git a/src/net/server/channel/handlers/ItemRewardHandler.java b/src/net/server/channel/handlers/ItemRewardHandler.java
index 2794c1aedd..6fc7586ecf 100644
--- a/src/net/server/channel/handlers/ItemRewardHandler.java
+++ b/src/net/server/channel/handlers/ItemRewardHandler.java
@@ -24,7 +24,7 @@ package net.server.channel.handlers;
import client.MapleClient;
import client.inventory.Item;
import client.inventory.MapleInventoryType;
-import constants.ItemConstants;
+import constants.inventory.ItemConstants;
import java.util.List;
import net.AbstractMaplePacketHandler;
import net.server.Server;
diff --git a/src/net/server/channel/handlers/KeymapChangeHandler.java b/src/net/server/channel/handlers/KeymapChangeHandler.java
index 5613ddaef6..7d97aa108c 100644
--- a/src/net/server/channel/handlers/KeymapChangeHandler.java
+++ b/src/net/server/channel/handlers/KeymapChangeHandler.java
@@ -21,7 +21,7 @@
*/
package net.server.channel.handlers;
-import constants.GameConstants;
+import constants.game.GameConstants;
import client.MapleClient;
import client.MapleKeyBinding;
import client.Skill;
diff --git a/src/net/server/channel/handlers/MTSHandler.java b/src/net/server/channel/handlers/MTSHandler.java
index 054e6f7261..50ca166f63 100644
--- a/src/net/server/channel/handlers/MTSHandler.java
+++ b/src/net/server/channel/handlers/MTSHandler.java
@@ -44,7 +44,7 @@ import client.MapleClient;
import client.inventory.Equip;
import client.inventory.Item;
import client.inventory.MapleInventoryType;
-import constants.ItemConstants;
+import constants.inventory.ItemConstants;
public final class MTSHandler extends AbstractMaplePacketHandler {
@@ -160,48 +160,55 @@ public final class MTSHandler extends AbstractMaplePacketHandler {
}
if (!i.getInventoryType().equals(MapleInventoryType.EQUIP)) {
Item item = (Item) i;
- ps = con.prepareStatement("INSERT INTO mts_items (tab, type, itemid, quantity, seller, price, owner, sellername, sell_ends) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
+ ps = con.prepareStatement("INSERT INTO mts_items (tab, type, itemid, quantity, expiration, giftFrom, seller, price, owner, sellername, sell_ends) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
ps.setInt(1, 1);
ps.setInt(2, (int) invType.getType());
ps.setInt(3, item.getItemId());
ps.setInt(4, quantity);
- ps.setInt(5, c.getPlayer().getId());
- ps.setInt(6, price);
- ps.setString(7, item.getOwner());
- ps.setString(8, c.getPlayer().getName());
- ps.setString(9, date);
+ ps.setLong(5, item.getExpiration());
+ ps.setString(6, item.getGiftFrom());
+ ps.setInt(7, c.getPlayer().getId());
+ ps.setInt(8, price);
+ ps.setString(9, item.getOwner());
+ ps.setString(10, c.getPlayer().getName());
+ ps.setString(11, date);
} else {
Equip equip = (Equip) i;
- ps = con.prepareStatement("INSERT INTO mts_items (tab, type, itemid, quantity, seller, price, upgradeslots, level, str, dex, `int`, luk, hp, mp, watk, matk, wdef, mdef, acc, avoid, hands, speed, jump, locked, owner, sellername, sell_ends, vicious, flag) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
+ ps = con.prepareStatement("INSERT INTO mts_items (tab, type, itemid, quantity, expiration, giftFrom, seller, price, upgradeslots, level, str, dex, `int`, luk, hp, mp, watk, matk, wdef, mdef, acc, avoid, hands, speed, jump, locked, owner, sellername, sell_ends, vicious, flag, itemexp, itemlevel, ringid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
ps.setInt(1, 1);
ps.setInt(2, (int) invType.getType());
ps.setInt(3, equip.getItemId());
ps.setInt(4, quantity);
- ps.setInt(5, c.getPlayer().getId());
- ps.setInt(6, price);
- ps.setInt(7, equip.getUpgradeSlots());
- ps.setInt(8, equip.getLevel());
- ps.setInt(9, equip.getStr());
- ps.setInt(10, equip.getDex());
- ps.setInt(11, equip.getInt());
- ps.setInt(12, equip.getLuk());
- ps.setInt(13, equip.getHp());
- ps.setInt(14, equip.getMp());
- ps.setInt(15, equip.getWatk());
- ps.setInt(16, equip.getMatk());
- ps.setInt(17, equip.getWdef());
- ps.setInt(18, equip.getMdef());
- ps.setInt(19, equip.getAcc());
- ps.setInt(20, equip.getAvoid());
- ps.setInt(21, equip.getHands());
- ps.setInt(22, equip.getSpeed());
- ps.setInt(23, equip.getJump());
- ps.setInt(24, 0);
- ps.setString(25, equip.getOwner());
- ps.setString(26, c.getPlayer().getName());
- ps.setString(27, date);
- ps.setInt(28, equip.getVicious());
- ps.setInt(29, equip.getFlag());
+ ps.setLong(5, equip.getExpiration());
+ ps.setString(6, equip.getGiftFrom());
+ ps.setInt(7, c.getPlayer().getId());
+ ps.setInt(8, price);
+ ps.setInt(9, equip.getUpgradeSlots());
+ ps.setInt(10, equip.getLevel());
+ ps.setInt(11, equip.getStr());
+ ps.setInt(12, equip.getDex());
+ ps.setInt(13, equip.getInt());
+ ps.setInt(14, equip.getLuk());
+ ps.setInt(15, equip.getHp());
+ ps.setInt(16, equip.getMp());
+ ps.setInt(17, equip.getWatk());
+ ps.setInt(18, equip.getMatk());
+ ps.setInt(19, equip.getWdef());
+ ps.setInt(20, equip.getMdef());
+ ps.setInt(21, equip.getAcc());
+ ps.setInt(22, equip.getAvoid());
+ ps.setInt(23, equip.getHands());
+ ps.setInt(24, equip.getSpeed());
+ ps.setInt(25, equip.getJump());
+ ps.setInt(26, 0);
+ ps.setString(27, equip.getOwner());
+ ps.setString(28, c.getPlayer().getName());
+ ps.setString(29, date);
+ ps.setInt(30, equip.getVicious());
+ ps.setInt(31, equip.getFlag());
+ ps.setInt(32, equip.getItemExp());
+ ps.setByte(33, equip.getItemLevel()); // thanks Jefe for noticing missing itemlevel labels
+ ps.setInt(34, equip.getRingId());
}
ps.executeUpdate();
ps.close();
@@ -320,8 +327,13 @@ public final class MTSHandler extends AbstractMaplePacketHandler {
equip.setWdef((short) rs.getInt("wdef"));
equip.setUpgradeSlots((byte) rs.getInt("upgradeslots"));
equip.setLevel((byte) rs.getInt("level"));
+ equip.setItemLevel(rs.getByte("itemlevel"));
+ equip.setItemExp(rs.getInt("itemexp"));
+ equip.setRingId(rs.getInt("ringid"));
equip.setVicious((byte) rs.getInt("vicious"));
- equip.setFlag((byte) rs.getInt("flag"));
+ equip.setFlag((short) rs.getInt("flag"));
+ equip.setExpiration(rs.getLong("expiration"));
+ equip.setGiftFrom(rs.getString("giftFrom"));
equip.setPosition(c.getPlayer().getInventory(ItemConstants.getInventoryType(rs.getInt("itemid"))).getNextFreeSlot());
i = equip.copy();
}
@@ -568,7 +580,12 @@ public final class MTSHandler extends AbstractMaplePacketHandler {
equip.setWdef((short) rs.getInt("wdef"));
equip.setUpgradeSlots((byte) rs.getInt("upgradeslots"));
equip.setLevel((byte) rs.getInt("level"));
- equip.setFlag((byte) rs.getInt("flag"));
+ equip.setFlag((short) rs.getInt("flag"));
+ equip.setItemLevel(rs.getByte("itemlevel"));
+ equip.setItemExp(rs.getInt("itemexp"));
+ equip.setRingId(rs.getInt("ringid"));
+ equip.setExpiration(rs.getLong("expiration"));
+ equip.setGiftFrom(rs.getString("giftFrom"));
items.add(new MTSItemInfo((Item) equip, rs.getInt("price"), rs.getInt("id"), rs.getInt("seller"), rs.getString("sellername"), rs.getString("sell_ends")));
}
}
@@ -623,7 +640,12 @@ public final class MTSHandler extends AbstractMaplePacketHandler {
equip.setWdef((short) rse.getInt("wdef"));
equip.setUpgradeSlots((byte) rse.getInt("upgradeslots"));
equip.setLevel((byte) rse.getInt("level"));
- equip.setFlag((byte) rs.getInt("flag"));
+ equip.setItemLevel(rs.getByte("itemlevel"));
+ equip.setItemExp(rs.getInt("itemexp"));
+ equip.setRingId(rs.getInt("ringid"));
+ equip.setFlag((short) rs.getInt("flag"));
+ equip.setExpiration(rs.getLong("expiration"));
+ equip.setGiftFrom(rs.getString("giftFrom"));
items.add(new MTSItemInfo((Item) equip, rse.getInt("price"), rse.getInt("id"), rse.getInt("seller"), rse.getString("sellername"), rse.getString("sell_ends")));
}
}
@@ -686,7 +708,12 @@ public final class MTSHandler extends AbstractMaplePacketHandler {
equip.setWdef((short) rs.getInt("wdef"));
equip.setUpgradeSlots((byte) rs.getInt("upgradeslots"));
equip.setLevel((byte) rs.getInt("level"));
- equip.setFlag((byte) rs.getInt("flag"));
+ equip.setItemLevel(rs.getByte("itemlevel"));
+ equip.setItemExp(rs.getInt("itemexp"));
+ equip.setRingId(rs.getInt("ringid"));
+ equip.setFlag((short) rs.getInt("flag"));
+ equip.setExpiration(rs.getLong("expiration"));
+ equip.setGiftFrom(rs.getString("giftFrom"));
items.add(new MTSItemInfo((Item) equip, rs.getInt("price"), rs.getInt("id"), rs.getInt("seller"), rs.getString("sellername"), rs.getString("sell_ends")));
}
}
@@ -747,7 +774,12 @@ public final class MTSHandler extends AbstractMaplePacketHandler {
equip.setWdef((short) rs.getInt("wdef"));
equip.setUpgradeSlots((byte) rs.getInt("upgradeslots"));
equip.setLevel((byte) rs.getInt("level"));
- equip.setFlag((byte) rs.getInt("flag"));
+ equip.setItemLevel(rs.getByte("itemlevel"));
+ equip.setItemExp(rs.getInt("itemexp"));
+ equip.setRingId(rs.getInt("ringid"));
+ equip.setFlag((short) rs.getInt("flag"));
+ equip.setExpiration(rs.getLong("expiration"));
+ equip.setGiftFrom(rs.getString("giftFrom"));
items.add(new MTSItemInfo((Item) equip, rs.getInt("price"), rs.getInt("id"), rs.getInt("seller"), rs.getString("sellername"), rs.getString("sell_ends")));
}
}
@@ -841,7 +873,12 @@ public final class MTSHandler extends AbstractMaplePacketHandler {
equip.setWdef((short) rs.getInt("wdef"));
equip.setUpgradeSlots((byte) rs.getInt("upgradeslots"));
equip.setLevel((byte) rs.getInt("level"));
- equip.setFlag((byte) rs.getInt("flag"));
+ equip.setItemLevel(rs.getByte("itemlevel"));
+ equip.setItemExp(rs.getInt("itemexp"));
+ equip.setRingId(rs.getInt("ringid"));
+ equip.setFlag((short) rs.getInt("flag"));
+ equip.setExpiration(rs.getLong("expiration"));
+ equip.setGiftFrom(rs.getString("giftFrom"));
items.add(new MTSItemInfo((Item) equip, rs.getInt("price"), rs.getInt("id"), rs.getInt("seller"), rs.getString("sellername"), rs.getString("sell_ends")));
}
}
diff --git a/src/net/server/channel/handlers/MagicDamageHandler.java b/src/net/server/channel/handlers/MagicDamageHandler.java
index b2288be8a6..fa82dbfd1c 100644
--- a/src/net/server/channel/handlers/MagicDamageHandler.java
+++ b/src/net/server/channel/handlers/MagicDamageHandler.java
@@ -21,25 +21,24 @@
*/
package net.server.channel.handlers;
-import server.MapleStatEffect;
-import tools.MaplePacketCreator;
-import tools.data.input.SeekableLittleEndianAccessor;
import client.MapleBuffStat;
import client.MapleCharacter;
import client.MapleClient;
import client.Skill;
import client.SkillFactory;
-import constants.ServerConstants;
+import config.YamlConfig;
import constants.skills.Bishop;
import constants.skills.Evan;
import constants.skills.FPArchMage;
import constants.skills.ILArchMage;
+import server.MapleStatEffect;
+import tools.MaplePacketCreator;
+import tools.data.input.SeekableLittleEndianAccessor;
public final class MagicDamageHandler extends AbstractDealDamageHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
- //chr.setPetLootCd(currentServerTime());
/*long timeElapsed = currentServerTime() - chr.getAutobanManager().getLastSpam(8);
if(timeElapsed < 300) {
@@ -58,7 +57,7 @@ public final class MagicDamageHandler extends AbstractDealDamageHandler {
}
if (chr.getMap().isDojoMap() && attack.numAttacked > 0) {
- chr.setDojoEnergy(chr.getDojoEnergy() + + ServerConstants.DOJO_ENERGY_ATK);
+ chr.setDojoEnergy(chr.getDojoEnergy() + + YamlConfig.config.server.DOJO_ENERGY_ATK);
c.announce(MaplePacketCreator.getEnergy("energy", chr.getDojoEnergy()));
}
diff --git a/src/net/server/channel/handlers/MakerSkillHandler.java b/src/net/server/channel/handlers/MakerSkillHandler.java
index 77062f96fb..2a108e64d0 100644
--- a/src/net/server/channel/handlers/MakerSkillHandler.java
+++ b/src/net/server/channel/handlers/MakerSkillHandler.java
@@ -22,7 +22,7 @@
package net.server.channel.handlers;
import client.MapleClient;
-import client.processor.MakerProcessor;
+import client.processor.action.MakerProcessor;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
diff --git a/src/net/server/channel/handlers/MessengerHandler.java b/src/net/server/channel/handlers/MessengerHandler.java
index 3b2539afbf..e30b9a8aca 100644
--- a/src/net/server/channel/handlers/MessengerHandler.java
+++ b/src/net/server/channel/handlers/MessengerHandler.java
@@ -24,14 +24,14 @@ package net.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
-import net.server.coordinator.MapleInviteCoordinator;
-import net.server.coordinator.MapleInviteCoordinator.InviteResult;
-import net.server.coordinator.MapleInviteCoordinator.InviteType;
+import net.server.coordinator.world.MapleInviteCoordinator;
+import net.server.coordinator.world.MapleInviteCoordinator.InviteResult;
+import net.server.coordinator.world.MapleInviteCoordinator.InviteType;
+import net.server.coordinator.world.MapleInviteCoordinator.MapleInviteResult;
import net.server.world.MapleMessenger;
import net.server.world.MapleMessengerCharacter;
import net.server.world.World;
import tools.MaplePacketCreator;
-import tools.Pair;
import tools.data.input.SeekableLittleEndianAccessor;
public final class MessengerHandler extends AbstractMaplePacketHandler {
@@ -58,8 +58,8 @@ public final class MessengerHandler extends AbstractMaplePacketHandler {
} else {
messenger = world.getMessenger(messengerid);
if (messenger != null) {
- Pair