From f958624f6a2a9fa196ca67dfeafc577e9b93b83a Mon Sep 17 00:00:00 2001 From: ronancpl Date: Wed, 14 Aug 2019 21:14:15 -0300 Subject: [PATCH] Reactor Loot + Obstacles damage mob + Static calls from scripts Revised starting AP, now working out with flags. To supply the 9AP shortage of 4/4/4/4, two options: one giving out 9 AP from the start, other giving 4/5 AP when changing jobs (1st, 2nd). This change would also work with the autoassign for beginners flag. Refactored several quest scripts, that would be glitching the player when doing quest start/complete and disposing under the same script status. Cleared some cases with the quest reward system where it would call out a "full inventory" even though new inventory slots could get discovered when doing the quest loot transaction. Fixed an issue with player stores being deployed overlapping in a few scenarios. Fixed reduced EXP gain from kills when triggering skill Mortal Blow. Added "open Duey" functionality when clicking "O" in the incoming package notification. Fixed packages without messages (a quirk from quick delivery) not accounting visually as a "quick" one. Fixed certain mounts (non-item skill mounts, such as Yeti or Spaceship) not showing up properly to other players when changing maps. Added handler for mob damage by environment objects (OrbisPQ jail storage area). Added a placeholder on mob's stolen items to prevent more steals to be placed as soon as the Steal mechanism is triggered. Patched boss logs not removing recent entries from the DB tables (the reset method is actually supposed to clear every entry). Revised a possible memory leak scenario happening due to an exception thrown midway monster kill method. Improved reactor drops, now placing loots visible for the acting player centered (similar as to how mob loots work). Refactored several issues in scripts, related to accessing static Java methods through an object, that would start appearing after transitioning to Java 8. --- docs/issues.txt | 3 + docs/mychanges_ptbr.txt | 36 +- scripts/event/3rdJob_bowman.js | 2 +- scripts/event/3rdJob_magician.js | 2 +- scripts/event/3rdJob_mount.js | 2 +- scripts/event/3rdJob_pirate.js | 2 +- scripts/event/3rdJob_thief.js | 2 +- scripts/event/3rdJob_warrior.js | 2 +- scripts/event/4jaerial.js | 2 +- scripts/event/4jship.js | 2 +- scripts/event/4jsuper.js | 2 +- scripts/event/Aran_2ndmount.js | 2 +- scripts/event/Aran_3rdmount.js | 2 +- scripts/event/BalrogQuest.js | 2 +- scripts/event/DelliBattle.js | 2 +- scripts/event/ElementalBattle.js | 2 +- scripts/event/MahaBattle.js | 2 +- scripts/npc/2010007.js | 6 +- scripts/npc/9201005.js | 6 +- scripts/npc/9201008.js | 6 +- scripts/npc/9201023.js | 4 +- scripts/npc/9201024.js | 4 +- scripts/npc/9201025.js | 4 +- scripts/npc/9201026.js | 4 +- scripts/npc/9201027.js | 4 +- scripts/npc/9977777.js | 3 +- scripts/portal/party3_jailin.js | 100 +++-- scripts/quest/10940.js | 9 +- scripts/quest/20002.js | 7 +- scripts/quest/20008.js | 20 +- scripts/quest/20016.js | 5 +- scripts/quest/20100.js | 4 +- scripts/quest/20101.js | 3 +- scripts/quest/20102.js | 3 +- scripts/quest/20103.js | 3 +- scripts/quest/20104.js | 3 +- scripts/quest/20105.js | 3 +- scripts/quest/20200.js | 2 + scripts/quest/20311.js | 7 +- scripts/quest/20312.js | 8 +- scripts/quest/20313.js | 8 +- scripts/quest/20314.js | 8 +- scripts/quest/20315.js | 8 +- scripts/quest/2034.js | 10 +- scripts/quest/20520.js | 5 +- scripts/quest/20522.js | 11 +- scripts/quest/20526.js | 10 +- scripts/quest/20527.js | 4 +- scripts/quest/20600.js | 2 +- scripts/quest/20610.js | 4 +- scripts/quest/21011.js | 5 +- scripts/quest/21012.js | 10 +- scripts/quest/21013.js | 2 +- scripts/quest/21100.js | 5 +- scripts/quest/21200.js | 1 + scripts/quest/21201.js | 2 +- scripts/quest/21202.js | 2 +- scripts/quest/2124.js | 35 +- scripts/quest/2126.js | 35 +- scripts/quest/2127.js | 24 +- scripts/quest/21300.js | 17 +- scripts/quest/21301.js | 7 +- scripts/quest/21302.js | 1 + scripts/quest/21400.js | 9 +- scripts/quest/21401.js | 4 +- scripts/quest/2148.js | 21 +- scripts/quest/2149.js | 22 +- scripts/quest/2150.js | 22 +- scripts/quest/2151.js | 22 +- scripts/quest/2152.js | 22 +- scripts/quest/21600.js | 4 +- scripts/quest/21613.js | 5 +- scripts/quest/21618.js | 5 +- scripts/quest/21700.js | 5 +- scripts/quest/21703.js | 2 + scripts/quest/21712.js | 3 +- scripts/quest/21728.js | 2 +- scripts/quest/21733.js | 2 +- scripts/quest/21734.js | 5 +- scripts/quest/21736.js | 2 +- scripts/quest/21738.js | 2 +- scripts/quest/21739.js | 4 +- scripts/quest/21740.js | 5 +- scripts/quest/21741.js | 4 +- scripts/quest/21749.js | 4 +- scripts/quest/21750.js | 2 +- scripts/quest/21753.js | 2 +- scripts/quest/21757.js | 5 +- scripts/quest/21766.js | 4 +- scripts/quest/21767.js | 17 +- scripts/quest/2186.js | 74 ++-- scripts/quest/2197.js | 46 ++- scripts/quest/22001.js | 7 +- scripts/quest/22002.js | 4 +- scripts/quest/22007.js | 5 +- scripts/quest/22008.js | 5 +- scripts/quest/2214.js | 15 +- scripts/quest/2215.js | 17 +- scripts/quest/2216.js | 3 +- scripts/quest/2217.js | 3 +- scripts/quest/2218.js | 3 +- scripts/quest/2219.js | 3 +- scripts/quest/2228.js | 5 +- scripts/quest/2230.js | 18 +- scripts/quest/2236.js | 29 +- scripts/quest/2245.js | 4 +- scripts/quest/22501.js | 6 +- scripts/quest/22502.js | 6 +- scripts/quest/22503.js | 5 +- scripts/quest/22504.js | 4 +- scripts/quest/22507.js | 5 +- scripts/quest/2251.js | 37 +- scripts/quest/2257.js | 2 +- scripts/quest/2258.js | 4 +- scripts/quest/2259.js | 3 +- scripts/quest/2260.js | 4 +- scripts/quest/2293.js | 18 +- scripts/quest/2312.js | 14 +- scripts/quest/2313.js | 7 +- scripts/quest/2314.js | 20 +- scripts/quest/2315.js | 18 +- scripts/quest/2316.js | 12 +- scripts/quest/2317.js | 14 +- scripts/quest/2318.js | 26 +- scripts/quest/2319.js | 12 +- scripts/quest/2320.js | 12 +- scripts/quest/2321.js | 12 +- scripts/quest/2322.js | 16 +- scripts/quest/2325.js | 7 +- scripts/quest/2338.js | 5 +- scripts/quest/2342.js | 48 ++- scripts/quest/2560.js | 6 +- scripts/quest/2573.js | 7 +- scripts/quest/28004.js | 2 +- scripts/quest/29900.js | 18 +- scripts/quest/29901.js | 18 +- scripts/quest/29902.js | 18 +- scripts/quest/29903.js | 18 +- scripts/quest/3108.js | 2 +- scripts/quest/3301.js | 3 +- scripts/quest/3303.js | 3 +- scripts/quest/3311.js | 2 +- scripts/quest/3314.js | 2 +- scripts/quest/3321.js | 2 +- scripts/quest/3345.js | 2 +- scripts/quest/3360.js | 6 +- scripts/quest/3382.js | 70 ++-- scripts/quest/3437.js | 13 +- scripts/quest/3452.js | 5 +- scripts/quest/3454.js | 55 ++- scripts/quest/3507.js | 30 +- scripts/quest/3523.js | 27 +- scripts/quest/3524.js | 27 +- scripts/quest/3525.js | 27 +- scripts/quest/3526.js | 27 +- scripts/quest/3527.js | 27 +- scripts/quest/3539.js | 27 +- scripts/quest/3714.js | 3 +- scripts/quest/3833.js | 10 +- scripts/quest/3926.js | 4 +- scripts/quest/3929.js | 2 +- scripts/quest/3933.js | 6 +- scripts/quest/3941.js | 35 +- scripts/quest/3953.js | 10 +- scripts/quest/4647.js | 8 +- scripts/quest/4659.js | 11 +- scripts/quest/6033.js | 6 +- scripts/quest/6036.js | 7 +- scripts/quest/8185.js | 5 +- scripts/quest/8189.js | 7 +- scripts/quest/8219.js | 10 +- scripts/quest/8221.js | 5 +- scripts/quest/8223.js | 7 +- scripts/quest/8224.js | 1 + scripts/quest/8225.js | 5 +- scripts/quest/8226.js | 5 +- scripts/quest/8227.js | 4 +- scripts/quest/8228.js | 4 +- scripts/quest/8230.js | 7 +- scripts/quest/8231.js | 1 + scripts/quest/8232.js | 1 + scripts/quest/8233.js | 1 + scripts/quest/8234.js | 1 + scripts/quest/8235.js | 1 + scripts/quest/8236.js | 1 + scripts/quest/8237.js | 1 + scripts/quest/8238.js | 1 + scripts/reactor/2008007.js | 29 ++ sql/db_database.sql | 2 +- src/client/MapleCharacter.java | 84 ++++- .../creator/CharacterFactoryRecipe.java | 12 +- src/client/processor/DueyProcessor.java | 22 +- src/constants/GameConstants.java | 37 ++ src/constants/ServerConstants.java | 1 + src/net/PacketProcessor.java | 1 + src/net/opcodes/RecvOpcode.java | 1 + src/net/server/Server.java | 6 +- .../handlers/AbstractDealDamageHandler.java | 11 +- .../handlers/CashShopSurpriseHandler.java | 8 +- .../server/channel/handlers/DueyHandler.java | 8 +- .../handlers/FieldDamageMobHandler.java | 59 +++ .../channel/handlers/HealOvertimeHandler.java | 11 +- .../handlers/HiredMerchantRequest.java | 33 +- .../channel/handlers/NPCAnimationHandler.java | 4 + .../handlers/PlayerInteractionHandler.java | 50 ++- .../channel/handlers/RaiseUIStateHandler.java | 4 +- src/net/server/worker/RespawnWorker.java | 12 +- src/scripting/AbstractPlayerInteraction.java | 5 +- src/scripting/AbstractScriptManager.java | 2 +- src/scripting/event/EventManager.java | 6 + src/scripting/map/MapScriptMethods.java | 5 +- src/scripting/npc/NPCScriptManager.java | 2 + src/scripting/quest/QuestScriptManager.java | 1 + .../reactor/ReactorActionManager.java | 90 +++-- src/server/CashShop.java | 10 +- src/server/DueyPackage.java | 14 +- src/server/MaplePortal.java | 1 + src/server/MapleStatEffect.java | 27 +- .../expeditions/MapleExpeditionBossLog.java | 5 +- src/server/life/MapleMonster.java | 2 +- .../life/MapleMonsterInformationProvider.java | 2 +- src/server/maps/MapleMap.java | 137 +++---- src/server/maps/MapleMapFactory.java | 14 +- src/server/maps/MapleMapManager.java | 3 - src/server/quest/MapleQuest.java | 3 +- src/server/quest/actions/ItemAction.java | 35 +- src/tools/MaplePacketCreator.java | 35 +- tools/ScriptStaticMethodTracker/method_list.c | 85 +++++ tools/ScriptStaticMethodTracker/method_list.h | 43 +++ .../method_tracker.c | 347 ++++++++++++++++++ tools/ScriptStaticMethodTracker/pcre3.dll | Bin 0 -> 140288 bytes tools/ScriptStaticMethodTracker/script_path.c | 72 ++++ tools/ScriptStaticMethodTracker/script_path.h | 34 ++ 233 files changed, 2368 insertions(+), 888 deletions(-) create mode 100644 scripts/reactor/2008007.js create mode 100644 src/net/server/channel/handlers/FieldDamageMobHandler.java create mode 100644 tools/ScriptStaticMethodTracker/method_list.c create mode 100644 tools/ScriptStaticMethodTracker/method_list.h create mode 100644 tools/ScriptStaticMethodTracker/method_tracker.c create mode 100644 tools/ScriptStaticMethodTracker/pcre3.dll create mode 100644 tools/ScriptStaticMethodTracker/script_path.c create mode 100644 tools/ScriptStaticMethodTracker/script_path.h diff --git a/docs/issues.txt b/docs/issues.txt index ccff9e18d8..b0d48368cb 100644 --- a/docs/issues.txt +++ b/docs/issues.txt @@ -10,6 +10,9 @@ 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. +- Using Shark Wave with Transformation on female thunderbreakers will cause consecutive attacks to proc immediately. - 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. - 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. diff --git a/docs/mychanges_ptbr.txt b/docs/mychanges_ptbr.txt index c876cdebb7..5109643785 100644 --- a/docs/mychanges_ptbr.txt +++ b/docs/mychanges_ptbr.txt @@ -2049,4 +2049,38 @@ Corrigido alguns danos de summons sendo calculados extremamente baixos quando o 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. \ No newline at end of file +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. \ No newline at end of file diff --git a/scripts/event/3rdJob_bowman.js b/scripts/event/3rdJob_bowman.js index 447ae673d7..2fe501b8c5 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 aa244b5114..9742e19f14 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 cd366824ed..5a04044b66 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 ef18f1dc31..82e268496a 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 285c4d0484..a940130997 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 f3b7f0bf97..ce0e50da82 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 d4dc9708d7..95ec6c3e1f 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/4jship.js b/scripts/event/4jship.js index ddb0da2502..17f62c4454 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 565d7c6f27..cffac5f48f 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 1be6114b18..ce31cc64e5 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 04e135d0b8..c5c5058fae 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/BalrogQuest.js b/scripts/event/BalrogQuest.js index fcef456bf4..c69e05b521 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/DelliBattle.js b/scripts/event/DelliBattle.js index ef3869e124..415521505c 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 00a2a18dee..6a32a98b7b 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/MahaBattle.js b/scripts/event/MahaBattle.js index 08698a3994..3d533e6740 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/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/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/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/9977777.js b/scripts/npc/9977777.js index 06a5f714a5..a02e7870f6 100644 --- a/scripts/npc/9977777.js +++ b/scripts/npc/9977777.js @@ -75,6 +75,7 @@ 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."); } function writeFeatureTab_PlayerSocialNetwork() { @@ -295,7 +296,7 @@ function writeAllFeatures() { feature_cursor = []; var tabName = (tabs[i]).replace(re, ""); - eval("writeFeatureTab_" + tabName)(); + this["writeFeatureTab_" + tabName](); feature_tree.push(feature_cursor); } 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/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/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/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..5c4fb9ea9c 100644 --- a/scripts/quest/20101.js +++ b/scripts/quest/20101.js @@ -49,6 +49,7 @@ function end(mode, type, selection) { 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?"); } 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..852b4d7337 100644 --- a/scripts/quest/20102.js +++ b/scripts/quest/20102.js @@ -49,6 +49,7 @@ function end(mode, type, selection) { 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?"); } 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..2c119025c2 100644 --- a/scripts/quest/20103.js +++ b/scripts/quest/20103.js @@ -50,6 +50,7 @@ function end(mode, type, selection) { 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?"); } 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..3957ff6101 100644 --- a/scripts/quest/20104.js +++ b/scripts/quest/20104.js @@ -50,6 +50,7 @@ function end(mode, type, selection) { 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?"); } 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..5d957edb9d 100644 --- a/scripts/quest/20105.js +++ b/scripts/quest/20105.js @@ -49,6 +49,7 @@ function end(mode, type, selection) { 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?"); } 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/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 feaf651d3a..b6ebc54198 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/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..db80f5d8e1 100644 --- a/scripts/quest/21201.js +++ b/scripts/quest/21201.js @@ -60,7 +60,6 @@ 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; } @@ -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..451b5f4131 100644 --- a/scripts/quest/2124.js +++ b/scripts/quest/2124.js @@ -24,15 +24,30 @@ */ 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..451b5f4131 100644 --- a/scripts/quest/2126.js +++ b/scripts/quest/2126.js @@ -24,15 +24,30 @@ */ 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..822ace8788 100644 --- a/scripts/quest/2127.js +++ b/scripts/quest/2127.js @@ -24,8 +24,24 @@ */ 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..69a40ee7b7 100644 --- a/scripts/quest/21302.js +++ b/scripts/quest/21302.js @@ -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 7d5f2e1c3d..f30354e46f 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 cc99db89f4..488aa7cef8 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 1f606ef1cd..fae1da010e 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/21728.js b/scripts/quest/21728.js index 4795cf915e..59ef6d5e4d 100644 --- a/scripts/quest/21728.js +++ b/scripts/quest/21728.js @@ -42,7 +42,7 @@ function end(mode, type, selection) { qm.gainExp(200); qm.forceCompleteQuest(); } - + } else if (status == 1) { qm.dispose(); } } diff --git a/scripts/quest/21733.js b/scripts/quest/21733.js index 5f00ad6dab..bba95c9621 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 a5fa4b7f96..2377d6db84 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 b9bda8727c..12be56e8a0 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 04eb91b521..fdb5bc4606 100644 --- a/scripts/quest/21738.js +++ b/scripts/quest/21738.js @@ -50,7 +50,7 @@ function start(mode, type, selection) { 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 { + } else if (status == 8) { qm.forceStartQuest(); qm.dispose(); } diff --git a/scripts/quest/21739.js b/scripts/quest/21739.js index 94f544f74f..a86b8aa286 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 f5f4fd3b8a..e1800ca83e 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 e591800988..25bebfd533 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 e628d27071..8d38167650 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 ea2dd7cd7f..b10b401ea3 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 e59a01ca8a..91e35ccce2 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 71dcf57805..2f344bef33 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 5361dd9c9e..56ca1e0a38 100644 --- a/scripts/quest/2186.js +++ b/scripts/quest/2186.js @@ -4,37 +4,53 @@ */ 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); + 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!"); + 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 e76ce9d2ef..c4b5952089 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 4f0070edbe..e486d74797 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 0816921512..68f56e27fd 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 72b4e81f33..c2dbd7b7db 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 80d8ee7748..7e1c47dcd0 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 ee04b77db9..2a8730e351 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 fe7a66086c..d7e9826d26 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/2236.js b/scripts/quest/2236.js index e460077dd0..41e90b07a0 100644 --- a/scripts/quest/2236.js +++ b/scripts/quest/2236.js @@ -8,6 +8,7 @@ Version 1.0 - Script Done.(20/3/2017) */ var status = -1; +var canStart; function start(mode, type, selection) { status++; @@ -16,20 +17,28 @@ function start(mode, type, selection) { status -= 2; else{ qm.sendOk("If we don't place these Charms on the Shaman Rocks, evil might awaken..."); - qm.dispose(); + canStart = false; + status = 0; return; } } - if (status == 0) + 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); + canStart = true; + } else if (status == 1) { + if (canStart) { + qm.sendOk("Take these Charms and place them on the Shaman Rocks in the dungeon. I'm giving you a total of 6 Charms."); + } else { + qm.dispose(); + } + } else { + qm.forceStartQuest(); + + 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) { @@ -48,7 +57,7 @@ function end(mode, type, selection) { 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); } - + } else if (status == 1) { qm.dispose(); - } + } } \ No newline at end of file diff --git a/scripts/quest/2245.js b/scripts/quest/2245.js index f5d503c153..2007688819 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..0eea0dc779 100644 --- a/scripts/quest/2251.js +++ b/scripts/quest/2251.js @@ -6,16 +6,31 @@ */ 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 94a483926f..f21d36115f 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 78ae395217..8f2d5f0903 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 ac59e7278f..783dfc5cf5 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 0603161acd..4c196cdf26 100644 --- a/scripts/quest/2260.js +++ b/scripts/quest/2260.js @@ -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 3b667a8d61..3b72709bed 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 40b9d04010..e5e69bd569 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 cfa542d54f..58b157d0ee 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 e345ab6e2a..b0571a8622 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 3b15ff46e8..9c5d62897f 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 359cd2b951..1e3db1a23e 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 3babb9a864..ff1281e504 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 8f5e650664..b51d69db2e 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 cf5e5d389f..2b6cc9bcde 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 8b54b52f23..126e531a9a 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 fd114c25d1..00b7a8cc22 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 b2d909564d..8722341bef 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/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 f5db1d4a01..3cb9ea2675 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 71e60da7c9..5321d3839b 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/3301.js b/scripts/quest/3301.js index 38db5d56cc..bcf0edca88 100644 --- a/scripts/quest/3301.js +++ b/scripts/quest/3301.js @@ -48,8 +48,7 @@ function end(mode, type, selection) { 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.forceCompleteQuest(); - qm.dispose(); - } else { + } else if (status == 1) { qm.dispose(); } } diff --git a/scripts/quest/3303.js b/scripts/quest/3303.js index 806589be97..a9d44c42fe 100644 --- a/scripts/quest/3303.js +++ b/scripts/quest/3303.js @@ -48,8 +48,7 @@ function end(mode, type, selection) { 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.forceCompleteQuest(); - qm.dispose(); - } else { + } else if (status == 1) { qm.dispose(); } } diff --git a/scripts/quest/3311.js b/scripts/quest/3311.js index ee0f6e054e..572eb80bc4 100644 --- a/scripts/quest/3311.js +++ b/scripts/quest/3311.js @@ -42,7 +42,7 @@ function end(mode, type, selection) { } 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."); } - + } else if (status == 1) { qm.dispose(); } } diff --git a/scripts/quest/3314.js b/scripts/quest/3314.js index 576717e7dc..31edf6da5d 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 577995ea74..686c60fe30 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/3345.js b/scripts/quest/3345.js index 83cb1b74ac..def3916b24 100644 --- a/scripts/quest/3345.js +++ b/scripts/quest/3345.js @@ -43,7 +43,7 @@ function end(mode, type, selection) { } else { qm.sendNext("Did you not seal the #rmagic circle beneath Magatia#k yet? It is a matter of great importance, please haste yourself."); } - + } else if (status == 1) { qm.dispose(); } } diff --git a/scripts/quest/3360.js b/scripts/quest/3360.js index d9f572b8b2..1b1246c66b 100644 --- a/scripts/quest/3360.js +++ b/scripts/quest/3360.js @@ -51,6 +51,7 @@ function start(mode, type, selection) { 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.dispose(); } } @@ -69,10 +70,11 @@ function end(mode, type, selection) { qm.sendNext("What's up? You haven't opened the Secret Passage yet?"); } else { qm.forceCompleteQuest(); + qm.dispose(); } - + } else if (status == 1) { qm.dispose(); - } + } } } diff --git a/scripts/quest/3382.js b/scripts/quest/3382.js index 046e056dfb..ce732bbd29 100644 --- a/scripts/quest/3382.js +++ b/scripts/quest/3382.js @@ -28,36 +28,50 @@ */ 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..cf33327420 100644 --- a/scripts/quest/3454.js +++ b/scripts/quest/3454.js @@ -28,26 +28,43 @@ */ 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..80f44994fa 100644 --- a/scripts/quest/3507.js +++ b/scripts/quest/3507.js @@ -1,10 +1,26 @@ 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..1bca9087c8 100644 --- a/scripts/quest/3523.js +++ b/scripts/quest/3523.js @@ -24,9 +24,26 @@ */ 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.getPlayer().updateQuestInfo(3507, "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/3524.js b/scripts/quest/3524.js index 744ca4f701..6fde502f1b 100644 --- a/scripts/quest/3524.js +++ b/scripts/quest/3524.js @@ -24,9 +24,26 @@ */ 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.getPlayer().updateQuestInfo(3507, "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..319a71ae0a 100644 --- a/scripts/quest/3525.js +++ b/scripts/quest/3525.js @@ -24,9 +24,26 @@ */ 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.getPlayer().updateQuestInfo(3507, "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..7601322390 100644 --- a/scripts/quest/3526.js +++ b/scripts/quest/3526.js @@ -24,9 +24,26 @@ */ 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.getPlayer().updateQuestInfo(3507, "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..8b6c855857 100644 --- a/scripts/quest/3527.js +++ b/scripts/quest/3527.js @@ -24,9 +24,26 @@ */ 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.getPlayer().updateQuestInfo(3507, "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/3539.js b/scripts/quest/3539.js index 5ba2606c08..8b6c855857 100644 --- a/scripts/quest/3539.js +++ b/scripts/quest/3539.js @@ -24,9 +24,26 @@ */ 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.getPlayer().updateQuestInfo(3507, "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 7868cb80bc..e142e844f8 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 index 4a6bf56015..dce1ce974a 100644 --- a/scripts/quest/3926.js +++ b/scripts/quest/3926.js @@ -51,8 +51,8 @@ function end(mode, type, selection) { 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."); - } - + } + } else if (status == 1) { qm.dispose(); } } diff --git a/scripts/quest/3929.js b/scripts/quest/3929.js index 205cd60561..26b254eba3 100644 --- a/scripts/quest/3929.js +++ b/scripts/quest/3929.js @@ -63,7 +63,7 @@ function end(mode, type, selection) { 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."); } } - + } else if (status == 1) { qm.dispose(); } } diff --git a/scripts/quest/3933.js b/scripts/quest/3933.js index 86dc102299..401d2bf45f 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.forceStartQuest(); + qm.dispose(); } - - qm.dispose(); } } } diff --git a/scripts/quest/3941.js b/scripts/quest/3941.js index 93be8f435f..ecee5987ea 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 d338f06545..0229c9b019 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 a44563086f..3362c48d8f 100644 --- a/scripts/quest/6033.js +++ b/scripts/quest/6033.js @@ -48,12 +48,12 @@ function end(mode, type, selection) { 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 b04c3e9c85..af09ed2295 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/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..64b6b82f5b 100644 --- a/scripts/quest/8189.js +++ b/scripts/quest/8189.js @@ -63,6 +63,7 @@ function end(mode, type, selection) { if (id < 5000029 || id > 5000033) { qm.sendOk("Something wrong, try again."); qm.dispose(); + return; } var rand = 1 + Math.floor(Math.random() * 10); var after = 0; @@ -77,6 +78,7 @@ function end(mode, type, selection) { } else { qm.sendOk("Something wrong. Try again."); qm.dispose(); + return; } /*if (name.equals(MapleItemInformationProvider.getInstance().getName(id))) { @@ -88,7 +90,8 @@ function end(mode, type, selection) { qm.evolvePet(pet, 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/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/sql/db_database.sql b/sql/db_database.sql index d8a8dc3824..da70aa9637 100644 --- a/sql/db_database.sql +++ b/sql/db_database.sql @@ -12828,7 +12828,7 @@ CREATE TABLE IF NOT EXISTS `dueypackages` ( `SenderName` varchar(13) NOT NULL, `Mesos` int(10) unsigned DEFAULT '0', `TimeStamp` timestamp NOT NULL DEFAULT '2015-01-01 05:00:00', - `Message` varchar(200) NOT NULL DEFAULT "", + `Message` varchar(200) NULL, `Checked` tinyint(1) unsigned DEFAULT '1', `Type` tinyint(1) unsigned DEFAULT '0', PRIMARY KEY (`PackageId`) diff --git a/src/client/MapleCharacter.java b/src/client/MapleCharacter.java index 7e588748cd..bfa645f25a 100644 --- a/src/client/MapleCharacter.java +++ b/src/client/MapleCharacter.java @@ -168,6 +168,7 @@ import server.maps.MapleMapItem; import net.server.audit.locks.MonitoredLockType; import net.server.audit.locks.factory.MonitoredReentrantLockFactory; import org.apache.mina.util.ConcurrentHashSet; +import scripting.quest.QuestActionManager; import server.maps.FieldLimit; public class MapleCharacter extends AbstractMapleCharacterObject { @@ -305,6 +306,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; @@ -1173,7 +1175,13 @@ public class MapleCharacter extends AbstractMapleCharacterObject { if (this.isCygnus()) { gainAp(7, true); } else { - gainAp(5, true); + if (ServerConstants.USE_STARTING_AP_4 || newJob.getId() % 10 >= 1) { + gainAp(5, true); + } + } + } else { // thanks Periwinks for noticing an AP shortage from lower levels + if (ServerConstants.USE_STARTING_AP_4 && newJob.getId() % 1000 >= 1) { + gainAp(4, true); } } @@ -3877,10 +3885,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject { 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) { @@ -6168,7 +6174,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { spGain += (expectedSp - curSp); } - return getSpGain(spGain, curSp, job); + return getSpGain(spGain, curSp, newJob); } private int getUsedSp(MapleJob job) { @@ -7391,7 +7397,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { continue; } if (q.progress(id)) { - client.announce(MaplePacketCreator.updateQuest(q, false)); + announceUpdateQuest(DelayedQuestUpdate.UPDATE, q, false); } } } @@ -7400,8 +7406,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } } - public void mount(int id, int skillid) { + public MapleMount mount(int id, int skillid) { maplemount = new MapleMount(this, id, skillid); + return maplemount; } private void playerDead() { @@ -9632,9 +9639,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject { quests.put(q.getId(), qs); } - announce(MaplePacketCreator.updateQuest(qs, false)); + announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, false); if (qs.getQuest().getInfoNumber() > 0) { - announce(MaplePacketCreator.updateQuest(qs, true)); + announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, true); } announce(MaplePacketCreator.updateQuestInfo((short) qs.getQuest().getId(), qs.getNpc())); } @@ -9657,14 +9664,61 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } } + public enum DelayedQuestUpdate { // quest updates allow player actions during NPC talk... + UPDATE, FORFEIT, COMPLETE + } + + private void announceUpdateQuestInternal(Pair questUpdate) { + Object[] objs = questUpdate.getRight(); + + switch (questUpdate.getLeft()) { + case UPDATE: + announce(MaplePacketCreator.updateQuest((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; + } + } + + 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(p); + } + } + + public void flushDelayedUpdateQuests() { + List> qmQuestUpdateList; + + synchronized (npcUpdateQuests) { + qmQuestUpdateList = new ArrayList<>(npcUpdateQuests); + npcUpdateQuests.clear(); + } + + for (Pair q : qmQuestUpdateList) { + announceUpdateQuestInternal(q); + } + } + public void updateQuest(MapleQuestStatus quest) { synchronized (quests) { quests.put(quest.getQuestID(), quest); } if (quest.getStatus().equals(MapleQuestStatus.Status.STARTED)) { - announce(MaplePacketCreator.updateQuest(quest, false)); + announceUpdateQuest(DelayedQuestUpdate.UPDATE, quest, false); if (quest.getQuest().getInfoNumber() > 0) { - announce(MaplePacketCreator.updateQuest(quest, true)); + announceUpdateQuest(DelayedQuestUpdate.UPDATE, quest, true); } announce(MaplePacketCreator.updateQuestInfo((short) quest.getQuest().getId(), quest.getNpc())); } else if (quest.getStatus().equals(MapleQuestStatus.Status.COMPLETED)) { @@ -9675,11 +9729,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } quest.setCompleted(quest.getCompleted() + 1); // count quest completed Jayd's idea - announce(MaplePacketCreator.completeQuest(questid, quest.getCompletionTime())); + announceUpdateQuest(DelayedQuestUpdate.COMPLETE, questid, quest.getCompletionTime()); } else if (quest.getStatus().equals(MapleQuestStatus.Status.NOT_STARTED)) { - announce(MaplePacketCreator.updateQuest(quest, false)); + announceUpdateQuest(DelayedQuestUpdate.UPDATE, quest, false); if (quest.getQuest().getInfoNumber() > 0) { - announce(MaplePacketCreator.updateQuest(quest, true)); + announceUpdateQuest(DelayedQuestUpdate.UPDATE, quest, true); } } } diff --git a/src/client/creator/CharacterFactoryRecipe.java b/src/client/creator/CharacterFactoryRecipe.java index 80b391c39c..74d73f001b 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 constants.ServerConstants; import java.util.concurrent.atomic.AtomicInteger; import java.util.LinkedHashMap; import java.util.LinkedList; @@ -39,7 +40,7 @@ public class CharacterFactoryRecipe { private int level, map, top, bottom, shoes, weapon; private int str = 4, dex = 4, int_ = 4, luk = 4; private int maxHp = 50, maxMp = 5; - private int ap = 9, sp = 0; + private int ap = 0, sp = 0; private int meso = 0; private List> skills = new LinkedList<>(); @@ -54,6 +55,15 @@ public class CharacterFactoryRecipe { this.bottom = bottom; this.shoes = shoes; this.weapon = weapon; + + if (!ServerConstants.USE_STARTING_AP_4) { + if (ServerConstants.USE_AUTOASSIGN_STARTERS_AP) { + str = 12; + dex = 5; + } else { + ap = 9; + } + } } public void setStr(int v) { diff --git a/src/client/processor/DueyProcessor.java b/src/client/processor/DueyProcessor.java index 793b0c179e..d629e565c2 100644 --- a/src/client/processor/DueyProcessor.java +++ b/src/client/processor/DueyProcessor.java @@ -60,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), @@ -113,15 +114,6 @@ public class DueyProcessor { return null; } - private static Timestamp getCurrentDate(boolean quick) { - Calendar cal = Calendar.getInstance(); - if (!quick) { - cal.add(Calendar.DATE, 1); - } - - return new Timestamp(cal.getTime().getTime()); - } - private static void showDueyNotification(MapleClient c, MapleCharacter player) { Connection con = null; PreparedStatement ps = null; @@ -204,7 +196,7 @@ public class DueyProcessor { dueypack.setSender(rs.getString("SenderName")); dueypack.setMesos(rs.getInt("Mesos")); - dueypack.setSentTime(rs.getTimestamp("TimeStamp")); + dueypack.setSentTime(rs.getTimestamp("TimeStamp"), rs.getBoolean("Type")); dueypack.setMessage(rs.getString("Message")); return dueypack; @@ -250,7 +242,7 @@ public class DueyProcessor { ps.setInt(1, toCid); ps.setString(2, sender); ps.setInt(3, mesos); - ps.setTimestamp(4, getCurrentDate(quick)); + ps.setTimestamp(4, new Timestamp(System.currentTimeMillis())); ps.setString(5, message); ps.setInt(6, quick ? 1 : 0); @@ -515,7 +507,11 @@ public class DueyProcessor { } c.getPlayer().setNpcCooldown(timeNow); - c.announce(MaplePacketCreator.sendDuey(quickDelivery ? 0x1A : 0x8, loadPackages(c.getPlayer()))); + if (quickDelivery) { + c.announce(MaplePacketCreator.sendDuey(0x1A, null)); + } else { + c.announce(MaplePacketCreator.sendDuey(0x8, loadPackages(c.getPlayer()))); + } } finally { c.releaseClient(); } @@ -523,7 +519,7 @@ public class DueyProcessor { } public static void dueyCreatePackage(Item item, int mesos, String sender, int recipientCid) { - int packageId = createPackage(mesos, "", sender, recipientCid, false); + int packageId = createPackage(mesos, null, sender, recipientCid, false); if (packageId != -1) { insertPackageItem(packageId, item); } diff --git a/src/constants/GameConstants.java b/src/constants/GameConstants.java index b7e64813d4..a869edb18b 100644 --- a/src/constants/GameConstants.java +++ b/src/constants/GameConstants.java @@ -7,9 +7,16 @@ import java.util.HashMap; import java.util.Map; import client.MapleJob; 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; @@ -38,6 +45,8 @@ public class GameConstants { 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]); } @@ -672,4 +681,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/ServerConstants.java b/src/constants/ServerConstants.java index 0ace201a7b..b037901aec 100644 --- a/src/constants/ServerConstants.java +++ b/src/constants/ServerConstants.java @@ -80,6 +80,7 @@ public class ServerConstants { 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_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. 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). diff --git a/src/net/PacketProcessor.java b/src/net/PacketProcessor.java index 0112631fff..16d7accdc3 100644 --- a/src/net/PacketProcessor.java +++ b/src/net/PacketProcessor.java @@ -245,6 +245,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/opcodes/RecvOpcode.java b/src/net/opcodes/RecvOpcode.java index 3d1a942f09..e357620210 100644 --- a/src/net/opcodes/RecvOpcode.java +++ b/src/net/opcodes/RecvOpcode.java @@ -170,6 +170,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/server/Server.java b/src/net/server/Server.java index 7892ce7d41..94537cb291 100644 --- a/src/net/server/Server.java +++ b/src/net/server/Server.java @@ -1868,12 +1868,12 @@ public class Server { } } - resetServerWorlds(); - ThreadManager.getInstance().stop(); TimerManager.getInstance().purge(); TimerManager.getInstance().stop(); - + + resetServerWorlds(); + System.out.println("Worlds + Channels are offline."); acceptor.unbind(); acceptor = null; diff --git a/src/net/server/channel/handlers/AbstractDealDamageHandler.java b/src/net/server/channel/handlers/AbstractDealDamageHandler.java index 576bf33f23..7172750966 100644 --- a/src/net/server/channel/handlers/AbstractDealDamageHandler.java +++ b/src/net/server/channel/handlers/AbstractDealDamageHandler.java @@ -321,8 +321,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)); @@ -441,11 +442,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 } } } diff --git a/src/net/server/channel/handlers/CashShopSurpriseHandler.java b/src/net/server/channel/handlers/CashShopSurpriseHandler.java index 7a12f9acc0..9f6e9d697a 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/DueyHandler.java b/src/net/server/channel/handlers/DueyHandler.java index 9f7166c1e0..89fc361282 100644 --- a/src/net/server/channel/handlers/DueyHandler.java +++ b/src/net/server/channel/handlers/DueyHandler.java @@ -37,16 +37,18 @@ public final class DueyHandler extends AbstractMaplePacketHandler { 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(); boolean quick = slea.readByte() != 0; - String message = quick ? slea.readMapleAsciiString() : ""; + 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()) { diff --git a/src/net/server/channel/handlers/FieldDamageMobHandler.java b/src/net/server/channel/handlers/FieldDamageMobHandler.java new file mode 100644 index 0000000000..4ae3153e96 --- /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.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/HealOvertimeHandler.java b/src/net/server/channel/handlers/HealOvertimeHandler.java index dec1b5c1b9..35ab9233d0 100644 --- a/src/net/server/channel/handlers/HealOvertimeHandler.java +++ b/src/net/server/channel/handlers/HealOvertimeHandler.java @@ -25,10 +25,9 @@ import client.MapleCharacter; import client.MapleClient; import client.autoban.AutobanFactory; import client.autoban.AutobanManager; -import constants.GameConstants; import net.AbstractMaplePacketHandler; import net.server.Server; -import server.maps.MapleMapFactory; +import server.maps.MapleMap; import tools.data.input.SeekableLittleEndianAccessor; import tools.MaplePacketCreator; @@ -47,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 = (int)(77 * MapleMapFactory.getMapRecoveryRate(chr.getMapId()) * 1.5); // thanks Ari for noticing players not getting healed in sauna in certain cases + 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; @@ -60,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..ab3a75e6e1 100644 --- a/src/net/server/channel/handlers/HiredMerchantRequest.java +++ b/src/net/server/channel/handlers/HiredMerchantRequest.java @@ -27,8 +27,12 @@ import java.sql.SQLException; import java.util.Arrays; import client.MapleClient; import constants.GameConstants; +import java.awt.Point; import net.AbstractMaplePacketHandler; +import server.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/NPCAnimationHandler.java b/src/net/server/channel/handlers/NPCAnimationHandler.java index d12960167b..372fa4293d 100644 --- a/src/net/server/channel/handlers/NPCAnimationHandler.java +++ b/src/net/server/channel/handlers/NPCAnimationHandler.java @@ -30,6 +30,10 @@ import tools.data.output.MaplePacketLittleEndianWriter; public final class NPCAnimationHandler extends AbstractMaplePacketHandler { @Override public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) { + if (c.getPlayer().isChangingMaps()) { // possible cause of error 38 in some map transition scenarios, thanks Arnah + return; + } + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); int length = (int) slea.available(); if (length == 6) { // NPC Talk diff --git a/src/net/server/channel/handlers/PlayerInteractionHandler.java b/src/net/server/channel/handlers/PlayerInteractionHandler.java index bd38fa41e7..463dcb4f18 100644 --- a/src/net/server/channel/handlers/PlayerInteractionHandler.java +++ b/src/net/server/channel/handlers/PlayerInteractionHandler.java @@ -34,11 +34,13 @@ import constants.ServerConstants; import net.AbstractMaplePacketHandler; import server.MapleItemInformationProvider; +import server.MaplePortal; import server.MapleTrade; import constants.GameConstants; import server.maps.FieldLimit; import server.maps.MapleHiredMerchant; import server.maps.MapleMapObject; +import server.maps.MapleMapObjectType; import server.maps.MapleMiniGame; import server.maps.MapleMiniGame.MiniGameType; import server.maps.MaplePlayerShop; @@ -49,6 +51,7 @@ import tools.data.input.SeekableLittleEndianAccessor; import java.awt.Point; import java.sql.SQLException; +import java.util.Arrays; /** * @@ -237,13 +240,9 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler { return; } - try { - Point cpos = chr.getPosition(); - if (chr.getMap().findClosestWarpPortal(cpos).getPosition().distance(cpos) < 120.0) { - chr.getClient().announce(MaplePacketCreator.getMiniRoomError(10)); - return; - } - } catch (NullPointerException npe) {} + if (!canPlaceStore(chr)) { + return; + } String desc = slea.readMapleAsciiString(); slea.skip(3); @@ -362,6 +361,10 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler { c.announce(MaplePacketCreator.hiredMerchantOwnerMaintenanceLeave()); } + + if (!canPlaceStore(chr)) { // thanks Ari for noticing player shops overlapping on opening time + return; + } MaplePlayerShop shop = chr.getPlayerShop(); MapleHiredMerchant merchant = chr.getHiredMerchant(); @@ -797,4 +800,37 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler { return false; } + + private static boolean canPlaceStore(MapleCharacter chr) { + 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; + if (mc.getId() == chr.getId()) { + continue; + } + + MaplePlayerShop shop = mc.getPlayerShop(); + if (shop != null && shop.isOwner(mc)) { + chr.announce(MaplePacketCreator.getMiniRoomError(13)); + return false; + } + } else { + chr.announce(MaplePacketCreator.getMiniRoomError(13)); + return false; + } + } + + 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 false; + } + } catch (Exception e) { + e.printStackTrace(); + } + + return true; + } } diff --git a/src/net/server/channel/handlers/RaiseUIStateHandler.java b/src/net/server/channel/handlers/RaiseUIStateHandler.java index d5add73e1e..e0d602d941 100644 --- a/src/net/server/channel/handlers/RaiseUIStateHandler.java +++ b/src/net/server/channel/handlers/RaiseUIStateHandler.java @@ -1,10 +1,10 @@ package net.server.channel.handlers; +import client.MapleCharacter.DelayedQuestUpdate; import client.MapleClient; import client.MapleQuestStatus; import net.AbstractMaplePacketHandler; import server.quest.MapleQuest; -import tools.MaplePacketCreator; import tools.data.input.SeekableLittleEndianAccessor; /** @@ -25,7 +25,7 @@ public class RaiseUIStateHandler extends AbstractMaplePacketHandler { quest.forceStart(c.getPlayer(), 22000); c.getPlayer().updateQuestInfo(quest.getId(), "0"); } else if (mqs.getStatus() == MapleQuestStatus.Status.STARTED) { - c.announce(MaplePacketCreator.updateQuest(mqs, false)); + c.getPlayer().announceUpdateQuest(DelayedQuestUpdate.UPDATE, mqs, false); } else { //c.announce(MaplePacketCreator.updateQuestInfo(mqs.getQuestID(), 22000, "0")); } diff --git a/src/net/server/worker/RespawnWorker.java b/src/net/server/worker/RespawnWorker.java index 3ea15c373f..f5eda668fa 100644 --- a/src/net/server/worker/RespawnWorker.java +++ b/src/net/server/worker/RespawnWorker.java @@ -1,7 +1,9 @@ package net.server.worker; +import net.server.PlayerStorage; import net.server.Server; import net.server.channel.Channel; +import server.maps.MapleMapManager; /** * @author Resinate @@ -11,8 +13,14 @@ public class RespawnWorker implements Runnable { @Override public void run() { for (Channel ch : Server.getInstance().getAllChannels()) { - if (!ch.getPlayerStorage().getAllCharacters().isEmpty()) { - ch.getMapFactory().updateMaps(); + PlayerStorage ps = ch.getPlayerStorage(); + if (ps != null) { + if (!ps.getAllCharacters().isEmpty()) { + MapleMapManager mapManager = ch.getMapFactory(); + if (mapManager != null) { + mapManager.updateMaps(); + } + } } } } diff --git a/src/scripting/AbstractPlayerInteraction.java b/src/scripting/AbstractPlayerInteraction.java index b6f8c031a6..1aea538343 100644 --- a/src/scripting/AbstractPlayerInteraction.java +++ b/src/scripting/AbstractPlayerInteraction.java @@ -53,6 +53,7 @@ import server.partyquest.Pyramid; import server.quest.MapleQuest; import tools.MaplePacketCreator; import client.MapleCharacter; +import client.MapleCharacter.DelayedQuestUpdate; import client.MapleClient; import client.MapleQuestStatus; import client.SkillFactory; @@ -468,12 +469,12 @@ public class AbstractPlayerInteraction { public void resetAllQuestProgress(int qid) { getPlayer().getQuest(MapleQuest.getInstance(qid)).resetAllProgress(); - getClient().announce(MaplePacketCreator.updateQuest(getPlayer().getQuest(MapleQuest.getInstance(qid)), false)); + getPlayer().announceUpdateQuest(DelayedQuestUpdate.UPDATE, getPlayer().getQuest(MapleQuest.getInstance(qid)), false); } public void resetQuestProgress(int qid, int pid) { getPlayer().getQuest(MapleQuest.getInstance(qid)).resetProgress(pid); - getClient().announce(MaplePacketCreator.updateQuest(getPlayer().getQuest(MapleQuest.getInstance(qid)), false)); + getPlayer().announceUpdateQuest(DelayedQuestUpdate.UPDATE, getPlayer().getQuest(MapleQuest.getInstance(qid)), false); } public boolean forceStartQuest(int id) { diff --git a/src/scripting/AbstractScriptManager.java b/src/scripting/AbstractScriptManager.java index 1fdf81c3e4..beacea5784 100644 --- a/src/scripting/AbstractScriptManager.java +++ b/src/scripting/AbstractScriptManager.java @@ -70,7 +70,7 @@ public abstract class AbstractScriptManager { NashornScriptEngine engine = c.getScriptEngine(cachePath); if (engine == null) { - engine = getScriptEngine(cachePath); + engine = getScriptEngine(path); c.setScriptEngine(path, engine); } diff --git a/src/scripting/event/EventManager.java b/src/scripting/event/EventManager.java index 2a15dc2946..c2f89d3a55 100644 --- a/src/scripting/event/EventManager.java +++ b/src/scripting/event/EventManager.java @@ -347,6 +347,12 @@ public class EventManager { private boolean startLobbyInstance(int lobbyId) { lobbyLock.lock(); try { + if (lobbyId < 0) { + lobbyId = 0; + } else if (lobbyId >= maxLobbys) { + lobbyId = maxLobbys - 1; + } + if(!openedLobbys.get(lobbyId)) { openedLobbys.set(lobbyId, true); return true; diff --git a/src/scripting/map/MapScriptMethods.java b/src/scripting/map/MapScriptMethods.java index d9faa6cb34..b302cfe694 100644 --- a/src/scripting/map/MapScriptMethods.java +++ b/src/scripting/map/MapScriptMethods.java @@ -21,6 +21,7 @@ along with this program. If not, see . */ package scripting.map; +import client.MapleCharacter.DelayedQuestUpdate; import client.MapleClient; import client.MapleQuestStatus; import scripting.AbstractPlayerInteraction; @@ -99,7 +100,7 @@ public class MapScriptMethods extends AbstractPlayerInteraction { } String status = Integer.toString(q.getMedalProgress()); String infoex = quest.getInfoEx(); - getPlayer().announce(MaplePacketCreator.updateQuest(q, true)); + getPlayer().announceUpdateQuest(DelayedQuestUpdate.UPDATE, q, true); StringBuilder smp = new StringBuilder(); StringBuilder etm = new StringBuilder(); if (status.equals(infoex)) { @@ -127,7 +128,7 @@ public class MapScriptMethods extends AbstractPlayerInteraction { return; } String status = Integer.toString(q.getMedalProgress()); - getPlayer().announce(MaplePacketCreator.updateQuest(q, true)); + getPlayer().announceUpdateQuest(DelayedQuestUpdate.UPDATE, q, true); getPlayer().announce(MaplePacketCreator.earnTitleMessage(status + "/5 Completed")); getPlayer().announce(MaplePacketCreator.earnTitleMessage("The One Who's Touched the Sky title in progress.")); if (Integer.toString(q.getMedalProgress()).equals(quest.getInfoEx())) { diff --git a/src/scripting/npc/NPCScriptManager.java b/src/scripting/npc/NPCScriptManager.java index 1abc218633..bee8cc60fc 100644 --- a/src/scripting/npc/NPCScriptManager.java +++ b/src/scripting/npc/NPCScriptManager.java @@ -200,6 +200,8 @@ public class NPCScriptManager extends AbstractScriptManager { } else { resetContext(scriptFolder + "/" + cm.getNpc() + ".js", c); } + + c.getPlayer().flushDelayedUpdateQuests(); } public void dispose(MapleClient c) { diff --git a/src/scripting/quest/QuestScriptManager.java b/src/scripting/quest/QuestScriptManager.java index 46b7dc7f6e..97cbc75e6c 100644 --- a/src/scripting/quest/QuestScriptManager.java +++ b/src/scripting/quest/QuestScriptManager.java @@ -163,6 +163,7 @@ public class QuestScriptManager extends AbstractScriptManager { scripts.remove(c); c.getPlayer().setNpcCooldown(System.currentTimeMillis()); resetContext("quest/" + qm.getQuest() + ".js", c); + c.getPlayer().flushDelayedUpdateQuests(); } public void dispose(MapleClient c) { diff --git a/src/scripting/reactor/ReactorActionManager.java b/src/scripting/reactor/ReactorActionManager.java index 89ff6c338a..cecac74361 100644 --- a/src/scripting/reactor/ReactorActionManager.java +++ b/src/scripting/reactor/ReactorActionManager.java @@ -30,6 +30,7 @@ import constants.ItemConstants; import constants.ServerConstants; import java.awt.Point; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.ScheduledFuture; import java.util.logging.Level; @@ -57,24 +58,70 @@ import tools.MaplePacketCreator; */ public class ReactorActionManager extends AbstractPlayerInteraction { private MapleReactor reactor; - private MapleClient client; private Invocable iv; private ScheduledFuture sprayTask = null; public ReactorActionManager(MapleClient c, MapleReactor reactor, Invocable iv) { super(c); this.reactor = reactor; - this.client = c; this.iv = iv; } public void hitReactor() { - reactor.hitReactor(client); + reactor.hitReactor(c); } public void destroyNpc(int npcId) { reactor.getMap().destroyNPC(npcId); } + + private static void sortDropEntries(List from, List item, List visibleQuest, List otherQuest, MapleCharacter chr) { + MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); + + for(ReactorDropEntry mde : from) { + if(!ii.isQuestItem(mde.itemId)) { + item.add(mde); + } else { + if(chr.needQuestItem(mde.questid, mde.itemId)) { + visibleQuest.add(mde); + } else { + otherQuest.add(mde); + } + } + } + } + + private static List assembleReactorDropEntries(MapleCharacter chr, List items) { + final List dropEntry = new ArrayList<>(); + final List visibleQuestEntry = new ArrayList<>(); + final List otherQuestEntry = new ArrayList<>(); + sortDropEntries(items, dropEntry, visibleQuestEntry, otherQuestEntry, chr); + + Collections.shuffle(dropEntry); + Collections.shuffle(visibleQuestEntry); + Collections.shuffle(otherQuestEntry); + + items.clear(); + items.addAll(dropEntry); + items.addAll(visibleQuestEntry); + items.addAll(otherQuestEntry); + + List items1 = new ArrayList<>(items.size()); + List items2 = new ArrayList<>(items.size() / 2); + + for (int i = 0; i < items.size(); i++) { + if (i % 2 == 0) { + items1.add(items.get(i)); + } else { + items2.add(items.get(i)); + } + } + + Collections.reverse(items1); + items1.addAll(items2); + + return items1; + } public void sprayItems() { sprayItems(false, 0, 0, 0, 0); @@ -109,10 +156,10 @@ public class ReactorActionManager extends AbstractPlayerInteraction { } public void dropItems(boolean delayed, int posX, int posY, boolean meso, int mesoChance, final int minMeso, final int maxMeso, int minItems) { - if(c.getPlayer() == null) return; - - List items = generateDropList(getDropChances(), c.getPlayer().getDropRate(), meso, mesoChance, minItems); + MapleCharacter chr = c.getPlayer(); + if(chr == null) return; + List items = assembleReactorDropEntries(chr, generateDropList(getDropChances(), chr.getDropRate(), meso, mesoChance, minItems)); if(items.size() % 2 == 0) posX -= 12; final Point dropPos = new Point(posX, posY); @@ -127,8 +174,8 @@ public class ReactorActionManager extends AbstractPlayerInteraction { if (d.itemId == 0) { int range = maxMeso - minMeso; int displayDrop = (int) (Math.random() * range) + minMeso; - int mesoDrop = (displayDrop * client.getWorldServer().getMesoRate()); - reactor.getMap().spawnMesoDrop(mesoDrop, reactor.getMap().calcDropPos(dropPos, reactor.getPosition()), reactor, client.getPlayer(), false, (byte) 2); + int mesoDrop = (displayDrop * c.getWorldServer().getMesoRate()); + reactor.getMap().spawnMesoDrop(mesoDrop, reactor.getMap().calcDropPos(dropPos, reactor.getPosition()), reactor, c.getPlayer(), false, (byte) 2); } else { Item drop; @@ -142,10 +189,9 @@ public class ReactorActionManager extends AbstractPlayerInteraction { } } } else { - final MapleCharacter chr = client.getPlayer(); final MapleReactor r = reactor; final List dropItems = items; - final int worldMesoRate = client.getWorldServer().getMesoRate(); + final int worldMesoRate = c.getWorldServer().getMesoRate(); dropPos.x -= (12 * items.size()); @@ -178,7 +224,7 @@ public class ReactorActionManager extends AbstractPlayerInteraction { dropPos.x += 25; } - }, 100); + }, 200); } } @@ -187,37 +233,21 @@ public class ReactorActionManager extends AbstractPlayerInteraction { } private List generateDropList(List drops, int dropRate, boolean meso, int mesoChance, int minItems) { - MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); - List items = new ArrayList<>(); - List questItems = new ArrayList<>(); - int numItems = 0; - if (meso && Math.random() < (1 / (double) mesoChance)) { items.add(new ReactorDropEntry(0, mesoChance, -1)); } for(ReactorDropEntry mde : drops) { if (Math.random() < (dropRate / (double) mde.chance)) { - if(!ii.isQuestItem(mde.itemId)) { - items.add(mde); - } else { - questItems.add(mde); - } - - numItems++; + items.add(mde); } } - while (numItems < minItems) { + while (items.size() < minItems) { items.add(new ReactorDropEntry(0, mesoChance, -1)); - numItems++; } - java.util.Collections.shuffle(items); - java.util.Collections.shuffle(questItems); - - items.addAll(questItems); return items; } @@ -226,7 +256,7 @@ public class ReactorActionManager extends AbstractPlayerInteraction { } public void createMapMonitor(int mapId, String portal) { - new MapMonitor(client.getChannelServer().getMapFactory().getMap(mapId), portal); + new MapMonitor(c.getChannelServer().getMapFactory().getMap(mapId), portal); } public void spawnMonster(int id, int qty) { diff --git a/src/server/CashShop.java b/src/server/CashShop.java index ae07b48907..acdd2ddc5f 100644 --- a/src/server/CashShop.java +++ b/src/server/CashShop.java @@ -157,7 +157,7 @@ public class CashShop { private static final Map items = new HashMap<>(); private static final Map> packages = new HashMap<>(); private static final List specialcashitems = new ArrayList<>(); - private static final List randomitemids = new ArrayList<>(); + private static final List randomitemsns = new ArrayList<>(); static { MapleDataProvider etc = MapleDataProviderFactory.getDataProvider(new File("wz/Etc.wz")); @@ -184,7 +184,7 @@ public class CashShop { for(Entry e : items.entrySet()) { if(e.getValue().isOnSale()) { - randomitemids.add(e.getKey()); + randomitemsns.add(e.getKey()); } } @@ -212,10 +212,10 @@ public class CashShop { } public static CashItem getRandomCashItem() { - if(randomitemids.isEmpty()) return null; + if(randomitemsns.isEmpty()) return null; - int rnd = (int)(Math.random() * randomitemids.size()); - return items.get(randomitemids.get(rnd)); + int rnd = (int)(Math.random() * randomitemsns.size()); + return items.get(randomitemsns.get(rnd)); } public static CashItem getItem(int sn) { diff --git a/src/server/DueyPackage.java b/src/server/DueyPackage.java index a7f7f69671..1b95a0250c 100644 --- a/src/server/DueyPackage.java +++ b/src/server/DueyPackage.java @@ -29,7 +29,7 @@ public class DueyPackage { private String sender = null; private Item item = null; private int mesos = 0; - private String message = ""; + private String message = null; private Calendar timestamp; private int packageId = 0; @@ -96,13 +96,15 @@ public class DueyPackage { } } - public void setSentTime(Timestamp ts) { + public void setSentTime(Timestamp ts, boolean quick) { Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(ts.getTime()); - cal.set(Calendar.HOUR, 0); - cal.set(Calendar.MINUTE, 0); - cal.set(Calendar.SECOND, 0); - cal.set(Calendar.MILLISECOND, 0); + + if (quick) { + if (System.currentTimeMillis() - ts.getTime() < 24 * 60 * 60 * 1000) { // thanks inhyuk for noticing quick delivery packages unavailable to retrieve from the get-go + cal.add(Calendar.DATE, -1); + } + } this.timestamp = cal; } diff --git a/src/server/MaplePortal.java b/src/server/MaplePortal.java index 3e0c02c096..23ff66043b 100644 --- a/src/server/MaplePortal.java +++ b/src/server/MaplePortal.java @@ -25,6 +25,7 @@ import java.awt.Point; import client.MapleClient; public interface MaplePortal { + public final int TELEPORT_PORTAL = 1; public final int MAP_PORTAL = 2; public final int DOOR_PORTAL = 6; public static boolean OPEN = true; diff --git a/src/server/MapleStatEffect.java b/src/server/MapleStatEffect.java index 64f9e72401..a0c2dbac47 100644 --- a/src/server/MapleStatEffect.java +++ b/src/server/MapleStatEffect.java @@ -1288,6 +1288,7 @@ public class MapleStatEffect { if (mount != null) { ridingMountId = mount.getItemId(); } + if (sourceid == Corsair.BATTLE_SHIP) { ridingMountId = 1932000; } else if (sourceid == Beginner.SPACESHIP || sourceid == Noblesse.SPACESHIP) { @@ -1300,28 +1301,12 @@ public class MapleStatEffect { ridingMountId = 1932005; } else if (sourceid == Beginner.BALROG_MOUNT || sourceid == Noblesse.BALROG_MOUNT || sourceid == Legend.BALROG_MOUNT) { ridingMountId = 1932010; - } else { - if (applyto.getMount() == null) { - applyto.mount(ridingMountId, sourceid); - } - - applyto.getClient().getWorldServer().registerMountHunger(applyto); - } - if (sourceid == Corsair.BATTLE_SHIP) { - givemount = new MapleMount(applyto, 1932000, sourceid); - } else if (sourceid == Beginner.SPACESHIP || sourceid == Noblesse.SPACESHIP) { - givemount = new MapleMount(applyto, 1932000 + applyto.getSkillLevel(sourceid), sourceid); - } else if (sourceid == Beginner.YETI_MOUNT1 || sourceid == Noblesse.YETI_MOUNT1 || sourceid == Legend.YETI_MOUNT1) { - givemount = new MapleMount(applyto, 1932003, sourceid); - } else if (sourceid == Beginner.YETI_MOUNT2 || sourceid == Noblesse.YETI_MOUNT2 || sourceid == Legend.YETI_MOUNT2) { - givemount = new MapleMount(applyto, 1932004, sourceid); - } else if (sourceid == Beginner.WITCH_BROOMSTICK || sourceid == Noblesse.WITCH_BROOMSTICK || sourceid == Legend.WITCH_BROOMSTICK) { - givemount = new MapleMount(applyto, 1932005, sourceid); - } else if (sourceid == Beginner.BALROG_MOUNT || sourceid == Noblesse.BALROG_MOUNT || sourceid == Legend.BALROG_MOUNT) { - givemount = new MapleMount(applyto, 1932010, sourceid); - } else { - givemount = applyto.getMount(); } + + // thanks inhyuk for noticing some skill mounts not acting properly for other players when changing maps + givemount = applyto.mount(ridingMountId, sourceid); + applyto.getClient().getWorldServer().registerMountHunger(applyto); + localDuration = sourceid; localsourceid = ridingMountId; localstatups = Collections.singletonList(new Pair<>(MapleBuffStat.MONSTER_RIDING, 0)); diff --git a/src/server/expeditions/MapleExpeditionBossLog.java b/src/server/expeditions/MapleExpeditionBossLog.java index 02549ec4fa..fac70f4ae3 100644 --- a/src/server/expeditions/MapleExpeditionBossLog.java +++ b/src/server/expeditions/MapleExpeditionBossLog.java @@ -65,12 +65,9 @@ public class MapleExpeditionBossLog { private static List> getBossLogResetTimestamps(Calendar timeNow, boolean week) { List> resetTimestamps = new LinkedList<>(); + Timestamp ts = new Timestamp(timeNow.getTime().getTime()); // reset all table entries actually, thanks Conrad for (BossLogEntry b : BossLogEntry.values()) { if (b.week == week) { - Calendar c = (Calendar) timeNow.clone(); - c.roll(Calendar.DAY_OF_MONTH, -1 * (week ? 7 : 1) * b.timeLength); - Timestamp ts = new Timestamp(c.getTime().getTime()); - resetTimestamps.add(new Pair<>(ts, b)); } } diff --git a/src/server/life/MapleMonster.java b/src/server/life/MapleMonster.java index 0bb34c0d7f..c65000697d 100644 --- a/src/server/life/MapleMonster.java +++ b/src/server/life/MapleMonster.java @@ -97,7 +97,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { private Set usedAttacks = new HashSet<>(); private Set calledMobOids = null; private WeakReference callerMob = new WeakReference<>(null); - private List stolenItems = new ArrayList<>(); + private List stolenItems = new ArrayList<>(5); private int team; private int parentMobOid = 0; private final HashMap takenDamage = new HashMap<>(); diff --git a/src/server/life/MapleMonsterInformationProvider.java b/src/server/life/MapleMonsterInformationProvider.java index f4d44ea319..f5c4394331 100644 --- a/src/server/life/MapleMonsterInformationProvider.java +++ b/src/server/life/MapleMonsterInformationProvider.java @@ -152,7 +152,7 @@ public class MapleMonsterInformationProvider { int rnd = Randomizer.rand(mde.Minimum, mde.Maximum); for (int i = 0; i < rnd - 1; i++) { - extra.add(mde); // this passes copies of the equips' MDE with min/max quantity > 1, but idc it'll be unused anyways + extra.add(mde); // this passes copies of the equips' MDE with min/max quantity > 1, but idc on equips they are unused anyways } } } diff --git a/src/server/maps/MapleMap.java b/src/server/maps/MapleMap.java index 98eca82656..e7503d2275 100644 --- a/src/server/maps/MapleMap.java +++ b/src/server/maps/MapleMap.java @@ -137,6 +137,7 @@ public class MapleMap { private int timeLimit; private long mapTimer; private int decHP = 0; + private float recovery = 1.0f; private int protectItem = 0; private boolean town; private MapleOxQuiz ox; @@ -1408,81 +1409,85 @@ public class MapleMap { } } else { if (removeKilledMonsterObject(monster)) { - if (monster.getStats().getLevel() >= chr.getLevel() + 30 && !chr.isGM()) { - AutobanFactory.GENERAL.alert(chr, " for killing a " + monster.getName() + " which is over 30 levels higher."); - } - - /*if (chr.getQuest(MapleQuest.getInstance(29400)).getStatus().equals(MapleQuestStatus.Status.STARTED)) { - if (chr.getLevel() >= 120 && monster.getStats().getLevel() >= 120) { - //FIX MEDAL SHET - } else if (monster.getStats().getLevel() >= chr.getLevel()) { - } - }*/ - - if (monster.getCP() > 0 && chr.getMap().isCPQMap()) { - chr.gainCP(monster.getCP()); - } - - int buff = monster.getBuffToGive(); - if (buff > -1) { - MapleItemInformationProvider mii = MapleItemInformationProvider.getInstance(); - for (MapleMapObject mmo : this.getPlayers()) { - MapleCharacter character = (MapleCharacter) mmo; - if (character.isAlive()) { - MapleStatEffect statEffect = mii.getItemEffect(buff); - character.getClient().announce(MaplePacketCreator.showOwnBuffEffect(buff, 1)); - broadcastMessage(character, MaplePacketCreator.showBuffeffect(character.getId(), buff, 1), false); - statEffect.applyTo(character); - } + try { + if (monster.getStats().getLevel() >= chr.getLevel() + 30 && !chr.isGM()) { + AutobanFactory.GENERAL.alert(chr, " for killing a " + monster.getName() + " which is over 30 levels higher."); } - } - - if (monster.getId() >= 8800003 && monster.getId() <= 8800010) { - boolean makeZakReal = true; - Collection objects = getMapObjects(); - for (MapleMapObject object : objects) { - MapleMonster mons = getMonsterByOid(object.getObjectId()); - if (mons != null) { - if (mons.getId() >= 8800003 && mons.getId() <= 8800010) { - makeZakReal = false; - break; + + /*if (chr.getQuest(MapleQuest.getInstance(29400)).getStatus().equals(MapleQuestStatus.Status.STARTED)) { + if (chr.getLevel() >= 120 && monster.getStats().getLevel() >= 120) { + //FIX MEDAL SHET + } else if (monster.getStats().getLevel() >= chr.getLevel()) { + } + }*/ + + if (monster.getCP() > 0 && chr.getMap().isCPQMap()) { + chr.gainCP(monster.getCP()); + } + + int buff = monster.getBuffToGive(); + if (buff > -1) { + MapleItemInformationProvider mii = MapleItemInformationProvider.getInstance(); + for (MapleMapObject mmo : this.getPlayers()) { + MapleCharacter character = (MapleCharacter) mmo; + if (character.isAlive()) { + MapleStatEffect statEffect = mii.getItemEffect(buff); + character.getClient().announce(MaplePacketCreator.showOwnBuffEffect(buff, 1)); + broadcastMessage(character, MaplePacketCreator.showBuffeffect(character.getId(), buff, 1), false); + statEffect.applyTo(character); } } } - if (makeZakReal) { - MapleMap map = chr.getMap(); + if (monster.getId() >= 8800003 && monster.getId() <= 8800010) { + boolean makeZakReal = true; + Collection objects = getMapObjects(); for (MapleMapObject object : objects) { - MapleMonster mons = map.getMonsterByOid(object.getObjectId()); + MapleMonster mons = getMonsterByOid(object.getObjectId()); if (mons != null) { - if (mons.getId() == 8800000) { - makeMonsterReal(mons); - mons.aggroUpdateController(); + if (mons.getId() >= 8800003 && mons.getId() <= 8800010) { + makeZakReal = false; break; } } } - } - } + if (makeZakReal) { + MapleMap map = chr.getMap(); - MapleCharacter dropOwner = monster.killBy(chr); - if (withDrops && !monster.dropsDisabled()) { - if (dropOwner == null) { - dropOwner = chr; - } - dropFromMonster(dropOwner, monster, false); - } - - if (monster.hasBossHPBar()) { - for(MapleCharacter mc : this.getAllPlayers()) { - if(mc.getTargetHpBarHash() == monster.hashCode()) { - mc.resetPlayerAggro(); + for (MapleMapObject object : objects) { + MapleMonster mons = map.getMonsterByOid(object.getObjectId()); + if (mons != null) { + if (mons.getId() == 8800000) { + makeMonsterReal(mons); + mons.aggroUpdateController(); + break; + } + } + } } } - } - monster.dispatchMonsterKilled(true); - broadcastMessage(MaplePacketCreator.killMonster(monster.getObjectId(), animation), monster.getPosition()); + MapleCharacter dropOwner = monster.killBy(chr); + if (withDrops && !monster.dropsDisabled()) { + if (dropOwner == null) { + dropOwner = chr; + } + dropFromMonster(dropOwner, monster, false); + } + + if (monster.hasBossHPBar()) { + for(MapleCharacter mc : this.getAllPlayers()) { + if(mc.getTargetHpBarHash() == monster.hashCode()) { + mc.resetPlayerAggro(); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { // thanks resinate for pointing out a memory leak possibly from an exception thrown + monster.dispatchMonsterKilled(true); + broadcastMessage(MaplePacketCreator.killMonster(monster.getObjectId(), animation), monster.getPosition()); + } } } } @@ -2707,12 +2712,12 @@ public class MapleMap { return portal != null ? portal : getPortal(0); } - public MaplePortal findClosestWarpPortal(Point from) { + public MaplePortal findClosestTeleportPortal(Point from) { MaplePortal closest = null; double shortestDistance = Double.POSITIVE_INFINITY; for (MaplePortal portal : portals.values()) { double distance = portal.getPosition().distanceSq(from); - if (portal.getType() == MaplePortal.MAP_PORTAL && distance < shortestDistance && portal.getTargetMapId() == 999999999) { + if (portal.getType() == MaplePortal.TELEPORT_PORTAL && distance < shortestDistance && portal.getTargetMapId() != 999999999) { closest = portal; shortestDistance = distance; } @@ -3777,6 +3782,14 @@ public class MapleMap { public void setHPDecProtect(int delta) { this.protectItem = delta; } + + public float getRecovery() { + return recovery; + } + + public void setRecovery(float recRate) { + recovery = recRate; + } private int hasBoat() { return !boat ? 0 : (docked ? 1 : 2); diff --git a/src/server/maps/MapleMapFactory.java b/src/server/maps/MapleMapFactory.java index 036bd77578..0c37f54d6e 100644 --- a/src/server/maps/MapleMapFactory.java +++ b/src/server/maps/MapleMapFactory.java @@ -31,7 +31,6 @@ import java.sql.SQLException; import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; import provider.MapleData; import provider.MapleDataProvider; import provider.MapleDataProviderFactory; @@ -49,8 +48,6 @@ import tools.StringUtil; public class MapleMapFactory { - private static Map mapRecoveryRateCache = new HashMap<>(); - private static MapleData nameData; private static MapleDataProvider mapSource; @@ -336,11 +333,10 @@ public class MapleMapFactory { map.setTimeLimit(MapleDataTool.getIntConvert("timeLimit", infoData, -1)); map.setFieldType(MapleDataTool.getIntConvert("fieldType", infoData, 0)); map.setMobCapacity(MapleDataTool.getIntConvert("fixedMobCapacity", infoData, 500));//Is there a map that contains more than 500 mobs? - + MapleData recData = infoData.getChildByPath("recovery"); if (recData != null) { - float recoveryRate = MapleDataTool.getFloat(recData); - mapRecoveryRateCache.put(mapid, recoveryRate); + map.setRecovery(MapleDataTool.getFloat(recData)); } HashMap backTypes = new HashMap<>(); @@ -438,9 +434,5 @@ public class MapleMapFactory { builder.append("/").append(mapid); return builder.toString(); } - - public static float getMapRecoveryRate(int mapid) { - Float recRate = mapRecoveryRateCache.get(mapid); - return recRate != null ? recRate : 1.0f; - } + } diff --git a/src/server/maps/MapleMapManager.java b/src/server/maps/MapleMapManager.java index 36d36212c5..db3df6d49a 100644 --- a/src/server/maps/MapleMapManager.java +++ b/src/server/maps/MapleMapManager.java @@ -139,7 +139,4 @@ public class MapleMapManager { this.event = null; } - public static float getMapRecoveryRate(int mapid) { - return MapleMapFactory.getMapRecoveryRate(mapid); - } } diff --git a/src/server/quest/MapleQuest.java b/src/server/quest/MapleQuest.java index cefceb45d3..cf7e8f94f2 100644 --- a/src/server/quest/MapleQuest.java +++ b/src/server/quest/MapleQuest.java @@ -28,6 +28,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import client.MapleCharacter; +import client.MapleCharacter.DelayedQuestUpdate; import client.MapleQuestStatus; import client.MapleQuestStatus.Status; import constants.ServerConstants; @@ -337,7 +338,7 @@ public class MapleQuest { if(pid >= 8200000 && pid <= 8200012) { String pr = StringUtil.getLeftPaddedStr(Integer.toString(setProg), '0', 3); newStatus.setProgress(pid, pr); - c.announce(MaplePacketCreator.updateQuest(newStatus, false)); + c.announceUpdateQuest(DelayedQuestUpdate.UPDATE, newStatus, false); } } } diff --git a/src/server/quest/actions/ItemAction.java b/src/server/quest/actions/ItemAction.java index a395035f46..a4e2d0a21e 100644 --- a/src/server/quest/actions/ItemAction.java +++ b/src/server/quest/actions/ItemAction.java @@ -109,6 +109,7 @@ public class ItemAction extends MapleQuestAction { if (!canGetItem(iEntry, chr)) { continue; } + if(iEntry.getProp() != null) { if(iEntry.getProp() == -1) { if(extSelection != extNum++) @@ -181,11 +182,11 @@ public class ItemAction extends MapleQuestAction { } } else { - if(item.getCount() > 0) { - // Make sure they can hold the item. - Item toItem = new Item(item.getId(), (short) 0, (short) item.getCount()); - gainList.add(new Pair<>(toItem, type)); - } else { + // Make sure they can hold the item. + Item toItem = new Item(item.getId(), (short) 0, (short) item.getCount()); + gainList.add(new Pair<>(toItem, type)); + + if(item.getCount() < 0) { // Make sure they actually have the item. int quantity = item.getCount() * -1; @@ -229,12 +230,34 @@ public class ItemAction extends MapleQuestAction { gainList.add(selected); } - if (!MapleInventory.checkSpots(chr, gainList, allSlotUsed, false)) { + if (!canHold(chr, gainList)) { chr.dropMessage(1, "Please check if you have enough space in your inventory."); return false; } return true; } + + private boolean canHold(MapleCharacter chr, List> gainList) { + List toAddItemids = new LinkedList<>(); + List toAddQuantity = new LinkedList<>(); + List toRemoveItemids = new LinkedList<>(); + List toRemoveQuantity = new LinkedList<>(); + + for (Pair item : gainList) { + Item it = item.getLeft(); + + if (it.getQuantity() > 0) { + toAddItemids.add(it.getItemId()); + toAddQuantity.add((int) it.getQuantity()); + } else { + toRemoveItemids.add(it.getItemId()); + toRemoveQuantity.add(-1 * ((int) it.getQuantity())); + } + } + + // thanks onechord for noticing quests unnecessarily giving out "full inventory" from quests that also takes items from players + return chr.getClient().getAbstractPlayerInteraction().canHoldAllAfterRemoving(toAddItemids, toAddQuantity, toRemoveItemids, toRemoveQuantity); + } private boolean canGetItem(ItemData item, MapleCharacter chr) { if (item.getGender() != 2 && item.getGender() != chr.getGender()) { diff --git a/src/tools/MaplePacketCreator.java b/src/tools/MaplePacketCreator.java index fe25226db8..6006443afa 100644 --- a/src/tools/MaplePacketCreator.java +++ b/src/tools/MaplePacketCreator.java @@ -1916,17 +1916,12 @@ public class MaplePacketCreator { Integer bv = chr.getBuffedValue(MapleBuffStat.MONSTER_RIDING); if (bv != null) { - if(bv.equals(Corsair.BATTLE_SHIP)) { - mplew.writeInt(1932000); - mplew.writeInt(Corsair.BATTLE_SHIP); + MapleMount mount = chr.getMount(); + if (mount != null) { + mplew.writeInt(mount.getItemId()); + mplew.writeInt(mount.getSkillId()); } else { - final Item mount = chr.getInventory(MapleInventoryType.EQUIPPED).getItem((short) -18); - if(mount != null) { - mplew.writeInt(mount.getItemId()); - mplew.writeInt(1004); - } else { - mplew.writeLong(0); - } + mplew.writeLong(0); } } else { mplew.writeLong(0); @@ -6975,14 +6970,14 @@ public class MaplePacketCreator { public static byte[] onCashItemGachaponOpenFailed(){ MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); mplew.writeShort(SendOpcode.CASHSHOP_CASH_ITEM_GACHAPON_RESULT.getValue()); - mplew.write(189); + mplew.write(0xE4); return mplew.getPacket(); } public static byte[] onCashGachaponOpenSuccess(int accountid, long sn, int remainingBoxes, Item item, int itemid, int nSelectedItemCount, boolean bJackpot){ MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); mplew.writeShort(SendOpcode.CASHSHOP_CASH_ITEM_GACHAPON_RESULT.getValue()); - mplew.write(190); + mplew.write(0xE5); // subopcode thanks to Ubaware mplew.writeLong(sn);// sn of the box used mplew.writeInt(remainingBoxes); addCashItemInformation(mplew, item, accountid); @@ -7253,15 +7248,15 @@ public class MaplePacketCreator { mplew.writeLong(getTime(dp.sentTimeInMilliseconds())); String msg = dp.getMessage(); - if (!msg.isEmpty()) { - mplew.writeInt(1); - mplew.writeAsciiString(msg); - for (int i = msg.length(); i < 200; i++) { - mplew.write(0); - } + if (msg != null) { + mplew.writeInt(1); + mplew.writeAsciiString(msg); + for (int i = msg.length(); i < 200; i++) { + mplew.write(0); + } } else { - mplew.writeInt(0); - mplew.skip(200); + mplew.writeInt(0); + mplew.skip(200); } mplew.write(0); diff --git a/tools/ScriptStaticMethodTracker/method_list.c b/tools/ScriptStaticMethodTracker/method_list.c new file mode 100644 index 0000000000..4fd6a87372 --- /dev/null +++ b/tools/ScriptStaticMethodTracker/method_list.c @@ -0,0 +1,85 @@ +/* + 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 . +*/ + +JavaMethod* createJavaMethod(const char *name) { + JavaMethod* method = (JavaMethod *)malloc(sizeof(JavaMethod)); + method->name = (char *)malloc((strlen(name) + 1) * sizeof(char)); + strcpy(method->name, name); + return method; +} + +void freeJavaMethod(JavaMethod *method) { + free(method->name); + free(method); +} + +JavaMethodList createJavaMethodList() { + JavaMethodList list; + list.size = 0; + + JavaMethodListItem *item = (JavaMethodListItem *)malloc(sizeof(JavaMethodListItem)); + item->prox = NULL; + + list.last = item; + list.first = list.last; + + return list; +} + +void insertJavaMethod(JavaMethodList *list, JavaMethod *method) { + JavaMethodListItem *item = (JavaMethodListItem *)malloc(sizeof(JavaMethodListItem)); + item->prox = NULL; + + list->last->method = method; + list->last->prox = item; + + list->last = item; + list->size++; +} + +void freeJavaMethodList(JavaMethodList *list) { + JavaMethodListItem *aux = list->first; + + list->first = list->last; + list->size = 0; + + while (aux->prox != NULL) { + JavaMethodListItem *aux2 = aux; + aux = aux->prox; + + freeJavaMethod(aux2->method); + free(aux2); + } + free(aux); +} + +void resetJavaMethodCursor(JavaMethodList *list) { + list->cursor = list->first; +} + +JavaMethod* readJavaMethod(JavaMethodList *list) { + JavaMethodListItem *aux = list->cursor; + if (aux->prox == NULL) { + return NULL; + } + + list->cursor = aux->prox; + return aux->method; +} diff --git a/tools/ScriptStaticMethodTracker/method_list.h b/tools/ScriptStaticMethodTracker/method_list.h new file mode 100644 index 0000000000..ae4fabed1d --- /dev/null +++ b/tools/ScriptStaticMethodTracker/method_list.h @@ -0,0 +1,43 @@ +/* + 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 . +*/ + +#ifndef METHOD_LIST_H_ +#define METHOD_LIST_H_ + +typedef struct { + char *name; +} JavaMethod; + +typedef struct JavaMethodListItem { + JavaMethod *method; + struct JavaMethodListItem *prox; +} JavaMethodListItem; + +typedef struct { + JavaMethodListItem *first; + JavaMethodListItem *last; + JavaMethodListItem *cursor; + + int size; +} JavaMethodList; + +#include "method_list.c" + +#endif /* METHOD_LIST_H_ */ diff --git a/tools/ScriptStaticMethodTracker/method_tracker.c b/tools/ScriptStaticMethodTracker/method_tracker.c new file mode 100644 index 0000000000..63af248dec --- /dev/null +++ b/tools/ScriptStaticMethodTracker/method_tracker.c @@ -0,0 +1,347 @@ +/* + 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 . +*/ + +#include +#include +#include +#include +#include + +#define SCRIPT_FILES_MAX_CONTENT_SIZE 1777777 + +#include "method_list.h" +#include "script_path.h" + +JavaMethodList getBestSubstringsFromStringList(char *aStrRegex, JavaMethodList *lines, int lines_size) { + JavaMethodList ret = createJavaMethodList(); + + // ------------ an adaptation from Mitch Richling's https://www.mitchr.me/SS/exampleCode/AUPG/pcre_example.c.html ----------- + + int subStrVec[30]; + int subStrVecLength = 30; + const char *pcreErrorStr; + int pcreErrorOffset; + + pcre *reCompiled = pcre_compile(aStrRegex, 0, &pcreErrorStr, &pcreErrorOffset, NULL); + if(reCompiled == NULL) { + printf("ERROR: Could not compile '%s': %s\n", aStrRegex, pcreErrorStr); + return ret; + } + + pcre_extra *pcreExtra = pcre_study(reCompiled, 0, &pcreErrorStr); + if(pcreErrorStr != NULL) { + printf("ERROR: Could not study '%s': %s\n", aStrRegex, pcreErrorStr); + return ret; + } + + int i; + for (i = 0; i < lines_size; i++) { + JavaMethodList list = lines[i]; + + resetJavaMethodCursor(&list); + while(true) { + JavaMethod *method = readJavaMethod(&list); + if (method == NULL) { + break; + } + + char *str = method->name; + int pcreExecRet = pcre_exec(reCompiled, pcreExtra, str, strlen(str), 0, 0, subStrVec, subStrVecLength); + if(pcreExecRet < 0) { + switch(pcreExecRet) { + //case PCRE_ERROR_NOMATCH : printf("String did not match the pattern\n"); break; + case PCRE_ERROR_NULL : printf("Something was null\n"); break; + case PCRE_ERROR_BADOPTION : printf("A bad option was passed\n"); break; + case PCRE_ERROR_BADMAGIC : printf("Magic number bad (compiled re corrupt?)\n"); break; + case PCRE_ERROR_UNKNOWN_NODE : printf("Something kooky in the compiled re\n"); break; + case PCRE_ERROR_NOMEMORY : printf("Ran out of memory\n"); break; + //default : printf("Unknown error\n"); break; + } + } else { + if(pcreExecRet == 0) { + printf("But too many substrings were found to fit in subStrVec!\n"); + // Set rc to the max number of substring matches possible. + pcreExecRet = 30 / 3; + } + + const char *psubStrMatchStr; + pcre_get_substring(str, subStrVec, pcreExecRet, 0, &(psubStrMatchStr)); + + insertJavaMethod(&ret, createJavaMethod(psubStrMatchStr)); + pcre_free_substring(psubStrMatchStr); + } + } + } + + pcre_free(reCompiled); + + if(pcreExtra != NULL) { + pcre_free(pcreExtra); + } + + return ret; +} + +char* extractStaticMethodName(const char *method_line) { + char *aStrRegex = "([A-Za-z0-9])+(\\s)*\\("; + + int lines_size = 1; + JavaMethodList *lines = (JavaMethodList *)malloc(lines_size * sizeof(JavaMethodList)); + + int i; + for (i = 0; i < lines_size; i++) { + lines[i] = createJavaMethodList(); + insertJavaMethod(&(lines[i]), createJavaMethod(method_line)); + } + + JavaMethodList subs = getBestSubstringsFromStringList(aStrRegex, lines, lines_size); + + char *ret; + if (subs.size > 0) { + resetJavaMethodCursor(&subs); + JavaMethod *method = readJavaMethod(&subs); + + char *method_scoop = method->name; + int i; + for (i = 0; i < strlen(method_scoop) - 1; i++) { + char ch = method_scoop[i]; + if (ch == '(' || ch == ' ' || ch == '\t') { + break; + } + } + method->name[i] = 0; + + ret = (char *)malloc((strlen(method->name) + 1) * sizeof(char)); + strcpy(ret, method->name); + } else { + ret = NULL; + } + + freeJavaMethodList(&subs); + + for (i = 0; i < lines_size; i++) { + freeJavaMethodList(&(lines[i])); + } + + free(lines); + + return ret; +} + +JavaMethodList getStaticJavaMethodNames(char *aStrRegex, JavaMethodList *lines, int lines_size) { + JavaMethodList subs = getBestSubstringsFromStringList(aStrRegex, lines, lines_size); + JavaMethodList ret = createJavaMethodList(); + + resetJavaMethodCursor(&subs); + while (true) { + JavaMethod *method = readJavaMethod(&subs); + if (method == NULL) { + break; + } + + char *method_name = extractStaticMethodName(method->name); + if (method_name != NULL) { + insertJavaMethod(&ret, createJavaMethod(method_name)); + free(method_name); + } + } + + freeJavaMethodList(&subs); + + return ret; +} + +bool isIgnoreMethod(char *method_name) { + const char * ignoreMethods[] = {"getInstance", "toString", NULL}; + + int i = 0; + while(true) { + const char *ign = ignoreMethods[i]; + if (ign == NULL) { + break; + } + + if (!strcmp(method_name, ign)) { + return true; + } + + i++; + } + + return false; +} + +JavaMethodList trackerFindSourceStaticMethods(JavaMethodList *lines, int lines_size) { + char *aStrRegex = "(public static\\s).*([A-Za-z0-9])+(\\s)*\\(.*\\{"; + JavaMethodList ret = createJavaMethodList(); + + JavaMethodList list = getStaticJavaMethodNames(aStrRegex, lines, lines_size); + resetJavaMethodCursor(&list); + while(true) { + JavaMethod *method = readJavaMethod(&list); + if (method == NULL) { + break; + } + + if (isIgnoreMethod(method->name)) { + continue; + } + + //printf("Java Method: %s\n", method->name); + insertJavaMethod(&ret, createJavaMethod(method->name)); + } + + freeJavaMethodList(&list); + + return ret; +} + +char *getContentFromFile(FILE *f) { + char str[10240]; + + char *content = (char *)malloc(SCRIPT_FILES_MAX_CONTENT_SIZE * sizeof(char)); + content[0] = 0; + + while (!feof(f)) { + fgets(str, 10240, f); + strcat(content, str); + } + + return content; +} + +bool locateMethodCall(const char *method_name, char *file_path) { + FILE *f = fopen(file_path, "r+t"); + + char aStrRegex[1000]; + strcpy(aStrRegex, method_name); + strcat(aStrRegex, "(\\s)*\\("); + + JavaMethodList *file_content = (JavaMethodList *)malloc(sizeof(JavaMethodList)); + file_content[0] = createJavaMethodList(); + + char *content = getContentFromFile(f); + + JavaMethod *method = createJavaMethod(content); + insertJavaMethod(&(file_content[0]), method); + free(content); + + JavaMethodList list = getBestSubstringsFromStringList(aStrRegex, file_content, 1); + bool found = (list.size > 0); + + free(file_content); + fclose(f); + + return found; +} + +void locateMethodCalls(const char *method_name, char **file_paths, int file_paths_size) { + int i; + for (i = 0; i < file_paths_size; i++) { + char *path = file_paths[i]; + if (locateMethodCall(method_name, path)) { + printf(" %s : \'%s\'\n", path, method_name); + } + } +} + +int trackerLocateScriptsStaticCalls(JavaMethodList method_names) { + ScriptFiles *files = createScriptFiles("../../HeavenMS/scripts"); + if (files == NULL) { + printf("ERROR: Could not initialize script files.\n"); + return -1; + } + + resetJavaMethodCursor(&method_names); + while (true) { + JavaMethod *method = readJavaMethod(&method_names); + if (method == NULL) { + break; + } + + locateMethodCalls(method->name, files->file_paths, files->file_paths_size); + } + + freeScriptFiles(files); + return 0; +} + +typedef struct { + JavaMethodList *file_content; + int size; +} SourceFilesContent; + +SourceFilesContent* readSourceFileContents() { + ScriptFiles *srcFilePaths = createScriptFiles("../../HeavenMS/src"); + + SourceFilesContent *files = (SourceFilesContent *)malloc(sizeof(SourceFilesContent)); + files->file_content = (JavaMethodList *)malloc(srcFilePaths->file_paths_size * sizeof(JavaMethodList)); + files->size = srcFilePaths->file_paths_size; + + //int max_len = 0; + int i; + for (i = 0; i < srcFilePaths->file_paths_size; i++) { + files->file_content[i] = createJavaMethodList(); + + FILE *f = fopen(srcFilePaths->file_paths[i], "r+t"); + char *content = getContentFromFile(f); + + //int this_len = strlen(content); + //if (max_len < this_len) max_len = this_len; + + fclose(f); + + insertJavaMethod(&(files->file_content[i]), createJavaMethod(content)); + } + + //printf("len: %d\n", max_len); + freeScriptFiles(srcFilePaths); + + return files; +} + +void freeSourceFileContents(SourceFilesContent *files) { + int i; + for (i = 0; i < files->size; i++) { + freeJavaMethodList(&(files->file_content[i])); + } + + free(files->file_content); + free(files); +} + +int main() { + printf("Loading source files...\n"); + SourceFilesContent *src_contents = readSourceFileContents(); + + int lines_size = src_contents->size; + JavaMethodList *lines = src_contents->file_content; + + printf("Tracking static methods on source...\n"); + JavaMethodList method_names = trackerFindSourceStaticMethods(lines, lines_size); + printf("Finding static methods calls on scripts...\n"); + trackerLocateScriptsStaticCalls(method_names); + printf("Track complete!\n"); + + freeSourceFileContents(src_contents); + freeJavaMethodList(&method_names); + + return 0; +} diff --git a/tools/ScriptStaticMethodTracker/pcre3.dll b/tools/ScriptStaticMethodTracker/pcre3.dll new file mode 100644 index 0000000000000000000000000000000000000000..b5fd2a63785922c9898e7d25d9c50ef47524ba13 GIT binary patch literal 140288 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 literal 0 HcmV?d00001 diff --git a/tools/ScriptStaticMethodTracker/script_path.c b/tools/ScriptStaticMethodTracker/script_path.c new file mode 100644 index 0000000000..aab9ddd1b8 --- /dev/null +++ b/tools/ScriptStaticMethodTracker/script_path.c @@ -0,0 +1,72 @@ +/* + 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 . +*/ + +#include +#include +#include +#include +#include + +void fetchScriptFilesFromDirectory(ScriptFiles *files, char *root_dir) { + struct dirent *de; + struct stat info; + DIR *dir = opendir(root_dir); + if (dir != NULL) { + de = readdir(dir); // skip . + de = readdir(dir); // skip .. + + while ((de = readdir(dir)) != NULL) { + char file_path[SCRIPT_FILES_MAX_PATH_SIZE]; + strcpy(file_path, root_dir); + strcat(file_path, "/"); + strcat(file_path, de->d_name); + + stat(file_path, &info); + if (S_ISREG(info.st_mode)) { + files->file_paths[files->file_paths_size] = (char *)malloc(SCRIPT_FILES_MAX_PATH_SIZE * sizeof(char)); + strcpy(files->file_paths[files->file_paths_size], file_path); + files->file_paths_size++; + } else { + fetchScriptFilesFromDirectory(files, file_path); + } + } + } +} + +ScriptFiles* createScriptFiles(char *root_dir) { + ScriptFiles *files = (ScriptFiles *)malloc(sizeof(ScriptFiles)); + + files->file_paths = (char **)malloc(SCRIPT_FILES_MAX_COUNT * sizeof(char *)); + files->file_paths_size = 0; + + fetchScriptFilesFromDirectory(files, root_dir); + + return files; +} + +void freeScriptFiles(ScriptFiles *files) { + int i; + for (i = 0; i < files->file_paths_size; i++) { + free(files->file_paths[i]); + } + + free(files->file_paths); + free(files); +} diff --git a/tools/ScriptStaticMethodTracker/script_path.h b/tools/ScriptStaticMethodTracker/script_path.h new file mode 100644 index 0000000000..553d28d260 --- /dev/null +++ b/tools/ScriptStaticMethodTracker/script_path.h @@ -0,0 +1,34 @@ +/* + 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 . +*/ + +#ifndef SCRIPT_PATH_H_ +#define SCRIPT_PATH_H_ + +#define SCRIPT_FILES_MAX_COUNT 20000 +#define SCRIPT_FILES_MAX_PATH_SIZE 1000 + +typedef struct { + char **file_paths; + int file_paths_size; +} ScriptFiles; + +#include "script_path.c" + +#endif /* SCRIPT_PATH_H_ */