diff --git a/config.yaml b/config.yaml
index c288ae3795..314d719972 100644
--- a/config.yaml
+++ b/config.yaml
@@ -174,11 +174,11 @@ server:
CHANNEL_LOAD: 100 #Max players per channel (limit actually used to calculate the World server capacity).
CHANNEL_LOCKS: 20 #Total number of structure management locks each channel has.
- RESPAWN_INTERVAL: 10000 #10 seconds, 10000.
- PURGING_INTERVAL: 300000 #5 minutes, 300000.
- RANKING_INTERVAL: 3600000 #60 minutes, 3600000.
- COUPON_INTERVAL: 3600000 #60 minutes, 3600000.
- UPDATE_INTERVAL: 777 #Dictates the frequency on which the "centralized server time" is updated.
+ RESPAWN_INTERVAL: 10000 #10 seconds, 10000.
+ PURGING_INTERVAL: 300000 #5 minutes, 300000.
+ RANKING_INTERVAL: 3600000 #60 minutes, 3600000.
+ COUPON_INTERVAL: 3600000 #60 minutes, 3600000.
+ UPDATE_INTERVAL: 777 #Dictates the frequency on which the "centralized server time" is updated.
ENABLE_PIC: false #Pick true/false to enable or disable Pic. Delete character requires PIC available.
ENABLE_PIN: false #Pick true/false to enable or disable Pin.
diff --git a/cores/jackson-annotations-2.9.9.jar b/cores/jackson-annotations-2.9.9.jar
deleted file mode 100644
index 8e059d9711..0000000000
Binary files a/cores/jackson-annotations-2.9.9.jar and /dev/null differ
diff --git a/cores/jackson-core-2.9.9.jar b/cores/jackson-core-2.9.9.jar
deleted file mode 100644
index 02bd446ddf..0000000000
Binary files a/cores/jackson-core-2.9.9.jar and /dev/null differ
diff --git a/cores/jackson-databind-2.9.9.3.jar b/cores/jackson-databind-2.9.9.3.jar
deleted file mode 100644
index 5bf4ba88d1..0000000000
Binary files a/cores/jackson-databind-2.9.9.3.jar and /dev/null differ
diff --git a/cores/jackson-dataformat-yaml-2.9.9.jar b/cores/jackson-dataformat-yaml-2.9.9.jar
deleted file mode 100644
index 36829fc6f9..0000000000
Binary files a/cores/jackson-dataformat-yaml-2.9.9.jar and /dev/null differ
diff --git a/cores/snakeyaml-1.25.jar b/cores/snakeyaml-1.25.jar
deleted file mode 100644
index 0004985059..0000000000
Binary files a/cores/snakeyaml-1.25.jar and /dev/null differ
diff --git a/cores/yamlbeans-1.13.jar b/cores/yamlbeans-1.13.jar
new file mode 100644
index 0000000000..45cac40fe9
Binary files /dev/null and b/cores/yamlbeans-1.13.jar differ
diff --git a/docs/mychanges_ptbr.txt b/docs/mychanges_ptbr.txt
index 09e8877a9d..22b9a22d82 100644
--- a/docs/mychanges_ptbr.txt
+++ b/docs/mychanges_ptbr.txt
@@ -2143,4 +2143,41 @@ Adicionado checagem no uso de autopots ao usar HP/MP, limites são calculados ba
20 Setembro 2019,
Adicionado update de macros ao usar SP reset.
Refatorado vários pacotes Java contendo classes diversificadas.
-Corrigido nomenclatura errônea de "worker" introduzida, querendo significar "task".
\ No newline at end of file
+Corrigido nomenclatura errônea de "worker" introduzida, querendo significar "task".
+
+21 - 24 Setembro 2019,
+Corrigido ferramenta detectora de métodos estáticos não realizando varredura completa em arquivos, parando em casos onde um método estático é encontrado em cada.
+Implementado ferramenta detectora de scripts de quest que estiveram sendo usados como paliativo.
+Refatorado amplamente métodos que lidam com atribuição de progresso de quests.
+Revisado uso de vários scripts de quest que estiveram sendo usados como paliativo.
+Alterado declaração de "MapleCharacter c", considerado ambíguo à de MapleClient.
+Revisado uso de progresso de quests feito pelos scripts, de forma a parear com o novo modelo.
+
+26 - 28 Setembro 2019,
+Corrigido casos no novo modelo onde algumas quests utilizando informações de progresso não conseguiriam ser completadas.
+Corrigido uso envio desnecessário de pacote ao atualizar progresso de quest causando popup inesperado de mensagens de quests para jogadores.
+Corrigido alguns scripts não levando a atualização dos endereços dos pacotes alterados na última refatoração.
+Corrigido script de quest de Magatia checando errado quantidade de livros adquiridos pelo jogador no progresso de quest.
+
+29 Setembro 2019,
+Revisado Raise UI, agora utilizando o novo sistema de progressão.
+Corrigido checagem por espaço no inventário, ao tentar ganhar itens via quest, não informando o jogador adequadamente sobre itens one-of-a-kind.
+Corrigido uso de itens na Raise UI, quando não atualizando progresso algum (nenhum pacote enviado ao jogador), não permitindo jogador acesso a certos recursos (como Cash Shop/MTS).
+Revisado aplicação geral do novo modelo de progressão de quests implementado.
+
+01 - 02 Outubro 2019,
+Corrigido caso de exceção de modificação concorrente dentro de módulo de incremento de progresso de mob em quests.
+Corrigido caixa de diálogo com conteúdo extra, ao terminar uma quest, não sendo enviada ao jogador.
+Corrigido retransmissão de pacotes de movimentos com sequência vazia crashando outros jogadores.
+Refatorado checagem por pacotes de movimentos com sequência vazia, agora atuando no módulo abstrato.
+Corrigido progresso de mobs em quests não atualizando o infoex devidamente ao jogador, levando à falta do balão de "quest completa".
+Corrigido quest de 1o job de Cygnus permitindo retornar para estado que tenta concluir quest, permitindo assim múltiplas instâncias de conclusão da mesma.
+Adicionado scripting atuante ao abrir Raise UI, permitindo assim utilizar ações elaboradas, tais como EXP de combate para Mimiana.
+Corrigido pets não sendo despawnados assim que se dá o tempo de expiração.
+Corrigido jogadores com "hide" controlando mobs em certas situações.
+Corrigido análise de alerta de HP/MP lado-servidor não contando com os atributos de HP/MP de equipamentos e buffs.
+
+03 Outubro 2019,
+Corrigido skill "Energy Charge" levando atualização de buff ao tocar em mobs, levando a casos onde o buff nos stats poderia inesperadamente ficar retido além do tempo de atuação previsto.
+Substituído utilização de "Jackson annotations + SnakeYaml" por "YamlBeans", utilizando-se assim menos artefatos JARs no processo (anteriormente 5, agora somente 1). Nota: na transição, fora constatado que a utilização da tecnologia anterior era mais permissiva perante o arquivo de configurações, porém estrutura do novo arquivo foi normalizado e está agora funcional.
+Refatorado inicialização de eventos ao iniciar o servidor, em busca de melhorar o tempo de startup.
\ No newline at end of file
diff --git a/nbproject/project.properties b/nbproject/project.properties
index 0f9bb87365..4188fc88d4 100644
--- a/nbproject/project.properties
+++ b/nbproject/project.properties
@@ -29,16 +29,12 @@ dist.javadoc.dir=${dist.dir}/javadoc
endorsed.classpath=
excludes=
file.reference.HikariCP-java7-2.4.13.jar=cores/HikariCP-java7-2.4.13.jar
-file.reference.jackson-annotations-2.9.9.jar=cores/jackson-annotations-2.9.9.jar
-file.reference.jackson-core-2.9.9.jar=cores/jackson-core-2.9.9.jar
-file.reference.jackson-databind-2.9.9.3.jar=cores/jackson-databind-2.9.9.3.jar
-file.reference.jackson-dataformat-yaml-2.9.9.jar=cores/jackson-dataformat-yaml-2.9.9.jar
file.reference.MapleSolaxia-src=src
file.reference.mina-core-2.0.19.jar=cores/mina-core-2.0.19.jar
file.reference.mysql-connector-java-bin.jar=cores/mysql-connector-java-bin.jar
file.reference.slf4j-api-1.7.21.jar=cores/slf4j-api-1.7.21.jar
file.reference.slf4j-jdk14-1.7.5.jar=cores/slf4j-jdk14-1.7.5.jar
-file.reference.snakeyaml-1.25.jar=cores/snakeyaml-1.25.jar
+file.reference.yamlbeans-1.13.jar=cores/yamlbeans-1.13.jar
includes=**
jar.archive.disabled=${jnlp.enabled}
jar.compress=true
@@ -49,11 +45,7 @@ javac.classpath=\
${file.reference.HikariCP-java7-2.4.13.jar}:\
${file.reference.mysql-connector-java-bin.jar}:\
${file.reference.slf4j-jdk14-1.7.5.jar}:\
- ${file.reference.jackson-annotations-2.9.9.jar}:\
- ${file.reference.jackson-core-2.9.9.jar}:\
- ${file.reference.jackson-databind-2.9.9.3.jar}:\
- ${file.reference.jackson-dataformat-yaml-2.9.9.jar}:\
- ${file.reference.snakeyaml-1.25.jar}
+ ${file.reference.yamlbeans-1.13.jar}
# Space-separated list of extra javac options
javac.compilerargs=
javac.deprecation=false
diff --git a/scripts/event/BalrogBattle.js b/scripts/event/BalrogBattle.js
index 499d793ec3..33c7422eab 100644
--- a/scripts/event/BalrogBattle.js
+++ b/scripts/event/BalrogBattle.js
@@ -244,8 +244,8 @@ function monsterKilled(mob, eim) {
eim.showClearEffect();
eim.clearPQ();
- eim.dispatchUpdateQuestMobCount(bossMobId, entryMap);
- eim.dispatchUpdateQuestMobCount(9101003, entryMap); // thanks Atoot for noticing quest not getting updated after boss kill
+ eim.dispatchRaiseQuestMobCount(bossMobId, entryMap);
+ eim.dispatchRaiseQuestMobCount(9101003, entryMap); // thanks Atoot for noticing quest not getting updated after boss kill
mob.getMap().broadcastBalrogVictory(eim.getLeader().getName());
} else {
if(count == 1) {
diff --git a/scripts/event/BalrogBattle_Easy.js b/scripts/event/BalrogBattle_Easy.js
index 031c31d859..a2b6c03f14 100644
--- a/scripts/event/BalrogBattle_Easy.js
+++ b/scripts/event/BalrogBattle_Easy.js
@@ -244,7 +244,7 @@ function monsterKilled(mob, eim) {
eim.showClearEffect();
eim.clearPQ();
- eim.dispatchUpdateQuestMobCount(bossMobId, entryMap);
+ eim.dispatchRaiseQuestMobCount(bossMobId, entryMap);
mob.getMap().broadcastBalrogVictory(eim.getLeader().getName());
} else {
if(count == 1) {
diff --git a/scripts/event/HorntailBattle.js b/scripts/event/HorntailBattle.js
index f31c2cdb06..433d236241 100644
--- a/scripts/event/HorntailBattle.js
+++ b/scripts/event/HorntailBattle.js
@@ -214,7 +214,7 @@ function monsterKilled(mob, eim) {
eim.showClearEffect(mob.getMap().getId());
eim.clearPQ();
- eim.dispatchUpdateQuestMobCount(8810018, 240060200);
+ eim.dispatchRaiseQuestMobCount(8810018, 240060200);
mob.getMap().broadcastHorntailVictory();
} else if(isHorntailHead(mob)) {
var killed = eim.getIntProperty("defeatedHead");
diff --git a/scripts/event/MK_PrimeMinister.js b/scripts/event/MK_PrimeMinister.js
index d29be7e5ed..0ef72ad21d 100644
--- a/scripts/event/MK_PrimeMinister.js
+++ b/scripts/event/MK_PrimeMinister.js
@@ -52,7 +52,7 @@ function primeMinisterCheck(eim) {
var pIter = map.getAllPlayers().iterator();
while (pIter.hasNext()) {
var player = pIter.next();
- if (player.getQuestStatus(2333) == 1 && player.getAbstractPlayerInteraction().getQuestProgress(2333, mobId) == 0) {
+ if (player.getQuestStatus(2333) == 1 && player.getAbstractPlayerInteraction().getQuestProgressInt(2333, mobId) == 0) {
return true;
}
}
diff --git a/scripts/map/onUserEnter/130030000.js b/scripts/map/onUserEnter/130030000.js
index 1d94337e2e..f789e5ab3b 100644
--- a/scripts/map/onUserEnter/130030000.js
+++ b/scripts/map/onUserEnter/130030000.js
@@ -21,5 +21,5 @@
*/
function start(ms) {
- ms.getPlayer().updateQuestInfo(20010, "1");
+ ms.setQuestProgress(20010, 20022, 1);
}
\ No newline at end of file
diff --git a/scripts/map/onUserEnter/130030001.js b/scripts/map/onUserEnter/130030001.js
index 1d94337e2e..f789e5ab3b 100644
--- a/scripts/map/onUserEnter/130030001.js
+++ b/scripts/map/onUserEnter/130030001.js
@@ -21,5 +21,5 @@
*/
function start(ms) {
- ms.getPlayer().updateQuestInfo(20010, "1");
+ ms.setQuestProgress(20010, 20022, 1);
}
\ No newline at end of file
diff --git a/scripts/map/onUserEnter/910510000.js b/scripts/map/onUserEnter/910510000.js
index c489ca085b..51e18daa4b 100644
--- a/scripts/map/onUserEnter/910510000.js
+++ b/scripts/map/onUserEnter/910510000.js
@@ -5,11 +5,11 @@ function start(ms){
var map = player.getMap();
if(player.isCygnus()) {
- if(ms.isQuestStarted(20730) && ms.getQuestProgress(20730, 9300285) == 0) {
+ if(ms.isQuestStarted(20730) && ms.getQuestProgressInt(20730, 9300285) == 0) {
map.spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(9300285), new java.awt.Point(680, 258));
}
} else {
- if(ms.isQuestStarted(21731) && ms.getQuestProgress(21731, 9300344) == 0) {
+ if(ms.isQuestStarted(21731) && ms.getQuestProgressInt(21731, 9300344) == 0) {
map.spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(9300344), new java.awt.Point(680, 258));
}
}
diff --git a/scripts/map/onUserEnter/914000100.js b/scripts/map/onUserEnter/914000100.js
index 6ec1755650..108f8c451c 100644
--- a/scripts/map/onUserEnter/914000100.js
+++ b/scripts/map/onUserEnter/914000100.js
@@ -21,5 +21,5 @@
*/
function start(ms) {
- ms.getPlayer().updateQuestInfo(21000, "1");
+ ms.setQuestProgress(21000, 21002, 1);
}
\ No newline at end of file
diff --git a/scripts/map/onUserEnter/925040100.js b/scripts/map/onUserEnter/925040100.js
index 14f9c3dce8..738b9c75ac 100644
--- a/scripts/map/onUserEnter/925040100.js
+++ b/scripts/map/onUserEnter/925040100.js
@@ -4,7 +4,7 @@ function start(ms){
var player = ms.getPlayer();
var map = player.getMap();
- if(ms.isQuestStarted(21747) && ms.getQuestProgress(21747, 9300351) == 0) {
+ if(ms.isQuestStarted(21747) && ms.getQuestProgressInt(21747, 9300351) == 0) {
map.spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(9300351), new java.awt.Point(897, 51));
}
}
\ No newline at end of file
diff --git a/scripts/npc/1012100.js b/scripts/npc/1012100.js
index abebcb671a..5d44d1e5f1 100644
--- a/scripts/npc/1012100.js
+++ b/scripts/npc/1012100.js
@@ -34,7 +34,7 @@ spawnPnpcFee = 7000000;
jobType = 3;
function start() {
- if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()))) {
+ if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()))) {
spawnPnpc = true;
var sendStr = "You have walked a long way to reach the power, wisdom and courage you hold today, haven't you? What do you say about having right now #ra NPC on the Hall of Fame holding the current image of your character#k? Do you like it?";
@@ -93,7 +93,7 @@ function action(mode, type, selection) {
return;
}
- if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
+ if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
cm.sendOk("There you go! Hope you will like it.");
cm.gainMeso(-spawnPnpcFee);
} else {
diff --git a/scripts/npc/1022000.js b/scripts/npc/1022000.js
index 4d4aaeae59..ccea9025d8 100644
--- a/scripts/npc/1022000.js
+++ b/scripts/npc/1022000.js
@@ -35,7 +35,7 @@ spawnPnpcFee = 7000000;
jobType = 1;
function start() {
- if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()))) {
+ if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()))) {
spawnPnpc = true;
var sendStr = "You have walked a long way to reach the power, wisdom and courage you hold today, haven't you? What do you say about having right now #ra NPC on the Hall of Fame holding the current image of your character#k? Do you like it?";
@@ -94,7 +94,7 @@ function action(mode, type, selection) {
return;
}
- if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
+ if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
cm.sendOk("There you go! Hope you will like it.");
cm.gainMeso(-spawnPnpcFee);
} else {
diff --git a/scripts/npc/1032001.js b/scripts/npc/1032001.js
index 98bb35d84a..c10656286c 100644
--- a/scripts/npc/1032001.js
+++ b/scripts/npc/1032001.js
@@ -35,7 +35,7 @@ spawnPnpcFee = 7000000;
jobType = 2;
function start() {
- if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()))) {
+ if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()))) {
spawnPnpc = true;
var sendStr = "You have walked a long way to reach the power, wisdom and courage you hold today, haven't you? What do you say about having right now #ra NPC on the Hall of Fame holding the current image of your character#k? Do you like it?";
@@ -94,7 +94,7 @@ function action(mode, type, selection) {
return;
}
- if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
+ if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
cm.sendOk("There you go! Hope you will like it.");
cm.gainMeso(-spawnPnpcFee);
} else {
diff --git a/scripts/npc/1052001.js b/scripts/npc/1052001.js
index a9ae74c161..9ab5b9f37d 100644
--- a/scripts/npc/1052001.js
+++ b/scripts/npc/1052001.js
@@ -34,7 +34,7 @@ spawnPnpcFee = 7000000;
jobType = 4;
function start() {
- if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()))) {
+ if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()))) {
spawnPnpc = true;
var sendStr = "You have walked a long way to reach the power, wisdom and courage you hold today, haven't you? What do you say about having right now #ra NPC on the Hall of Fame holding the current image of your character#k? Do you like it?";
@@ -95,7 +95,7 @@ function action(mode, type, selection) {
return;
}
- if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
+ if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
cm.sendOk("There you go! Hope you will like it.");
cm.gainMeso(-spawnPnpcFee);
} else {
diff --git a/scripts/npc/1063012.js b/scripts/npc/1063012.js
index 54b0167de3..282cc42fe0 100644
--- a/scripts/npc/1063012.js
+++ b/scripts/npc/1063012.js
@@ -22,11 +22,11 @@
var status = -1;
function activateShamanRock(slot,progress) {
- var active = (progress >> slot) % 2;
- if(!active) {
- progress |= (1 << slot);
+ var ch = progress[slot];
+ if(ch == '0') {
+ var nextProgress = progress.substr(0, slot) + '1' + progress.substr(slot + 1);
- cm.updateQuest(2236, progress);
+ cm.setQuestProgress(2236, nextProgress);
cm.gainItem(4032263, -1);
cm.sendOk("The seal took it's place, repelling the evil in the area.");
return 1;
@@ -45,7 +45,11 @@ function start() {
else if(map == 105070000) activateShamanRock(2,progress);
else if(map == 105090000) { // workaround... TWO SAME NPC ID ON SAME MAP
- if(!activateShamanRock(3,progress)) {
+ var npcOid = cm.getQuestProgressInt(2236, 1);
+ if (npcOid == 0) {
+ activateShamanRock(3,progress);
+ cm.setQuestProgress(2236, 1, cm.getNpcObjectId());
+ } else if (cm.getNpcObjectId() != npcOid) {
activateShamanRock(4,progress);
}
}
diff --git a/scripts/npc/1063013.js b/scripts/npc/1063013.js
index 54b0167de3..282cc42fe0 100644
--- a/scripts/npc/1063013.js
+++ b/scripts/npc/1063013.js
@@ -22,11 +22,11 @@
var status = -1;
function activateShamanRock(slot,progress) {
- var active = (progress >> slot) % 2;
- if(!active) {
- progress |= (1 << slot);
+ var ch = progress[slot];
+ if(ch == '0') {
+ var nextProgress = progress.substr(0, slot) + '1' + progress.substr(slot + 1);
- cm.updateQuest(2236, progress);
+ cm.setQuestProgress(2236, nextProgress);
cm.gainItem(4032263, -1);
cm.sendOk("The seal took it's place, repelling the evil in the area.");
return 1;
@@ -45,7 +45,11 @@ function start() {
else if(map == 105070000) activateShamanRock(2,progress);
else if(map == 105090000) { // workaround... TWO SAME NPC ID ON SAME MAP
- if(!activateShamanRock(3,progress)) {
+ var npcOid = cm.getQuestProgressInt(2236, 1);
+ if (npcOid == 0) {
+ activateShamanRock(3,progress);
+ cm.setQuestProgress(2236, 1, cm.getNpcObjectId());
+ } else if (cm.getNpcObjectId() != npcOid) {
activateShamanRock(4,progress);
}
}
diff --git a/scripts/npc/1090000.js b/scripts/npc/1090000.js
index a15d3b3a3d..2255ae3b3c 100644
--- a/scripts/npc/1090000.js
+++ b/scripts/npc/1090000.js
@@ -39,8 +39,7 @@ function start() {
if (cm.getEventInstance() != null) { // missing script for skill test found thanks to Lost(tm)
advQuest = 5; // string visibility thanks to iPunchEm & Glvelturall
cm.sendNext("Not bad at all. Let's discuss this outside!");
- cm.setQuestProgress(6330, 0, 1);
- } else if (cm.getQuestProgress(6330, 0) == 0) {
+ } else if (cm.getQuestProgressInt(6330, 6331) == 0) {
advQuest = 1;
cm.sendNext("You're ready, right? Now try to withstand my attacks for 2 minutes. I won't go easy on you. Good luck, because you will need it.");
} else {
@@ -54,8 +53,7 @@ function start() {
if (cm.getEventInstance() != null) {
advQuest = 6;
cm.sendNext("Not bad at all. Let's discuss this outside!");
- cm.setQuestProgress(6370, 0, 1);
- } else if (cm.getQuestProgress(6370, 0) == 0) {
+ } else if (cm.getQuestProgressInt(6370, 6371) == 0) {
advQuest = 2;
cm.sendNext("You're ready, right? Now try to withstand my attacks for 2 minutes. I won't go easy on you. Good luck, because you will need it.");
} else {
@@ -65,7 +63,7 @@ function start() {
cm.sendNext("Congratulations. You have managed to pass my test. I'll teach you a new skill called \"Battleship\".\r\n\r\n #s5221006# #b#q5221006##k");
}
- } else if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()))) {
+ } else if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()))) {
spawnPnpc = true;
var sendStr = "You have walked a long way to reach the power, wisdom and courage you hold today, haven't you? What do you say about having right now #ra NPC on the Hall of Fame holding the current image of your character#k? Do you like it?";
@@ -126,6 +124,12 @@ function action(mode, type, selection) {
cm.sendOk("Unlike most of the other skills you used as a Pirate, this one definitely is different. You can actually ride the 'Battleship' and attack enemies with it. Your DEF level will increase for the time you're on board, so that'll help you tremendously in combat situations. May you become the best Gunslinger out there...");
}
} else {
+ if (advQuest < 6) {
+ cm.setQuestProgress(6330, 6331, 2);
+ } else {
+ cm.setQuestProgress(6370, 6371, 2);
+ }
+
cm.warp(120000101);
}
@@ -138,7 +142,7 @@ function action(mode, type, selection) {
return;
}
- if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
+ if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
cm.sendOk("There you go! Hope you will like it.");
cm.gainMeso(-spawnPnpcFee);
} else {
diff --git a/scripts/npc/1092019.js b/scripts/npc/1092019.js
index f0152d9b94..ecc9910a71 100644
--- a/scripts/npc/1092019.js
+++ b/scripts/npc/1092019.js
@@ -64,7 +64,7 @@ function action(mode, type, selection) {
cm.sendOk("Who are you talking to me? If you're just bored, go bother somebody else.");
cm.dispose();
} else {
- seagullProgress = cm.getQuestProgress(6400, 0);
+ seagullProgress = cm.getQuestProgressInt(6400, 1);
if (seagullProgress == 0) {
seagullIdx = Math.floor(Math.random() * seagullQuestion.length);
@@ -90,7 +90,7 @@ function action(mode, type, selection) {
var answer = cm.getText();
if (answer == seagullAnswer[seagullIdx]) {
cm.sendNext("What! I can't believe how incredibly smart you are! Incredible! In the seagull world, that kind of intellingence would give you a Ph.D. and then some. You're really amazing... I can't believe it... I simply can't believe it!");
- cm.setQuestProgress(6400, 0, 1);
+ cm.setQuestProgress(6400, 1, 1);
cm.dispose();
} else {
cm.sendOk("Hmm, that's not quite how I recall it. Try again!");
@@ -99,9 +99,11 @@ function action(mode, type, selection) {
} else if (seagullProgress != 2) {
cm.sendNextPrev("Anyway, only one of 9 Barts is the real Bart. You know that Pirates are known for the strength of their friendships and camaraderie with their fellow pirates. If you're a true pirate, you should be able to find your own mate with ease. Alright then, I'll send you to the room where Bart is.");
} else {
- cm.gainExp(1000000);
- cm.teachSkill(5221003, 0, 10, -1);
- cm.forceCompleteQuest(6400);
+ //cm.gainExp(1000000);
+ //cm.teachSkill(5221003, 0, 10, -1);
+ //cm.forceCompleteQuest(6400);
+
+ cm.sendNextPrev("You have met all my challenges, and passed! Good job!");
cm.dispose();
}
} else if (status == 3) {
diff --git a/scripts/npc/1092090.js b/scripts/npc/1092090.js
index 2dac576325..6b1cde8950 100644
--- a/scripts/npc/1092090.js
+++ b/scripts/npc/1092090.js
@@ -21,7 +21,7 @@
*/
function start() {
- if(cm.getQuestProgress(2180, 0) == 1) {
+ if(cm.getQuestProgressInt(2180, 1) == 1) {
cm.sendNext("You have taken milk from this cow recently, check another cow.");
cm.dispose();
return;
@@ -32,19 +32,19 @@ function start() {
cm.gainItem(4031847, -1);
cm.gainItem(4031848, 1);
- cm.setQuestProgress(2180, 0, 1);
+ cm.setQuestProgress(2180, 1, 1);
} else if (cm.canHold(4031849, 1) && cm.haveItem(4031848)) {
cm.sendNext("Now filling up the bottle with milk. The bottle is now 2/3 full of milk.");
cm.gainItem(4031848, -1);
cm.gainItem(4031849, 1);
- cm.setQuestProgress(2180, 0, 1);
+ cm.setQuestProgress(2180, 1, 1);
} else if (cm.canHold(4031850) && cm.haveItem(4031849)) {
cm.sendNext("Now filling up the bottle with milk. The bottle is now completely full of milk.");
cm.gainItem(4031849, -1);
cm.gainItem(4031850, 1);
- cm.setQuestProgress(2180, 0, 1);
+ cm.setQuestProgress(2180, 1, 1);
} else {
cm.sendNext("Your inventory is full, and there's no room for a milk bottle.");
}
diff --git a/scripts/npc/1092091.js b/scripts/npc/1092091.js
index 5d5db97d54..ec40aff0a8 100644
--- a/scripts/npc/1092091.js
+++ b/scripts/npc/1092091.js
@@ -21,7 +21,7 @@
*/
function start() {
- if(cm.getQuestProgress(2180, 0) == 2) {
+ if(cm.getQuestProgressInt(2180, 1) == 2) {
cm.sendNext("You have taken milk from this cow recently, check another cow.");
cm.dispose();
return;
@@ -32,19 +32,19 @@ function start() {
cm.gainItem(4031847, -1);
cm.gainItem(4031848, 1);
- cm.setQuestProgress(2180, 0, 2);
+ cm.setQuestProgress(2180, 1, 2);
} else if(cm.canHold(4031849) && cm.haveItem(4031848)){
cm.sendNext("Now filling up the bottle with milk. The bottle is now 2/3 full of milk.");
cm.gainItem(4031848, -1);
cm.gainItem(4031849, 1);
- cm.setQuestProgress(2180, 0, 2);
+ cm.setQuestProgress(2180, 1, 2);
} else if(cm.canHold(4031850) && cm.haveItem(4031849)){
cm.sendNext("Now filling up the bottle with milk. The bottle is now completely full of milk.");
cm.gainItem(4031849, -1);
cm.gainItem(4031850, 1);
- cm.setQuestProgress(2180, 0, 2);
+ cm.setQuestProgress(2180, 1, 2);
} else {
cm.sendNext("Your inventory is full, and there's no room for a milk bottle.");
}
diff --git a/scripts/npc/1101001.js b/scripts/npc/1101001.js
index e08c21fb28..138d871853 100644
--- a/scripts/npc/1101001.js
+++ b/scripts/npc/1101001.js
@@ -3,7 +3,7 @@
Map(s): Erev
Description: 3rd job KoC Buff
*/
-importPackage(Packages.constants);
+importPackage(Packages.constants.game);
function start() {
if (cm.getPlayer().isCygnus() && GameConstants.getJobBranch(cm.getJob()) > 2) {
diff --git a/scripts/npc/1102003.js b/scripts/npc/1102003.js
index 0433223b51..cdeacbd9e7 100644
--- a/scripts/npc/1102003.js
+++ b/scripts/npc/1102003.js
@@ -31,7 +31,7 @@ var maxJobType = 15;
function start() {
var jobType = parseInt(cm.getJobId() / 100);
- if (jobType >= minJobType && jobType <= maxJobType && cm.canSpawnPlayerNpc(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()))) {
+ if (jobType >= minJobType && jobType <= maxJobType && cm.canSpawnPlayerNpc(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()))) {
spawnPnpc = true;
var sendStr = "You have walked a long way to reach the power, wisdom and courage you hold today, haven't you? What do you say about having right now #ra NPC on the Hall of Fame holding the current image of your character#k? Do you like it?";
@@ -62,7 +62,7 @@ function action(mode, type, selection) {
return;
}
- if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
+ if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
cm.sendOk("There you go! Hope you will like it.");
cm.gainMeso(-spawnPnpcFee);
} else {
diff --git a/scripts/npc/1104201.js b/scripts/npc/1104201.js
index 38b68df694..5a993b03bc 100644
--- a/scripts/npc/1104201.js
+++ b/scripts/npc/1104201.js
@@ -39,7 +39,7 @@ function action(mode, type, selection) {
status--;
if(status == 0) {
- if (!(cm.isQuestCompleted(20407) || cm.isQuestStarted(20407) && cm.getQuestProgress(20407, 9001010) != 0) && cm.getMap().countMonster(9001010) == 0 && cm.getMap().getNPCById(1104002) == null) {
+ if (!(cm.isQuestCompleted(20407) || cm.isQuestStarted(20407) && cm.getQuestProgressInt(20407, 9001010) != 0) && cm.getMap().countMonster(9001010) == 0 && cm.getMap().getNPCById(1104002) == null) {
cm.sendOk("... Hnngh... #b#h0##k, is that you...? #r#p1104002##k... She's already here... #b#h0##k, I'm truly sorry I can't help you right now in this state, just when a bigger threat appeared I could do nothing for my people.... Please I beg you, please defeat her, #b#h0##k!! ....");
cm.spawnNpc(1104002, new java.awt.Point(850, 0), cm.getMap());
} else {
diff --git a/scripts/npc/1202010.js b/scripts/npc/1202010.js
index da06e68e88..0978526cdf 100644
--- a/scripts/npc/1202010.js
+++ b/scripts/npc/1202010.js
@@ -5,7 +5,7 @@ var spawnPnpcFee = 7000000;
var jobType = 21;
function start() {
- if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()))) {
+ if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()))) {
spawnPnpc = true;
var sendStr = "You have walked a long way to reach the power, wisdom and courage you hold today, haven't you? What do you say about having right now #ra NPC on the Hall of Fame holding the current image of your character#k? Do you like it?";
@@ -36,7 +36,7 @@ function action(mode, type, selection) {
return;
}
- if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
+ if(Packages.server.life.MaplePlayerNPC.spawnPlayerNPC(Packages.constants.game.GameConstants.getHallOfFameMapid(cm.getJob()), cm.getPlayer())) {
cm.sendOk("There you go! Hope you will like it.");
cm.gainMeso(-spawnPnpcFee);
} else {
diff --git a/scripts/npc/1209000.js b/scripts/npc/1209000.js
index 29b94792ff..1856337261 100644
--- a/scripts/npc/1209000.js
+++ b/scripts/npc/1209000.js
@@ -46,7 +46,7 @@ function action(mode, type, selection) {
} else if (status == 2) {
cm.sendNext("The other heroes? They've left to fight the Black Mage. They're buying us time to escape. What? You want to fight with them? No! You can't! You're hurt. You must leave with us!");
} else if (status == 3) {
- cm.updateQuest(21002, "1");
+ //cm.setQuestProgress(21002, 1);
cm.showIntro("Effect/Direction1.img/aranTutorial/Trio");
cm.dispose();
}
diff --git a/scripts/npc/1300013.js b/scripts/npc/1300013.js
index 29bd5ec7c8..56a7be723b 100644
--- a/scripts/npc/1300013.js
+++ b/scripts/npc/1300013.js
@@ -62,7 +62,7 @@ function action(mode, type, selection){
}
}
} else {
- var questProgress = cm.getQuestProgress(2330, 3300005) + cm.getQuestProgress(2330, 3300006) + cm.getQuestProgress(2330, 3300007); //3 Yetis
+ var questProgress = cm.getQuestProgressInt(2330, 3300005) + cm.getQuestProgressInt(2330, 3300006) + cm.getQuestProgressInt(2330, 3300007); //3 Yetis
if (!(cm.isQuestStarted(2330) && questProgress < 3)) { // thanks Vcoc for finding an exploit with boss entry through NPC
cm.dispose();
return;
diff --git a/scripts/npc/2012027.js b/scripts/npc/2012027.js
index 7c43a161ba..84081ee49c 100644
--- a/scripts/npc/2012027.js
+++ b/scripts/npc/2012027.js
@@ -50,13 +50,13 @@ function action(mode, type, selection) {
cm.getMap().broadcastMessage(MaplePacketCreator.playSound("orbis/" + harpSounds[cm.getNpc() - 2012027]));
if(cm.isQuestStarted(3114)) {
- var idx = cm.getQuestProgress(3114, 7777);
+ var idx = -1 * cm.getQuestProgressInt(3114); // infoEx without infoNumber, must use one progress only, critical hit!
- if(idx != -1) {
+ if(idx > -1) {
var nextNote = harpSong[idx];
if(harpNote != nextNote) {
- cm.setQuestProgress(3114, 7777, 0);
+ cm.setQuestProgress(3114, 0);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/wrong_kor"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Failed"));
@@ -70,7 +70,7 @@ function action(mode, type, selection) {
if(idx == 45) { // finished lullaby
cm.message("Twinkle, twinkle, little star, how I wonder what you are.");
- cm.setQuestProgress(3114, 7777, -1);
+ cm.setQuestProgress(3114, 42);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/clear"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Clear"));
@@ -88,7 +88,7 @@ function action(mode, type, selection) {
}
}
- cm.setQuestProgress(3114, 7777, idx + 1);
+ cm.setQuestProgress(3114, -1 * (idx + 1));
}
}
}
diff --git a/scripts/npc/2012028.js b/scripts/npc/2012028.js
index 90e0006589..800c32ada3 100644
--- a/scripts/npc/2012028.js
+++ b/scripts/npc/2012028.js
@@ -50,13 +50,13 @@ function action(mode, type, selection) {
cm.getMap().broadcastMessage(MaplePacketCreator.playSound("orbis/" + harpSounds[cm.getNpc() - 2012027]));
if(cm.isQuestStarted(3114)) {
- var idx = cm.getQuestProgress(3114, 7777);
+ var idx = -1 * cm.getQuestProgressInt(3114);
- if(idx != -1) {
+ if(idx > -1) {
var nextNote = harpSong[idx];
if(harpNote != nextNote) {
- cm.setQuestProgress(3114, 7777, 0);
+ cm.setQuestProgress(3114, 0);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/wrong_kor"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Failed"));
@@ -70,7 +70,7 @@ function action(mode, type, selection) {
if(idx == 45) { // finished lullaby
cm.message("Twinkle, twinkle, little star, how I wonder what you are.");
- cm.setQuestProgress(3114, 7777, -1);
+ cm.setQuestProgress(3114, 42);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/clear"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Clear"));
@@ -88,7 +88,7 @@ function action(mode, type, selection) {
}
}
- cm.setQuestProgress(3114, 7777, idx + 1);
+ cm.setQuestProgress(3114, -1 * (idx + 1));
}
}
}
diff --git a/scripts/npc/2012029.js b/scripts/npc/2012029.js
index 41b10d0867..a21b84d4e7 100644
--- a/scripts/npc/2012029.js
+++ b/scripts/npc/2012029.js
@@ -50,13 +50,13 @@ function action(mode, type, selection) {
cm.getMap().broadcastMessage(MaplePacketCreator.playSound("orbis/" + harpSounds[cm.getNpc() - 2012027]));
if(cm.isQuestStarted(3114)) {
- var idx = cm.getQuestProgress(3114, 7777);
+ var idx = -1 * cm.getQuestProgressInt(3114);
- if(idx != -1) {
+ if(idx > -1) {
var nextNote = harpSong[idx];
if(harpNote != nextNote) {
- cm.setQuestProgress(3114, 7777, 0);
+ cm.setQuestProgress(3114, 0);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/wrong_kor"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Failed"));
@@ -70,7 +70,7 @@ function action(mode, type, selection) {
if(idx == 45) { // finished lullaby
cm.message("Twinkle, twinkle, little star, how I wonder what you are.");
- cm.setQuestProgress(3114, 7777, -1);
+ cm.setQuestProgress(3114, 42);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/clear"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Clear"));
@@ -88,7 +88,7 @@ function action(mode, type, selection) {
}
}
- cm.setQuestProgress(3114, 7777, idx + 1);
+ cm.setQuestProgress(3114, -1 * (idx + 1));
}
}
}
diff --git a/scripts/npc/2012030.js b/scripts/npc/2012030.js
index 3e9dfb80e9..e421c02582 100644
--- a/scripts/npc/2012030.js
+++ b/scripts/npc/2012030.js
@@ -50,13 +50,13 @@ function action(mode, type, selection) {
cm.getMap().broadcastMessage(MaplePacketCreator.playSound("orbis/" + harpSounds[cm.getNpc() - 2012027]));
if(cm.isQuestStarted(3114)) {
- var idx = cm.getQuestProgress(3114, 7777);
+ var idx = -1 * cm.getQuestProgressInt(3114);
- if(idx != -1) {
+ if(idx > -1) {
var nextNote = harpSong[idx];
if(harpNote != nextNote) {
- cm.setQuestProgress(3114, 7777, 0);
+ cm.setQuestProgress(3114, 0);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/wrong_kor"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Failed"));
@@ -70,7 +70,7 @@ function action(mode, type, selection) {
if(idx == 45) { // finished lullaby
cm.message("Twinkle, twinkle, little star, how I wonder what you are.");
- cm.setQuestProgress(3114, 7777, -1);
+ cm.setQuestProgress(3114, 42);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/clear"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Clear"));
@@ -88,7 +88,7 @@ function action(mode, type, selection) {
}
}
- cm.setQuestProgress(3114, 7777, idx + 1);
+ cm.setQuestProgress(3114, -1 * (idx + 1));
}
}
}
diff --git a/scripts/npc/2012031.js b/scripts/npc/2012031.js
index 4e8946e69a..6f30b9c151 100644
--- a/scripts/npc/2012031.js
+++ b/scripts/npc/2012031.js
@@ -50,13 +50,13 @@ function action(mode, type, selection) {
cm.getMap().broadcastMessage(MaplePacketCreator.playSound("orbis/" + harpSounds[cm.getNpc() - 2012027]));
if(cm.isQuestStarted(3114)) {
- var idx = cm.getQuestProgress(3114, 7777);
+ var idx = -1 * cm.getQuestProgressInt(3114);
- if(idx != -1) {
+ if(idx > -1) {
var nextNote = harpSong[idx];
if(harpNote != nextNote) {
- cm.setQuestProgress(3114, 7777, 0);
+ cm.setQuestProgress(3114, 0);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/wrong_kor"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Failed"));
@@ -70,7 +70,7 @@ function action(mode, type, selection) {
if(idx == 45) { // finished lullaby
cm.message("Twinkle, twinkle, little star, how I wonder what you are.");
- cm.setQuestProgress(3114, 7777, -1);
+ cm.setQuestProgress(3114, 42);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/clear"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Clear"));
@@ -88,7 +88,7 @@ function action(mode, type, selection) {
}
}
- cm.setQuestProgress(3114, 7777, idx + 1);
+ cm.setQuestProgress(3114, -1 * (idx + 1));
}
}
}
diff --git a/scripts/npc/2012032.js b/scripts/npc/2012032.js
index 949480f276..52e985a993 100644
--- a/scripts/npc/2012032.js
+++ b/scripts/npc/2012032.js
@@ -50,13 +50,13 @@ function action(mode, type, selection) {
cm.getMap().broadcastMessage(MaplePacketCreator.playSound("orbis/" + harpSounds[cm.getNpc() - 2012027]));
if(cm.isQuestStarted(3114)) {
- var idx = cm.getQuestProgress(3114, 7777);
+ var idx = -1 * cm.getQuestProgressInt(3114);
- if(idx != -1) {
+ if(idx > -1) {
var nextNote = harpSong[idx];
if(harpNote != nextNote) {
- cm.setQuestProgress(3114, 7777, 0);
+ cm.setQuestProgress(3114, 0);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/wrong_kor"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Failed"));
@@ -70,7 +70,7 @@ function action(mode, type, selection) {
if(idx == 45) { // finished lullaby
cm.message("Twinkle, twinkle, little star, how I wonder what you are.");
- cm.setQuestProgress(3114, 7777, -1);
+ cm.setQuestProgress(3114, 42);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/clear"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Clear"));
@@ -88,7 +88,7 @@ function action(mode, type, selection) {
}
}
- cm.setQuestProgress(3114, 7777, idx + 1);
+ cm.setQuestProgress(3114, -1 * (idx + 1));
}
}
}
diff --git a/scripts/npc/2012033.js b/scripts/npc/2012033.js
index 98c196d054..aa9ac0d73c 100644
--- a/scripts/npc/2012033.js
+++ b/scripts/npc/2012033.js
@@ -50,13 +50,13 @@ function action(mode, type, selection) {
cm.getMap().broadcastMessage(MaplePacketCreator.playSound("orbis/" + harpSounds[cm.getNpc() - 2012027]));
if(cm.isQuestStarted(3114)) {
- var idx = cm.getQuestProgress(3114, 7777);
+ var idx = -1 * cm.getQuestProgressInt(3114);
- if(idx != -1) {
+ if(idx > -1) {
var nextNote = harpSong[idx];
if(harpNote != nextNote) {
- cm.setQuestProgress(3114, 7777, 0);
+ cm.setQuestProgress(3114, 0);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/wrong_kor"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Failed"));
@@ -70,7 +70,7 @@ function action(mode, type, selection) {
if(idx == 45) { // finished lullaby
cm.message("Twinkle, twinkle, little star, how I wonder what you are.");
- cm.setQuestProgress(3114, 7777, -1);
+ cm.setQuestProgress(3114, 42);
cm.getPlayer().announce(MaplePacketCreator.showEffect("quest/party/clear"));
cm.getPlayer().announce(MaplePacketCreator.playSound("Party1/Clear"));
@@ -88,7 +88,7 @@ function action(mode, type, selection) {
}
}
- cm.setQuestProgress(3114, 7777, idx + 1);
+ cm.setQuestProgress(3114, -1 * (idx + 1));
}
}
}
diff --git a/scripts/npc/2050014.js b/scripts/npc/2050014.js
index 5a43f0112e..ea93a0b9f8 100644
--- a/scripts/npc/2050014.js
+++ b/scripts/npc/2050014.js
@@ -45,13 +45,13 @@ function action(mode, type, selection) {
if(cm.isQuestStarted(3421)) {
var meteoriteId = cm.getNpc() - 2050014;
- var progress = cm.getQuestProgress(3421, 0);
+ var progress = cm.getQuestProgressInt(3421, 1);
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
if (cm.canHold(4031117, 1)) {
progress |= (1 << meteoriteId);
cm.gainItem(4031117, 1);
- cm.setQuestProgress(3421, 0, progress);
+ cm.setQuestProgress(3421, 1, progress);
} else {
cm.getPlayer().dropMessage(1, "Have a ETC slot available for this item.");
}
diff --git a/scripts/npc/2050015.js b/scripts/npc/2050015.js
index 5a43f0112e..ea93a0b9f8 100644
--- a/scripts/npc/2050015.js
+++ b/scripts/npc/2050015.js
@@ -45,13 +45,13 @@ function action(mode, type, selection) {
if(cm.isQuestStarted(3421)) {
var meteoriteId = cm.getNpc() - 2050014;
- var progress = cm.getQuestProgress(3421, 0);
+ var progress = cm.getQuestProgressInt(3421, 1);
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
if (cm.canHold(4031117, 1)) {
progress |= (1 << meteoriteId);
cm.gainItem(4031117, 1);
- cm.setQuestProgress(3421, 0, progress);
+ cm.setQuestProgress(3421, 1, progress);
} else {
cm.getPlayer().dropMessage(1, "Have a ETC slot available for this item.");
}
diff --git a/scripts/npc/2050016.js b/scripts/npc/2050016.js
index 5a43f0112e..ea93a0b9f8 100644
--- a/scripts/npc/2050016.js
+++ b/scripts/npc/2050016.js
@@ -45,13 +45,13 @@ function action(mode, type, selection) {
if(cm.isQuestStarted(3421)) {
var meteoriteId = cm.getNpc() - 2050014;
- var progress = cm.getQuestProgress(3421, 0);
+ var progress = cm.getQuestProgressInt(3421, 1);
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
if (cm.canHold(4031117, 1)) {
progress |= (1 << meteoriteId);
cm.gainItem(4031117, 1);
- cm.setQuestProgress(3421, 0, progress);
+ cm.setQuestProgress(3421, 1, progress);
} else {
cm.getPlayer().dropMessage(1, "Have a ETC slot available for this item.");
}
diff --git a/scripts/npc/2050017.js b/scripts/npc/2050017.js
index 5a43f0112e..ea93a0b9f8 100644
--- a/scripts/npc/2050017.js
+++ b/scripts/npc/2050017.js
@@ -45,13 +45,13 @@ function action(mode, type, selection) {
if(cm.isQuestStarted(3421)) {
var meteoriteId = cm.getNpc() - 2050014;
- var progress = cm.getQuestProgress(3421, 0);
+ var progress = cm.getQuestProgressInt(3421, 1);
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
if (cm.canHold(4031117, 1)) {
progress |= (1 << meteoriteId);
cm.gainItem(4031117, 1);
- cm.setQuestProgress(3421, 0, progress);
+ cm.setQuestProgress(3421, 1, progress);
} else {
cm.getPlayer().dropMessage(1, "Have a ETC slot available for this item.");
}
diff --git a/scripts/npc/2050018.js b/scripts/npc/2050018.js
index 5a43f0112e..ea93a0b9f8 100644
--- a/scripts/npc/2050018.js
+++ b/scripts/npc/2050018.js
@@ -45,13 +45,13 @@ function action(mode, type, selection) {
if(cm.isQuestStarted(3421)) {
var meteoriteId = cm.getNpc() - 2050014;
- var progress = cm.getQuestProgress(3421, 0);
+ var progress = cm.getQuestProgressInt(3421, 1);
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
if (cm.canHold(4031117, 1)) {
progress |= (1 << meteoriteId);
cm.gainItem(4031117, 1);
- cm.setQuestProgress(3421, 0, progress);
+ cm.setQuestProgress(3421, 1, progress);
} else {
cm.getPlayer().dropMessage(1, "Have a ETC slot available for this item.");
}
diff --git a/scripts/npc/2050019.js b/scripts/npc/2050019.js
index 5a43f0112e..ea93a0b9f8 100644
--- a/scripts/npc/2050019.js
+++ b/scripts/npc/2050019.js
@@ -45,13 +45,13 @@ function action(mode, type, selection) {
if(cm.isQuestStarted(3421)) {
var meteoriteId = cm.getNpc() - 2050014;
- var progress = cm.getQuestProgress(3421, 0);
+ var progress = cm.getQuestProgressInt(3421, 1);
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
if (cm.canHold(4031117, 1)) {
progress |= (1 << meteoriteId);
cm.gainItem(4031117, 1);
- cm.setQuestProgress(3421, 0, progress);
+ cm.setQuestProgress(3421, 1, progress);
} else {
cm.getPlayer().dropMessage(1, "Have a ETC slot available for this item.");
}
diff --git a/scripts/npc/2071012.js b/scripts/npc/2071012.js
index c50775950a..c5d24d199a 100644
--- a/scripts/npc/2071012.js
+++ b/scripts/npc/2071012.js
@@ -23,7 +23,7 @@ function action(mode, type, selection) {
status--;
if(status == 0) {
- if(cm.getQuestProgress(23647, 0) != 0) {
+ if(cm.getQuestProgressInt(23647, 1) != 0) {
cm.dispose();
return;
}
@@ -39,7 +39,7 @@ function action(mode, type, selection) {
cm.sendNext("Teehehee~ That's your reward for taking it from me, serves you well.");
cm.gainItem(4031793, -1);
cm.gainFame(-5);
- cm.setQuestProgress(23647, 0, 1);
+ cm.setQuestProgress(23647, 1, 1);
cm.dispose();
}
diff --git a/scripts/npc/2081009.js b/scripts/npc/2081009.js
index 553e5a8596..d49ae9513a 100644
--- a/scripts/npc/2081009.js
+++ b/scripts/npc/2081009.js
@@ -36,7 +36,7 @@ function action(mode, type, selection) {
status++;
if(status == 0) {
- if(cm.isQuestStarted(6180)) {
+ if(cm.isQuestStarted(6180) && cm.getQuestProgressInt(6180, 9300096) < 200) {
cm.sendYesNo("Pay attention: during the time you stay inside the training ground make sure you #bhave equipped your #t1092041##k, it is of the utmost importance. Are you ready to proceed to the training area?");
}
@@ -47,10 +47,15 @@ function action(mode, type, selection) {
}
else if(status == 1) {
- cm.warp(924000001, 0);
- cm.sendOk("Have your shield equipped until the end of the quest, or else you will need to start all over again!");
-
- cm.resetQuestProgress(6180,9300096);
+ if (cm.getPlayer().haveItemEquipped(1092041)) {
+ cm.sendNext("Have your shield equipped until the end of the quest, or else you will need to start all over again!");
+ } else {
+ cm.sendOk("Please equip the #r#t1092041##k before entering the training ground.");
+ cm.dispose();
+ }
+ }
+ else {
+ cm.warp(924000001, 0);
cm.dispose();
}
}
diff --git a/scripts/npc/2091009.js b/scripts/npc/2091009.js
index 2e6a02cb6e..c72fb2ca9b 100644
--- a/scripts/npc/2091009.js
+++ b/scripts/npc/2091009.js
@@ -27,10 +27,10 @@ function action(mode, type, selection){
return;
}
if(cm.getText() == "Actions speak louder than words"){
- if(cm.isQuestStarted(21747) && cm.getQuestProgress(21747, 9300351) == 0)
+ if(cm.isQuestStarted(21747) && cm.getQuestProgressInt(21747, 9300351) == 0)
cm.warp(925040100, 0);
else
- cm.playerMessage(5, "Although you said the right answer, some mysterious forces is blocking the way in.");
+ cm.playerMessage(5, "Although you said the right answer, some mysterious forces are blocking the way in.");
cm.dispose();
}
diff --git a/scripts/npc/2101017.js b/scripts/npc/2101017.js
index 03318dabce..035e2e0b94 100644
--- a/scripts/npc/2101017.js
+++ b/scripts/npc/2101017.js
@@ -115,7 +115,7 @@ function action(mode, type, selection) {
status = 2;
}
}
- } else if (Packages.constants.GameConstants.isAriantColiseumArena(cm.getPlayer().getMapId())) {
+ } else if (Packages.constants.game.GameConstants.isAriantColiseumArena(cm.getPlayer().getMapId())) {
if (cm.getPlayer().getMapId() == 980010101) {
exped = MapleExpeditionType.ARIANT;
expedicao = cm.getExpedition(exped);
diff --git a/scripts/npc/2103000.js b/scripts/npc/2103000.js
index f64485569e..16cde87e59 100644
--- a/scripts/npc/2103000.js
+++ b/scripts/npc/2103000.js
@@ -40,9 +40,9 @@ function action(mode, type, selection) {
else
status--;
if (status == 0 && mode == 1) {
- if(cm.isQuestStarted(3900) && cm.getPlayer().getQuestInfo(3900) != 5) {
+ if(cm.isQuestStarted(3900) && cm.getQuestProgressInt(3900) != 5) {
cm.sendOk("#b(You drink the water from the oasis and feel refreshed.)", 2);
- cm.getPlayer().updateQuestInfo(3900, "5");
+ cm.setQuestProgress(3900, 5);
} else if(cm.isQuestCompleted(3938)) {
if(cm.canHold(2210005)) {
if(!cm.haveItem(2210005) && !isTigunMorphed(cm.getPlayer())) {
diff --git a/scripts/npc/2103003.js b/scripts/npc/2103003.js
index 9b8040167f..a5a382dfaa 100644
--- a/scripts/npc/2103003.js
+++ b/scripts/npc/2103003.js
@@ -43,11 +43,15 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3929)) {
- if(cm.getQuestProgress(3929, 0) != 1) {
- if(cm.haveItem(4031580)) {
- cm.gainItem(4031580, -1);
- cm.setQuestProgress(3929, 0, 1);
- }
+ var progress = cm.getQuestProgress(3929);
+ var slot = 0;
+
+ var ch = progress[slot];
+ if(ch == '2') {
+ var nextProgress = progress.substr(0, slot) + '3' + progress.substr(slot + 1);
+
+ cm.gainItem(4031580, -1);
+ cm.setQuestProgress(3929, nextProgress);
}
}
diff --git a/scripts/npc/2103004.js b/scripts/npc/2103004.js
index 5891f00078..f78baaaa7e 100644
--- a/scripts/npc/2103004.js
+++ b/scripts/npc/2103004.js
@@ -43,11 +43,15 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3929)) {
- if(cm.getQuestProgress(3929, 2) != 1) {
- if(cm.haveItem(4031580)) {
- cm.gainItem(4031580, -1);
- cm.setQuestProgress(3929, 2, 1);
- }
+ var progress = cm.getQuestProgress(3929);
+ var slot = 2;
+
+ var ch = progress[slot];
+ if(ch == '2') {
+ var nextProgress = progress.substr(0, slot) + '3' + progress.substr(slot + 1);
+
+ cm.gainItem(4031580, -1);
+ cm.setQuestProgress(3929, nextProgress);
}
}
diff --git a/scripts/npc/2103005.js b/scripts/npc/2103005.js
index 01dc956858..1f49150290 100644
--- a/scripts/npc/2103005.js
+++ b/scripts/npc/2103005.js
@@ -43,11 +43,15 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3929)) {
- if(cm.getQuestProgress(3929, 1) != 1) {
- if(cm.haveItem(4031580)) {
- cm.gainItem(4031580, -1);
- cm.setQuestProgress(3929, 1, 1);
- }
+ var progress = cm.getQuestProgress(3929);
+ var slot = 1;
+
+ var ch = progress[slot];
+ if(ch == '2') {
+ var nextProgress = progress.substr(0, slot) + '3' + progress.substr(slot + 1);
+
+ cm.gainItem(4031580, -1);
+ cm.setQuestProgress(3929, nextProgress);
}
}
diff --git a/scripts/npc/2103006.js b/scripts/npc/2103006.js
index a25d62b4ac..d3bddd3a85 100644
--- a/scripts/npc/2103006.js
+++ b/scripts/npc/2103006.js
@@ -43,11 +43,15 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3929)) {
- if(cm.getQuestProgress(3929, 3) != 1) {
- if(cm.haveItem(4031580)) {
- cm.gainItem(4031580, -1);
- cm.setQuestProgress(3929, 3, 1);
- }
+ var progress = cm.getQuestProgress(3929);
+ var slot = 3;
+
+ var ch = progress[slot];
+ if(ch == '2') {
+ var nextProgress = progress.substr(0, slot) + '3' + progress.substr(slot + 1);
+
+ cm.gainItem(4031580, -1);
+ cm.setQuestProgress(3929, nextProgress);
}
}
diff --git a/scripts/npc/2103009.js b/scripts/npc/2103009.js
index 12d3129e1a..c8f6c47787 100644
--- a/scripts/npc/2103009.js
+++ b/scripts/npc/2103009.js
@@ -43,11 +43,15 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3926)) {
- if(cm.getQuestProgress(3926, 0) != 1) {
- if(cm.haveItem(4031579)) {
- cm.gainItem(4031579, -1);
- cm.setQuestProgress(3926, 0, 1);
- }
+ var progress = cm.getQuestProgress(3926);
+ var slot = 0;
+
+ var ch = progress[slot];
+ if(ch == '2') {
+ var nextProgress = progress.substr(0, slot) + '3' + progress.substr(slot + 1);
+
+ cm.gainItem(4031579, -1);
+ cm.setQuestProgress(3926, nextProgress);
}
}
diff --git a/scripts/npc/2103010.js b/scripts/npc/2103010.js
index 80f599e5bd..9fff919dea 100644
--- a/scripts/npc/2103010.js
+++ b/scripts/npc/2103010.js
@@ -43,11 +43,15 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3926)) {
- if(cm.getQuestProgress(3926, 2) != 1) {
- if(cm.haveItem(4031579)) {
- cm.gainItem(4031579, -1);
- cm.setQuestProgress(3926, 2, 1);
- }
+ var progress = cm.getQuestProgress(3926);
+ var slot = 2;
+
+ var ch = progress[slot];
+ if(ch == '2') {
+ var nextProgress = progress.substr(0, slot) + '3' + progress.substr(slot + 1);
+
+ cm.gainItem(4031579, -1);
+ cm.setQuestProgress(3926, nextProgress);
}
}
diff --git a/scripts/npc/2103011.js b/scripts/npc/2103011.js
index fdbb1a86ee..9321a46dc6 100644
--- a/scripts/npc/2103011.js
+++ b/scripts/npc/2103011.js
@@ -43,11 +43,15 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3926)) {
- if(cm.getQuestProgress(3926, 1) != 1) {
- if(cm.haveItem(4031579)) {
- cm.gainItem(4031579, -1);
- cm.setQuestProgress(3926, 1, 1);
- }
+ var progress = cm.getQuestProgress(3926);
+ var slot = 1;
+
+ var ch = progress[slot];
+ if(ch == '2') {
+ var nextProgress = progress.substr(0, slot) + '3' + progress.substr(slot + 1);
+
+ cm.gainItem(4031579, -1);
+ cm.setQuestProgress(3926, nextProgress);
}
}
diff --git a/scripts/npc/2103012.js b/scripts/npc/2103012.js
index 13a9f0bc9d..a4f3b17617 100644
--- a/scripts/npc/2103012.js
+++ b/scripts/npc/2103012.js
@@ -43,11 +43,15 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3926)) {
- if(cm.getQuestProgress(3926, 3) != 1) {
- if(cm.haveItem(4031579)) {
- cm.gainItem(4031579, -1);
- cm.setQuestProgress(3926, 3, 1);
- }
+ var progress = cm.getQuestProgress(3926);
+ var slot = 3;
+
+ var ch = progress[slot];
+ if(ch == '2') {
+ var nextProgress = progress.substr(0, slot) + '3' + progress.substr(slot + 1);
+
+ cm.gainItem(4031579, -1);
+ cm.setQuestProgress(3926, nextProgress);
}
}
diff --git a/scripts/npc/2103013.js b/scripts/npc/2103013.js
index 78f339dc10..9eddad86c0 100644
--- a/scripts/npc/2103013.js
+++ b/scripts/npc/2103013.js
@@ -66,7 +66,7 @@ function action(mode, type, selection) {
} else if (selection == 4) {
cm.sendNext("Inside Pharaoh Yeti's Tomb, you can acquire a #e#b#t2022613##k#n by proving yourself capable of defeating the #bPharaoh Jr. Yeti#k, the Pharaoh's clone. Inside that box lies a very special treasure. It is the #e#b#t1132012##k#n.\r\n#i1132012:# #t1132012#\r\n\r\n And if you are somehow able to survive Hell Mode, you will receive the #e#b#t1132013##k#n.\r\n\r\n#i1132013:# #t1132013#\r\n\r\n Though, of course, Nett won't allow that to happen.");
} else if (selection == 5) {
- var progress = cm.getQuestProgress(29932);
+ var progress = cm.getQuestProgressInt(29932);
if (progress >= 50000)
cm.dispose();
else
diff --git a/scripts/npc/2111011.js b/scripts/npc/2111011.js
new file mode 100644
index 0000000000..8b8b43f8de
--- /dev/null
+++ b/scripts/npc/2111011.js
@@ -0,0 +1,25 @@
+var status;
+
+function start() {
+ status = -1;
+ action(1, 0, 0);
+}
+
+function action(mode, type, selection) {
+ if (mode == -1) {
+ cm.dispose();
+ } else {
+ if (mode == 0 && type > 0) {
+ cm.dispose();
+ return;
+ }
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if(status == 0) {
+ cm.dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/scripts/npc/2111012.js b/scripts/npc/2111012.js
new file mode 100644
index 0000000000..8b8b43f8de
--- /dev/null
+++ b/scripts/npc/2111012.js
@@ -0,0 +1,25 @@
+var status;
+
+function start() {
+ status = -1;
+ action(1, 0, 0);
+}
+
+function action(mode, type, selection) {
+ if (mode == -1) {
+ cm.dispose();
+ } else {
+ if (mode == 0 && type > 0) {
+ cm.dispose();
+ return;
+ }
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if(status == 0) {
+ cm.dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/scripts/npc/2111013.js b/scripts/npc/2111013.js
index 3d897e4788..ab3289b9ff 100644
--- a/scripts/npc/2111013.js
+++ b/scripts/npc/2111013.js
@@ -40,7 +40,17 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3311)) {
- cm.setQuestProgress(3311, 0, 1);
+ var slot = 2;
+ var progress = cm.getQuestProgressInt(3311);
+
+ if (progress == 4) {
+ progress = 7;
+ } else {
+ progress = 5;
+ }
+
+ cm.setQuestProgress(3311, progress);
+
cm.sendOk("This is a mug picture of Dr. De Lang. It seems he is adorning a locket with the emblem of the Alcadno academy, he is a retainer of the Alcadno society.", 2);
}
diff --git a/scripts/npc/2111014.js b/scripts/npc/2111014.js
index 503554188a..cadbec00ea 100644
--- a/scripts/npc/2111014.js
+++ b/scripts/npc/2111014.js
@@ -40,7 +40,17 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3311)) {
- cm.setQuestProgress(3311, 1, 1);
+ var slot = 0;
+ var progress = cm.getQuestProgressInt(3311);
+
+ if (progress == 4) {
+ progress = 7;
+ } else {
+ progress = 5;
+ }
+
+ cm.setQuestProgress(3311, progress);
+
cm.sendOk("The diary of Dr. De Lang. A lot of formulas and pompous scientific texts can be found all way through the pages, but it is worth noting that in the last entry (3 weeks ago), it is written that he concluded the researches on an improvement on the blueprints for the Neo Huroids, thus making the last preparations to show it to the 'society'... No words after this...", 2);
} else if(cm.isQuestStarted(3322) && !cm.haveItem(4031697, 1)) {
if(cm.canHold(4031697, 1))
diff --git a/scripts/npc/2111016.js b/scripts/npc/2111016.js
new file mode 100644
index 0000000000..8b8b43f8de
--- /dev/null
+++ b/scripts/npc/2111016.js
@@ -0,0 +1,25 @@
+var status;
+
+function start() {
+ status = -1;
+ action(1, 0, 0);
+}
+
+function action(mode, type, selection) {
+ if (mode == -1) {
+ cm.dispose();
+ } else {
+ if (mode == 0 && type > 0) {
+ cm.dispose();
+ return;
+ }
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if(status == 0) {
+ cm.dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/scripts/npc/2111017.js b/scripts/npc/2111017.js
index f5ac4961fd..26b4ef159a 100644
--- a/scripts/npc/2111017.js
+++ b/scripts/npc/2111017.js
@@ -40,15 +40,15 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3339)) {
- var progress = cm.getQuestProgress(3339, 0);
+ var progress = cm.getQuestProgressInt(23339, 1);
if(progress == 3) {
cm.sendGetText("The pipe reacts as the water starts flowing. A secret compartment with a keypad shows up. #bPassword#k!");
} else if(progress == 0) {
- cm.setQuestProgress(3339, 0, 1);
+ cm.setQuestProgress(23339, 1, 1);
cm.dispose();
} else if(progress < 3) {
- cm.setQuestProgress(3339, 0, 0);
+ cm.setQuestProgress(23339, 1, 0);
cm.dispose();
} else {
cm.warp(261000001, 1);
@@ -63,7 +63,7 @@ function action(mode, type, selection) {
}
} else if(status == 1) {
if(cm.getText() == "my love Phyllia") {
- cm.setQuestProgress(3339, 0, 4);
+ cm.setQuestProgress(23339, 1, 4);
cm.warp(261000001, 1);
cm.dispose();
}
diff --git a/scripts/npc/2111018.js b/scripts/npc/2111018.js
index baf03db33d..7bd135dd29 100644
--- a/scripts/npc/2111018.js
+++ b/scripts/npc/2111018.js
@@ -40,15 +40,15 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3339)) {
- var progress = cm.getQuestProgress(3339, 0);
+ var progress = cm.getQuestProgressInt(23339, 1);
if(progress == 3) {
cm.sendGetText("The pipe reacts as the water starts flowing. A secret compartment with a keypad shows up. #bPassword#k!");
} else if(progress == 2) {
- cm.setQuestProgress(3339, 0, 3);
+ cm.setQuestProgress(23339, 1, 3);
cm.sendGetText("The pipe reacts as the water starts flowing. A secret compartment with a keypad shows up. #bPassword#k!");
} else if(progress < 3) {
- cm.setQuestProgress(3339, 0, 0);
+ cm.setQuestProgress(23339, 1, 0);
cm.dispose();
} else {
cm.warp(261000001, 1);
@@ -63,7 +63,7 @@ function action(mode, type, selection) {
}
} else if(status == 1) {
if(cm.getText() == "my love Phyllia") {
- cm.setQuestProgress(3339, 0, 4);
+ cm.setQuestProgress(23339, 1, 4);
cm.warp(261000001, 1);
cm.dispose();
}
diff --git a/scripts/npc/2111019.js b/scripts/npc/2111019.js
index 71da66886d..fbceccde4c 100644
--- a/scripts/npc/2111019.js
+++ b/scripts/npc/2111019.js
@@ -40,15 +40,15 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3339)) {
- var progress = cm.getQuestProgress(3339, 0);
+ var progress = cm.getQuestProgressInt(23339, 1);
if(progress == 3) {
cm.sendGetText("The pipe reacts as the water starts flowing. A secret compartment with a keypad shows up. #bPassword#k!");
} else if(progress == 1) {
- cm.setQuestProgress(3339, 0, 2);
+ cm.setQuestProgress(23339, 1, 2);
cm.dispose();
} else if(progress < 3) {
- cm.setQuestProgress(3339, 0, 0);
+ cm.setQuestProgress(23339, 1, 0);
cm.dispose();
} else {
cm.warp(261000001, 1);
@@ -63,7 +63,7 @@ function action(mode, type, selection) {
}
} else if(status == 1) {
if(cm.getText() == "my love Phyllia") {
- cm.setQuestProgress(3339, 0, 4);
+ cm.setQuestProgress(23339, 1, 4);
cm.warp(261000001, 1);
cm.dispose();
}
diff --git a/scripts/npc/2111020.js b/scripts/npc/2111020.js
index f9f07e7b09..1695c57816 100644
--- a/scripts/npc/2111020.js
+++ b/scripts/npc/2111020.js
@@ -40,13 +40,13 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3345)) {
- var progress = cm.getQuestProgress(3345, 0);
+ var progress = cm.getQuestProgressInt(3345);
if(progress == 0) {
- cm.setQuestProgress(3345, 0, 1);
+ cm.setQuestProgress(3345, 1);
cm.dispose();
} else if(progress < 4) {
- cm.setQuestProgress(3345, 0, 0);
+ cm.setQuestProgress(3345, 0);
cm.dispose();
} else {
cm.dispose();
diff --git a/scripts/npc/2111021.js b/scripts/npc/2111021.js
index 7b8336eb75..897ab66950 100644
--- a/scripts/npc/2111021.js
+++ b/scripts/npc/2111021.js
@@ -40,13 +40,13 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3345)) {
- var progress = cm.getQuestProgress(3345, 0);
+ var progress = cm.getQuestProgressInt(3345);
if(progress == 1) {
- cm.setQuestProgress(3345, 0, 2);
+ cm.setQuestProgress(3345, 2);
cm.dispose();
} else if(progress < 4) {
- cm.setQuestProgress(3345, 0, 0);
+ cm.setQuestProgress(3345, 0);
cm.dispose();
} else {
cm.dispose();
diff --git a/scripts/npc/2111022.js b/scripts/npc/2111022.js
index a6cca05dc7..2984e6b756 100644
--- a/scripts/npc/2111022.js
+++ b/scripts/npc/2111022.js
@@ -40,13 +40,13 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3345)) {
- var progress = cm.getQuestProgress(3345, 0);
+ var progress = cm.getQuestProgressInt(3345);
if(progress == 2) {
- cm.setQuestProgress(3345, 0, 3);
+ cm.setQuestProgress(3345, 3);
cm.dispose();
} else if(progress < 4) {
- cm.setQuestProgress(3345, 0, 0);
+ cm.setQuestProgress(3345, 0);
cm.dispose();
} else {
cm.dispose();
diff --git a/scripts/npc/2111023.js b/scripts/npc/2111023.js
index 0ea72a461e..6daefb0316 100644
--- a/scripts/npc/2111023.js
+++ b/scripts/npc/2111023.js
@@ -40,10 +40,10 @@ function action(mode, type, selection) {
if(status == 0) {
if(cm.isQuestStarted(3345)) {
- var progress = cm.getQuestProgress(3345, 0);
+ var progress = cm.getQuestProgressInt(3345);
if(progress == 3 && cm.haveItem(4031739, 1) && cm.haveItem(4031740, 1) && cm.haveItem(4031741, 1)) {
- cm.setQuestProgress(3345, 0, 4);
+ cm.setQuestProgress(3345, 4);
cm.gainItem(4031739, -1);
cm.gainItem(4031740, -1);
cm.gainItem(4031741, -1);
@@ -51,7 +51,7 @@ function action(mode, type, selection) {
cm.sendOk("(As you place the shards a light shines over the circle, repelling whatever omens were brewing inside the artifact.)", 2);
cm.dispose();
} else if(progress < 4) {
- cm.setQuestProgress(3345, 0, 0);
+ cm.setQuestProgress(3345, 0);
cm.dispose();
} else {
cm.dispose();
diff --git a/scripts/npc/2112016.js b/scripts/npc/2112016.js
index d0f7d16d83..3106645572 100644
--- a/scripts/npc/2112016.js
+++ b/scripts/npc/2112016.js
@@ -26,15 +26,15 @@
function start() {
if(cm.isQuestStarted(3367)) {
- var c = cm.getQuestProgress(3367, 30);
- if(c == 30) {
+ var c = cm.getQuestProgressInt(3367, 30);
+ if(c >= 30) {
cm.sendNext("(All files have been organized. Report the found files to Yulete.)", 2);
cm.dispose();
return;
}
var book = (cm.getNpcObjectId() % 30);
- var prog = cm.getQuestProgress(3367, book);
+ var prog = cm.getQuestProgressInt(3367, book);
if(prog == 0) {
c++;
@@ -45,7 +45,7 @@ function start() {
return;
} else {
cm.gainItem(4031797, 1);
- cm.setQuestProgress(3367, 31, cm.getQuestProgress(3367, 31) + 1);
+ cm.setQuestProgress(3367, 31, cm.getQuestProgressInt(3367, 31) + 1);
}
}
diff --git a/scripts/npc/9201003.js b/scripts/npc/9201003.js
index af2a3c6ecb..2f30233c03 100644
--- a/scripts/npc/9201003.js
+++ b/scripts/npc/9201003.js
@@ -63,7 +63,7 @@ function action(mode, type, selection) {
cm.sendOk("Hello we're Mom and Dad...");
cm.dispose();
} else {
- if (cm.getQuestProgress(100400, 1) == 0) {
+ if (cm.getQuestProgressInt(100400, 1) == 0) {
cm.sendNext("Mom, dad, I have a request to do to both of you... I wanna know more about the path you've already been walking since always, the path of loving and caring for someone dear to me.", 2);
} else {
if(!hasProofOfLoves(cm.getPlayer())) {
diff --git a/scripts/npc/9977777.js b/scripts/npc/9977777.js
index 5654952e9f..6990389bcd 100644
--- a/scripts/npc/9977777.js
+++ b/scripts/npc/9977777.js
@@ -77,6 +77,7 @@ function writeFeatureTab_Quests() {
addFeature("3rd job quiz with all 40-question pool available.");
addFeature("Item raising functional.");
addFeature("Cleared issue with player movement during NPC talk.");
+ addFeature("Reviewed usage of quest progress data as requirement.");
}
function writeFeatureTab_PlayerSocialNetwork() {
diff --git a/scripts/npc/MagatiaPassword.js b/scripts/npc/MagatiaPassword.js
index a6bd7bf9d4..eaab5b7a19 100644
--- a/scripts/npc/MagatiaPassword.js
+++ b/scripts/npc/MagatiaPassword.js
@@ -19,9 +19,10 @@ function action(mode, type, selection){
cm.sendGetText("The door reacts to the entry pass inserted. #bPassword#k!");
}
else if(status == 1){
- if(cm.getText() == cm.getStringQuestProgress(3360, 0)){
- cm.setQuestProgress(3360, 1, 1);
- cm.warp((cm.getMapId() == 261010000) ? 261020200 : 261010000, "secret00");
+ if(cm.getText() == cm.getQuestProgress(3360)){
+ cm.setQuestProgress(3360, 1);
+ cm.getPlayer().announce(Packages.tools.MaplePacketCreator.playPortalSound());
+ cm.warp(261030000, "sp_" + ((cm.getMapId() == 261010000) ? "jenu" : "alca"));
}
else {
cm.sendOk("#rWrong!");
diff --git a/scripts/npc/PupeteerPassword.js b/scripts/npc/PupeteerPassword.js
index 462f8157fb..8d3ca92136 100644
--- a/scripts/npc/PupeteerPassword.js
+++ b/scripts/npc/PupeteerPassword.js
@@ -20,7 +20,7 @@ function action(mode, type, selection){
if(status == 0){
if(cm.isQuestStarted(21728)) {
cm.sendOk("You search for any hints of the Puppeteer, but it seems a powerful force blocks the path... Better return to #b#p1061019##k.");
- cm.setQuestProgress(21728, 0, 1);
+ cm.setQuestProgress(21728, 21761, 0);
cm.dispose();
return;
}
@@ -29,12 +29,12 @@ function action(mode, type, selection){
}
else if(status == 1){
if(cm.getText() == "Francis is a genius Puppeteer!"){
- if(cm.isQuestStarted(20730) && cm.getQuestProgress(20730, 9300285) == 0)
+ if(cm.isQuestStarted(20730) && cm.getQuestProgressInt(20730, 9300285) == 0)
cm.warp(910510001, 1);
- else if(cm.isQuestStarted(21731) && cm.getQuestProgress(21731, 9300346) == 0)
+ else if(cm.isQuestStarted(21731) && cm.getQuestProgressInt(21731, 9300346) == 0)
cm.warp(910510001, 1);
else
- cm.playerMessage(5, "Although you said the right answer, some mysterious forces is blocking the way in.");
+ cm.playerMessage(5, "Although you said the right answer, some mysterious forces are blocking the way in.");
cm.dispose();
}
diff --git a/scripts/npc/cpqchallenge.js b/scripts/npc/cpqchallenge.js
index 1be873d469..c55c990717 100644
--- a/scripts/npc/cpqchallenge.js
+++ b/scripts/npc/cpqchallenge.js
@@ -5,7 +5,7 @@
---------------------------------------------------------------------------------------------------
**/
-importPackage(Packages.constants);
+importPackage(Packages.constants.game);
var status = 0;
var party;
diff --git a/scripts/npc/cpqchallenge2.js b/scripts/npc/cpqchallenge2.js
index 1be873d469..c55c990717 100644
--- a/scripts/npc/cpqchallenge2.js
+++ b/scripts/npc/cpqchallenge2.js
@@ -5,7 +5,7 @@
---------------------------------------------------------------------------------------------------
**/
-importPackage(Packages.constants);
+importPackage(Packages.constants.game);
var status = 0;
var party;
diff --git a/scripts/npc/credits.js b/scripts/npc/credits.js
index d5ea8e323f..29db73a8fc 100644
--- a/scripts/npc/credits.js
+++ b/scripts/npc/credits.js
@@ -93,6 +93,9 @@ function writeServerStaff_OdinMS() {
}
function writeServerStaff_Contributors() {
+ addPerson("IxianMace", "Contributor");
+ addPerson("Conrad", "Contributor");
+ addPerson("inhyuk", "Contributor");
addPerson("Jayd", "Contributor");
addPerson("Dragohe4rt", "Contributor");
addPerson("Jvlaple", "Contributor");
diff --git a/scripts/npc/rank_user.js b/scripts/npc/rank_user.js
index 323702e518..f958748535 100644
--- a/scripts/npc/rank_user.js
+++ b/scripts/npc/rank_user.js
@@ -21,7 +21,7 @@
* @Author Ronan
* Player NPC Ranking System */
-importPackage(Packages.constants);
+importPackage(Packages.constants.game);
var status;
diff --git a/scripts/portal/TD_MC_enterboss1.js b/scripts/portal/TD_MC_enterboss1.js
index 0718c1730a..260a8cb2b4 100644
--- a/scripts/portal/TD_MC_enterboss1.js
+++ b/scripts/portal/TD_MC_enterboss1.js
@@ -1,5 +1,5 @@
function enter(pi) {
- var questProgress = pi.getQuestProgress(2330, 3300005) + pi.getQuestProgress(2330, 3300006) + pi.getQuestProgress(2330, 3300007); //3 Yetis
+ var questProgress = pi.getQuestProgressInt(2330, 3300005) + pi.getQuestProgressInt(2330, 3300006) + pi.getQuestProgressInt(2330, 3300007); //3 Yetis
if(pi.isQuestStarted(2330) && questProgress < 3){
pi.openNpc(1300013);
diff --git a/scripts/portal/TD_neo_inTree.js b/scripts/portal/TD_neo_inTree.js
index 382fab3263..0ee32c0ac8 100644
--- a/scripts/portal/TD_neo_inTree.js
+++ b/scripts/portal/TD_neo_inTree.js
@@ -10,7 +10,7 @@ function enter(pi) {
for(var i = 0; i < quests.length; i++) {
if (pi.isQuestActive(quests[i])) {
- if(pi.getQuestProgress(quests[i], mobs[i]) != 0) {
+ if(pi.getQuestProgressInt(quests[i], mobs[i]) != 0) {
pi.message("You already faced Nex. Complete your mission.");
return false;
}
diff --git a/scripts/portal/enterInfo.js b/scripts/portal/enterInfo.js
index 02a1b45dec..466f53f0cd 100644
--- a/scripts/portal/enterInfo.js
+++ b/scripts/portal/enterInfo.js
@@ -1,7 +1,8 @@
function enter(pi) {
var mapobj = pi.getWarpMap(104000004);
- if(pi.isQuestActive(21733) && pi.getQuestProgress(21733, 9300345) == 0 && mapobj.countMonsters() == 0) {
+ if(pi.isQuestActive(21733) && pi.getQuestProgressInt(21733, 9300345) == 0 && mapobj.countMonsters() == 0) {
mapobj.spawnMonsterOnGroundBelow(Packages.server.life.MapleLifeFactory.getMonster(9300345), new java.awt.Point(0, 0));
+ pi.setQuestProgress(21733, 21762, 2);
}
pi.playPortalSound();
diff --git a/scripts/portal/enterMCave.js b/scripts/portal/enterMCave.js
index dc2052f0e5..e121cc1b5f 100644
--- a/scripts/portal/enterMCave.js
+++ b/scripts/portal/enterMCave.js
@@ -9,8 +9,7 @@ function enter(pi) {
pi.playPortalSound();
pi.warp(i, "out00");
- pi.getPlayer().updateQuestInfo(21202, "0");
- //pi.getPlayer().announce(Packages.tools.MaplePacketCreator.questProgress(21203, "21203"));
+ pi.setQuestProgress(21202, 21203, 0);
return true;
}
pi.message("The mirror is blank due to many players recalling their memories. Please wait and try again.");
@@ -24,7 +23,7 @@ function enter(pi) {
spawnMob(-210, 454, 9001013, map);
pi.playPortalSound();
- pi.getPlayer().updateQuestInfo(21203, "1");
+ pi.setQuestProgress(21303, 21203, 1);
pi.warp(108010701, "out00");
return true;
}
diff --git a/scripts/portal/enterPort.js b/scripts/portal/enterPort.js
index 58147bee61..e79056d85c 100644
--- a/scripts/portal/enterPort.js
+++ b/scripts/portal/enterPort.js
@@ -22,7 +22,7 @@
importPackage(Packages.server.life);
function enter(pi) {
- if(pi.isQuestStarted(21301) && pi.getQuestProgress(21301, 9001013) == 0) {
+ if(pi.isQuestStarted(21301) && pi.getQuestProgressInt(21301, 9001013) == 0) {
if(pi.getPlayerCount(108010700) != 0) {
pi.message("The portal is blocked from the other side. I wonder if someone is already fighting the Thief Crow?");
return false;
diff --git a/scripts/portal/out_pepeking.js b/scripts/portal/out_pepeking.js
index 5532f8eef0..67d59554f4 100644
--- a/scripts/portal/out_pepeking.js
+++ b/scripts/portal/out_pepeking.js
@@ -5,7 +5,7 @@ function enter(pi) {
eim.dispose();
}
- var questProgress = pi.getQuestProgress(2330, 3300005) + pi.getQuestProgress(2330, 3300006) + pi.getQuestProgress(2330, 3300007); //3 Yetis
+ var questProgress = pi.getQuestProgressInt(2330, 3300005) + pi.getQuestProgressInt(2330, 3300006) + pi.getQuestProgressInt(2330, 3300007); //3 Yetis
if(questProgress == 3 && !pi.hasItem(4032388)) {
if(pi.canHold(4032388)){
pi.getPlayer().message("You have aquired a key to the Wedding Hall. King Pepe must have dropped it.");
diff --git a/scripts/portal/q3367in.js b/scripts/portal/q3367in.js
index 05ec7966d1..9832335769 100644
--- a/scripts/portal/q3367in.js
+++ b/scripts/portal/q3367in.js
@@ -19,8 +19,11 @@
*/
function enter(pi) {
if(pi.isQuestStarted(3367)) {
- if(pi.getQuestProgress(3367, 31) < pi.getItemQuantity(4031797)) {
- pi.gainItem(4031797, pi.getQuestProgress(3367, 31) - pi.getItemQuantity(4031797));
+ var booksDone = pi.getQuestProgressInt(3367, 31);
+ var booksInv = pi.getItemQuantity(4031797);
+
+ if(booksInv < booksDone) {
+ pi.gainItem(4031797, booksDone - booksInv);
}
pi.playPortalSound(); pi.warp(926130102, 0);
diff --git a/scripts/portal/s4mind_end.js b/scripts/portal/s4mind_end.js
index 39007482c2..6b8343b7ae 100644
--- a/scripts/portal/s4mind_end.js
+++ b/scripts/portal/s4mind_end.js
@@ -23,7 +23,7 @@ function enter(pi) {
return false;
} else {
if (pi.isQuestStarted(6410)) {
- pi.setQuestProgress(6410, 0, 1);
+ pi.setQuestProgress(6410, 6411, "p2");
}
pi.playPortalSound();
diff --git a/scripts/portal/secretDoor.js b/scripts/portal/secretDoor.js
index 9748d0d367..392ec72f4d 100644
--- a/scripts/portal/secretDoor.js
+++ b/scripts/portal/secretDoor.js
@@ -30,7 +30,8 @@ function enter(pi) {
if(pi.isQuestCompleted(3360)) {
return doorCross(pi);
} else if(pi.isQuestStarted(3360)) {
- if(pi.getQuestProgress(3360, 1) == 0) {
+ var pw = pi.getQuestProgress(3360);
+ if(pw.length() > 1) {
pi.openNpc(2111024, "MagatiaPassword");
return false;
} else {
diff --git a/scripts/quest/1021.js b/scripts/quest/1021.js
index 143f404c80..b43519b843 100644
--- a/scripts/quest/1021.js
+++ b/scripts/quest/1021.js
@@ -43,7 +43,7 @@ function start(mode, type, selection) {
status--;
if (status == 0)
- qm.sendNext("Hey, Man~ What's up? Haha! I am Roger who can teach you adorable new Maplers lots of information.");
+ qm.sendNext("Hey, " + (qm.getPlayer().getGender() == 0 ? "Man" : "Miss") + "~ What's up? Haha! I am Roger who can teach you adorable new Maplers lots of information.");
else if (status == 1)
qm.sendNextPrev("You are asking who made me do this? Ahahahaha!\r\nMyself! I wanted to do this and just be kind to you new travellers.");
else if (status == 2)
@@ -60,7 +60,7 @@ function start(mode, type, selection) {
qm.forceStartQuest();
qm.sendNext("Surprised? If HP becomes 0, then you are in trouble. Now, I will give you #rRoger's Apple#k. Please take it. You will feel stronger. Open the Item window and double click to consume. Hey, it's very simple to open the Item window. Just press #bI#k on your keyboard.");
} else if (status == 4) {
- qm.sendNextPrev("Please take all Roger's Apples that I gave you. You will be able to see the HP bar increasing. Please talk to me again when you recover your HP 100%.");
+ qm.sendPrev("Please take all Roger's Apples that I gave you. You will be able to see the HP bar increasing. Please talk to me again when you recover your HP 100%.");
} else if (status == 5) {
qm.showInfo("UI/tutorial.img/28");
qm.dispose();
@@ -91,7 +91,7 @@ function end(mode, type, selection) {
else if (status == 1)
qm.sendNextPrev("Alright! Now that you have learned alot, I will give you a present. This is a must for your travel in Maple World, so thank me! Please use this under emergency cases!");
else if (status == 2)
- qm.sendNextPrev("Okay, this is all I can teach you. I know it's sad but it is time to say good bye. Well take care if yourself and Good luck my friend!\r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0#\r\n#v2010000# 3 #t2010000#\r\n#v2010009# 3 #t2010009#\r\n\r\n#fUI/UIWindow.img/QuestIcon/8/0# 10 exp");
+ qm.sendPrev("Okay, this is all I can teach you. I know it's sad but it is time to say good bye. Well take care if yourself and Good luck my friend!\r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0#\r\n#v2010000# 3 #t2010000#\r\n#v2010009# 3 #t2010009#\r\n\r\n#fUI/UIWindow.img/QuestIcon/8/0# 10 exp");
else if (status == 3) {
if(qm.isQuestCompleted(1021))
qm.dropMessage(1,"Unknown Error");
diff --git a/scripts/quest/20010.js b/scripts/quest/20010.js
index eb3d98ac80..e68d48f35f 100644
--- a/scripts/quest/20010.js
+++ b/scripts/quest/20010.js
@@ -5,6 +5,12 @@ function start(mode, type, selection) {
qm.sendNext("Whoa, whoa! Are you really declining my offer? Well, you'll be able to #blevel-up quicker #kwith our help, so let me know if you change your mind. Even if you've declined a Quest, you can receive the Quest again if you just come and talk to me.");
qm.dispose();
} else {
+ if(mode == 0 && type > 0) {
+ qm.sendNext("Whoa, whoa! Are you really declining my offer? Well, you'll be able to #blevel-up quicker #kwith our help, so let me know if you change your mind. Even if you've declined a Quest, you can receive the Quest again if you just come and talk to me.");
+ qm.dispose();
+ return;
+ }
+
if (mode == 1)
status++;
else
@@ -14,7 +20,7 @@ function start(mode, type, selection) {
} else if (status == 1) {
qm.sendNextPrev("If you want to officially become a part of Cygnus Knights, you must first meet the Empress. She's at the center of this island, accompained by Shinsoo. My brothers and I would like to share with you a few things that are considered #bBasic Knowledge#k in Maple World before you go. Would that be okay?");
} else if (status == 2) {
- qm.sendOk("Oh, let me warn you that this is a Quest. You may have noticed that NPCs around Maple World occasionally ask you for various favors. A favor of that sort is called a #bQuest#k. You will receive reward items or EXP upon completing Quests, so I strongly suggest you diligently fulfill the favors of Maple NPCs.");
+ qm.sendNextPrev("Oh, let me warn you that this is a Quest. You may have noticed that NPCs around Maple World occasionally ask you for various favors. A favor of that sort is called a #bQuest#k. You will receive reward items or EXP upon completing Quests, so I strongly suggest you diligently fulfill the favors of Maple NPCs.");
} else if (status == 3) {
qm.sendAcceptDecline("Would you like to meet #bKizan#k, who can tell you about hunting? You can find Kizan by following the arrow to the left.");
} else if (status == 4) {
@@ -31,7 +37,7 @@ function end(mode, type, selection) {
qm.dispose();
} else {
if (status == 0) {
- qm.sendNext("Are you the Noblesse my brother Kimu sent? Nice to meet you! I'm Kizan. I'll give you the reward Kimu asked me to give you. Remember, you can check your Inventory by pressing the #bI key#k. Red potions help you recover HP, and blue ones help recover MP. It's a good idea to learn how to use them beforehand so you'll be ready with them when you're in danger. \r\n\r\n#fUI/UIWindow.img/Quest/reward# \r\n\r\n#v2000020# #z2000020# \r\n#v2000021# #z2000021# \r\n\r\n#fUI/UIWindow.img/QuestIcon/8/0#15 exp");
+ qm.sendOk("Are you the Noblesse my brother Kimu sent? Nice to meet you! I'm Kizan. I'll give you the reward Kimu asked me to give you. Remember, you can check your Inventory by pressing the #bI key#k. Red potions help you recover HP, and blue ones help recover MP. It's a good idea to learn how to use them beforehand so you'll be ready with them when you're in danger. \r\n\r\n#fUI/UIWindow.img/Quest/reward# \r\n\r\n#v2000020# #z2000020# \r\n#v2000021# #z2000021# \r\n\r\n#fUI/UIWindow.img/QuestIcon/8/0#15 exp");
} else if (status == 1) {
if(qm.canHold(2000022) && qm.canHold(2000023)){
if(!qm.isQuestCompleted(21010)) {
diff --git a/scripts/quest/20011.js b/scripts/quest/20011.js
index 1153de5c31..be08d1c3fa 100644
--- a/scripts/quest/20011.js
+++ b/scripts/quest/20011.js
@@ -48,7 +48,7 @@ function end(mode, type, selection) {
if (status == 0) {
qm.sendNext("Ah, it seems like you've successfully hunted a #o100120#. Pretty simple, right? Regular Attacks may be easy to use, but they are pretty weak. Don't worry, though. #p1102006# will teach you how to use more powerful skills. Wait, let me give you a well-deserved quest reward before you go.");
} else if (status == 1) {
- qm.sendNextPrev("This equipment is for Noblesses. It's much cooler than what you're wearing right now, isn't it? Follow the arrows to your left to meet my younger brother #b#p1102006##k. How about you change into your new Noblesse outfit before you go? \r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0# \r\n#i1002869# #t1002869# - 1 \r\n#i1052177# #t1052177# - 1 \r\n\r\n#fUI/UIWindow.img/QuestIcon/8/0# 30 exp");
+ qm.sendPrev("This equipment is for Noblesses. It's much cooler than what you're wearing right now, isn't it? Follow the arrows to your left to meet my younger brother #b#p1102006##k. How about you change into your new Noblesse outfit before you go? \r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0# \r\n#i1002869# #t1002869# - 1 \r\n#i1052177# #t1052177# - 1 \r\n\r\n#fUI/UIWindow.img/QuestIcon/8/0# 30 exp");
} else if (status == 2) {
qm.gainItem(1002869, 1);
qm.gainItem(1052177, 1);
diff --git a/scripts/quest/20013.js b/scripts/quest/20013.js
index 6efdb7a762..6742172b5e 100644
--- a/scripts/quest/20013.js
+++ b/scripts/quest/20013.js
@@ -52,7 +52,7 @@ function end(mode, type, selection) {
if (status == 0) {
qm.sendNext("Did you bring me a Building Stone and a Drape? Let's see. Ah, these are just what I need! They indeed are a #t4032267# and a #t4032268#! I'll make you a Chair right away.");
} else if (status == 1) {
- qm.sendNextPrev("Here it is, a #t3010060#. What do you think? Nifty, huh? You can #bquickly recover your HP by sitting in this Chair#k. It will be stored in the #bSet-up#k window in your Inventory, so confirm that you've received the chair and head over to #b#p1102008##k. You'll see him if you keep following the arrow to the left. \r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0# \r\n#i3010060# 1 #t3010060# \r\n#fUI/UIWindow.img/QuestIcon/8/0# 95 exp");
+ qm.sendPrev("Here it is, a #t3010060#. What do you think? Nifty, huh? You can #bquickly recover your HP by sitting in this Chair#k. It will be stored in the #bSet-up#k window in your Inventory, so confirm that you've received the chair and head over to #b#p1102008##k. You'll see him if you keep following the arrow to the left. \r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0# \r\n#i3010060# 1 #t3010060# \r\n#fUI/UIWindow.img/QuestIcon/8/0# 95 exp");
} else if (status == 2) {
qm.gainItem(4032267, -1);
qm.gainItem(4032268, -1);
diff --git a/scripts/quest/20020.js b/scripts/quest/20020.js
new file mode 100644
index 0000000000..03e87a5f2f
--- /dev/null
+++ b/scripts/quest/20020.js
@@ -0,0 +1,38 @@
+/*
+ NPC Name: Nineheart
+ Description: Quest - Cygnus movie Intro
+*/
+var status = -1;
+
+function start(mode, type, selection) {
+ if (mode == -1) {
+ qm.sendOk("Talk to me after you have decided what you really want to do. Whatever you choose, you will not miss out or lose privileges, so don't take this too seriously...");
+ qm.dispose();
+ } else {
+ if(mode == 0 && type > 0 || selection == 1) {
+ qm.sendOk("Talk to me after you have decided what you really want to do. Whatever you choose, you will not miss out or lose privileges, so don't take this too seriously...");
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ qm.sendNext("I can tell you've worked really hard by seeing that you're already at Level 10. I think it's time now for you to break out as a Nobless and officially become the Knight-in-Training. Before doing that, however, I want to ask you one thing. Have you decided which Knight you'd want to beome?");
+ } else if (status == 1) {
+ qm.sendNextPrev("There isn't a single path to becoming a Knight. In fact, there are five of them laid out for you. It's up to you to choose which path you'd like to take, but it should definitely be something you will not regret. That's why... I am offering to show you what you'll look like once you become a Knight.");
+ } else if (status == 2) {
+ qm.sendSimple("What do you think? Are you interested in seeing yourself as the leader of the Knights? If you have already decided what kind of Knight you'd like to become, then you won't necessarily have to look at it...\r\n\r\n#b#L0#Show me how I'd look like as the leader of the Knights.#l ..#b#L1#No, I'm okay.");
+ } else if (status == 3) {
+ qm.sendYesNo("Would you like to see for it yourself right now? A short clip will come out soon. Be prepared for what you are about to witness.");
+ } else if (status == 4) {
+ qm.forceStartQuest();
+ qm.forceCompleteQuest();
+ //qm.warp(913040100, 0);
+ qm.dispose();
+ }
+ }
+}
diff --git a/scripts/quest/20101.js b/scripts/quest/20101.js
index 5c4fb9ea9c..a53b48f168 100644
--- a/scripts/quest/20101.js
+++ b/scripts/quest/20101.js
@@ -6,6 +6,7 @@ importPackage(Packages.client);
var status = -1;
var jobType = 1;
+var canTryFirstJob = true;
function end(mode, type, selection) {
if (mode == 0) {
@@ -21,32 +22,35 @@ function end(mode, type, selection) {
if (status == 0) {
qm.sendYesNo("Have you made your decision? The decision will be final, so think carefully before deciding what to do. Are you sure you want to become a Dawn Warrior?");
} else if (status == 1) {
- if(!qm.canGetFirstJob(jobType)) {
- qm.sendOk("Train a bit more until you reach #blevel 10, " + qm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rDawn Warrior#k.");
- qm.dispose();
- return;
+ if (canTryFirstJob) {
+ canTryFirstJob = false;
+ if (qm.getPlayer().getJob().getId() != 1100) {
+ if(!qm.canGetFirstJob(jobType)) {
+ qm.sendOk("Train a bit more until you reach #blevel 10, " + qm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rDawn Warrior#k.");
+ qm.dispose();
+ return;
+ }
+
+ if (!(qm.canHoldAll([1302077, 1142066]))) {
+ qm.sendOk("Make some room in your inventory and talk back to me.");
+ qm.dispose();
+ return;
+ }
+
+ qm.gainItem(1302077, 1);
+ qm.gainItem(1142066, 1);
+ qm.changeJob(MapleJob.DAWNWARRIOR1);
+ qm.getPlayer().resetStats();
+ }
+ qm.forceCompleteQuest();
}
-
- if (!(qm.canHoldAll([1302077, 1142066]))) {
- qm.sendOk("Make some room in your inventory and talk back to me.");
- qm.dispose();
- return;
- }
-
- qm.sendNext("I have just molded your body to make it perfect for a Dawn Warrior. If you wish to become more powerful, use Stat Window (S) to raise the appropriate stats. If you aren't sure what to raise, just click on #bAuto#k.");
- if (qm.getPlayer().getJob().getId() != 1100) {
- qm.gainItem(1302077, 1);
- qm.gainItem(1142066, 1);
- qm.changeJob(MapleJob.DAWNWARRIOR1);
- qm.getPlayer().resetStats();
- }
- qm.forceCompleteQuest();
+ qm.sendNext("I have just molded your body to make it perfect for a Dawn Warrior. If you wish to become more powerful, use Stat Window (S) to raise the appropriate stats. If you aren't sure what to raise, just click on #bAuto#k.");
} else if (status == 2) {
qm.sendNextPrev("I have also expanded your inventory slot counts for your equipment and etc. inventory. Use those slots wisely and fill them up with items required for Knights to carry.");
} else if (status == 3) {
qm.sendNextPrev("I have also given you a hint of #bSP#k, so open the #bSkill Menu#k to acquire new skills. Of course, you can't raise them at all once, and there are some skills out there where you won't be able to acquire them unless you master the basic skills first.");
} else if (status == 4) {
- qm.sendNextPrev("Unlike your time as a Nobless, once you become the Dawn Warrior, you will lost a portion of your EXP when you run out of HP, okay?");
+ qm.sendNextPrev("Unlike your time as a Noblesse, once you become the Dawn Warrior, you will lost a portion of your EXP when you run out of HP, okay?");
} else if (status == 5) {
qm.sendNextPrev("Now... I want you to go out there and show the world how the Knights of Cygnus operate.");
} else if (status == 6) {
diff --git a/scripts/quest/20102.js b/scripts/quest/20102.js
index 852b4d7337..fec8015c50 100644
--- a/scripts/quest/20102.js
+++ b/scripts/quest/20102.js
@@ -6,6 +6,7 @@ importPackage(Packages.client);
var status = -1;
var jobType = 2;
+var canTryFirstJob = true;
function end(mode, type, selection) {
if (mode == 0) {
@@ -21,32 +22,35 @@ function end(mode, type, selection) {
if (status == 0) {
qm.sendYesNo("Have you made your decision? The decision will be final, so think carefully before deciding what to do. Are you sure you want to become a Blaze Wizard?");
} else if (status == 1) {
- if(!qm.canGetFirstJob(jobType)) {
- qm.sendOk("Train a bit more until you reach #blevel 10, " + qm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rBlaze Wizard#k.");
- qm.dispose();
- return;
+ if (canTryFirstJob) {
+ canTryFirstJob = false;
+ if (qm.getPlayer().getJob().getId() != 1200) {
+ if(!qm.canGetFirstJob(jobType)) {
+ qm.sendOk("Train a bit more until you reach #blevel 10, " + qm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rBlaze Wizard#k.");
+ qm.dispose();
+ return;
+ }
+
+ if (!(qm.canHoldAll([1372043, 1142066]))) {
+ qm.sendOk("Make some room in your inventory and talk back to me.");
+ qm.dispose();
+ return;
+ }
+
+ qm.gainItem(1372043, 1);
+ qm.gainItem(1142066, 1);
+ qm.changeJob(MapleJob.BLAZEWIZARD1);
+ qm.getPlayer().resetStats();
+ }
+ qm.forceCompleteQuest();
}
-
- if (!(qm.canHoldAll([1372043, 1142066]))) {
- qm.sendOk("Make some room in your inventory and talk back to me.");
- qm.dispose();
- return;
- }
-
- qm.sendNext("I have just molded your body to make it perfect for a Blaze Wizard. If you wish to become more powerful, use Stat Window (S) to raise the appropriate stats. If you aren't sure what to raise, just click on #bAuto#k.");
- if (qm.getPlayer().getJob().getId() != 1200) {
- qm.gainItem(1372043, 1);
- qm.gainItem(1142066, 1);
- qm.changeJob(MapleJob.BLAZEWIZARD1);
- qm.getPlayer().resetStats();
- }
- qm.forceCompleteQuest();
+ qm.sendNext("I have just molded your body to make it perfect for a Blaze Wizard. If you wish to become more powerful, use Stat Window (S) to raise the appropriate stats. If you aren't sure what to raise, just click on #bAuto#k.");
} else if (status == 2) {
qm.sendNextPrev("I have also expanded your inventory slot counts for your equipment and etc. inventory. Use those slots wisely and fill them up with items required for Knights to carry.");
} else if (status == 3) {
qm.sendNextPrev("I have also given you a hint of #bSP#k, so open the #bSkill Menu#k to acquire new skills. Of course, you can't raise them at all once, and there are some skills out there where you won't be able to acquire them unless you master the basic skills first.");
} else if (status == 4) {
- qm.sendNextPrev("Unlike your time as a Nobless, once you become the Blaze Wizard, you will lost a portion of your EXP when you run out of HP, okay?");
+ qm.sendNextPrev("Unlike your time as a Noblesse, once you become the Blaze Wizard, you will lost a portion of your EXP when you run out of HP, okay?");
} else if (status == 5) {
qm.sendNextPrev("Now... I want you to go out there and show the world how the Knights of Cygnus operate.");
} else if (status == 6) {
diff --git a/scripts/quest/20103.js b/scripts/quest/20103.js
index 2c119025c2..8aadf16618 100644
--- a/scripts/quest/20103.js
+++ b/scripts/quest/20103.js
@@ -6,6 +6,7 @@ importPackage(Packages.client);
var status = -1;
var jobType = 3;
+var canTryFirstJob = true;
function end(mode, type, selection) {
if (mode == 0) {
@@ -21,33 +22,36 @@ function end(mode, type, selection) {
if (status == 0) {
qm.sendYesNo("Have you made your decision? The decision will be final, so think carefully before deciding what to do. Are you sure you want to become a Wind Archer?");
} else if (status == 1) {
- if(!qm.canGetFirstJob(jobType)) {
- qm.sendOk("Train a bit more until you reach #blevel 10, " + qm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rWind Archer#k.");
- qm.dispose();
- return;
+ if (canTryFirstJob) {
+ canTryFirstJob = false;
+ if (qm.getPlayer().getJob().getId() != 1300) {
+ if(!qm.canGetFirstJob(jobType)) {
+ qm.sendOk("Train a bit more until you reach #blevel 10, " + qm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rWind Archer#k.");
+ qm.dispose();
+ return;
+ }
+
+ if (!(qm.canHoldAll([1452051, 1142066]) && qm.canHold(2070000))) {
+ qm.sendOk("Make some room in your inventory and talk back to me.");
+ qm.dispose();
+ return;
+ }
+
+ qm.gainItem(2060000, 2000);
+ qm.gainItem(1452051, 1);
+ qm.gainItem(1142066, 1);
+ qm.changeJob(MapleJob.WINDARCHER1);
+ qm.getPlayer().resetStats();
+ }
+ qm.forceCompleteQuest();
}
-
- if (!(qm.canHoldAll([1452051, 1142066]) && qm.canHold(2070000))) {
- qm.sendOk("Make some room in your inventory and talk back to me.");
- qm.dispose();
- return;
- }
-
- qm.sendNext("I have just molded your body to make it perfect for a Wind Archer. If you wish to become more powerful, use Stat Window (S) to raise the appropriate stats. If you aren't sure what to raise, just click on #bAuto#k.");
- if (qm.getPlayer().getJob().getId() != 1300) {
- qm.gainItem(2060000, 2000);
- qm.gainItem(1452051, 1);
- qm.gainItem(1142066, 1);
- qm.changeJob(MapleJob.WINDARCHER1);
- qm.getPlayer().resetStats();
- }
- qm.forceCompleteQuest();
+ qm.sendNext("I have just molded your body to make it perfect for a Wind Archer. If you wish to become more powerful, use Stat Window (S) to raise the appropriate stats. If you aren't sure what to raise, just click on #bAuto#k.");
} else if (status == 2) {
qm.sendNextPrev("I have also expanded your inventory slot counts for your equipment and etc. inventory. Use those slots wisely and fill them up with items required for Knights to carry.");
} else if (status == 3) {
qm.sendNextPrev("I have also given you a hint of #bSP#k, so open the #bSkill Menu#k to acquire new skills. Of course, you can't raise them at all once, and there are some skills out there where you won't be able to acquire them unless you master the basic skills first.");
} else if (status == 4) {
- qm.sendNextPrev("Unlike your time as a Nobless, once you become the Wind Archer, you will lost a portion of your EXP when you run out of HP, okay?");
+ qm.sendNextPrev("Unlike your time as a Noblesse, once you become the Wind Archer, you will lost a portion of your EXP when you run out of HP, okay?");
} else if (status == 5) {
qm.sendNextPrev("Now... I want you to go out there and show the world how the Knights of Cygnus operate.");
} else if (status == 6) {
diff --git a/scripts/quest/20104.js b/scripts/quest/20104.js
index 3957ff6101..2f4ee320c7 100644
--- a/scripts/quest/20104.js
+++ b/scripts/quest/20104.js
@@ -6,6 +6,7 @@ importPackage(Packages.client);
var status = -1;
var jobType = 4;
+var canTryFirstJob = true;
function end(mode, type, selection) {
if (mode == 0) {
@@ -21,33 +22,36 @@ function end(mode, type, selection) {
if (status == 0) {
qm.sendYesNo("Have you made your decision? The decision will be final, so think carefully before deciding what to do. Are you sure you want to become a Night Walker?");
} else if (status == 1) {
- if(!qm.canGetFirstJob(jobType)) {
- qm.sendOk("Train a bit more until you reach #blevel 10, " + qm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rNight Walker#k.");
- qm.dispose();
- return;
+ if (canTryFirstJob) {
+ canTryFirstJob = false;
+ if (qm.getPlayer().getJob().getId() != 1400) {
+ if(!qm.canGetFirstJob(jobType)) {
+ qm.sendOk("Train a bit more until you reach #blevel 10, " + qm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rNight Walker#k.");
+ qm.dispose();
+ return;
+ }
+
+ if (!(qm.canHoldAll([1472061, 1142066]) && qm.canHold(2070000))) {
+ qm.sendOk("Make some room in your inventory and talk back to me.");
+ qm.dispose();
+ return;
+ }
+
+ qm.gainItem(1472061, 1);
+ qm.gainItem(2070000, 800);
+ qm.gainItem(1142066, 1);
+ qm.changeJob(MapleJob.NIGHTWALKER1);
+ qm.getPlayer().resetStats();
+ }
+ qm.forceCompleteQuest();
}
-
- if (!(qm.canHoldAll([1472061, 1142066]) && qm.canHold(2070000))) {
- qm.sendOk("Make some room in your inventory and talk back to me.");
- qm.dispose();
- return;
- }
-
- qm.sendNext("I have just molded your body to make it perfect for a Night Walker. If you wish to become more powerful, use Stat Window (S) to raise the appropriate stats. If you aren't sure what to raise, just click on #bAuto#k.");
- if (qm.getPlayer().getJob().getId() != 1400) {
- qm.gainItem(1472061, 1);
- qm.gainItem(2070000, 800);
- qm.gainItem(1142066, 1);
- qm.changeJob(MapleJob.NIGHTWALKER1);
- qm.getPlayer().resetStats();
- }
- qm.forceCompleteQuest();
+ qm.sendNext("I have just molded your body to make it perfect for a Night Walker. If you wish to become more powerful, use Stat Window (S) to raise the appropriate stats. If you aren't sure what to raise, just click on #bAuto#k.");
} else if (status == 2) {
qm.sendNextPrev("I have also expanded your inventory slot counts for your equipment and etc. inventory. Use those slots wisely and fill them up with items required for Knights to carry.");
} else if (status == 3) {
qm.sendNextPrev("I have also given you a hint of #bSP#k, so open the #bSkill Menu#k to acquire new skills. Of course, you can't raise them at all once, and there are some skills out there where you won't be able to acquire them unless you master the basic skills first.");
} else if (status == 4) {
- qm.sendNextPrev("Unlike your time as a Nobless, once you become the Night Walker, you will lost a portion of your EXP when you run out of HP, okay?");
+ qm.sendNextPrev("Unlike your time as a Noblesse, once you become the Night Walker, you will lost a portion of your EXP when you run out of HP, okay?");
} else if (status == 5) {
qm.sendNextPrev("Now... I want you to go out there and show the world how the Knights of Cygnus operate.");
} else if (status == 6) {
diff --git a/scripts/quest/20105.js b/scripts/quest/20105.js
index 5d957edb9d..03e933f019 100644
--- a/scripts/quest/20105.js
+++ b/scripts/quest/20105.js
@@ -6,6 +6,7 @@ importPackage(Packages.client);
var status = -1;
var jobType = 5;
+var canTryFirstJob = true;
function end(mode, type, selection) {
if (mode == 0) {
@@ -21,32 +22,35 @@ function end(mode, type, selection) {
if (status == 0) {
qm.sendYesNo("Have you made your decision? The decision will be final, so think carefully before deciding what to do. Are you sure you want to become a Thunder Breaker?");
} else if (status == 1) {
- if(!qm.canGetFirstJob(jobType)) {
- qm.sendOk("Train a bit more until you reach #blevel 10, " + qm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rThunder Breaker#k.");
- qm.dispose();
- return;
+ if (canTryFirstJob) {
+ canTryFirstJob = false;
+ if (qm.getPlayer().getJob().getId() != 1500) {
+ if(!qm.canGetFirstJob(jobType)) {
+ qm.sendOk("Train a bit more until you reach #blevel 10, " + qm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rThunder Breaker#k.");
+ qm.dispose();
+ return;
+ }
+
+ if (!(qm.canHoldAll([1482014, 1142066]))) {
+ qm.sendOk("Make some room in your inventory and talk back to me.");
+ qm.dispose();
+ return;
+ }
+
+ qm.gainItem(1482014, 1);
+ qm.gainItem(1142066, 1);
+ qm.getPlayer().changeJob(MapleJob.THUNDERBREAKER1);
+ qm.getPlayer().resetStats();
+ }
+ qm.forceCompleteQuest();
}
-
- if (!(qm.canHoldAll([1482014, 1142066]))) {
- qm.sendOk("Make some room in your inventory and talk back to me.");
- qm.dispose();
- return;
- }
-
- qm.sendNext("I have just molded your body to make it perfect for a Thunder Breaker. If you wish to become more powerful, use Stat Window (S) to raise the appropriate stats. If you aren't sure what to raise, just click on #bAuto#k.");
- if (qm.getPlayer().getJob().getId() != 1500) {
- qm.gainItem(1482014, 1);
- qm.gainItem(1142066, 1);
- qm.getPlayer().changeJob(MapleJob.THUNDERBREAKER1);
- qm.getPlayer().resetStats();
- }
- qm.forceCompleteQuest();
+ qm.sendNext("I have just molded your body to make it perfect for a Thunder Breaker. If you wish to become more powerful, use Stat Window (S) to raise the appropriate stats. If you aren't sure what to raise, just click on #bAuto#k.");
} else if (status == 2) {
qm.sendNextPrev("I have also expanded your inventory slot counts for your equipment and etc. inventory. Use those slots wisely and fill them up with items required for Knights to carry.");
} else if (status == 3) {
qm.sendNextPrev("I have also given you a hint of #bSP#k, so open the #bSkill Menu#k to acquire new skills. Of course, you can't raise them at all once, and there are some skills out there where you won't be able to acquire them unless you master the basic skills first.");
} else if (status == 4) {
- qm.sendNextPrev("Unlike your time as a Nobless, once you become the Thunder Breaker, you will lost a portion of your EXP when you run out of HP, okay?");
+ qm.sendNextPrev("Unlike your time as a Noblesse, once you become the Thunder Breaker, you will lost a portion of your EXP when you run out of HP, okay?");
} else if (status == 5) {
qm.sendNextPrev("Now... I want you to go out there and show the world how the Knights of Cygnus operate.");
} else if (status == 6) {
diff --git a/scripts/quest/20514.js b/scripts/quest/20514.js
new file mode 100644
index 0000000000..045fadc608
--- /dev/null
+++ b/scripts/quest/20514.js
@@ -0,0 +1,52 @@
+/*
+ This file is part of the HeavenMS MapleStory Server
+ Copyleft (L) 2016 - 2018 RonanLana
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation version 3 as published by
+ the Free Software Foundation. You may not use, modify or distribute
+ this program under any other version of the GNU Affero General Public
+ License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+// @Author Ronan
+
+importPackage(Packages.constants.game);
+importPackage(Packages.server);
+
+function raiseOpen() {
+ var chr = qm.getPlayer();
+ var questStatus = chr.getQuestStatus(qm.getQuest());
+
+ if (questStatus == 0) {
+ qm.setQuestProgress(20515, 0, chr.getLevel());
+ qm.setQuestProgress(20515, 1, chr.getExp());
+ } else if (questStatus == 1) { // update mimiana progress...
+ var diffExp = chr.getExp() - qm.getQuestProgressInt(20515, 1);
+
+ var initLevel = qm.getQuestProgressInt(20515, 0);
+ for (var i = initLevel; i < chr.getLevel(); i++) {
+ diffExp += ExpTable.getExpNeededForLevel(i);
+ }
+
+ if (diffExp > 0) { // thanks IxianMace for noticing Mimiana egg not following progress by EXP
+ var consItem = MapleItemInformationProvider.getInstance().getQuestConsumablesInfo(4220137);
+ var exp = consItem.exp;
+ var grade = consItem.grade;
+
+ qm.setQuestProgress(20514, 0, Math.min(diffExp, exp * grade));
+ }
+ }
+
+ qm.dispose();
+}
+
diff --git a/scripts/quest/2236.js b/scripts/quest/2236.js
deleted file mode 100644
index 41e90b07a0..0000000000
--- a/scripts/quest/2236.js
+++ /dev/null
@@ -1,63 +0,0 @@
-/* ===========================================================
- Ronan Lana
- NPC Name: Chrishrama
- Description: Quest - How to Shoo Away the Evil
-=============================================================
-Version 1.0 - Script Done.(20/3/2017)
-=============================================================
-*/
-
-var status = -1;
-var canStart;
-
-function start(mode, type, selection) {
- status++;
- if (mode != 1) {
- if(type == 1 && mode == 0)
- status -= 2;
- else{
- qm.sendOk("If we don't place these Charms on the Shaman Rocks, evil might awaken...");
- canStart = false;
- status = 0;
- return;
- }
- }
- if (status == 0) {
- qm.sendAcceptDecline("I can feel the forces of evil. They're deep inside the dungeon and they're very, very powerful. If we want to drive the evil away from this place, we must place Charms on the Shaman Rocks inside the dungeon. Will you do that for me?");
- 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.dispose();
- }
-}
-
-function end(mode, type, selection) {
- status++;
-
- if(status == 0) {
- if(qm.getQuestProgress(2236) == 63) { //111111
- qm.sendOk("I, too, felt it. The force of the Shaman Rocks began to overpower the forces of evil. I think Sleepywood is safe now. The evil has been eliminated.");
- qm.gainExp(60000);
- qm.forceCompleteQuest();
- }
- else {
- if(qm.haveItem(4032263)) qm.gainItem(4032263, -6);
- qm.gainItem(4032263, 6);
-
- qm.sendOk("Oh, not good. I still sense bad omens coming from the interior. Here, take these charms and seal them at the Shaman Rocks. We are counting on you.");
- qm.updateQuest(2236, 0);
- }
- } else if (status == 1) {
- qm.dispose();
- }
-}
\ No newline at end of file
diff --git a/scripts/quest/2251.js b/scripts/quest/2251.js
deleted file mode 100644
index e3e02b116f..0000000000
--- a/scripts/quest/2251.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- Author: Kevin
- Quest: Zombie Mushroom Signal 3 (2251)
- NPC: The Rememberer (1061011)
- Item: Recording Charm (4032399)
-*/
-
-var status = -1;
-
-function end(mode, type, selection) {
- if (mode == -1) {
- qm.dispose();
- } else {
- if(mode == 0 && type > 0) {
- qm.dispose();
- return;
- }
-
- if (mode == 1)
- status++;
- else
- status--;
-
- if (status == 0) {
- if(!qm.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();
- }
- }
-}
\ No newline at end of file
diff --git a/scripts/quest/2260.js b/scripts/quest/2260.js
index 4c196cdf26..6a99207e6d 100644
--- a/scripts/quest/2260.js
+++ b/scripts/quest/2260.js
@@ -18,7 +18,7 @@
along with this program. If not, see .
*/
-importPackage(Packages.constants);
+importPackage(Packages.constants.game);
var status = -1;
diff --git a/scripts/quest/3114.js b/scripts/quest/3114.js
deleted file mode 100644
index 46883d9ee5..0000000000
--- a/scripts/quest/3114.js
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- 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 .
-*/
-
-var status = -1;
-
-function end(mode, type, selection) {
- if (mode == -1) {
- qm.dispose();
- } else {
- if(mode == 0 && type > 0) {
- qm.dispose();
- return;
- }
-
- if (mode == 1)
- status++;
- else
- status--;
-
- if (status == 0) {
- if(qm.getQuestProgress(3114, 7777) != -1) {
- if(!qm.haveItem(4161036, 1)) {
- if(qm.canHold(4161036, 1)) {
- qm.gainItem(4161036, 1);
- qm.sendNext("Seems you lost a book with the notes to Little Star. Here is another one. Please play it for me.", 9);
- } else {
- qm.sendNext("Seems you lost a book with the notes to Little Star, but you don't have an ETC available. Please free some room.", 9);
- }
- } else {
- qm.sendNext(".....", 9);
- }
-
- qm.dispose();
- return;
- }
-
- qm.sendNext("(Eliza seems to be in deep sleep.)", 3);
- } else if (status == 1) {
- qm.gainFame(20);
-
- qm.forceCompleteQuest();
- qm.dispose();
- }
- }
-}
\ No newline at end of file
diff --git a/scripts/quest/3311.js b/scripts/quest/3311.js
deleted file mode 100644
index 572eb80bc4..0000000000
--- a/scripts/quest/3311.js
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- 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 .
-*/
-
-var status = -1;
-
-function end(mode, type, selection) {
- if (mode == -1) {
- qm.dispose();
- } else {
- if(mode == 0 && type > 0) {
- qm.dispose();
- return;
- }
-
- if (mode == 1)
- status++;
- else
- status--;
-
- if (status == 0) {
- if(qm.getQuestProgress(3311, 0) == 1 && qm.getQuestProgress(3311, 1) == 1) {
- qm.sendNext("Hmm, so the Alcadno doctor wrote something about researching some vanguardist Neo Huroid machine, that could beat by far the existing one, and was about to prepare the last steps of his rehearsal? We don't have a word about him for about three weeks now, something must have gone wrong...");
- qm.gainExp(60000);
- qm.forceCompleteQuest();
- } else {
- qm.sendNext("Found nothing yet? Please check out Dr. De Lang's house properly, something there may give out a clue about what is going on.");
- }
- } else if (status == 1) {
- qm.dispose();
- }
- }
-}
\ No newline at end of file
diff --git a/scripts/quest/3360.js b/scripts/quest/3360.js
index 1b1246c66b..78496c6381 100644
--- a/scripts/quest/3360.js
+++ b/scripts/quest/3360.js
@@ -24,6 +24,7 @@
Description: Quest - Verifying the password
*/
var status = -1;
+var pass;
function start(mode, type, selection) {
if (mode == -1) {
@@ -47,37 +48,16 @@ function start(mode, type, selection) {
} else if (status == 1) {
qm.sendAcceptDecline("All right, now, this key is very long and complex. I need you to memorize it very well. I won't say again, so you'd better write it down somewhere. Are you ready?");
} else if (status == 2) {
- var pass = generateString();
+ pass = generateString();
qm.sendOk("The key code is #b" + pass + "#k. Got that? Put the key into the door of the secret passage, and you will be able to walk around the passage freely.");
- qm.forceStartQuest();
- qm.setStringQuestProgress(3360, 0, pass);
} else if (status == 3) {
+ qm.forceStartQuest();
+ qm.setQuestProgress(3360, pass);
qm.dispose();
}
}
}
-function end(mode, type, selection) {
- if (mode == -1) {
- qm.dispose();
- } else {
- if (mode == 1)
- status++;
- else
- status--;
- if (status == 0) {
- if(qm.getQuestProgress(3360, 1) == 0) {
- qm.sendNext("What's up? You haven't opened the Secret Passage yet?");
- } else {
- qm.forceCompleteQuest();
- qm.dispose();
- }
- } else if (status == 1) {
- qm.dispose();
- }
- }
-}
-
function generateString() {
var thestring = "";
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
diff --git a/scripts/quest/3523.js b/scripts/quest/3523.js
index 46e47d819c..4f8ab2905d 100644
--- a/scripts/quest/3523.js
+++ b/scripts/quest/3523.js
@@ -41,7 +41,7 @@ function start(mode, type, selection) {
if (status == 0) {
qm.startQuest();
- //qm.getPlayer().updateQuestInfo(3507, "1");
+ qm.setQuestProgress(3507, 7081, 1); // thanks resinate for pointing out uncompletable quest due to non-updated progress
qm.completeQuest();
qm.sendOk("You have regained your memories, talk to #b#p2140001##k to get the pass.");
} else if (status == 1) {
diff --git a/scripts/quest/3524.js b/scripts/quest/3524.js
index 47fe08adc4..4b740dd36b 100644
--- a/scripts/quest/3524.js
+++ b/scripts/quest/3524.js
@@ -41,7 +41,7 @@ function start(mode, type, selection) {
if (status == 0) {
qm.startQuest();
- //qm.getPlayer().updateQuestInfo(3507, "1");
+ qm.setQuestProgress(3507, 7081, 1);
qm.completeQuest();
qm.sendOk("You have regained your memories, talk to #b#p2140001##k to get the pass.");
} else if (status == 1) {
diff --git a/scripts/quest/3525.js b/scripts/quest/3525.js
index 9ec196c5c2..97bbae92c7 100644
--- a/scripts/quest/3525.js
+++ b/scripts/quest/3525.js
@@ -41,7 +41,7 @@ function start(mode, type, selection) {
if (status == 0) {
qm.startQuest();
- //qm.getPlayer().updateQuestInfo(3507, "1");
+ qm.setQuestProgress(3507, 7081, 1);
qm.completeQuest();
qm.sendOk("You have regained your memories, talk to #b#p2140001##k to get the pass.");
} else if (status == 1) {
diff --git a/scripts/quest/3526.js b/scripts/quest/3526.js
index 0e7a4d32b8..77b49a7ce1 100644
--- a/scripts/quest/3526.js
+++ b/scripts/quest/3526.js
@@ -41,7 +41,7 @@ function start(mode, type, selection) {
if (status == 0) {
qm.startQuest();
- //qm.getPlayer().updateQuestInfo(3507, "1");
+ qm.setQuestProgress(3507, 7081, 1);
qm.completeQuest();
qm.sendOk("You have regained your memories, talk to #b#p2140001##k to get the pass.");
} else if (status == 1) {
diff --git a/scripts/quest/3527.js b/scripts/quest/3527.js
index 902ebb3f05..ce28f770f0 100644
--- a/scripts/quest/3527.js
+++ b/scripts/quest/3527.js
@@ -41,7 +41,7 @@ function start(mode, type, selection) {
if (status == 0) {
qm.startQuest();
- //qm.getPlayer().updateQuestInfo(3507, "1");
+ qm.setQuestProgress(3507, 7081, 1);
qm.completeQuest();
qm.sendOk("You have regained your memories, talk to #b#p2140001##k to get the pass.");
} else if (status == 1) {
diff --git a/scripts/quest/3529.js b/scripts/quest/3529.js
index 7e2c07ba54..0c7d0eccef 100644
--- a/scripts/quest/3529.js
+++ b/scripts/quest/3529.js
@@ -36,8 +36,9 @@ function start(mode, type, selection) {
if (status == 0) {
qm.sendOk("You have regained your memories, talk to #b#p2140001##k to get the pass.");
- } else if (status == 1) {
+ qm.setQuestProgress(3507, 7081, 1);
qm.forceCompleteQuest();
+ } else if (status == 1) {
qm.dispose();
}
}
diff --git a/scripts/quest/3539.js b/scripts/quest/3539.js
index 902ebb3f05..ce28f770f0 100644
--- a/scripts/quest/3539.js
+++ b/scripts/quest/3539.js
@@ -41,7 +41,7 @@ function start(mode, type, selection) {
if (status == 0) {
qm.startQuest();
- //qm.getPlayer().updateQuestInfo(3507, "1");
+ qm.setQuestProgress(3507, 7081, 1);
qm.completeQuest();
qm.sendOk("You have regained your memories, talk to #b#p2140001##k to get the pass.");
} else if (status == 1) {
diff --git a/scripts/quest/3926.js b/scripts/quest/3926.js
deleted file mode 100644
index dce1ce974a..0000000000
--- a/scripts/quest/3926.js
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- 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 .
-*/
-/* Screwing the Red Scorpions
- */
-
-var status = -1;
-
-function end(mode, type, selection) {
- if (mode == -1) {
- qm.dispose();
- } else {
- if(mode == 0 && type > 0) {
- qm.dispose();
- return;
- }
-
- if (mode == 1)
- status++;
- else
- status--;
-
- if (status == 0) {
- var c = 0;
-
- for(var i = 0; i < 4; i++) {
- if(qm.getQuestProgress(3926, i) == 1) {
- c++;
- }
- }
-
- if(c == 4) {
- qm.sendNext("You delivered all the jewels, well done!");
- qm.gainExp(6500);
- qm.forceCompleteQuest();
- } else {
- qm.sendNext("Have you brought all the jewels from the Red Scorpions? They have to be delivered to the Residential areas of the Sand Bandits.");
- }
- } else if (status == 1) {
- qm.dispose();
- }
- }
-}
diff --git a/scripts/quest/3927.js b/scripts/quest/3927.js
deleted file mode 100644
index 5fb4319180..0000000000
--- a/scripts/quest/3927.js
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- This file is part of the OdinMS Maple Story Server
- Copyright (C) 2008 Patrick Huy
- Matthias Butz
- Jan Christian Meyer
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation version 3 as published by
- the Free Software Foundation. You may not use, modify or distribute
- this program under any other version of the GNU Affero General Public
- License.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-*/
-/*
- Author : Ronan Lana
-*/
-
-var status = -1;
-
-function end(mode, type, selection) {
- if (mode == -1) {
- qm.dispose();
- } else {
- if (mode == 0 && status == 0) {
- qm.dispose();
- return;
- }
-
- if (mode == 1)
- status++;
- else
- status--;
-
-
- if(qm.getQuestProgress(3927) == 0) { // didn't find the wall yet, eh?
- qm.sendOk("Did you find the wall? Look closely, the wall is more near than you think!");
- qm.dispose();
- return;
- }
-
- if (status == 0) {
- qm.sendSimple("Did you find the wall?\r\n#L0##b I did, but... I have no idea what it's talking about.#l");
- } else if (status == 1) {
- qm.sendSimple("What did it say?\r\n#L0##b 'If I had an iron hammer and a dagger, a bow and an arrow...'#l\r\n#L1# 'Byron S2 Sirin'#l\r\n#L2# 'Ahhh I forgot.'");
- } else if (status == 2) {
- if(selection == 0) {
- qm.sendOk("If I had an iron hammer and a dagger... a bow and an arrow... what does that mean? Do you want me to tell you? I don't know myself. It's something you should think about. If you need a clue... it would go something like... a weapon is just an item... until someone uses it...?");
- } else if(selection == 1) {
- qm.sendOk("Man, Jiyur wrote on the wall again! Arrgh!!");
- qm.dispose();
- return;
- } else {
- qm.sendOk("What? You forgot? Do you remember where it was written?");
- qm.dispose();
- return;
- }
- } else if (status == 3) {
- qm.gainExp(1000);
- qm.forceCompleteQuest();
- qm.dispose();
- }
- }
-}
\ No newline at end of file
diff --git a/scripts/quest/3929.js b/scripts/quest/3929.js
deleted file mode 100644
index 26b254eba3..0000000000
--- a/scripts/quest/3929.js
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- 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 .
-*/
-/* Sejan's Test
- Food delivery on Ariant
- */
-
-var status = -1;
-
-function end(mode, type, selection) {
- if (mode == -1) {
- qm.dispose();
- } else {
- if(mode == 0 && type > 0) {
- qm.dispose();
- return;
- }
-
- if (mode == 1)
- status++;
- else
- status--;
-
- if (status == 0) {
- var c = 0;
-
- for(var i = 0; i < 4; i++) {
- if(qm.getQuestProgress(3929, i) == 1) {
- c++;
- }
- }
-
- if(c == 4) {
- qm.sendNext("You delivered all the food, good.");
- qm.gainExp(2000);
- qm.forceCompleteQuest();
- } else {
- var missed = (4 - qm.getItemQuantity(4031580)) - c;
- if(missed > 0) {
- if(qm.canHold(4031580, missed)) {
- qm.gainItem(4031580, missed);
- qm.sendNext("Hey, what are you trying to pull on? To pass my test you must deliver all the foods to the Residential areas.");
- } else {
- qm.sendNext("You don't completed the task, neither has slots available on the inventory to get the food. Free a slot on your ETC please.");
- }
- } else {
- qm.sendNext("Hey, what are you trying to pull on? To pass my test you must to deliver all the foods to the Residential areas.");
- }
- }
- } else if (status == 1) {
- qm.dispose();
- }
- }
-}
diff --git a/scripts/quest/6033.js b/scripts/quest/6033.js
index 3362c48d8f..8016d8279b 100644
--- a/scripts/quest/6033.js
+++ b/scripts/quest/6033.js
@@ -41,8 +41,8 @@ function end(mode, type, selection) {
if (status == 0) {
qm.sendNext("Hm, so you claim to have brought the #b#t4260003##k? Ok, let's take a look into it.");
} else if (status == 1) {
- if(qm.getQuestProgress(6033) == 1 && qm.haveItem(4260003, 1)) {
- qm.sendNext("You indeed have crafted a fine piece of Monster Crystal, I see. You passed! Now, I shall teach you the next steps of the Maker skill. Keep the monster crystal with you as well, it's your work.");
+ if(qm.getQuestProgressInt(6033) == 1 && qm.haveItem(4260003, 1)) {
+ qm.sendNextPrev("You indeed have crafted a fine piece of Monster Crystal, I see. You passed! Now, I shall teach you the next steps of the Maker skill. Keep the monster crystal with you as well, it's your work.");
} else {
qm.sendNext("Hey, what's wrong? I did tell you to make a monster crystal to pass my test, didn't I? Buying one or crafting before the start of the test is NOT part of the deal. Go craft me an #b#t4260003##k.");
qm.dispose();
diff --git a/scripts/quest/6410.js b/scripts/quest/6410.js
deleted file mode 100644
index cf9ae4054a..0000000000
--- a/scripts/quest/6410.js
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- 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 .
-*/
-/*
- Hypnotize skill quest
- */
-
-var status = -1;
-
-function end(mode, type, selection) {
- if (mode == -1) {
- qm.dispose();
- } else {
- if(mode == 0 && type > 0) {
- qm.dispose();
- return;
- }
-
- if (mode == 1)
- status++;
- else
- status--;
-
- if (status == 0) {
- if (qm.getQuestProgress(6410, 0) == 0) {
- qm.sendOk("You must save #r#p2095000##k first!");
- qm.dispose();
- } else {
- qm.sendNext("Again, thank you so much for rescuing me. I don't know how to repay you for all this... both Shulynch and you are the nicest people I have encountered. If you approach the mobs the same way you approached me, they may all end up becoming friends with you, as well. Please never lose the kindness you have in you.");
- }
- } else if (status == 1) {
- qm.sendNext("(Friends with the mobs... never lose the kindness.)\r\n\r\n #s5221009# #b#q5221009##k");
- } else if (status == 2) {
- qm.gainExp(1200000);
- qm.teachSkill(5221009, 0, 10, -1);
-
- qm.forceCompleteQuest();
- qm.dispose();
- }
- }
-}
\ No newline at end of file
diff --git a/scripts/reactor/1209000.js b/scripts/reactor/1209000.js
index 4f830d783f..915458338b 100644
--- a/scripts/reactor/1209000.js
+++ b/scripts/reactor/1209000.js
@@ -24,6 +24,10 @@
*/
function act() { // string visibility thanks to ProXAIMeRx & Glvelturall
- if (rm.isQuestStarted(6400)) rm.setQuestProgress(6400, 0, 2);
- rm.message("Real Bart has found. Return to Jonathan through portal.");
+ if (rm.isQuestStarted(6400)) {
+ rm.setQuestProgress(6400, 1, 2);
+ rm.setQuestProgress(6400, 6401, "q3");
+ }
+
+ rm.message("Real Bart has been found. Return to Jonathan through the portal.");
}
\ No newline at end of file
diff --git a/src/client/MapleCharacter.java b/src/client/MapleCharacter.java
index 3727d274df..43ad05aaeb 100644
--- a/src/client/MapleCharacter.java
+++ b/src/client/MapleCharacter.java
@@ -946,6 +946,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
for(MapleSummon ms: this.getSummonsValues()) {
getMap().broadcastNONGMMessage(this, MaplePacketCreator.spawnSummon(ms, false), false);
}
+
+ for (MapleMapObject mo : this.getMap().getMonsters()) {
+ MapleMonster m = (MapleMonster) mo;
+ m.aggroUpdateController();
+ }
} else {
this.hidden = true;
announce(MaplePacketCreator.getGMEffect(0x10, (byte) 1));
@@ -3050,6 +3055,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
deletedCoupon = true;
}
} else {
+ MaplePet pet = item.getPet(); // thanks Lame for noticing pets not getting despawned after expiration time
+ if (pet != null) {
+ unequipPet(pet, true);
+ }
+
if (ItemConstants.isExpirablePet(item.getItemId())) {
client.announce(MaplePacketCreator.itemExpired(item.getItemId()));
toberemove.add(item);
@@ -4711,19 +4721,23 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
return client.getAbstractPlayerInteraction();
}
- public final List getCompletedQuests() {
+ private List getQuests() {
synchronized (quests) {
- List ret = new LinkedList<>();
- for (MapleQuestStatus q : quests.values()) {
- if (q.getStatus().equals(MapleQuestStatus.Status.COMPLETED)) {
- ret.add(q);
- }
- }
-
- return Collections.unmodifiableList(ret);
+ return new ArrayList<>(quests.values());
}
}
+ public final List getCompletedQuests() {
+ List ret = new LinkedList<>();
+ for (MapleQuestStatus qs : getQuests()) {
+ if (qs.getStatus().equals(MapleQuestStatus.Status.COMPLETED)) {
+ ret.add(qs);
+ }
+ }
+
+ return Collections.unmodifiableList(ret);
+ }
+
public List getCrushRings() {
Collections.sort(crushRings);
return crushRings;
@@ -5780,19 +5794,19 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
- public final MapleQuestStatus getMapleQuestStatus(final int quest) {
- synchronized (quests) {
- MapleQuestStatus mqs = quests.get((short) quest);
- return mqs;
- }
+ public MapleQuestStatus getQuest(final int quest) {
+ return getQuest(MapleQuest.getInstance(quest));
}
-
+
public MapleQuestStatus getQuest(MapleQuest quest) {
synchronized (quests) {
- if (!quests.containsKey(quest.getId())) {
- return new MapleQuestStatus(quest, MapleQuestStatus.Status.NOT_STARTED);
+ short questid = quest.getId();
+ MapleQuestStatus qs = quests.get(questid);
+ if (qs == null) {
+ qs = new MapleQuestStatus(quest, MapleQuestStatus.Status.NOT_STARTED);
+ quests.put(questid, qs);
}
- return quests.get(quest.getId());
+ return qs;
}
}
@@ -5928,32 +5942,15 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public final List getStartedQuests() {
- synchronized (quests) {
- List ret = new LinkedList<>();
- for (MapleQuestStatus q : quests.values()) {
- if (q.getStatus().equals(MapleQuestStatus.Status.STARTED)) {
- ret.add(q);
- }
+ List ret = new LinkedList<>();
+ for (MapleQuestStatus qs : getQuests()) {
+ if (qs.getStatus().equals(MapleQuestStatus.Status.STARTED)) {
+ ret.add(qs);
}
- return Collections.unmodifiableList(ret);
}
+ return Collections.unmodifiableList(ret);
}
-
- public final int getStartedQuestsSize() {
- synchronized (quests) {
- int i = 0;
- for (MapleQuestStatus q : quests.values()) {
- if (q.getStatus().equals(MapleQuestStatus.Status.STARTED)) {
- if (q.getQuest().getInfoNumber() > 0) {
- i++;
- }
- i++;
- }
- }
- return i;
- }
- }
-
+
public MapleStatEffect getStatForBuff(MapleBuffStat effect) {
effLock.lock();
chrLock.lock();
@@ -7491,7 +7488,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public void reloadQuestExpirations() {
- for(MapleQuestStatus mqs: quests.values()) {
+ for(MapleQuestStatus mqs: getQuests()) {
if(mqs.getExpirationTime() > 0) {
questTimeLimit2(mqs.getQuest(), mqs.getExpirationTime());
}
@@ -7545,31 +7542,31 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
announce(MaplePacketCreator.sendYellowTip(m));
}
- public void updateQuestMobCount(int id) {
+ public void raiseQuestMobCount(int id) {
// It seems nexon uses monsters that don't exist in the WZ (except string) to merge multiple mobs together for these 3 monsters.
// We also want to run mobKilled for both since there are some quest that don't use the updated ID...
if (id == 1110100 || id == 1110130) {
- updateQuestMobCount(9101000);
+ raiseQuestMobCount(9101000);
} else if (id == 2230101 || id == 2230131) {
- updateQuestMobCount(9101001);
+ raiseQuestMobCount(9101001);
} else if (id == 1140100 || id == 1140130) {
- updateQuestMobCount(9101002);
+ raiseQuestMobCount(9101002);
}
int lastQuestProcessed = 0;
try {
synchronized (quests) {
- for (MapleQuestStatus q : quests.values()) {
- lastQuestProcessed = q.getQuest().getId();
- if (q.getStatus() == MapleQuestStatus.Status.COMPLETED || q.getQuest().canComplete(this, null)) {
+ for (MapleQuestStatus qs : getQuests()) {
+ lastQuestProcessed = qs.getQuest().getId();
+ if (qs.getStatus() == MapleQuestStatus.Status.COMPLETED || qs.getQuest().canComplete(this, null)) {
continue;
}
- String progress = q.getProgress(id);
- if (!progress.isEmpty() && Integer.parseInt(progress) >= q.getQuest().getMobAmountNeeded(id)) {
- continue;
- }
- if (q.progress(id)) {
- announceUpdateQuest(DelayedQuestUpdate.UPDATE, q, false);
+
+ if (qs.progress(id)) {
+ announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, false);
+ if (qs.getInfoNumber() > 0) {
+ announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, true);
+ }
}
}
}
@@ -8692,36 +8689,33 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
psf = con.prepareStatement("INSERT INTO medalmaps VALUES (DEFAULT, ?, ?, ?)");
ps.setInt(1, id);
- synchronized (quests) {
- for (MapleQuestStatus q : quests.values()) {
- ps.setInt(2, q.getQuest().getId());
- ps.setInt(3, q.getStatus().getId());
- ps.setInt(4, (int) (q.getCompletionTime() / 1000));
- ps.setLong(5, q.getExpirationTime());
- ps.setInt(6, q.getForfeited());
- ps.setInt(7, q.getCompleted());
- ps.executeUpdate();
- try (ResultSet rs = ps.getGeneratedKeys()) {
- rs.next();
- for (int mob : q.getProgress().keySet()) {
- pse.setInt(1, id);
- pse.setInt(2, rs.getInt(1));
- pse.setInt(3, mob);
- pse.setString(4, q.getProgress(mob));
- pse.addBatch();
- }
- for (int i = 0; i < q.getMedalMaps().size(); i++) {
- psf.setInt(1, id);
- psf.setInt(2, rs.getInt(1));
- psf.setInt(3, q.getMedalMaps().get(i));
- psf.addBatch();
- }
- pse.executeBatch();
- psf.executeBatch();
+ for (MapleQuestStatus qs : getQuests()) {
+ ps.setInt(2, qs.getQuest().getId());
+ ps.setInt(3, qs.getStatus().getId());
+ ps.setInt(4, (int) (qs.getCompletionTime() / 1000));
+ ps.setLong(5, qs.getExpirationTime());
+ ps.setInt(6, qs.getForfeited());
+ ps.setInt(7, qs.getCompleted());
+ ps.executeUpdate();
+ try (ResultSet rs = ps.getGeneratedKeys()) {
+ rs.next();
+ for (int mob : qs.getProgress().keySet()) {
+ pse.setInt(1, id);
+ pse.setInt(2, rs.getInt(1));
+ pse.setInt(3, mob);
+ pse.setString(4, qs.getProgress(mob));
+ pse.addBatch();
}
+ for (int i = 0; i < qs.getMedalMaps().size(); i++) {
+ psf.setInt(1, id);
+ psf.setInt(2, rs.getInt(1));
+ psf.setInt(3, qs.getMedalMaps().get(i));
+ psf.addBatch();
+ }
+ pse.executeBatch();
+ psf.executeBatch();
}
}
-
}
psf.close();
ps.close();
@@ -9149,7 +9143,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
MapleKeyBinding autohpPot = this.getKeymap().get(91);
if (autohpPot != null) {
int autohpItemid = autohpPot.getAction();
- if (((float) this.getHp()) / this.getMaxHp() <= this.getAutopotHpAlert()) { // try within user settings... thanks Lame, Optimist, Stealth2800
+ if (((float) this.getHp()) / this.getCurrentMaxHp() <= this.getAutopotHpAlert()) { // try within user settings... thanks Lame, Optimist, Stealth2800
Item autohpItem = this.getInventory(MapleInventoryType.USE).findById(autohpItemid);
if (autohpItem != null) {
PetAutopotProcessor.runAutopotAction(client, autohpItem.getPosition(), autohpItemid);
@@ -9162,7 +9156,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
MapleKeyBinding autompPot = this.getKeymap().get(92);
if (autompPot != null) {
int autompItemid = autompPot.getAction();
- if (((float) this.getMp()) / this.getMaxMp() <= this.getAutopotMpAlert()) {
+ if (((float) this.getMp()) / this.getCurrentMaxMp() <= this.getAutopotMpAlert()) {
Item autompItem = this.getInventory(MapleInventoryType.USE).findById(autompItemid);
if (autompItem != null) {
PetAutopotProcessor.runAutopotAction(client, autompItem.getPosition(), autompItemid);
@@ -9845,26 +9839,23 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
}
-
- public String getQuestInfo(int quest) {
- MapleQuestStatus qs = getQuest(MapleQuest.getInstance(quest));
- return qs.getInfo();
- }
-
- public void updateQuestInfo(int quest, String info) {
- MapleQuest q = MapleQuest.getInstance(quest);
+
+ public void setQuestProgress(int id, int infoNumber, String progress) {
+ MapleQuest q = MapleQuest.getInstance(id);
MapleQuestStatus qs = getQuest(q);
- qs.setInfo(info);
-
- synchronized (quests) {
- quests.put(q.getId(), qs);
+
+ if (qs.getInfoNumber() == infoNumber && infoNumber > 0) {
+ MapleQuest iq = MapleQuest.getInstance(infoNumber);
+ MapleQuestStatus iqs = getQuest(iq);
+ iqs.setProgress(0, progress);
+ } else {
+ qs.setProgress(infoNumber, progress); // quest progress is thoroughly a string match, infoNumber is actually another questid
}
announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, false);
- if (qs.getQuest().getInfoNumber() > 0) {
+ if (qs.getInfoNumber() > 0) {
announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, true);
}
- announce(MaplePacketCreator.updateQuestInfo((short) qs.getQuest().getId(), qs.getNpc()));
}
public void awardQuestPoint(int awardedPoints) {
@@ -9886,15 +9877,15 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public enum DelayedQuestUpdate { // quest updates allow player actions during NPC talk...
- UPDATE, FORFEIT, COMPLETE
+ UPDATE, FORFEIT, COMPLETE, INFO
}
- private void announceUpdateQuestInternal(Pair questUpdate) {
+ private void announceUpdateQuestInternal(MapleCharacter chr, Pair questUpdate) {
Object[] objs = questUpdate.getRight();
switch (questUpdate.getLeft()) {
case UPDATE:
- announce(MaplePacketCreator.updateQuest((MapleQuestStatus) objs[0], (Boolean) objs[1]));
+ announce(MaplePacketCreator.updateQuest(chr, (MapleQuestStatus) objs[0], (Boolean) objs[1]));
break;
case FORFEIT:
@@ -9904,6 +9895,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
case COMPLETE:
announce(MaplePacketCreator.completeQuest((Short) objs[0], (Long) objs[1]));
break;
+
+ case INFO:
+ MapleQuestStatus qs = (MapleQuestStatus) objs[0];
+ announce(MaplePacketCreator.updateQuestInfo(qs.getQuest().getId(), qs.getNpc()));
+ break;
}
}
@@ -9915,7 +9911,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
npcUpdateQuests.add(p);
}
} else {
- announceUpdateQuestInternal(p);
+ announceUpdateQuestInternal(this, p);
}
}
@@ -9928,49 +9924,52 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
for (Pair q : qmQuestUpdateList) {
- announceUpdateQuestInternal(q);
+ announceUpdateQuestInternal(this, q);
}
}
- public void updateQuest(MapleQuestStatus quest) {
+ public void updateQuestStatus(MapleQuestStatus qs) {
synchronized (quests) {
- quests.put(quest.getQuestID(), quest);
+ quests.put(qs.getQuestID(), qs);
}
- if (quest.getStatus().equals(MapleQuestStatus.Status.STARTED)) {
- announceUpdateQuest(DelayedQuestUpdate.UPDATE, quest, false);
- if (quest.getQuest().getInfoNumber() > 0) {
- announceUpdateQuest(DelayedQuestUpdate.UPDATE, quest, true);
+ if (qs.getStatus().equals(MapleQuestStatus.Status.STARTED)) {
+ announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, false);
+ if (qs.getInfoNumber() > 0) {
+ announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, true);
}
- announce(MaplePacketCreator.updateQuestInfo((short) quest.getQuest().getId(), quest.getNpc()));
- } else if (quest.getStatus().equals(MapleQuestStatus.Status.COMPLETED)) {
- MapleQuest mquest = quest.getQuest();
+ announceUpdateQuest(DelayedQuestUpdate.INFO, qs);
+ } else if (qs.getStatus().equals(MapleQuestStatus.Status.COMPLETED)) {
+ MapleQuest mquest = qs.getQuest();
short questid = mquest.getId();
if (!mquest.isSameDayRepeatable() && !MapleQuest.isExploitableQuest(questid)) {
awardQuestPoint(YamlConfig.config.server.QUEST_POINT_PER_QUEST_COMPLETE);
}
- quest.setCompleted(quest.getCompleted() + 1); // count quest completed Jayd's idea
+ qs.setCompleted(qs.getCompleted() + 1); // count quest completed Jayd's idea
- announceUpdateQuest(DelayedQuestUpdate.COMPLETE, questid, quest.getCompletionTime());
- } else if (quest.getStatus().equals(MapleQuestStatus.Status.NOT_STARTED)) {
- announceUpdateQuest(DelayedQuestUpdate.UPDATE, quest, false);
- if (quest.getQuest().getInfoNumber() > 0) {
- announceUpdateQuest(DelayedQuestUpdate.UPDATE, quest, true);
+ announceUpdateQuest(DelayedQuestUpdate.COMPLETE, questid, qs.getCompletionTime());
+ announceUpdateQuest(DelayedQuestUpdate.INFO, qs);
+ } else if (qs.getStatus().equals(MapleQuestStatus.Status.NOT_STARTED)) {
+ announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, false);
+ if (qs.getInfoNumber() > 0) {
+ announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, true);
}
}
}
-
+
private void expireQuest(MapleQuest quest) {
- if(getQuestStatus(quest.getId()) == MapleQuestStatus.Status.COMPLETED.getId()) {
+ MapleQuestStatus mqs = getQuest(quest);
+ if(mqs.getStatus().equals(MapleQuestStatus.Status.COMPLETED)) {
return;
}
- if(System.currentTimeMillis() < getMapleQuestStatus(quest.getId()).getExpirationTime()) {
+
+ if(System.currentTimeMillis() < mqs.getExpirationTime()) {
return;
}
announce(MaplePacketCreator.questExpire(quest.getId()));
MapleQuestStatus newStatus = new MapleQuestStatus(quest, MapleQuestStatus.Status.NOT_STARTED);
- newStatus.setForfeited(getQuest(quest).getForfeited() + 1);
- updateQuest(newStatus);
+ newStatus.setForfeited(mqs.getForfeited() + 1);
+ updateQuestStatus(newStatus);
}
public void cancelQuestExpirationTask() {
@@ -11016,7 +11015,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
try (PreparedStatement ps = con.prepareStatement("UPDATE characters SET world = ?, meso = ?, guildid = ?, guildrank = ? WHERE id = ?")) {
ps.setInt(1, newWorld);
- ps.setInt(2, Math.min(mesos, 1000000)); //might want a limit in YamlConfig.config.server.for this
+ ps.setInt(2, Math.min(mesos, 1000000)); // might want a limit in "YamlConfig.config.server" for this
ps.setInt(3, 0);
ps.setInt(4, 5);
ps.setInt(5, characterId);
diff --git a/src/client/MapleClient.java b/src/client/MapleClient.java
index a3ea8f6986..887f225e9e 100644
--- a/src/client/MapleClient.java
+++ b/src/client/MapleClient.java
@@ -1002,7 +1002,7 @@ public class MapleClient {
if (quest.getTimeLimit() > 0) {
MapleQuestStatus newStatus = new MapleQuestStatus(quest, MapleQuestStatus.Status.NOT_STARTED);
newStatus.setForfeited(player.getQuest(quest).getForfeited() + 1);
- player.updateQuest(newStatus);
+ player.updateQuestStatus(newStatus);
}
}
if (guild != null) {
diff --git a/src/client/MapleQuestStatus.java b/src/client/MapleQuestStatus.java
index 9e0ccc9dd1..e7ce741d57 100644
--- a/src/client/MapleQuestStatus.java
+++ b/src/client/MapleQuestStatus.java
@@ -151,14 +151,20 @@ public class MapleQuestStatus {
}
public boolean progress(int id) {
- if (progress.get(id) != null) {
- int current = Integer.parseInt(progress.get(id));
- String str = StringUtil.getLeftPaddedStr(Integer.toString(current + 1), '0', 3);
- progress.put(id, str);
- //this.setUpdated();
- return true;
+ String currentStr = progress.get(id);
+ if (currentStr == null) {
+ return false;
}
- return false;
+
+ int current = Integer.parseInt(currentStr);
+ if (current >= this.getQuest().getMobAmountNeeded(id)) {
+ return false;
+ }
+
+ String str = StringUtil.getLeftPaddedStr(Integer.toString(++current), '0', 3);
+ progress.put(id, str);
+ //this.setUpdated();
+ return true;
}
public void setProgress(int id, String pr) {
@@ -169,15 +175,14 @@ public class MapleQuestStatus {
public boolean madeProgress() {
return progress.size() > 0;
}
-
- public Integer getAnyProgressKey() {
- if (!progress.isEmpty()) return progress.entrySet().iterator().next().getKey();
- return 0;
- }
public String getProgress(int id) {
- if (progress.get(id) == null) return "";
- return progress.get(id);
+ String ret = progress.get(id);
+ if (ret == null) {
+ return "";
+ } else {
+ return ret;
+ }
}
public void resetProgress(int id) {
@@ -193,6 +198,27 @@ public class MapleQuestStatus {
public Map getProgress() {
return Collections.unmodifiableMap(progress);
}
+
+ public short getInfoNumber() {
+ MapleQuest q = this.getQuest();
+ Status s = this.getStatus();
+
+ return q.getInfoNumber(s);
+ }
+
+ public String getInfoEx(int index) {
+ MapleQuest q = this.getQuest();
+ Status s = this.getStatus();
+
+ return q.getInfoEx(s, index);
+ }
+
+ public List getInfoEx() {
+ MapleQuest q = this.getQuest();
+ Status s = this.getStatus();
+
+ return q.getInfoEx(s);
+ }
public long getCompletionTime() {
return completionTime;
@@ -217,18 +243,6 @@ public class MapleQuestStatus {
public int getCompleted() {
return completed;
}
-
- public String getInfo() {
- if(!progress.containsKey(0) && !getMedalMaps().isEmpty()) {
- return Integer.toString(getMedalProgress());
- }
- return getProgress(0);
- }
-
- public void setInfo(String newInfo) {
- progress.put(0, newInfo);
- //this.setUpdated();
- }
public void setForfeited(int forfeited) {
if (forfeited >= this.forfeited) {
@@ -254,11 +268,11 @@ public class MapleQuestStatus {
return customData;
}
- public String getQuestData() {
+ public String getProgressData() {
StringBuilder str = new StringBuilder();
for (String ps : progress.values()) {
str.append(ps);
}
return str.toString();
}
-}
\ No newline at end of file
+}
diff --git a/src/client/command/commands/gm5/SetCommand.java b/src/client/command/commands/gm5/SetCommand.java
index 53ee949184..898e8f6b7b 100644
--- a/src/client/command/commands/gm5/SetCommand.java
+++ b/src/client/command/commands/gm5/SetCommand.java
@@ -25,7 +25,7 @@ package client.command.commands.gm5;
import client.command.Command;
import client.MapleClient;
-import config.YamlConfig;
+import constants.net.ServerConstants;
public class SetCommand extends Command {
{
@@ -35,7 +35,7 @@ public class SetCommand extends Command {
@Override
public void execute(MapleClient c, String[] params) {
for (int i = 0; i < params.length; i++) {
- YamlConfig.config.server.DEBUG_VALUES[i] = Integer.parseInt(params[i]);
+ ServerConstants.DEBUG_VALUES[i] = Integer.parseInt(params[i]);
}
}
}
diff --git a/src/config/ServerConfig.java b/src/config/ServerConfig.java
index 18343598d6..ccc0a8f7c8 100644
--- a/src/config/ServerConfig.java
+++ b/src/config/ServerConfig.java
@@ -301,6 +301,4 @@ public class ServerConfig {
//Event End Timestamp
public long EVENT_END_TIMESTAMP;
- //Debug Variables
- public int DEBUG_VALUES[];
}
diff --git a/src/config/YamlConfig.java b/src/config/YamlConfig.java
index 0af88cad37..c8adc338d1 100644
--- a/src/config/YamlConfig.java
+++ b/src/config/YamlConfig.java
@@ -1,10 +1,9 @@
package config;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import com.esotericsoftware.yamlbeans.YamlReader;
-import java.io.File;
import java.io.FileNotFoundException;
+import java.io.FileReader;
import java.io.IOException;
import java.util.List;
@@ -12,13 +11,16 @@ import java.util.List;
public class YamlConfig {
public static final YamlConfig config = fromFile("config.yaml");
+
public List worlds;
public ServerConfig server;
public static YamlConfig fromFile(String filename) {
- ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
try {
- return mapper.readValue(new File(filename), YamlConfig.class);
+ YamlReader reader = new YamlReader(new FileReader(filename));
+ YamlConfig config = reader.read(YamlConfig.class);
+ reader.close();
+ return config;
} catch (FileNotFoundException e) {
String message = "Could not read config file " + filename + ": " + e.getMessage();
throw new RuntimeException(message);
diff --git a/src/constants/net/ServerConstants.java b/src/constants/net/ServerConstants.java
index f151bc3f31..869a135f5d 100644
--- a/src/constants/net/ServerConstants.java
+++ b/src/constants/net/ServerConstants.java
@@ -1,313 +1,16 @@
package constants.net;
public class ServerConstants {
+
//Server Version
public static short VERSION = 83;
//Java Configuration
public static final boolean JAVA_8 = getJavaVersion() >= 8; //Max amount of times a party leader is allowed to persist on the Party Search before entry expiration (thus needing to manually restart the Party Search to be able to search for members).
-
- //Login Configuration
- public static final int WLDLIST_SIZE = 21; //Max possible worlds on the server.
- public static final int CHANNEL_SIZE = 20; //Max possible channels per world (which is 20, based on the channel list on login phase).
- public static final int CHANNEL_LOAD = 100; //Max players per channel (limit actually used to calculate the World server capacity).
- public static final int CHANNEL_LOCKS = 20; //Total number of structure management locks each channel has.
- public static final long RESPAWN_INTERVAL = 10 * 1000; //10 seconds, 10000.
- public static final long PURGING_INTERVAL = 5 * 60 * 1000;
- public static final long RANKING_INTERVAL = 60 * 60 * 1000; //60 minutes, 3600000.
- public static final long COUPON_INTERVAL = 60 * 60 * 1000; //60 minutes, 3600000.
- public static final long UPDATE_INTERVAL = 777; //Dictates the frequency on which the "centralized server time" is updated.
-
- public static final boolean ENABLE_PIC = false; //Pick true/false to enable or disable Pic. Delete character requires PIC available.
- public static final boolean ENABLE_PIN = false; //Pick true/false to enable or disable Pin.
-
- public static final int BYPASS_PIC_EXPIRATION = 20; //Enables PIC bypass, which will remain active for that account by that client machine for N minutes. Set 0 to disable.
- public static final int BYPASS_PIN_EXPIRATION = 15; //Enables PIN bypass, which will remain active for that account by that client machine for N minutes. Set 0 to disable.
-
- public static final boolean AUTOMATIC_REGISTER = true; //Automatically register players when they login with a nonexistent username.
- public static final boolean BCRYPT_MIGRATION = true; //Performs a migration from old SHA-1 and SHA-512 password to bcrypt.
- public static final boolean COLLECTIVE_CHARSLOT = false; //Available character slots are contabilized globally rather than per world server.
- public static final boolean DETERRED_MULTICLIENT = false; //Enables detection of multi-client and suspicious remote IP on the login system.
-
- //Besides blocking logging in with several client sessions on the same machine, this also blocks suspicious login attempts for players that tries to login on an account using several diferent remote addresses.
-
- //Multiclient Coordinator Configuration
- public static final int MAX_ALLOWED_ACCOUNT_HWID = 4; //Allows up to N concurrent HWID's for an account. HWID's remains linked to an account longer the more times it's used to login.
- public static final int MAX_ACCOUNT_LOGIN_ATTEMPT = 15; //After N tries on an account, login on that account gets disabled for a short period.
- public static final int LOGIN_ATTEMPT_DURATION = 120; //Period in seconds the login attempt remains registered on the system.
-
- //Ip Configuration
- public static String HOST;
- public static boolean LOCALSERVER;
-
- //Other Configuration
- public static boolean SHUTDOWNHOOK;
-
- //Server Flags
- public static final boolean USE_CUSTOM_KEYSET = true; //Enables auto-setup of the HeavenMS's custom keybindings when creating characters.
- public static final boolean USE_DEBUG = false; //Will enable some text prints on the client, oriented for debugging purposes.
- public static final boolean USE_DEBUG_SHOW_INFO_EQPEXP = false; //Prints on the cmd all equip exp gain info.
- public static boolean USE_DEBUG_SHOW_RCVD_PACKET = false; //Prints on the cmd all received packet ids.
- public static boolean USE_DEBUG_SHOW_RCVD_MVLIFE = false; //Prints on the cmd all received move life content.
- public static final boolean USE_DEBUG_SHOW_PACKET = false;
- public static boolean USE_SUPPLY_RATE_COUPONS = true; //Allows rate coupons to be sold through the Cash Shop.
- public static final boolean USE_IP_VALIDATION = true; //Enables IP checking when logging in.
-
- public static final boolean USE_MAXRANGE = true; //Will send and receive packets from all events on a map, rather than those of only view range.
- public static final boolean USE_MAXRANGE_ECHO_OF_HERO = true;
- public static final boolean USE_MTS = false;
- public static final boolean USE_CPQ = true; //Renders the CPQ available or not.
- public static final boolean USE_AUTOHIDE_GM = false; //When enabled, GMs are automatically hidden when joining. Thanks to Steven Deblois (steven1152).
- public static final boolean USE_BUYBACK_SYSTEM = true; //Enables the HeavenMS-builtin buyback system, to be used by dead players when clicking the MTS button.
- public static final boolean USE_FIXED_RATIO_HPMP_UPDATE = true; //Enables the HeavenMS-builtin HPMP update based on the current pool to max pool ratio.
- public static final boolean USE_FAMILY_SYSTEM = true;
- public static final boolean USE_DUEY = true;
- public static final boolean USE_RANDOMIZE_HPMP_GAIN = true; //Enables randomizing on MaxHP/MaxMP gains and INT accounting for the MaxMP gain on level up.
- public static final boolean USE_STORAGE_ITEM_SORT = true; //Enables storage "Arrange Items" feature.
- public static final boolean USE_ITEM_SORT = true; //Enables inventory "Item Sort/Merge" feature.
- public static final boolean USE_ITEM_SORT_BY_NAME = false; //Item sorting based on name rather than id.
- public static final boolean USE_PARTY_FOR_STARTERS = true; //Players level 10 or below can create/invite other players on the given level range.
- public static final boolean USE_AUTOASSIGN_STARTERS_AP = false; //Beginners level 10 or below have their AP autoassigned (they can't choose to levelup a stat). Set true ONLY if the localhost doesn't support AP assigning for beginners level 10 or below.
- public static final boolean USE_AUTOASSIGN_SECONDARY_CAP = true;//Prevents AP autoassign from spending on secondary stats after the player class' cap (defined on the autoassign handler) has been reached.
- public static final boolean USE_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).
- public static final boolean USE_SERVER_AUTOASSIGNER = true; //HeavenMS-builtin autoassigner, uses algorithm based on distributing AP accordingly with required secondary stat on equipments.
- public static final boolean USE_REFRESH_RANK_MOVE = true;
- public static final boolean USE_ENFORCE_ADMIN_ACCOUNT = false; //Forces accounts having GM characters to be treated as a "GM account" by the client (localhost). Some of the GM account perks is the ability to FLY, but unable to TRADE.
- public static final boolean USE_ENFORCE_NOVICE_EXPRATE = false; //Hardsets experience rate 1x for beginners level 10 or under. Ideal for roaming on novice areas without caring too much about losing some stats.
- public static final boolean USE_ENFORCE_HPMP_SWAP = false; //Forces players to reuse stats (via AP Resetting) located on HP/MP pool only inside the HP/MP stats.
- public static final boolean USE_ENFORCE_MOB_LEVEL_RANGE = true; //Players N levels below the killed mob will gain no experience from defeating it.
- public static final boolean USE_ENFORCE_JOB_LEVEL_RANGE = false;//Caps the player level on the minimum required to advance their current jobs.
- public static final boolean USE_ENFORCE_JOB_SP_RANGE = false; //Caps the player SP level on the total obtainable by their current jobs. After changing jobs, missing SP will be retrieved.
- public static final boolean USE_ENFORCE_ITEM_SUGGESTION = false;//Forces the Owl of Minerva and the Cash Shop to always display the defined item array instead of those featured by the players.
- public static final boolean USE_ENFORCE_UNMERCHABLE_CASH = true;//Forces players to not sell CASH items via merchants, drops of it disappears.
- public static final boolean USE_ENFORCE_UNMERCHABLE_PET = true; //Forces players to not sell pets via merchants, drops of it disappears. (since non-named pets gets dirty name and other possible DB-related issues)
- public static final boolean USE_ENFORCE_MERCHANT_SAVE = true; //Forces automatic DB save on merchant owners, at every item movement on shop.
- public static final boolean USE_ENFORCE_MDOOR_POSITION = false; //Forces mystic door to be spawned near spawnpoints.
- public static final boolean USE_SPAWN_CLEAN_MDOOR = false; //Makes mystic doors to be spawned without deploy animation. This clears disconnecting issues that may happen when trying to cancel doors a couple seconds after deployment.
- public static final boolean USE_SPAWN_LOOT_ON_ANIMATION = false;//Makes loot appear some time after the mob has been killed (following the mob death animation, instead of instantly).
- public static final boolean USE_SPAWN_RELEVANT_LOOT = true; //Forces to only spawn loots that are collectable by the player or any of their party members.
- public static final boolean USE_ERASE_PERMIT_ON_OPENSHOP = true;//Forces "shop permit" item to be consumed when player deploy his/her player shop.
- public static final boolean USE_ERASE_UNTRADEABLE_DROP = true; //Forces flagged untradeable items to disappear when dropped.
- public static final boolean USE_ERASE_PET_ON_EXPIRATION = false;//Forces pets to be removed from inventory when expire time comes, rather than converting it to a doll.
- public static final boolean USE_BUFF_MOST_SIGNIFICANT = true; //When applying buffs, the player will stick with the highest stat boost among the listed, rather than overwriting stats.
- public static final boolean USE_BUFF_EVERLASTING = false; //Every applied buff on players holds expiration time so high it'd be considered permanent. Suggestion thanks to Vcoc.
- public static final boolean USE_MULTIPLE_SAME_EQUIP_DROP = true;//Enables multiple drops by mobs of the same equipment, number of possible drops based on the quantities provided at the drop data.
- public static final boolean USE_BANISHABLE_TOWN_SCROLL = true; //Enables town scrolls to act as if it's a "player banish", rendering the antibanish scroll effect available.
- public static final boolean USE_ENABLE_FULL_RESPAWN = true; //At respawn task, always respawn missing mobs when they're available. Spawn count doesn't depend on how many players are currently there.
- public static final boolean USE_ENABLE_CHAT_LOG = false; //Write in-game chat to log
- public static final boolean USE_REBIRTH_SYSTEM = false; //Flag to enable/disable rebirth system
- public static final boolean USE_MAP_OWNERSHIP_SYSTEM = true; //Flag to enable/disable map ownership system
- public static final boolean USE_FISHING_SYSTEM = true; //Flag to enable/disable custom fishing system
- public static final boolean USE_NPCS_SCRIPTABLE = true; //Flag to enable/disable serverside predefined script NPCs.
-
- //Events/PQs Configuration
- public static final boolean USE_OLD_GMS_STYLED_PQ_NPCS = true; //Enables PQ NPCs with similar behaviour to old GMS style, that skips info about the PQs and immediately tries to register the party in.
- public static final boolean USE_ENABLE_SOLO_EXPEDITIONS = true; //Enables start expeditions with any number of players. This will also bypass all the Zakum prequest.
- public static final boolean USE_ENABLE_DAILY_EXPEDITIONS = false;//Enables daily entry limitations in expeditions.
- public static final boolean USE_ENABLE_RECALL_EVENT = false; //Enables a disconnected player to reaccess the last event instance they were in before logging out. Recall only works if the event isn't cleared or disposed yet. Suggestion thanks to Alisson (Goukken).
-
- //Announcement Configuration
- public static final boolean USE_ANNOUNCE_SHOPITEMSOLD = false; //Automatic message sent to owner when an item from the Player Shop or Hired Merchant is sold.
- public static final boolean USE_ANNOUNCE_CHANGEJOB = false; //Automatic message sent to acquantainces when changing jobs.
-
- //Cash Shop Configuration
- public static final boolean USE_JOINT_CASHSHOP_INVENTORY = true;//Enables usage of a same cash shop inventory for explorers, cygnus and legends. Items from exclusive cash shop inventories won't show up on the shared inventory, though.
- public static final boolean USE_CLEAR_OUTDATED_COUPONS = true; //Enables deletion of older code coupon registry from the DB, freeing so-long irrelevant data.
- public static final boolean ALLOW_CASHSHOP_NAME_CHANGE = true; //Allows players to buy name changes in the cash shop.
- public static final boolean ALLOW_CASHSHOP_WORLD_TRANSFER =true;//Allows players to buy world transfers in the cash shop.
-
- //Maker Configuration
- public static final boolean USE_MAKER_PERMISSIVE_ATKUP = true; //Allows players to use attack-based strengthening gems on non-weapon items.
- public static final boolean USE_MAKER_FEE_HEURISTICS = true; //Apply compiled values for stimulants and reagents into the Maker fee calculations (max error revolves around 50k mesos). Set false to use basic constant values instead (results are never higher than requested by the client-side).
-
- //Custom Configuration
- public static final boolean USE_ENABLE_CUSTOM_NPC_SCRIPT = true;//Enables usage of custom HeavenMS NPC scripts (Agent E, Coco, etc). Will not disable Abdula (it's actually useful for the gameplay) or quests.
- public static final boolean USE_STARTER_MERGE = false; //Allows any players to use the Equipment Merge custom mechanic (as opposed to the high-level, Maker lv3 requisites).
-
- //Commands Configuration
- public static final boolean BLOCK_GENERATE_CASH_ITEM = false; //Prevents creation of cash items with the item/drop command.
- public static final boolean USE_WHOLE_SERVER_RANKING = false; //Enables a ranking pool made from every character registered on the server for the "ranks" command, instead of separated by worlds.
-
- //Server Rates And Experience
- public static final int EXP_RATE = 10; //NOTE: World-specific rates within "world.ini" OVERRIDES the default rates from here.
- public static final int MESO_RATE = 10;
- public static final int DROP_RATE = 10;
- public static final int BOSS_DROP_RATE = 10; //NOTE: Boss drop rate OVERRIDES common drop rate, for bosses-only.
- public static final int QUEST_RATE = 5; //Multiplier for Exp & Meso gains when completing a quest. Only available when USE_QUEST_RATE is true. Stacks with server Exp & Meso rates.
- public static final int FISHING_RATE = 10; //Multiplier for success likelihood on meso thrown during fishing.
- public static final int TRAVEL_RATE = 10; //Means of transportation rides/departs using 1/N of the default time.
-
- public static final double EQUIP_EXP_RATE = 1.0; //Rate for equipment exp gain, grows linearly. Set 1.0 for default (about 100~200 same-level range mobs killed to pass equip from level 1 to 2).
- public static final double PQ_BONUS_EXP_RATE = 0.5; //Rate for the PQ exp reward.
-
- public static final byte EXP_SPLIT_LEVEL_INTERVAL = 5; //Non-contributing players must be within N level between the mob to receive EXP.
- public static final byte EXP_SPLIT_LEECH_INTERVAL = 5; //Non-contributing players must be within N level between any contributing party member to receive EXP.
- public static final float EXP_SPLIT_MVP_MOD = 0.2f;
- public static final float EXP_SPLIT_COMMON_MOD = 0.8f;
- public static final float PARTY_BONUS_EXP_RATE = 1.0f; //Rate for the party exp bonus reward.
-
- //Miscellaneous Configuration
- public static String TIMEZONE = "GMT-3";
- public static boolean USE_DISPLAY_NUMBERS_WITH_COMMA = true; //Enforce comma on displayed strings (use this when USE_UNITPRICE_WITH_COMMA is active and you still want to display comma-separated values).
- public static boolean USE_UNITPRICE_WITH_COMMA = true; //Set this accordingly with the layout of the unitPrices on Item.wz XML's, whether it's using commas or dots to represent fractions.
- public static final byte MAX_MONITORED_BUFFSTATS = 5; //Limits accounting for "dormant" buff effects, that should take place when stronger stat buffs expires.
- public static final int MAX_AP = 32767; //Max AP allotted on the auto-assigner.
- public static final int MAX_EVENT_LEVELS = 8; //Event has different levels of rewarding system.
- public static final long BLOCK_NPC_RACE_CONDT = (long)(0.5 * 1000); //Time the player client must wait before reopening a conversation with an NPC.
- public static final long PET_LOOT_UPON_ATTACK = (long)(0.7 * 1000); //Time the pet must wait before trying to pick items up.
- public static final int TOT_MOB_QUEST_REQUIREMENT = 77; //Overwrites old 999-mobs requirement for the ToT questline with new requirement value, set 0 for default.
- public static final int MOB_REACTOR_REFRESH_TIME = 30 * 1000; //Overwrites refresh time for those reactors oriented to inflict damage to bosses (Ice Queen, Riche), set 0 for default.
- public static final int PARTY_SEARCH_REENTRY_LIMIT = 10; //Max amount of times a party leader is allowed to persist on the Party Search before entry expiration (thus needing to manually restart the Party Search to be able to search for members).
- public static final int NAME_CHANGE_COOLDOWN = 30*24*60*60*1000; //Cooldown for name changes, default (GMS) is 30 days.
- public static final int WORLD_TRANSFER_COOLDOWN=NAME_CHANGE_COOLDOWN;//Cooldown for world tranfers, default is same as name change (30 days).
- public static final boolean INSTANT_NAME_CHANGE = false; //Whether or not to wait for server restart to apply name changes. Does on reconnect otherwise (requires queries on every login).
-
- //Dangling Items/Locks Configuration
- public static final int ITEM_EXPIRE_TIME = 3 * 60 * 1000; //Time before items start disappearing. Recommended to be set up to 3 minutes.
- public static final int KITE_EXPIRE_TIME = 60 * 60 * 1000; //Time before kites (cash item) disappears.
- public static final int ITEM_MONITOR_TIME = 5 * 60 * 1000; //Interval between item monitoring tasks on maps, which checks for dangling (null) item objects on the map item history.
- public static final int LOCK_MONITOR_TIME = 30 * 1000; //Waiting time for a lock to be released. If it reaches timeout, a critical server deadlock has made present.
-
- //Map Monitor Configuration
- public static final int ITEM_EXPIRE_CHECK = 10 * 1000; //Interval between item expiring tasks on maps, which checks and makes disappear expired items.
- public static final int ITEM_LIMIT_ON_MAP = 200; //Max number of items allowed on a map.
- public static final int MAP_VISITED_SIZE = 5; //Max length for last mapids visited by a player. This is used to recover and update drops on these maps accordingly with player actions.
- public static final int MAP_DAMAGE_OVERTIME_INTERVAL = 5000;//Interval in milliseconds between map environment damage (e.g. El Nath and Aqua Road surrondings).
-
- //Channel Mob Disease Monitor Configuration
- public static final int MOB_STATUS_MONITOR_PROC = 200; //Frequency in milliseconds between each proc on the mob disease monitor schedule.
- public static final int MOB_STATUS_MONITOR_LIFE = 84; //Idle proc count the mob disease monitor is allowed to be there before closing it due to inactivity.
- public static final int MOB_STATUS_AGGRO_PERSISTENCE = 2; //Idle proc count on aggro update for a mob to keep following the current controller, given him/her is the leading damage dealer.
- public static final int MOB_STATUS_AGGRO_INTERVAL = 5000; //Interval in milliseconds between aggro logistics update.
-
- //Some Gameplay Enhancing Configurations
- //Scroll Configuration
- public static final boolean USE_PERFECT_GM_SCROLL = true; //Scrolls from GMs never uses up slots nor fails.
- public static final boolean USE_PERFECT_SCROLLING = true; //Scrolls doesn't use slots upon failure.
- public static final boolean USE_ENHANCED_CHSCROLL = true; //Equips even more powerful with chaos upgrade.
- public static final boolean USE_ENHANCED_CRAFTING = true; //Apply chaos scroll on every equip crafted.
- public static final boolean USE_ENHANCED_CLNSLATE = true; //Clean slates can be applied to recover successfully used slots as well.
- public static final int SCROLL_CHANCE_ROLLS = 10; //Number of rolls for success on a scroll, set 1 for default.
- public static final int CHSCROLL_STAT_ROLLS = 3; //Number of rolls of stat upgrade on a successfully applied chaos scroll, set 1 for default.
- public static final int CHSCROLL_STAT_RANGE = 6; //Stat upgrade range (-N, N) on chaos scrolls.
-
- //Beginner Skills Configuration
- public static final boolean USE_ULTRA_NIMBLE_FEET = true; //Massive speed & jump upgrade.
- public static final boolean USE_ULTRA_RECOVERY = true; //Massive recovery amounts overtime.
- public static final boolean USE_ULTRA_THREE_SNAILS = true; //Massive damage on shell toss.
-
- //Other Skills Configuration
- public static final boolean USE_FULL_ARAN_SKILLSET = false; //Enables starter availability to all Aran job skills. Suggestion thanks to Masterrulax.
- public static final boolean USE_FAST_REUSE_HERO_WILL = true;//Greatly reduce cooldown on Hero's Will.
- public static final boolean USE_ANTI_IMMUNITY_CRASH = true; //Crash skills additionally removes the mob's invincibility buffs. Suggestion thanks to Celestial.
- public static final boolean USE_UNDISPEL_HOLY_SHIELD = true;//Holy shield buff also prevents players from suffering dispel from mobs.
- public static final boolean USE_FULL_HOLY_SYMBOL = true; //Holy symbol doesn't require EXP sharers to work in full.
-
- //Character Configuration
- public static final boolean USE_ADD_SLOTS_BY_LEVEL = true; //Slots are added each 20 levels.
- public static final boolean USE_ADD_RATES_BY_LEVEL = true; //Rates are added each 20 levels.
- public static final boolean USE_STACK_COUPON_RATES = false; //Multiple coupons effects builds up together.
- public static final boolean USE_PERFECT_PITCH = true; //For lvl 30 or above, each lvlup grants player 1 perfect pitch.
-
- //Quest Configuration
- public static final boolean USE_QUEST_RATE = false; //Exp/Meso gained by quests uses fixed server exp/meso rate times quest rate as multiplier, instead of player rates.
-
- //Quest Points Configuration
- public static final int QUEST_POINT_REPEATABLE_INTERVAL = 24;//Minimum interval between repeatable quest completions for quest points to be awarded.
- public static final int QUEST_POINT_REQUIREMENT = 16; //Exchange factor between N quest points to +1 fame, set 0 to disable the entire quest point mechanism.
- public static final int QUEST_POINT_PER_QUEST_COMPLETE = 4; //Each completed quest awards N quest points, set 0 to disable.
- public static final int QUEST_POINT_PER_EVENT_CLEAR = 1; //Each completed event instance awards N quest points, set 0 to disable.
-
- //Guild Configuration
- public static final int CREATE_GUILD_MIN_PARTNERS = 6; //Minimum number of members on Guild Headquarters to establish a new guild.
- public static final int CREATE_GUILD_COST = 1500000;
- public static final int CHANGE_EMBLEM_COST = 5000000;
- public static final int EXPAND_GUILD_BASE_COST = 500000;
- public static final int EXPAND_GUILD_TIER_COST = 1000000;
- public static final int EXPAND_GUILD_MAX_COST = 5000000;
-
- //Family Configuration
- public static final int FAMILY_REP_PER_KILL = 4; //Amount of rep gained per monster kill.
- public static final int FAMILY_REP_PER_BOSS_KILL = 20; //Amount of rep gained per boss kill.
- public static final int FAMILY_REP_PER_LEVELUP = 200; //Amount of rep gained upon leveling up.
- public static final int FAMILY_MAX_GENERATIONS = 1000; //Maximum depth of family tree. (Distance from leader to farthest junior)
-
- //Equipment Configuration
- public static final boolean USE_EQUIPMNT_LVLUP_SLOTS = true;//Equips can upgrade slots at level up.
- public static final boolean USE_EQUIPMNT_LVLUP_POWER = true;//Enable more powerful stat upgrades at equip level up.
- public static final boolean USE_EQUIPMNT_LVLUP_CASH = true; //Enable equip leveling up on cash equipments as well.
- public static final boolean USE_SPIKES_AVOID_BANISH = true; //Shoes equipped with spikes prevents mobs from banishing wearer.
- public static final int MAX_EQUIPMNT_LVLUP_STAT_UP = 10000; //Max stat upgrade an equipment can have on a levelup.
- public static final int MAX_EQUIPMNT_STAT = 32767; //Max stat on an equipment by leveling up.
- public static final int USE_EQUIPMNT_LVLUP = 7; //All equips lvlup at max level of N, set 1 to disable.
-
- //Map-Chair Configuration
- public static final boolean USE_CHAIR_EXTRAHEAL = true; //Enable map chairs to further recover player's HP and MP (player must have the Chair Mastery skill).
- public static final byte CHAIR_EXTRA_HEAL_MULTIPLIER = 10; //Due to only being able to be send up-to-255 heal values, values being actually updated is the one displayed times this.
- public static final int CHAIR_EXTRA_HEAL_MAX_DELAY = 21; //Players are expected to recover fully after using this skill for N seconds.
-
- //Player NPC Configuration
- public static final int PLAYERNPC_INITIAL_X = 262; //Map frame width for putting PlayerNPCs.
- public static final int PLAYERNPC_INITIAL_Y = 262; //Map frame height for putting PlayerNPCs.
- public static final int PLAYERNPC_AREA_X = 320; //Initial width gap between PlayerNPCs.
- public static final int PLAYERNPC_AREA_Y = 160; //Initial height gap between PlayerNPCs.
- public static final int PLAYERNPC_AREA_STEPS = 4; //Max number of times gap is shortened to comport PlayerNPCs.
- public static final boolean PLAYERNPC_ORGANIZE_AREA = true; //Automatically rearranges PlayerNPCs on the map if there is no space set the new NPC. Current distance gap between NPCs is decreased to solve this issue.
- public static final boolean PLAYERNPC_AUTODEPLOY = true; //Makes PlayerNPC automatically deployed on the Hall of Fame at the instant one reaches max level. If false, eligible players must talk to 1st job instructor to deploy a NPC.
-
- //Pet Auto-Pot Configuration
- public static final boolean USE_COMPULSORY_AUTOPOT = true; //Pets will consume as many potions as needed to fulfill the AUTOHP/MP ratio threshold.
- public static final boolean USE_EQUIPS_ON_AUTOPOT = true; //Player MaxHP and MaxMP check values on autopot handler will be updated by the HP/MP bonuses on equipped items.
- public static final double PET_AUTOHP_RATIO = 0.99; //Will automatically consume potions until given ratio of the MaxHP/MaxMP is reached.
- public static final double PET_AUTOMP_RATIO = 0.99;
-
- //Pet & Mount Configuration
- public static final byte PET_EXHAUST_COUNT = 3; //Number of proc counts (1 per minute) on the exhaust schedule for fullness.
- public static final byte MOUNT_EXHAUST_COUNT = 1; //Number of proc counts (1 per minute) on the exhaust schedule for tiredness.
-
- //Pet Hunger Configuration
- public static final boolean PETS_NEVER_HUNGRY = false; //If true, pets and mounts will never grow hungry.
- public static final boolean GM_PETS_NEVER_HUNGRY = true; //If true, pets and mounts owned by GMs will never grow hungry.
-
- //Event Configuration
- public static final int EVENT_MAX_GUILD_QUEUE = 10; //Max number of guilds in queue for GPQ.
- public static final long EVENT_LOBBY_DELAY = 10; //Cooldown duration in seconds before reopening an event lobby.
-
- //Dojo Configuration
- public static final boolean USE_FAST_DOJO_UPGRADE = true; //Reduced Dojo training points amount required for a belt upgrade.
- public static final boolean USE_DEADLY_DOJO = false; //Should bosses really use 1HP,1MP attacks in dojo?
- public static final int DOJO_ENERGY_ATK = 100; //Dojo energy gain when deal attack
- public static final int DOJO_ENERGY_DMG = 20; //Dojo energy gain when recv attack
-
- //Wedding Configuration
- public static final int WEDDING_RESERVATION_DELAY = 3; //Minimum idle slots before processing a wedding reservation.
- public static final int WEDDING_RESERVATION_TIMEOUT = 10; //Limit time in minutes for the couple to show up before cancelling the wedding reservation.
- public static final int WEDDING_RESERVATION_INTERVAL = 60; //Time between wedding starts in minutes.
- public static final int WEDDING_BLESS_EXP = 30000; //Exp gained per bless count.
- public static final int WEDDING_GIFT_LIMIT = 1; //Max number of gifts per person to same wishlist on marriage instances.
- public static final boolean WEDDING_BLESSER_SHOWFX = true; //Pops bubble sprite effect on players blessing the couple. Setting this false shows the blessing effect on the couple instead.
-
- //Buyback Configuration
- public static final boolean USE_BUYBACK_WITH_MESOS = true; //Enables usage of either mesos or NX for the buyback fee.
- public static final float BUYBACK_FEE = 77.70f; //Sets the base amount needed to buyback (level 30 or under will use the base value).
- public static final float BUYBACK_LEVEL_STACK_FEE = 85.47f; //Sets the level-stacking portion of the amount needed to buyback (fee will sum up linearly until level 120, when it reaches the peak).
- public static final int BUYBACK_MESO_MULTIPLIER = 1000; //Sets a multiplier for the fee when using meso as the charge unit.
- public static final int BUYBACK_RETURN_MINUTES = 1; //Sets the maximum amount of time the player can wait before decide to buyback.
- public static final int BUYBACK_COOLDOWN_MINUTES = 7; //Sets the time the player must wait before using buyback again.
-
- // Login timeout by shavit
- public static long TIMEOUT_DURATION = 3600000L; // Kicks clients who don't send any packet to the game server in due time (in millisseconds).
-
- //Event End Timestamp
- public static final long EVENT_END_TIMESTAMP = 1428897600000L;
-
//Debug Variables
public static int DEBUG_VALUES[] = new int[10]; // Field designed for packet testing purposes
-
+
// https://github.com/openstreetmap/josm/blob/a3a6e8a6b657cf4c5b4c64ea14d6e87be6280d65/src/org/openstreetmap/josm/tools/Utils.java#L1566-L1585
/**
* Returns the Java version as an int value.
diff --git a/src/constants/skills/FPWizard.java b/src/constants/skills/FPWizard.java
index 2025c05924..b62b90208c 100644
--- a/src/constants/skills/FPWizard.java
+++ b/src/constants/skills/FPWizard.java
@@ -29,5 +29,6 @@ public class FPWizard {
public static final int MP_EATER = 2100000;
public static final int MEDITATION = 2101001;
public static final int SLOW = 2101003;
+ public static final int FIRE_ARROW = 2101004;
public static final int POISON_BREATH = 2101005;
}
diff --git a/src/net/server/Server.java b/src/net/server/Server.java
index bc7023394c..9ca9dfdf39 100644
--- a/src/net/server/Server.java
+++ b/src/net/server/Server.java
@@ -862,7 +862,7 @@ public class Server {
}
applyAllNameChanges(); //name changes can be missed by INSTANT_NAME_CHANGE
applyAllWorldTransfers();
- MaplePet.clearMissingPetsFromDb();
+ //MaplePet.clearMissingPetsFromDb(); // thanks Optimist for noticing this taking too long to run
MapleCashidGenerator.loadExistentCashIdsFromDb();
IoBuffer.setUseDirectBuffer(false);
@@ -877,17 +877,17 @@ public class Server {
disconnectIdlesOnLoginTask();
long timeLeft = getTimeLeftForNextHour();
- tMan.register(new CharacterDiseaseTask(), ServerConstants.UPDATE_INTERVAL, ServerConstants.UPDATE_INTERVAL);
+ tMan.register(new CharacterDiseaseTask(), YamlConfig.config.server.UPDATE_INTERVAL, YamlConfig.config.server.UPDATE_INTERVAL);
tMan.register(new ReleaseLockTask(), 2 * 60 * 1000, 2 * 60 * 1000);
- tMan.register(new CouponTask(), ServerConstants.COUPON_INTERVAL, timeLeft);
+ tMan.register(new CouponTask(), YamlConfig.config.server.COUPON_INTERVAL, timeLeft);
tMan.register(new RankingCommandTask(), 5 * 60 * 1000, 5 * 60 * 1000);
- tMan.register(new RankingLoginTask(), ServerConstants.RANKING_INTERVAL, timeLeft);
+ tMan.register(new RankingLoginTask(), YamlConfig.config.server.RANKING_INTERVAL, timeLeft);
tMan.register(new LoginCoordinatorTask(), 60 * 60 * 1000, timeLeft);
tMan.register(new EventRecallCoordinatorTask(), 60 * 60 * 1000, timeLeft);
tMan.register(new LoginStorageTask(), 2 * 60 * 1000, 2 * 60 * 1000);
tMan.register(new DueyFredrickTask(), 60 * 60 * 1000, timeLeft);
tMan.register(new InvitationTask(), 30 * 1000, 30 * 1000);
- tMan.register(new RespawnTask(), ServerConstants.RESPAWN_INTERVAL, ServerConstants.RESPAWN_INTERVAL);
+ tMan.register(new RespawnTask(), YamlConfig.config.server.RESPAWN_INTERVAL, YamlConfig.config.server.RESPAWN_INTERVAL);
timeLeft = getTimeLeftForNextDay();
MapleExpeditionBossLog.resetBossLogTable();
@@ -952,6 +952,10 @@ public class Server {
MapleSkillbookInformationProvider.getInstance();
OpcodeConstants.generateOpcodeNames();
CommandsExecutor.getInstance();
+
+ for (Channel ch : this.getAllChannels()) {
+ ch.reloadEventScriptManager();
+ }
}
public static void main(String args[]) {
diff --git a/src/net/server/channel/Channel.java b/src/net/server/channel/Channel.java
index 3ee7013f8b..13542c73b2 100644
--- a/src/net/server/channel/Channel.java
+++ b/src/net/server/channel/Channel.java
@@ -21,13 +21,6 @@ along with this program. If not, see .
*/
package net.server.channel;
-import net.server.channel.task.FaceExpressionScheduler;
-import net.server.channel.task.MobMistScheduler;
-import net.server.channel.task.OverallScheduler;
-import net.server.channel.task.MobAnimationScheduler;
-import net.server.channel.task.MobStatusScheduler;
-import net.server.channel.task.MobClearSkillScheduler;
-import net.server.channel.task.EventScheduler;
import java.io.File;
import java.net.InetSocketAddress;
import java.util.ArrayList;
@@ -57,6 +50,7 @@ import net.mina.MapleCodecFactory;
import net.server.PlayerStorage;
import net.server.Server;
+import net.server.channel.task.*;
import net.server.world.World;
import net.server.world.MapleParty;
@@ -84,7 +78,6 @@ import tools.MaplePacketCreator;
import tools.Pair;
import client.MapleCharacter;
import client.status.MonsterStatusEffect;
-import constants.net.ServerConstants;
import server.maps.MapleMiniDungeonInfo;
public final class Channel {
@@ -148,7 +141,6 @@ public final class Channel {
this.ongoingStartTime = startTime + 10000; // rude approach to a world's last channel boot time, placeholder for the 1st wedding reservation ever
this.mapManager = new MapleMapManager(null, world, channel);
try {
- eventSM = new EventScriptManager(this, getEvents());
port = 7575 + this.channel - 1;
port += (world * 100);
ip = YamlConfig.config.server.HOST + ":" + port;
@@ -163,7 +155,14 @@ public final class Channel {
for (MapleExpeditionType exped : MapleExpeditionType.values()) {
expedType.add(exped);
}
- eventSM.init();
+
+ if (Server.getInstance().isOnline()) { // postpone event loading to improve boot time... thanks Riizade, daronhudson for noticing slow startup times
+ eventSM = new EventScriptManager(this, getEvents());
+ eventSM.init();
+ } else {
+ String[] ev = {};
+ eventSM = new EventScriptManager(null, ev);
+ }
dojoStage = new int[20];
dojoFinishTime = new long[20];
@@ -493,6 +492,11 @@ public final class Channel {
return getPlayerStorage().getCharacterByName(name) != null;
}
+ public boolean isActive() {
+ EventScriptManager esm = this.getEventSM();
+ return esm != null && esm.isActive();
+ }
+
public boolean finishedShutdown() {
return finishedShutdown;
}
diff --git a/src/net/server/channel/handlers/AbstractDealDamageHandler.java b/src/net/server/channel/handlers/AbstractDealDamageHandler.java
index dd9124d1a5..cee5019ea5 100644
--- a/src/net/server/channel/handlers/AbstractDealDamageHandler.java
+++ b/src/net/server/channel/handlers/AbstractDealDamageHandler.java
@@ -163,9 +163,11 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
int mobCount = attackEffect.getMobCount();
if (attack.skill != Cleric.HEAL) {
if (player.isAlive()) {
- if(attack.skill == NightWalker.POISON_BOMB) {// Poison Bomb
+ if(attack.skill == Aran.BODY_PRESSURE || attack.skill == Marauder.ENERGY_CHARGE || attack.skill == ThunderBreaker.ENERGY_CHARGE) { // thanks IxianMace for noticing Energy Charge skills refreshing on touch, leading to misleading buff applies
+ // prevent touch dmg skills refreshing
+ } else if(attack.skill == NightWalker.POISON_BOMB) {// Poison Bomb
attackEffect.applyTo(player, new Point(attack.position.x, attack.position.y));
- } else if(attack.skill != Aran.BODY_PRESSURE) {// prevent BP refreshing
+ } else {
attackEffect.applyTo(player);
if (attack.skill == DawnWarrior.FINAL_ATTACK || attack.skill == Page.FINAL_ATTACK_BW || attack.skill == Page.FINAL_ATTACK_SWORD || attack.skill == Fighter.FINAL_ATTACK_SWORD
diff --git a/src/net/server/channel/handlers/AbstractMovementPacketHandler.java b/src/net/server/channel/handlers/AbstractMovementPacketHandler.java
index ed9cd86812..621946e15d 100644
--- a/src/net/server/channel/handlers/AbstractMovementPacketHandler.java
+++ b/src/net/server/channel/handlers/AbstractMovementPacketHandler.java
@@ -34,10 +34,11 @@ import server.movement.LifeMovementFragment;
import server.movement.RelativeLifeMovement;
import server.movement.TeleportMovement;
import tools.data.input.LittleEndianAccessor;
+import tools.exceptions.EmptyMovementException;
public abstract class AbstractMovementPacketHandler extends AbstractMaplePacketHandler {
- protected List parseMovement(LittleEndianAccessor lea) {
+ protected List parseMovement(LittleEndianAccessor lea) throws EmptyMovementException {
List res = new ArrayList<>();
byte numCommands = lea.readByte();
for (byte i = 0; i < numCommands; i++) {
@@ -138,15 +139,20 @@ public abstract class AbstractMovementPacketHandler extends AbstractMaplePacketH
}
default:
System.out.println("Unhandled Case:" + command);
- return null;
+ throw new EmptyMovementException(lea);
}
}
+
+ if (res.isEmpty()) {
+ throw new EmptyMovementException(lea);
+ }
return res;
}
- protected void updatePosition(LittleEndianAccessor lea, AnimatedMapleMapObject target, int yOffset) {
+ protected void updatePosition(LittleEndianAccessor lea, AnimatedMapleMapObject target, int yOffset) throws EmptyMovementException {
byte numCommands = lea.readByte();
+ if (numCommands < 1) throw new EmptyMovementException(lea);
for (byte i = 0; i < numCommands; i++) {
byte command = lea.readByte();
switch (command) {
@@ -233,6 +239,5 @@ public abstract class AbstractMovementPacketHandler extends AbstractMaplePacketH
return;
}
}
- return;
}
}
diff --git a/src/net/server/channel/handlers/BBSOperationHandler.java b/src/net/server/channel/handlers/BBSOperationHandler.java
index 020fa8ba0f..0e9e67cf20 100644
--- a/src/net/server/channel/handlers/BBSOperationHandler.java
+++ b/src/net/server/channel/handlers/BBSOperationHandler.java
@@ -149,8 +149,8 @@ public final class BBSOperationHandler extends AbstractMaplePacketHandler {
}
private static void editBBSThread(MapleClient client, String title, String text, int icon, int localthreadid) {
- MapleCharacter c = client.getPlayer();
- if (c.getGuildId() < 1) {
+ MapleCharacter chr = client.getPlayer();
+ if (chr.getGuildId() < 1) {
return;
}
try {
@@ -160,10 +160,10 @@ public final class BBSOperationHandler extends AbstractMaplePacketHandler {
ps.setLong(2, currentServerTime());
ps.setInt(3, icon);
ps.setString(4, text);
- ps.setInt(5, c.getGuildId());
+ ps.setInt(5, chr.getGuildId());
ps.setInt(6, localthreadid);
- ps.setInt(7, c.getId());
- ps.setBoolean(8, c.getGuildRank() < 3);
+ ps.setInt(7, chr.getId());
+ ps.setBoolean(8, chr.getGuildRank() < 3);
ps.execute();
}
con.close();
@@ -174,8 +174,8 @@ public final class BBSOperationHandler extends AbstractMaplePacketHandler {
}
private static void newBBSThread(MapleClient client, String title, String text, int icon, boolean bNotice) {
- MapleCharacter c = client.getPlayer();
- if (c.getGuildId() <= 0) {
+ MapleCharacter chr = client.getPlayer();
+ if (chr.getGuildId() <= 0) {
return;
}
int nextId = 0;
@@ -184,7 +184,7 @@ public final class BBSOperationHandler extends AbstractMaplePacketHandler {
PreparedStatement ps;
if (!bNotice) {
ps = con.prepareStatement("SELECT MAX(localthreadid) AS lastLocalId FROM bbs_threads WHERE guildid = ?");
- ps.setInt(1, c.getGuildId());
+ ps.setInt(1, chr.getGuildId());
try (ResultSet rs = ps.executeQuery()) {
rs.next();
nextId = rs.getInt("lastLocalId") + 1;
@@ -192,12 +192,12 @@ public final class BBSOperationHandler extends AbstractMaplePacketHandler {
ps.close();
}
ps = con.prepareStatement("INSERT INTO bbs_threads " + "(`postercid`, `name`, `timestamp`, `icon`, `startpost`, " + "`guildid`, `localthreadid`) " + "VALUES(?, ?, ?, ?, ?, ?, ?)");
- ps.setInt(1, c.getId());
+ ps.setInt(1, chr.getId());
ps.setString(2, title);
ps.setLong(3, currentServerTime());
ps.setInt(4, icon);
ps.setString(5, text);
- ps.setInt(6, c.getGuildId());
+ ps.setInt(6, chr.getGuildId());
ps.setInt(7, nextId);
ps.execute();
ps.close();
diff --git a/src/net/server/channel/handlers/MagicDamageHandler.java b/src/net/server/channel/handlers/MagicDamageHandler.java
index 1065f4eeb3..3a8e812b64 100644
--- a/src/net/server/channel/handlers/MagicDamageHandler.java
+++ b/src/net/server/channel/handlers/MagicDamageHandler.java
@@ -30,7 +30,6 @@ import client.MapleCharacter;
import client.MapleClient;
import client.Skill;
import client.SkillFactory;
-import constants.net.ServerConstants;
import constants.skills.Bishop;
import constants.skills.Evan;
import constants.skills.FPArchMage;
@@ -63,13 +62,9 @@ public final class MagicDamageHandler extends AbstractDealDamageHandler {
c.announce(MaplePacketCreator.getEnergy("energy", chr.getDojoEnergy()));
}
- byte[] packet;
- if ((attack.skill == Evan.FIRE_BREATH || attack.skill == Evan.ICE_BREATH || attack.skill == FPArchMage.BIG_BANG || attack.skill == ILArchMage.BIG_BANG || attack.skill == Bishop.BIG_BANG)) {
- packet = MaplePacketCreator.magicAttack(chr, attack.skill, attack.skilllevel, attack.stance, attack.numAttackedAndDamage, attack.allDamage, attack.charge, attack.speed, attack.direction, attack.display);
- } else {
- packet = MaplePacketCreator.closeRangeAttack(chr, attack.skill, attack.skilllevel, attack.stance, attack.numAttackedAndDamage, attack.allDamage, attack.speed, attack.direction, attack.display);
- }
-
+ int charge = (attack.skill == Evan.FIRE_BREATH || attack.skill == Evan.ICE_BREATH || attack.skill == FPArchMage.BIG_BANG || attack.skill == ILArchMage.BIG_BANG || attack.skill == Bishop.BIG_BANG) ? attack.charge : -1;
+ byte[] packet = MaplePacketCreator.magicAttack(chr, attack.skill, attack.skilllevel, attack.stance, attack.numAttackedAndDamage, attack.allDamage, charge, attack.speed, attack.direction, attack.display);
+
chr.getMap().broadcastMessage(chr, packet, false, true);
MapleStatEffect effect = attack.getAttackEffect(chr, null);
Skill skill = SkillFactory.getSkill(attack.skill);
diff --git a/src/net/server/channel/handlers/MoveDragonHandler.java b/src/net/server/channel/handlers/MoveDragonHandler.java
index 0b8bb9f099..d66e0abac0 100644
--- a/src/net/server/channel/handlers/MoveDragonHandler.java
+++ b/src/net/server/channel/handlers/MoveDragonHandler.java
@@ -28,6 +28,7 @@ import client.MapleClient;
import server.maps.MapleDragon;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
+import tools.exceptions.EmptyMovementException;
public class MoveDragonHandler extends AbstractMovementPacketHandler {
@@ -35,19 +36,20 @@ public class MoveDragonHandler extends AbstractMovementPacketHandler {
public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
final MapleCharacter chr = c.getPlayer();
final Point startPos = new Point(slea.readShort(), slea.readShort());
- long movementDataStart = slea.getPosition();
final MapleDragon dragon = chr.getDragon();
if (dragon != null) {
- updatePosition(slea, dragon, 0);
- long movementDataLength = slea.getPosition() - movementDataStart; //how many bytes were read by updatePosition
- if (movementDataLength > 0) {
+ try {
+ long movementDataStart = slea.getPosition();
+ updatePosition(slea, dragon, 0);
+ long movementDataLength = slea.getPosition() - movementDataStart; //how many bytes were read by updatePosition
slea.seek(movementDataStart);
+
if (chr.isHidden()) {
chr.getMap().broadcastGMMessage(chr, MaplePacketCreator.moveDragon(dragon, startPos, slea, movementDataLength));
} else {
chr.getMap().broadcastMessage(chr, MaplePacketCreator.moveDragon(dragon, startPos, slea, movementDataLength), dragon.getPosition());
}
- }
+ } catch (EmptyMovementException e) {}
}
}
}
\ No newline at end of file
diff --git a/src/net/server/channel/handlers/MoveLifeHandler.java b/src/net/server/channel/handlers/MoveLifeHandler.java
index a3d1053ac0..3097dffbfc 100644
--- a/src/net/server/channel/handlers/MoveLifeHandler.java
+++ b/src/net/server/channel/handlers/MoveLifeHandler.java
@@ -41,6 +41,7 @@ import tools.MaplePacketCreator;
import tools.Pair;
import tools.Randomizer;
import tools.data.input.SeekableLittleEndianAccessor;
+import tools.exceptions.EmptyMovementException;
/**
* @author Danny (Leifde)
@@ -142,11 +143,7 @@ public final class MoveLifeHandler extends AbstractMovementPacketHandler {
short start_y = slea.readShort(); // hmm...
Point startPos = new Point(start_x, start_y - 2);
Point serverStartPos = new Point(monster.getPosition());
- long movementDataStart = slea.getPosition();
- updatePosition(slea, monster, -2); // Thanks Doodle and ZERO傑洛 for noticing sponge-based bosses moving out of stage in case of no-offset applied
- long movementDataLength = slea.getPosition() - movementDataStart; //how many bytes were read by updatePosition
-
Boolean aggro = monster.aggroMoveLifeUpdate(player);
if (aggro == null) return;
@@ -156,15 +153,21 @@ public final class MoveLifeHandler extends AbstractMovementPacketHandler {
c.announce(MaplePacketCreator.moveMonsterResponse(objectid, moveid, mobMp, aggro));
}
- if (movementDataLength > 0) {
- if (YamlConfig.config.server.USE_DEBUG_SHOW_RCVD_MVLIFE) {
- System.out.println((isSkill ? "SKILL " : (isAttack ? "ATTCK " : " ")) + "castPos: " + castPos + " rawAct: " + rawActivity + " opt: " + pOption + " skillID: " + useSkillId + " skillLV: " + useSkillLevel + " " + "allowSkill: " + nextMovementCouldBeSkill + " mobMp: " + mobMp);
- }
- slea.seek(movementDataStart);
- map.broadcastMessage(player, MaplePacketCreator.moveMonster(objectid, nextMovementCouldBeSkill, rawActivity, useSkillId, useSkillLevel, pOption, startPos, slea, movementDataLength), serverStartPos);
- //updatePosition(res, monster, -2); //does this need to be done after the packet is broadcast?
- map.moveMonster(monster, monster.getPosition());
- }
+
+ try {
+ long movementDataStart = slea.getPosition();
+ updatePosition(slea, monster, -2); // Thanks Doodle and ZERO傑洛 for noticing sponge-based bosses moving out of stage in case of no-offset applied
+ long movementDataLength = slea.getPosition() - movementDataStart; //how many bytes were read by updatePosition
+ slea.seek(movementDataStart);
+
+ if (YamlConfig.config.server.USE_DEBUG_SHOW_RCVD_MVLIFE) {
+ System.out.println((isSkill ? "SKILL " : (isAttack ? "ATTCK " : " ")) + "castPos: " + castPos + " rawAct: " + rawActivity + " opt: " + pOption + " skillID: " + useSkillId + " skillLV: " + useSkillLevel + " " + "allowSkill: " + nextMovementCouldBeSkill + " mobMp: " + mobMp);
+ }
+
+ map.broadcastMessage(player, MaplePacketCreator.moveMonster(objectid, nextMovementCouldBeSkill, rawActivity, useSkillId, useSkillLevel, pOption, startPos, slea, movementDataLength), serverStartPos);
+ //updatePosition(res, monster, -2); //does this need to be done after the packet is broadcast?
+ map.moveMonster(monster, monster.getPosition());
+ } catch (EmptyMovementException e) {}
if (banishPlayers != null) {
for (MapleCharacter chr : banishPlayers) {
diff --git a/src/net/server/channel/handlers/MovePetHandler.java b/src/net/server/channel/handlers/MovePetHandler.java
index dd62570498..fd8b120ab7 100644
--- a/src/net/server/channel/handlers/MovePetHandler.java
+++ b/src/net/server/channel/handlers/MovePetHandler.java
@@ -27,6 +27,7 @@ import client.MapleClient;
import server.movement.LifeMovementFragment;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
+import tools.exceptions.EmptyMovementException;
public final class MovePetHandler extends AbstractMovementPacketHandler {
@Override
@@ -34,8 +35,11 @@ public final class MovePetHandler extends AbstractMovementPacketHandler {
int petId = slea.readInt();
slea.readLong();
// Point startPos = StreamUtil.readShortPoint(slea);
- List res = parseMovement(slea);
- if (res == null || res.isEmpty()) {
+ List res;
+
+ try {
+ res = parseMovement(slea);
+ } catch (EmptyMovementException e) {
return;
}
MapleCharacter player = c.getPlayer();
diff --git a/src/net/server/channel/handlers/MovePlayerHandler.java b/src/net/server/channel/handlers/MovePlayerHandler.java
index 2a572003bd..85fc546951 100644
--- a/src/net/server/channel/handlers/MovePlayerHandler.java
+++ b/src/net/server/channel/handlers/MovePlayerHandler.java
@@ -24,22 +24,24 @@ package net.server.channel.handlers;
import client.MapleClient;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
+import tools.exceptions.EmptyMovementException;
public final class MovePlayerHandler extends AbstractMovementPacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
slea.skip(9);
- long movementDataStart = slea.getPosition();
- updatePosition(slea, c.getPlayer(), 0);
- long movementDataLength = slea.getPosition() - movementDataStart; //how many bytes were read by updatePosition
- if (movementDataLength > 0) {
- slea.seek(movementDataStart);
+ try { // thanks Sa for noticing empty movement sequences crashing players
+ long movementDataStart = slea.getPosition();
+ updatePosition(slea, c.getPlayer(), 0);
+ long movementDataLength = slea.getPosition() - movementDataStart; //how many bytes were read by updatePosition
+ slea.seek(movementDataStart);
+
c.getPlayer().getMap().movePlayer(c.getPlayer(), c.getPlayer().getPosition());
if (c.getPlayer().isHidden()) {
c.getPlayer().getMap().broadcastGMMessage(c.getPlayer(), MaplePacketCreator.movePlayer(c.getPlayer().getId(), slea, movementDataLength), false);
} else {
c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.movePlayer(c.getPlayer().getId(), slea, movementDataLength), false);
}
- }
+ } catch (EmptyMovementException e) {}
}
}
diff --git a/src/net/server/channel/handlers/MoveSummonHandler.java b/src/net/server/channel/handlers/MoveSummonHandler.java
index 911ffd2ce8..a6cf0a4420 100644
--- a/src/net/server/channel/handlers/MoveSummonHandler.java
+++ b/src/net/server/channel/handlers/MoveSummonHandler.java
@@ -29,6 +29,7 @@ import client.MapleClient;
import server.maps.MapleSummon;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
+import tools.exceptions.EmptyMovementException;
public final class MoveSummonHandler extends AbstractMovementPacketHandler {
@Override
@@ -45,11 +46,14 @@ public final class MoveSummonHandler extends AbstractMovementPacketHandler {
}
}
if (summon != null) {
- long movementDataStart = slea.getPosition();
- updatePosition(slea, summon, 0);
- long movementDataLength = slea.getPosition() - movementDataStart; //how many bytes were read by updatePosition
- slea.seek(movementDataStart);
- player.getMap().broadcastMessage(player, MaplePacketCreator.moveSummon(player.getId(), oid, startPos, slea, movementDataLength), summon.getPosition());
+ try {
+ long movementDataStart = slea.getPosition();
+ updatePosition(slea, summon, 0);
+ long movementDataLength = slea.getPosition() - movementDataStart; //how many bytes were read by updatePosition
+ slea.seek(movementDataStart);
+
+ player.getMap().broadcastMessage(player, MaplePacketCreator.moveSummon(player.getId(), oid, startPos, slea, movementDataLength), summon.getPosition());
+ } catch (EmptyMovementException e) {}
}
}
}
diff --git a/src/net/server/channel/handlers/PetAutoPotHandler.java b/src/net/server/channel/handlers/PetAutoPotHandler.java
index f1ea8a7518..1e20797d52 100644
--- a/src/net/server/channel/handlers/PetAutoPotHandler.java
+++ b/src/net/server/channel/handlers/PetAutoPotHandler.java
@@ -43,12 +43,12 @@ public final class PetAutoPotHandler extends AbstractMaplePacketHandler {
MapleStatEffect stat = MapleItemInformationProvider.getInstance().getItemEffect(itemId);
if (stat.getHp() > 0 || stat.getHpRate() > 0.0) {
float estimatedHp = ((float) chr.getHp()) / chr.getMaxHp();
- chr.setAutopotHpAlert(estimatedHp);
+ chr.setAutopotHpAlert(estimatedHp + 0.05f);
}
if (stat.getMp() > 0 || stat.getMpRate() > 0.0) {
float estimatedMp = ((float) chr.getMp()) / chr.getMaxMp();
- chr.setAutopotMpAlert(estimatedMp);
+ chr.setAutopotMpAlert(estimatedMp + 0.05f);
}
PetAutopotProcessor.runAutopotAction(c, slot, itemId);
diff --git a/src/net/server/channel/handlers/PlayerLoggedinHandler.java b/src/net/server/channel/handlers/PlayerLoggedinHandler.java
index 379ffeb5ab..34b43627c8 100644
--- a/src/net/server/channel/handlers/PlayerLoggedinHandler.java
+++ b/src/net/server/channel/handlers/PlayerLoggedinHandler.java
@@ -116,13 +116,16 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
}
Channel cserv = wserv.getChannel(c.getChannel());
- if(cserv == null) {
+ if(cserv == null || !cserv.isActive()) {
c.setChannel(1);
cserv = wserv.getChannel(c.getChannel());
if(cserv == null) {
c.disconnect(true, false);
return;
+ } else if (!cserv.isActive()) {
+ c.announce(MaplePacketCreator.getAfterLoginError(7));
+ return;
}
}
diff --git a/src/net/server/channel/handlers/PlayerMapTransitionHandler.java b/src/net/server/channel/handlers/PlayerMapTransitionHandler.java
index 13a02d3cc3..0828593921 100644
--- a/src/net/server/channel/handlers/PlayerMapTransitionHandler.java
+++ b/src/net/server/channel/handlers/PlayerMapTransitionHandler.java
@@ -51,19 +51,21 @@ public final class PlayerMapTransitionHandler extends AbstractMaplePacketHandler
chr.announce(MaplePacketCreator.giveBuff(1, beaconid, stat));
}
- for (MapleMapObject mo : chr.getMap().getMonsters()) { // thanks BHB, IxianMace, Jefe for noticing several issues regarding mob statuses (such as freeze)
- MapleMonster m = (MapleMonster) mo;
- if (m.getSpawnEffect() == 0 || m.getHp() < m.getMaxHp()) { // avoid effect-spawning mobs
- if (m.getController() == chr) {
- c.announce(MaplePacketCreator.stopControllingMonster(m.getObjectId()));
- m.sendDestroyData(c);
- m.aggroRedirectController();
- } else {
- m.sendDestroyData(c);
- }
+ if (!chr.isHidden()) { // thanks Lame for noticing hidden characters controlling mobs
+ for (MapleMapObject mo : chr.getMap().getMonsters()) { // thanks BHB, IxianMace, Jefe for noticing several issues regarding mob statuses (such as freeze)
+ MapleMonster m = (MapleMonster) mo;
+ if (m.getSpawnEffect() == 0 || m.getHp() < m.getMaxHp()) { // avoid effect-spawning mobs
+ if (m.getController() == chr) {
+ c.announce(MaplePacketCreator.stopControllingMonster(m.getObjectId()));
+ m.sendDestroyData(c);
+ m.aggroRedirectController();
+ } else {
+ m.sendDestroyData(c);
+ }
- m.aggroSwitchController(chr, false);
- m.sendSpawnData(c);
+ m.aggroSwitchController(chr, false);
+ m.sendSpawnData(c);
+ }
}
}
}
diff --git a/src/net/server/channel/handlers/RaiseIncExpHandler.java b/src/net/server/channel/handlers/RaiseIncExpHandler.java
index 68261b42c0..89c3dd3c2a 100644
--- a/src/net/server/channel/handlers/RaiseIncExpHandler.java
+++ b/src/net/server/channel/handlers/RaiseIncExpHandler.java
@@ -2,13 +2,17 @@ package net.server.channel.handlers;
import java.util.Map;
+import client.MapleCharacter;
import client.MapleClient;
+import client.MapleQuestStatus;
import client.inventory.MapleInventory;
import client.inventory.MapleInventoryType;
import net.AbstractMaplePacketHandler;
import client.inventory.manipulator.MapleInventoryManipulator;
import server.MapleItemInformationProvider;
import server.MapleItemInformationProvider.QuestConsItem;
+import server.quest.MapleQuest;
+import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
/**
@@ -22,7 +26,7 @@ public class RaiseIncExpHandler extends AbstractMaplePacketHandler {
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
byte inventorytype = slea.readByte();//nItemIT
short slot = slea.readShort();//nSlotPosition
- int itemid = slea.readInt();//nItemID
+ int itemid = slea.readInt();//nItemID
if (c.tryacquireClient()) {
try {
@@ -32,15 +36,22 @@ public class RaiseIncExpHandler extends AbstractMaplePacketHandler {
return;
}
- int questid = consItem.questid;
+ int infoNumber = consItem.questid;
Map consumables = consItem.items;
-
+
+ MapleCharacter chr = c.getPlayer();
+ MapleQuest quest = MapleQuest.getInstanceFromInfoNumber(infoNumber);
+ if (!chr.getQuest(quest).getStatus().equals(MapleQuestStatus.Status.STARTED)) {
+ c.announce(MaplePacketCreator.enableActions());
+ return;
+ }
+
int consId;
- MapleInventory inv = c.getPlayer().getInventory(MapleInventoryType.getByType(inventorytype));
+ MapleInventory inv = chr.getInventory(MapleInventoryType.getByType(inventorytype));
inv.lockInventory();
try {
consId = inv.getItem(slot).getItemId();
- if (!consumables.containsKey(consId) || !c.getPlayer().haveItem(consId)) {
+ if (!consumables.containsKey(consId) || !chr.haveItem(consId)) {
return;
}
@@ -48,9 +59,12 @@ public class RaiseIncExpHandler extends AbstractMaplePacketHandler {
} finally {
inv.unlockInventory();
}
-
- int nextValue = Math.min(consumables.get(consId) + Integer.parseInt(c.getPlayer().getQuestInfo(questid)), consItem.exp * consItem.grade);
- c.getPlayer().updateQuestInfo(questid, "" + nextValue);
+
+ int questid = quest.getId();
+ int nextValue = Math.min(consumables.get(consId) + c.getAbstractPlayerInteraction().getQuestProgressInt(questid, infoNumber), consItem.exp * consItem.grade);
+ c.getAbstractPlayerInteraction().setQuestProgress(questid, infoNumber, nextValue);
+
+ c.announce(MaplePacketCreator.enableActions());
} finally {
c.releaseClient();
}
diff --git a/src/net/server/channel/handlers/RaiseUIStateHandler.java b/src/net/server/channel/handlers/RaiseUIStateHandler.java
index e0d602d941..287de88347 100644
--- a/src/net/server/channel/handlers/RaiseUIStateHandler.java
+++ b/src/net/server/channel/handlers/RaiseUIStateHandler.java
@@ -1,9 +1,11 @@
package net.server.channel.handlers;
import client.MapleCharacter.DelayedQuestUpdate;
+import client.MapleCharacter;
import client.MapleClient;
import client.MapleQuestStatus;
import net.AbstractMaplePacketHandler;
+import scripting.quest.QuestScriptManager;
import server.quest.MapleQuest;
import tools.data.input.SeekableLittleEndianAccessor;
@@ -15,19 +17,21 @@ public class RaiseUIStateHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
- int questid = slea.readShort();
+ int infoNumber = slea.readShort();
if (c.tryacquireClient()) {
try {
- MapleQuest quest = MapleQuest.getInstance(questid);
- MapleQuestStatus mqs = c.getPlayer().getQuest(quest);
+ MapleCharacter chr = c.getPlayer();
+ MapleQuest quest = MapleQuest.getInstanceFromInfoNumber(infoNumber);
+ MapleQuestStatus mqs = chr.getQuest(quest);
+
+ QuestScriptManager.getInstance().raiseOpen(c, (short) infoNumber, mqs.getNpc());
+
if (mqs.getStatus() == MapleQuestStatus.Status.NOT_STARTED) {
- quest.forceStart(c.getPlayer(), 22000);
- c.getPlayer().updateQuestInfo(quest.getId(), "0");
+ quest.forceStart(chr, 22000);
+ c.getAbstractPlayerInteraction().setQuestProgress(quest.getId(), infoNumber, 0);
} else if (mqs.getStatus() == MapleQuestStatus.Status.STARTED) {
- c.getPlayer().announceUpdateQuest(DelayedQuestUpdate.UPDATE, mqs, false);
- } else {
- //c.announce(MaplePacketCreator.updateQuestInfo(mqs.getQuestID(), 22000, "0"));
+ chr.announceUpdateQuest(DelayedQuestUpdate.UPDATE, mqs, mqs.getInfoNumber() > 0);
}
} finally {
c.releaseClient();
diff --git a/src/net/server/guild/MapleGuildCharacter.java b/src/net/server/guild/MapleGuildCharacter.java
index 41e12ca42b..aff55becba 100644
--- a/src/net/server/guild/MapleGuildCharacter.java
+++ b/src/net/server/guild/MapleGuildCharacter.java
@@ -35,22 +35,22 @@ public class MapleGuildCharacter {
private boolean online;
private String name;
- public MapleGuildCharacter(MapleCharacter c) {
- this.character = c;
- this.name = c.getName();
- this.level = c.getLevel();
- this.id = c.getId();
- this.channel = c.getClient().getChannel();
- this.world = c.getWorld();
- this.jobid = c.getJob().getId();
- this.guildrank = c.getGuildRank();
- this.guildid = c.getGuildId();
+ public MapleGuildCharacter(MapleCharacter chr) {
+ this.character = chr;
+ this.name = chr.getName();
+ this.level = chr.getLevel();
+ this.id = chr.getId();
+ this.channel = chr.getClient().getChannel();
+ this.world = chr.getWorld();
+ this.jobid = chr.getJob().getId();
+ this.guildrank = chr.getGuildRank();
+ this.guildid = chr.getGuildId();
this.online = true;
- this.allianceRank = c.getAllianceRank();
+ this.allianceRank = chr.getAllianceRank();
}
- public MapleGuildCharacter(MapleCharacter c, int _id, int _lv, String _name, int _channel, int _world, int _job, int _rank, int _gid, boolean _on, int _allianceRank) {
- this.character = c;
+ public MapleGuildCharacter(MapleCharacter chr, int _id, int _lv, String _name, int _channel, int _world, int _job, int _rank, int _gid, boolean _on, int _allianceRank) {
+ this.character = chr;
this.level = _lv;
this.id = _id;
this.name = _name;
diff --git a/src/net/server/handlers/login/CharlistRequestHandler.java b/src/net/server/handlers/login/CharlistRequestHandler.java
index 72f29c06ca..547156edfd 100644
--- a/src/net/server/handlers/login/CharlistRequestHandler.java
+++ b/src/net/server/handlers/login/CharlistRequestHandler.java
@@ -24,6 +24,7 @@ package net.server.handlers.login;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import net.server.Server;
+import net.server.channel.Channel;
import net.server.world.World;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
@@ -42,7 +43,8 @@ public final class CharlistRequestHandler extends AbstractMaplePacketHandler {
}
int channel = slea.readByte() + 1;
- if(wserv.getChannel(channel) == null) {
+ Channel ch = wserv.getChannel(channel);
+ if(ch == null || !ch.isActive()) {
c.announce(MaplePacketCreator.getServerStatus(2));
return;
}
diff --git a/src/net/server/world/World.java b/src/net/server/world/World.java
index b46b42a884..6847f5ca7d 100644
--- a/src/net/server/world/World.java
+++ b/src/net/server/world/World.java
@@ -212,7 +212,7 @@ public class World {
merchantSchedule = tman.register(new HiredMerchantTask(this), 10 * 60 * 1000, 10 * 60 * 1000);
timedMapObjectsSchedule = tman.register(new TimedMapObjectTask(this), 60 * 1000, 60 * 1000);
charactersSchedule = tman.register(new CharacterAutosaverTask(this), 60 * 60 * 1000, 60 * 60 * 1000);
- marriagesSchedule = tman.register(new WeddingReservationTask(this), ServerConstants.WEDDING_RESERVATION_INTERVAL * 60 * 1000, ServerConstants.WEDDING_RESERVATION_INTERVAL * 60 * 1000);
+ marriagesSchedule = tman.register(new WeddingReservationTask(this), YamlConfig.config.server.WEDDING_RESERVATION_INTERVAL * 60 * 1000, YamlConfig.config.server.WEDDING_RESERVATION_INTERVAL * 60 * 1000);
mapOwnershipSchedule = tman.register(new MapOwnershipTask(this), 20 * 1000, 20 * 1000);
fishingSchedule = tman.register(new FishingTask(this), 10 * 1000, 10 * 1000);
partySearchSchedule = tman.register(new PartySearchTask(this), 10 * 1000, 10 * 1000);
@@ -730,14 +730,14 @@ public class World {
}
public void sendPacket(List targetIds, final byte[] packet, int exception) {
- MapleCharacter c;
+ MapleCharacter chr;
for (int i : targetIds) {
if (i == exception) {
continue;
}
- c = getPlayerStorage().getCharacterById(i);
- if (c != null) {
- c.getClient().announce(packet);
+ chr = getPlayerStorage().getCharacterById(i);
+ if (chr != null) {
+ chr.getClient().announce(packet);
}
}
}
diff --git a/src/scripting/AbstractPlayerInteraction.java b/src/scripting/AbstractPlayerInteraction.java
index 7ea9a0ec04..b7528f8fc3 100644
--- a/src/scripting/AbstractPlayerInteraction.java
+++ b/src/scripting/AbstractPlayerInteraction.java
@@ -365,28 +365,7 @@ public class AbstractPlayerInteraction {
NPCScriptManager.getInstance().start(c, npcid, script, null);
}
- public void updateQuest(int questid, int data) {
- MapleQuestStatus status = c.getPlayer().getQuest(MapleQuest.getInstance(questid));
- updateQuest(questid, status.getAnyProgressKey(), data);
- }
-
- public void updateQuest(int questid, String data) {
- MapleQuestStatus status = c.getPlayer().getQuest(MapleQuest.getInstance(questid));
- updateQuest(questid, status.getAnyProgressKey(), data);
- }
-
- public void updateQuest(int questid, int pid, int data) {
- updateQuest(questid, pid, String.valueOf(data));
- }
-
- public void updateQuest(int questid, int pid, String data) {
- MapleQuestStatus status = c.getPlayer().getQuest(MapleQuest.getInstance(questid));
- status.setStatus(MapleQuestStatus.Status.STARTED);
- status.setProgress(pid, data);//override old if exists
- c.getPlayer().updateQuest(status);
- }
-
- public int getQuestStatus(int id) {
+ public int getQuestStatus(int id) {
return c.getPlayer().getQuest(MapleQuest.getInstance(id)).getStatus().getId();
}
@@ -394,75 +373,93 @@ public class AbstractPlayerInteraction {
return c.getPlayer().getQuest(MapleQuest.getInstance(id)).getStatus();
}
- public boolean isQuestCompleted(int quest) {
+ public boolean isQuestCompleted(int id) {
try {
- return getQuestStat(quest) == MapleQuestStatus.Status.COMPLETED;
+ return getQuestStat(id) == MapleQuestStatus.Status.COMPLETED;
} catch (NullPointerException e) {
e.printStackTrace();
return false;
}
}
- public boolean isQuestActive(int quest) {
- return isQuestStarted(quest);
+ public boolean isQuestActive(int id) {
+ return isQuestStarted(id);
}
- public boolean isQuestStarted(int quest) {
+ public boolean isQuestStarted(int id) {
try {
- return getQuestStat(quest) == MapleQuestStatus.Status.STARTED;
+ return getQuestStat(id) == MapleQuestStatus.Status.STARTED;
} catch (NullPointerException e) {
e.printStackTrace();
return false;
}
}
- public void setQuestProgress(int qid, int progress) {
- MapleQuestStatus status = c.getPlayer().getQuest(MapleQuest.getInstance(qid));
- status.setProgress(status.getAnyProgressKey(), String.valueOf(progress));
+ public void setQuestProgress(int id, String progress) {
+ setQuestProgress(id, 0, progress);
}
- public void setQuestProgress(int qid, int pid, int progress) {
- MapleQuestStatus status = c.getPlayer().getQuest(MapleQuest.getInstance(qid));
- status.setProgress(pid, String.valueOf(progress));
- }
-
- public void setStringQuestProgress(int qid, int pid, String progress) {
- MapleQuestStatus status = c.getPlayer().getQuest(MapleQuest.getInstance(qid));
- status.setProgress(pid, progress);
+ public void setQuestProgress(int id, int progress) {
+ setQuestProgress(id, 0, "" + progress);
}
- public int getQuestProgress(int qid) {
- MapleQuestStatus status = c.getPlayer().getQuest(MapleQuest.getInstance(qid));
- String progress = status.getProgress(status.getAnyProgressKey());
-
- if (progress.isEmpty()) {
+ public void setQuestProgress(int id, int infoNumber, int progress) {
+ setQuestProgress(id, infoNumber, "" + progress);
+ }
+
+ public void setQuestProgress(int id, int infoNumber, String progress) {
+ c.getPlayer().setQuestProgress(id, infoNumber, progress);
+ }
+
+ public String getQuestProgress(int id) {
+ return getQuestProgress(id, 0);
+ }
+
+ public String getQuestProgress(int id, int infoNumber) {
+ MapleQuestStatus qs = getPlayer().getQuest(MapleQuest.getInstance(id));
+
+ if (qs.getInfoNumber() == infoNumber && infoNumber > 0) {
+ qs = getPlayer().getQuest(MapleQuest.getInstance(infoNumber));
+ infoNumber = 0;
+ }
+
+ if (qs != null) {
+ return qs.getProgress(infoNumber);
+ } else {
+ return "";
+ }
+ }
+
+ public int getQuestProgressInt(int id) {
+ try {
+ return Integer.valueOf(getQuestProgress(id));
+ } catch (NumberFormatException nfe) {
return 0;
}
- return Integer.parseInt(progress);
}
- public int getQuestProgress(int qid, int pid) {
- if (getPlayer().getQuest(MapleQuest.getInstance(qid)).getProgress(pid).isEmpty()) {
- return 0;
+ public int getQuestProgressInt(int id, int infoNumber) {
+ try {
+ return Integer.valueOf(getQuestProgress(id, infoNumber));
+ } catch (NumberFormatException nfe) {
+ return 0;
}
- return Integer.parseInt(getPlayer().getQuest(MapleQuest.getInstance(qid)).getProgress(pid));
- }
+ }
- public String getStringQuestProgress(int qid, int pid) {
- if (getPlayer().getQuest(MapleQuest.getInstance(qid)).getProgress(pid).isEmpty()) {
- return "";
+ public void resetAllQuestProgress(int id) {
+ MapleQuestStatus qs = getPlayer().getQuest(MapleQuest.getInstance(id));
+ if (qs != null) {
+ qs.resetAllProgress();
+ getPlayer().announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, false);
}
- return getPlayer().getQuest(MapleQuest.getInstance(qid)).getProgress(pid);
}
- public void resetAllQuestProgress(int qid) {
- getPlayer().getQuest(MapleQuest.getInstance(qid)).resetAllProgress();
- getPlayer().announceUpdateQuest(DelayedQuestUpdate.UPDATE, getPlayer().getQuest(MapleQuest.getInstance(qid)), false);
- }
-
- public void resetQuestProgress(int qid, int pid) {
- getPlayer().getQuest(MapleQuest.getInstance(qid)).resetProgress(pid);
- getPlayer().announceUpdateQuest(DelayedQuestUpdate.UPDATE, getPlayer().getQuest(MapleQuest.getInstance(qid)), false);
+ public void resetQuestProgress(int id, int infoNumber) {
+ MapleQuestStatus qs = getPlayer().getQuest(MapleQuest.getInstance(id));
+ if (qs != null) {
+ qs.resetProgress(infoNumber);
+ getPlayer().announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, false);
+ }
}
public boolean forceStartQuest(int id) {
@@ -497,26 +494,26 @@ public class AbstractPlayerInteraction {
return completeQuest(id, 9010000);
}
- public boolean startQuest(short id, int npcId) {
- return startQuest((int) id, npcId);
+ public boolean startQuest(short id, int npc) {
+ return startQuest((int) id, npc);
}
- public boolean completeQuest(short id, int npcId) {
- return completeQuest((int) id, npcId);
+ public boolean completeQuest(short id, int npc) {
+ return completeQuest((int) id, npc);
}
- public boolean startQuest(int id, int npcId) {
+ public boolean startQuest(int id, int npc) {
try {
- return MapleQuest.getInstance(id).forceStart(getPlayer(), npcId);
+ return MapleQuest.getInstance(id).forceStart(getPlayer(), npc);
} catch (NullPointerException ex) {
ex.printStackTrace();
return false;
}
}
- public boolean completeQuest(int id, int npcId) {
+ public boolean completeQuest(int id, int npc) {
try {
- return MapleQuest.getInstance(id).forceComplete(getPlayer(), npcId);
+ return MapleQuest.getInstance(id).forceComplete(getPlayer(), npc);
} catch (NullPointerException ex) {
ex.printStackTrace();
return false;
@@ -682,6 +679,10 @@ public class AbstractPlayerInteraction {
public void message(String message) {
getPlayer().message(message);
}
+
+ public void dropMessage(int type, String message) {
+ getPlayer().dropMessage(type, message);
+ }
public void mapMessage(int type, String message) {
getPlayer().getMap().broadcastMessage(MaplePacketCreator.serverNotice(type, message));
diff --git a/src/scripting/event/EventInstanceManager.java b/src/scripting/event/EventInstanceManager.java
index cf08ac3ed4..6a6e574ceb 100644
--- a/src/scripting/event/EventInstanceManager.java
+++ b/src/scripting/event/EventInstanceManager.java
@@ -898,7 +898,7 @@ public class EventInstanceManager {
}
}
- public void dispatchUpdateQuestMobCount(int mobid, int mapid) {
+ public void dispatchRaiseQuestMobCount(int mobid, int mapid) {
Map mapChars = getInstanceMap(mapid).getMapPlayers();
if(!mapChars.isEmpty()) {
List eventMembers = getPlayers();
@@ -907,7 +907,7 @@ public class EventInstanceManager {
MapleCharacter chr = mapChars.get(evChr.getId());
if(chr != null && chr.isLoggedinWorld()) {
- chr.updateQuestMobCount(mobid);
+ chr.raiseQuestMobCount(mobid);
}
}
}
diff --git a/src/scripting/event/EventScriptManager.java b/src/scripting/event/EventScriptManager.java
index af13ce6891..448b0bdfec 100644
--- a/src/scripting/event/EventScriptManager.java
+++ b/src/scripting/event/EventScriptManager.java
@@ -27,7 +27,6 @@ import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
-import javax.script.ScriptEngine;
import jdk.nashorn.api.scripting.NashornScriptEngine;
import net.server.channel.Channel;
@@ -48,7 +47,9 @@ public class EventScriptManager extends AbstractScriptManager {
public NashornScriptEngine iv;
public EventManager em;
}
+
private Map events = new LinkedHashMap<>();
+ private boolean active = false;
public EventScriptManager(Channel cserv, String[] scripts) {
super();
@@ -67,6 +68,10 @@ public class EventScriptManager extends AbstractScriptManager {
}
return entry.em;
}
+
+ public boolean isActive() {
+ return active;
+ }
public void init() {
for (EventEntry entry : events.values()) {
@@ -78,6 +83,8 @@ public class EventScriptManager extends AbstractScriptManager {
System.out.println("Error on script: " + entry.em.getName());
}
}
+
+ active = true;
}
private void reloadScripts() {
@@ -100,6 +107,7 @@ public class EventScriptManager extends AbstractScriptManager {
}
public void cancel() {
+ active = false;
for (EventEntry entry : events.values()) {
entry.em.cancel();
}
diff --git a/src/scripting/map/MapScriptMethods.java b/src/scripting/map/MapScriptMethods.java
index b302cfe694..575cc41ed8 100644
--- a/src/scripting/map/MapScriptMethods.java
+++ b/src/scripting/map/MapScriptMethods.java
@@ -94,13 +94,13 @@ public class MapScriptMethods extends AbstractPlayerInteraction {
return;
}
}
- MapleQuestStatus q = getPlayer().getQuest(quest);
- if (!q.addMedalMap(getPlayer().getMapId())) {
+ MapleQuestStatus qs = getPlayer().getQuest(quest);
+ if (!qs.addMedalMap(getPlayer().getMapId())) {
return;
}
- String status = Integer.toString(q.getMedalProgress());
- String infoex = quest.getInfoEx();
- getPlayer().announceUpdateQuest(DelayedQuestUpdate.UPDATE, q, true);
+ String status = Integer.toString(qs.getMedalProgress());
+ String infoex = qs.getInfoEx(0);
+ getPlayer().announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, true);
StringBuilder smp = new StringBuilder();
StringBuilder etm = new StringBuilder();
if (status.equals(infoex)) {
@@ -123,15 +123,15 @@ public class MapScriptMethods extends AbstractPlayerInteraction {
return;
}
}
- MapleQuestStatus q = getPlayer().getQuest(quest);
- if (!q.addMedalMap(getPlayer().getMapId())) {
+ MapleQuestStatus qs = getPlayer().getQuest(quest);
+ if (!qs.addMedalMap(getPlayer().getMapId())) {
return;
}
- String status = Integer.toString(q.getMedalProgress());
- getPlayer().announceUpdateQuest(DelayedQuestUpdate.UPDATE, q, true);
+ String status = Integer.toString(qs.getMedalProgress());
+ getPlayer().announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, 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())) {
+ if (Integer.toString(qs.getMedalProgress()).equals(qs.getInfoEx(0))) {
showInfoText("The One Who's Touched the Sky" + rewardstring);
getPlayer().announce(MaplePacketCreator.getShowQuestCompletion(quest.getId()));
} else {
diff --git a/src/scripting/npc/NPCConversationManager.java b/src/scripting/npc/NPCConversationManager.java
index 1d59e12836..57c1929aa1 100644
--- a/src/scripting/npc/NPCConversationManager.java
+++ b/src/scripting/npc/NPCConversationManager.java
@@ -579,7 +579,7 @@ public class NPCConversationManager extends AbstractPlayerInteraction {
return itemid != baseid && itemExists(baseid) ? baseid : -1;
}
- private int getEquippedItemid(int itemid) {
+ private int getEquippedCosmeticid(int itemid) {
if (itemid < 30000) {
return getPlayer().getFace();
} else {
@@ -588,7 +588,7 @@ public class NPCConversationManager extends AbstractPlayerInteraction {
}
public boolean isCosmeticEquipped(int itemid) {
- return getEquippedItemid(itemid) == itemid;
+ return getEquippedCosmeticid(itemid) == itemid;
}
public boolean isUsingOldPqNpcStyle() {
diff --git a/src/scripting/quest/QuestScriptManager.java b/src/scripting/quest/QuestScriptManager.java
index 6116cbbfbc..c67de4b196 100644
--- a/src/scripting/quest/QuestScriptManager.java
+++ b/src/scripting/quest/QuestScriptManager.java
@@ -59,10 +59,6 @@ public class QuestScriptManager extends AbstractScriptManager {
public void start(MapleClient c, short questid, int npc) {
MapleQuest quest = MapleQuest.getInstance(questid);
- if (!quest.canStartWithoutRequirements(c.getPlayer())) {
- dispose(c);
- return;
- }
try {
QuestActionManager qm = new QuestActionManager(c, questid, npc, true);
if (qms.containsKey(c)) {
@@ -169,6 +165,36 @@ public class QuestScriptManager extends AbstractScriptManager {
}
}
+ public void raiseOpen(MapleClient c, short questid, int npc) {
+ try {
+ QuestActionManager qm = new QuestActionManager(c, questid, npc, true);
+ if (qms.containsKey(c)) {
+ return;
+ }
+ if(c.canClickNPC()) {
+ qms.put(c, qm);
+
+ NashornScriptEngine iv = getQuestScriptEngine(c, questid);
+ if (iv == null) {
+ //FilePrinter.printError(FilePrinter.QUEST_UNCODED, "RAISE Quest " + questid + " is uncoded.");
+ qm.dispose();
+ return;
+ }
+
+ iv.put("qm", qm);
+ scripts.put(c, iv);
+ c.setClickedNPC();
+ iv.invokeFunction("raiseOpen");
+ }
+ } catch (final UndeclaredThrowableException ute) {
+ FilePrinter.printError(FilePrinter.QUEST + questid + ".txt", ute);
+ dispose(c);
+ } catch (final Throwable t) {
+ FilePrinter.printError(FilePrinter.QUEST + getQM(c).getQuest() + ".txt", t);
+ dispose(c);
+ }
+ }
+
public void dispose(QuestActionManager qm, MapleClient c) {
qms.remove(c);
scripts.remove(c);
diff --git a/src/server/MapleItemInformationProvider.java b/src/server/MapleItemInformationProvider.java
index 4a2148e8c5..6ce159d95a 100644
--- a/src/server/MapleItemInformationProvider.java
+++ b/src/server/MapleItemInformationProvider.java
@@ -2156,11 +2156,10 @@ public class MapleItemInformationProvider {
return questItemConsCache.get(itemId);
}
MapleData data = getItemData(itemId);
+ QuestConsItem qcItem = null;
MapleData infoData = data.getChildByPath("info");
- MapleData ciData = infoData.getChildByPath("consumeItem");
- QuestConsItem qcItem = null;
- if (ciData != null) {
+ if (infoData.getChildByPath("uiData") != null) {
qcItem = new QuestConsItem();
qcItem.exp = MapleDataTool.getInt("exp", infoData);
qcItem.grade = MapleDataTool.getInt("grade", infoData);
@@ -2168,11 +2167,14 @@ public class MapleItemInformationProvider {
qcItem.items = new HashMap<>(2);
Map cItems = qcItem.items;
- for (MapleData ciItem : ciData.getChildren()) {
- int itemid = MapleDataTool.getInt("0", ciItem);
- int qty = MapleDataTool.getInt("1", ciItem);
-
- cItems.put(itemid, qty);
+ MapleData ciData = infoData.getChildByPath("consumeItem");
+ if (ciData != null) {
+ for (MapleData ciItem : ciData.getChildren()) {
+ int itemid = MapleDataTool.getInt("0", ciItem);
+ int qty = MapleDataTool.getInt("1", ciItem);
+
+ cItems.put(itemid, qty);
+ }
}
}
diff --git a/src/server/MapleTrade.java b/src/server/MapleTrade.java
index c5a6a50d1a..194d0fb07a 100644
--- a/src/server/MapleTrade.java
+++ b/src/server/MapleTrade.java
@@ -80,8 +80,8 @@ public class MapleTrade {
private byte number;
private boolean fullTrade = false;
- public MapleTrade(byte number, MapleCharacter c) {
- chr = c;
+ public MapleTrade(byte number, MapleCharacter chr) {
+ this.chr = chr;
this.number = number;
}
@@ -291,8 +291,8 @@ public class MapleTrade {
}
}
- public static void completeTrade(MapleCharacter c) {
- MapleTrade local = c.getTrade();
+ public static void completeTrade(MapleCharacter chr) {
+ MapleTrade local = chr.getTrade();
MapleTrade partner = local.getPartner();
if (local.checkCompleteHandshake()) {
local.fetchExchangedItems();
@@ -300,12 +300,12 @@ public class MapleTrade {
if (!local.fitsMeso()) {
cancelTrade(local.getChr(), TradeResult.UNSUCCESSFUL);
- c.message("There is not enough meso inventory space to complete the trade.");
+ chr.message("There is not enough meso inventory space to complete the trade.");
partner.getChr().message("Partner does not have enough meso inventory space to complete the trade.");
return;
} else if (!partner.fitsMeso()) {
cancelTrade(partner.getChr(), TradeResult.UNSUCCESSFUL);
- c.message("Partner does not have enough meso inventory space to complete the trade.");
+ chr.message("Partner does not have enough meso inventory space to complete the trade.");
partner.getChr().message("There is not enough meso inventory space to complete the trade.");
return;
}
@@ -313,7 +313,7 @@ public class MapleTrade {
if (!local.fitsInInventory()) {
if (local.fitsUniquesInInventory()) {
cancelTrade(local.getChr(), TradeResult.UNSUCCESSFUL);
- c.message("There is not enough inventory space to complete the trade.");
+ chr.message("There is not enough inventory space to complete the trade.");
partner.getChr().message("Partner does not have enough inventory space to complete the trade.");
} else {
cancelTrade(local.getChr(), TradeResult.UNSUCCESSFUL_UNIQUE_ITEM_LIMIT);
@@ -323,11 +323,11 @@ public class MapleTrade {
} else if (!partner.fitsInInventory()) {
if (partner.fitsUniquesInInventory()) {
cancelTrade(partner.getChr(), TradeResult.UNSUCCESSFUL);
- c.message("Partner does not have enough inventory space to complete the trade.");
+ chr.message("Partner does not have enough inventory space to complete the trade.");
partner.getChr().message("There is not enough inventory space to complete the trade.");
} else {
cancelTrade(partner.getChr(), TradeResult.UNSUCCESSFUL_UNIQUE_ITEM_LIMIT);
- c.message("Partner cannot hold more than one one-of-a-kind item at a time.");
+ chr.message("Partner cannot hold more than one one-of-a-kind item at a time.");
}
return;
}
@@ -355,7 +355,7 @@ public class MapleTrade {
partner.completeTrade();
partner.getChr().setTrade(null);
- c.setTrade(null);
+ chr.setTrade(null);
}
}
@@ -424,9 +424,9 @@ public class MapleTrade {
trade.cancelHandshake(result.getValue());
}
- public static void startTrade(MapleCharacter c) {
- if (c.getTrade() == null) {
- c.setTrade(new MapleTrade((byte) 0, c));
+ public static void startTrade(MapleCharacter chr) {
+ if (chr.getTrade() == null) {
+ chr.setTrade(new MapleTrade((byte) 0, chr));
}
}
@@ -496,13 +496,13 @@ public class MapleTrade {
}
}
- public static void declineTrade(MapleCharacter c) {
- MapleTrade trade = c.getTrade();
+ public static void declineTrade(MapleCharacter chr) {
+ MapleTrade trade = chr.getTrade();
if (trade != null) {
if (trade.getPartner() != null) {
MapleCharacter other = trade.getPartner().getChr();
- if (MapleInviteCoordinator.answerInvite(InviteType.TRADE, c.getId(), other.getId(), false).result == InviteResult.DENIED) {
- other.message(c.getName() + " has declined your trade request.");
+ if (MapleInviteCoordinator.answerInvite(InviteType.TRADE, chr.getId(), other.getId(), false).result == InviteResult.DENIED) {
+ other.message(chr.getName() + " has declined your trade request.");
}
other.getTrade().cancel(TradeResult.PARTNER_CANCEL.getValue());
@@ -510,7 +510,7 @@ public class MapleTrade {
}
trade.cancel(TradeResult.NO_RESPONSE.getValue());
- c.setTrade(null);
+ chr.setTrade(null);
}
}
diff --git a/src/server/life/MapleLifeFactory.java b/src/server/life/MapleLifeFactory.java
index b691581503..50202629e9 100644
--- a/src/server/life/MapleLifeFactory.java
+++ b/src/server/life/MapleLifeFactory.java
@@ -25,9 +25,11 @@ import java.awt.Point;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import provider.MapleData;
import provider.MapleDataProvider;
import provider.MapleDataProviderFactory;
@@ -43,7 +45,19 @@ public class MapleLifeFactory {
private static MapleData mobStringData = stringDataWZ.getData("Mob.img");
private static MapleData npcStringData = stringDataWZ.getData("Npc.img");
private static Map monsterStats = new HashMap<>();
+ private static Set hpbarBosses = getHpBarBosses();
+ private static Set getHpBarBosses() {
+ Set ret = new HashSet<>();
+
+ MapleDataProvider uiDataWZ = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/UI.wz"));
+ for (MapleData bossData : uiDataWZ.getData("UIWindow.img").getChildByPath("MobGage/Mob").getChildren()) {
+ ret.add(Integer.valueOf(bossData.getName()));
+ }
+
+ return ret;
+ }
+
public static AbstractLoadedMapleLife getLife(int id, String type) {
if (type.equalsIgnoreCase("n")) {
return getNPC(id);
@@ -150,9 +164,11 @@ public class MapleLifeFactory {
stats.setFirstAttack(firstAttack > 0);
stats.setDropPeriod(MapleDataTool.getIntConvert("dropItemPeriod", monsterInfoData, stats.getDropPeriod() / 10000) * 10000);
- stats.setTagColor(MapleDataTool.getIntConvert("hpTagColor", monsterInfoData, 0));
- stats.setTagBgColor(MapleDataTool.getIntConvert("hpTagBgcolor", monsterInfoData, 0));
-
+ if (!(stats.isBoss() && !hpbarBosses.contains(mid))) { // thanks Riizade, Z1peR, Anesthetic for noticing some bosses crashing players due to missing requirements
+ stats.setTagColor(MapleDataTool.getIntConvert("hpTagColor", monsterInfoData, 0));
+ stats.setTagBgColor(MapleDataTool.getIntConvert("hpTagBgcolor", monsterInfoData, 0));
+ }
+
for (MapleData idata : monsterData) {
if (!idata.getName().equals("info")) {
int delay = 0;
diff --git a/src/server/life/MapleMonster.java b/src/server/life/MapleMonster.java
index 931ee5a0f2..6cb8132a86 100644
--- a/src/server/life/MapleMonster.java
+++ b/src/server/life/MapleMonster.java
@@ -743,7 +743,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
attacker.gainExp(_personalExp, _partyExp, true, false, white);
attacker.increaseEquipExp(_personalExp);
- attacker.updateQuestMobCount(getId());
+ attacker.raiseQuestMobCount(getId());
}
}
@@ -873,7 +873,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
}, delay, delay);
}
- private void dispatchUpdateQuestMobCount() {
+ private void dispatchRaiseQuestMobCount() {
Set attackerChrids = takenDamage.keySet();
if(!attackerChrids.isEmpty()) {
Map mapChars = map.getMapPlayers();
@@ -884,7 +884,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
MapleCharacter chr = mapChars.get(chrid);
if(chr != null && chr.isLoggedinWorld()) {
- chr.updateQuestMobCount(mobid);
+ chr.raiseQuestMobCount(mobid);
}
}
}
@@ -906,7 +906,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
private synchronized void processMonsterKilled(boolean hasKiller) {
if(!hasKiller) { // players won't gain EXP from a mob that has no killer, but a quest count they should
- dispatchUpdateQuestMobCount();
+ dispatchRaiseQuestMobCount();
}
this.aggroClearDamages();
diff --git a/src/server/maps/MapleMap.java b/src/server/maps/MapleMap.java
index 5c6f6ffbb6..efb6f96c54 100644
--- a/src/server/maps/MapleMap.java
+++ b/src/server/maps/MapleMap.java
@@ -3261,9 +3261,9 @@ public class MapleMap {
public MapleCharacter getCharacterById(int id) {
chrRLock.lock();
try {
- for (MapleCharacter c : this.characters) {
- if (c.getId() == id) {
- return c;
+ for (MapleCharacter chr : this.characters) {
+ if (chr.getId() == id) {
+ return chr;
}
}
} finally {
@@ -3421,8 +3421,8 @@ public class MapleMap {
public void broadcastNightEffect() {
chrRLock.lock();
try {
- for (MapleCharacter c : characters) {
- sendNightEffect(c);
+ for (MapleCharacter chr : this.characters) {
+ sendNightEffect(chr);
}
} finally {
chrRLock.unlock();
@@ -3432,9 +3432,9 @@ public class MapleMap {
public MapleCharacter getCharacterByName(String name) {
chrRLock.lock();
try {
- for (MapleCharacter c : this.characters) {
- if (c.getName().toLowerCase().equals(name.toLowerCase())) {
- return c;
+ for (MapleCharacter chr : this.characters) {
+ if (chr.getName().toLowerCase().equals(name.toLowerCase())) {
+ return chr;
}
}
} finally {
diff --git a/src/server/maps/MapleMiniGame.java b/src/server/maps/MapleMiniGame.java
index b0fd6c843b..30b7066fe2 100644
--- a/src/server/maps/MapleMiniGame.java
+++ b/src/server/maps/MapleMiniGame.java
@@ -89,8 +89,8 @@ public class MapleMiniGame extends AbstractMapleMapObject {
return visitor == null;
}
- public boolean isOwner(MapleCharacter c) {
- return owner.equals(c);
+ public boolean isOwner(MapleCharacter chr) {
+ return owner.equals(chr);
}
public void addVisitor(MapleCharacter challenger) {
diff --git a/src/server/maps/MaplePlayerShop.java b/src/server/maps/MaplePlayerShop.java
index ed3ba67bc7..c895ae998a 100644
--- a/src/server/maps/MaplePlayerShop.java
+++ b/src/server/maps/MaplePlayerShop.java
@@ -120,8 +120,8 @@ public class MaplePlayerShop extends AbstractMapleMapObject {
}
}
- public boolean isOwner(MapleCharacter c) {
- return owner.equals(c);
+ public boolean isOwner(MapleCharacter chr) {
+ return owner.equals(chr);
}
private void addVisitor(MapleCharacter visitor) {
diff --git a/src/server/quest/MapleQuest.java b/src/server/quest/MapleQuest.java
index 9760847427..a33167d190 100644
--- a/src/server/quest/MapleQuest.java
+++ b/src/server/quest/MapleQuest.java
@@ -28,11 +28,12 @@ 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 config.YamlConfig;
+import java.util.Collection;
import java.util.EnumMap;
+import java.util.Map.Entry;
import java.util.Set;
import provider.MapleData;
import provider.MapleDataProvider;
@@ -51,6 +52,7 @@ import tools.StringUtil;
public class MapleQuest {
private static Map quests = new HashMap<>();
+ private static Map infoNumberQuests = new HashMap<>();
private static Map medals = new HashMap<>();
private static final Set exploitableQuests = new HashSet<>();
@@ -61,9 +63,8 @@ public class MapleQuest {
exploitableQuests.add((short) 21752);
}
- protected short infoNumber, id;
+ protected short id;
protected int timeLimit, timeLimit2;
- protected String infoex;
protected Map startReqs = new EnumMap<>(MapleQuestRequirementType.class);
protected Map completeReqs = new EnumMap<>(MapleQuestRequirementType.class);
protected Map startActs = new EnumMap<>(MapleQuestActionType.class);
@@ -111,8 +112,6 @@ public class MapleQuest {
MapleQuestRequirementType type = MapleQuestRequirementType.getByWZName(startReq.getName());
if (type.equals(MapleQuestRequirementType.INTERVAL)) {
repeatable = true;
- } else if (type.equals(MapleQuestRequirementType.INFO_NUMBER)) {
- infoNumber = (short) MapleDataTool.getInt(startReq, 0);
} else if (type.equals(MapleQuestRequirementType.MOB)) {
for (MapleData mob : startReq.getChildren()) {
relevantMobs.add(MapleDataTool.getInt(mob.getChildByPath("id")));
@@ -120,8 +119,9 @@ public class MapleQuest {
}
MapleQuestRequirement req = this.getRequirement(type, startReq);
- if(req == null)
- continue;
+ if (req == null) {
+ continue;
+ }
startReqs.put(type, req);
}
@@ -131,14 +131,13 @@ public class MapleQuest {
if (completeReqData != null) {
for (MapleData completeReq : completeReqData.getChildren()) {
MapleQuestRequirementType type = MapleQuestRequirementType.getByWZName(completeReq.getName());
- MapleQuestRequirement req = this.getRequirement(type, completeReq);
- if(req == null)
- continue;
+ MapleQuestRequirement req = this.getRequirement(type, completeReq);
+ if (req == null) {
+ continue;
+ }
- if (type.equals(MapleQuestRequirementType.INFO_NUMBER)) {
- infoNumber = (short) MapleDataTool.getInt(completeReq, 0);
- } else if (type.equals(MapleQuestRequirementType.MOB)) {
+ if (type.equals(MapleQuestRequirementType.MOB)) {
for (MapleData mob : completeReq.getChildren()) {
relevantMobs.add(MapleDataTool.getInt(mob.getChildByPath("id")));
}
@@ -193,35 +192,13 @@ public class MapleQuest {
return ret;
}
- private String getIntervalTimeLeft(MapleCharacter c, IntervalRequirement r) {
- StringBuilder str = new StringBuilder();
-
- long futureTime = c.getQuest(MapleQuest.getInstance(getId())).getCompletionTime() + r.getInterval();
- long leftTime = futureTime - System.currentTimeMillis();
-
- byte mode = 0;
- if(leftTime / (60*1000) > 0) {
- mode++; //counts minutes
-
- if(leftTime / (60*60*1000) > 0)
- mode++; //counts hours
+ public static MapleQuest getInstanceFromInfoNumber(int infoNumber) {
+ Integer id = infoNumberQuests.get(infoNumber);
+ if (id == null) {
+ id = infoNumber;
}
- switch(mode) {
- case 2:
- int hours = (int) ((leftTime / (1000*60*60)));
- str.append(hours + " hours, ");
-
- case 1:
- int minutes = (int) ((leftTime / (1000*60)) % 60);
- str.append(minutes + " minutes, ");
-
- default:
- int seconds = (int) (leftTime / 1000) % 60 ;
- str.append(seconds + " seconds");
- }
-
- return str.toString();
+ return getInstance(id);
}
public boolean isSameDayRepeatable() {
@@ -231,105 +208,129 @@ public class MapleQuest {
return ir.getInterval() < YamlConfig.config.server.QUEST_POINT_REPEATABLE_INTERVAL * 60 * 60 * 1000;
}
- public boolean canStartWithoutRequirements(MapleCharacter c) {
- MapleQuestStatus mqs = c.getQuest(this);
- return !(mqs.getStatus() != Status.NOT_STARTED && !(mqs.getStatus() == Status.COMPLETED && repeatable));
+ public boolean canStartQuestByStatus(MapleCharacter chr) {
+ MapleQuestStatus mqs = chr.getQuest(this);
+ return !(!mqs.getStatus().equals(Status.NOT_STARTED) && !(mqs.getStatus().equals(Status.COMPLETED) && repeatable));
}
- public boolean canStart(MapleCharacter c, int npcid) {
- if (!canStartWithoutRequirements(c)) {
+ public boolean canQuestByInfoProgress(MapleCharacter chr) {
+ MapleQuestStatus mqs = chr.getQuest(this);
+ List ix = mqs.getInfoEx();
+ if (!ix.isEmpty()) {
+ short questid = mqs.getQuestID();
+ short infoNumber = mqs.getInfoNumber();
+ if (infoNumber <= 0) {
+ infoNumber = questid; // on default infoNumber mimics questid
+ }
+
+ int ixSize = ix.size();
+ for (int i = 0; i < ixSize; i++) {
+ String progress = chr.getClient().getAbstractPlayerInteraction().getQuestProgress(infoNumber, i);
+ String ixProgress = ix.get(i);
+
+ if (!progress.contentEquals(ixProgress)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public boolean canStart(MapleCharacter chr, int npcid) {
+ if (!canStartQuestByStatus(chr)) {
return false;
}
+
for (MapleQuestRequirement r : startReqs.values()) {
- if (!r.check(c, npcid)) {
- if(r.getType().getType() == MapleQuestRequirementType.INTERVAL.getType()) {
- c.message("This quest will become available again in approximately " + getIntervalTimeLeft(c, (IntervalRequirement)r) + ".");
- }
+ if (!r.check(chr, npcid)) {
return false;
}
}
- return true;
- }
-
- public boolean canComplete(MapleCharacter c, Integer npcid) {
- if (!c.getQuest(this).getStatus().equals(Status.STARTED)) {
+
+ if (!canQuestByInfoProgress(chr)) {
return false;
}
- for (MapleQuestRequirement r : completeReqs.values()) {
- if (r == null) {
- return false;
- } else if(!r.check(c, npcid)) {
- if(r.getType() == MapleQuestRequirementType.MESO) { // TODO: find a way to tell the client about the new MESO requirement type.
- c.dropMessage(5, "You don't have enough mesos to complete this quest.");
- }
- return false;
- }
- }
+
return true;
}
- public void start(MapleCharacter c, int npc) {
- if (autoStart || canStart(c, npc)) {
- for (MapleQuestAction a : startActs.values()) {
- if (!a.check(c, null)) { // would null be good ?
- return;
- }
- a.run(c, null);
- }
- forceStart(c, npc);
+ public boolean canComplete(MapleCharacter chr, Integer npcid) {
+ MapleQuestStatus mqs = chr.getQuest(this);
+ if (!mqs.getStatus().equals(Status.STARTED)) {
+ return false;
}
+
+ for (MapleQuestRequirement r : completeReqs.values()) {
+ if (!r.check(chr, npcid)) {
+ return false;
+ }
+ }
+
+ if (!canQuestByInfoProgress(chr)) {
+ return false;
+ }
+
+ return true;
}
- public void complete(MapleCharacter c, int npc) {
- complete(c, npc, null);
- }
-
- public void complete(MapleCharacter c, int npc, Integer selection) {
- if (autoPreComplete || canComplete(c, npc)) {
- for (MapleQuestAction a : completeActs.values()) {
- if (!a.check(c, selection)) {
+ public void start(MapleCharacter chr, int npc) {
+ if (autoStart || canStart(chr, npc)) {
+ Collection acts = startActs.values();
+ for (MapleQuestAction a : acts) {
+ if (!a.check(chr, null)) { // would null be good ?
return;
}
}
+ for (MapleQuestAction a : acts) {
+ a.run(chr, null);
+ }
+ forceStart(chr, npc);
+ }
+ }
- forceComplete(c, npc);
- for (MapleQuestAction a : completeActs.values()) {
- a.run(c, selection);
+ public void complete(MapleCharacter chr, int npc) {
+ complete(chr, npc, null);
+ }
+
+ public void complete(MapleCharacter chr, int npc, Integer selection) {
+ if (autoPreComplete || canComplete(chr, npc)) {
+ Collection acts = completeActs.values();
+ for (MapleQuestAction a : acts) {
+ if (!a.check(chr, selection)) {
+ return;
+ }
+ }
+ forceComplete(chr, npc);
+ for (MapleQuestAction a : acts) {
+ a.run(chr, selection);
}
}
}
- public void reset(MapleCharacter c) {
- c.updateQuest(new MapleQuestStatus(this, MapleQuestStatus.Status.NOT_STARTED));
+ public void reset(MapleCharacter chr) {
+ chr.updateQuestStatus(new MapleQuestStatus(this, MapleQuestStatus.Status.NOT_STARTED));
}
- public void forfeit(MapleCharacter c) {
- if (!c.getQuest(this).getStatus().equals(Status.STARTED)) {
+ public void forfeit(MapleCharacter chr) {
+ if (!chr.getQuest(this).getStatus().equals(Status.STARTED)) {
return;
}
if (timeLimit > 0) {
- c.announce(MaplePacketCreator.removeQuestTimeLimit(id));
+ chr.announce(MaplePacketCreator.removeQuestTimeLimit(id));
}
MapleQuestStatus newStatus = new MapleQuestStatus(this, MapleQuestStatus.Status.NOT_STARTED);
- newStatus.setForfeited(c.getQuest(this).getForfeited() + 1);
- c.updateQuest(newStatus);
+ newStatus.setForfeited(chr.getQuest(this).getForfeited() + 1);
+ chr.updateQuestStatus(newStatus);
}
- public boolean forceStart(MapleCharacter c, int npc) {
+ public boolean forceStart(MapleCharacter chr, int npc) {
MapleQuestStatus newStatus = new MapleQuestStatus(this, MapleQuestStatus.Status.STARTED, npc);
- newStatus.setForfeited(c.getQuest(this).getForfeited());
- newStatus.setCompleted(c.getQuest(this).getCompleted());
-
- if (timeLimit > 0) {
- newStatus.setExpirationTime(System.currentTimeMillis() + (timeLimit * 1000));
- c.questTimeLimit(this, timeLimit);
- }
- if (timeLimit2 > 0) {
- newStatus.setExpirationTime(System.currentTimeMillis() + timeLimit2);
- c.questTimeLimit2(this, newStatus.getExpirationTime());
- }
- c.updateQuest(newStatus);
+ MapleQuestStatus oldStatus = chr.getQuest(this.getId());
+ for (Entry e : oldStatus.getProgress().entrySet()) {
+ newStatus.setProgress(e.getKey(), e.getValue());
+ }
if(id / 100 == 35 && YamlConfig.config.server.TOT_MOB_QUEST_REQUIREMENT > 0) {
int setProg = 999 - Math.min(999, YamlConfig.config.server.TOT_MOB_QUEST_REQUIREMENT);
@@ -338,27 +339,40 @@ public class MapleQuest {
if(pid >= 8200000 && pid <= 8200012) {
String pr = StringUtil.getLeftPaddedStr(Integer.toString(setProg), '0', 3);
newStatus.setProgress(pid, pr);
- c.announceUpdateQuest(DelayedQuestUpdate.UPDATE, newStatus, false);
}
}
}
+ newStatus.setForfeited(chr.getQuest(this).getForfeited());
+ newStatus.setCompleted(chr.getQuest(this).getCompleted());
+
+ if (timeLimit > 0) {
+ newStatus.setExpirationTime(System.currentTimeMillis() + (timeLimit * 1000));
+ chr.questTimeLimit(this, timeLimit);
+ }
+ if (timeLimit2 > 0) {
+ newStatus.setExpirationTime(System.currentTimeMillis() + timeLimit2);
+ chr.questTimeLimit2(this, newStatus.getExpirationTime());
+ }
+
+ chr.updateQuestStatus(newStatus);
+
return true;
}
- public boolean forceComplete(MapleCharacter c, int npc) {
+ public boolean forceComplete(MapleCharacter chr, int npc) {
if (timeLimit > 0) {
- c.announce(MaplePacketCreator.removeQuestTimeLimit(id));
+ chr.announce(MaplePacketCreator.removeQuestTimeLimit(id));
}
MapleQuestStatus newStatus = new MapleQuestStatus(this, MapleQuestStatus.Status.COMPLETED, npc);
- newStatus.setForfeited(c.getQuest(this).getForfeited());
- newStatus.setCompleted(c.getQuest(this).getCompleted());
+ newStatus.setForfeited(chr.getQuest(this).getForfeited());
+ newStatus.setCompleted(chr.getQuest(this).getCompleted());
newStatus.setCompletionTime(System.currentTimeMillis());
- c.updateQuest(newStatus);
+ chr.updateQuestStatus(newStatus);
- c.announce(MaplePacketCreator.showSpecialEffect(9)); // Quest completion
- c.getMap().broadcastMessage(c, MaplePacketCreator.showForeignEffect(c.getId(), 9), false); //use 9 instead of 12 for both
+ chr.announce(MaplePacketCreator.showSpecialEffect(9)); // Quest completion
+ chr.getMap().broadcastMessage(chr, MaplePacketCreator.showForeignEffect(chr.getId(), 9), false); //use 9 instead of 12 for both
return true;
}
@@ -390,32 +404,49 @@ public class MapleQuest {
public int getMobAmountNeeded(int mid) {
MapleQuestRequirement req = completeReqs.get(MapleQuestRequirementType.MOB);
- if(req == null)
- return 0;
-
- MobRequirement mreq = (MobRequirement) req;
-
- return mreq.getRequiredMobCount(mid);
+ if(req == null)
+ return 0;
+
+ MobRequirement mreq = (MobRequirement) req;
+
+ return mreq.getRequiredMobCount(mid);
}
- public short getInfoNumber() {
- return infoNumber;
+ public short getInfoNumber(Status qs) {
+ boolean checkEnd = qs.equals(Status.STARTED);
+ Map reqs = !checkEnd ? startReqs : completeReqs;
+
+ MapleQuestRequirement req = reqs.get(MapleQuestRequirementType.INFO_NUMBER);
+ if (req != null) {
+ InfoNumberRequirement inReq = (InfoNumberRequirement) req;
+ return inReq.getInfoNumber();
+ } else {
+ return 0;
+ }
}
- public String getInfoEx() {
- MapleQuestRequirement req = startReqs.get(MapleQuestRequirementType.INFO_EX);
- String ret = "";
- if(req != null) {
- InfoExRequirement ireq = (InfoExRequirement) req;
- ret = ireq.getFirstInfo();
- } else { // Check complete requirements.
- req = completeReqs.get(MapleQuestRequirementType.INFO_EX);
- if(req != null) {
- InfoExRequirement ireq = (InfoExRequirement) req;
- ret = ireq.getFirstInfo();
- }
- }
- return ret;
+ public String getInfoEx(Status qs, int index) {
+ boolean checkEnd = qs.equals(Status.STARTED);
+ Map reqs = !checkEnd ? startReqs : completeReqs;
+ try {
+ MapleQuestRequirement req = reqs.get(MapleQuestRequirementType.INFO_EX);
+ InfoExRequirement ixReq = (InfoExRequirement) req;
+ return ixReq.getInfo().get(index);
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ public List getInfoEx(Status qs) {
+ boolean checkEnd = qs.equals(Status.STARTED);
+ Map reqs = !checkEnd ? startReqs : completeReqs;
+ try {
+ MapleQuestRequirement req = reqs.get(MapleQuestRequirementType.INFO_EX);
+ InfoExRequirement ixReq = (InfoExRequirement) req;
+ return ixReq.getInfo();
+ } catch (Exception e) {
+ return new LinkedList<>();
+ }
}
public int getTimeLimit() {
@@ -447,6 +478,9 @@ public class MapleQuest {
case FIELD_ENTER:
ret = new FieldEnterRequirement(this, data);
break;
+ case INFO_NUMBER:
+ ret = new InfoNumberRequirement(this, data);
+ break;
case INFO_EX:
ret = new InfoExRequirement(this, data);
break;
@@ -495,7 +529,6 @@ public class MapleQuest {
case NORMAL_AUTO_START:
case START:
case END:
- case INFO_NUMBER:
break;
default:
//FilePrinter.printError(FilePrinter.EXCEPTION_CAUGHT, "Unhandled Requirement Type: " + type.toString() + " QuestID: " + this.getId());
@@ -540,6 +573,9 @@ public class MapleQuest {
case PETSPEED:
ret = new PetSpeedAction(this, data);
break;
+ case INFO:
+ ret = new InfoAction(this, data);
+ break;
default:
//FilePrinter.printError(FilePrinter.EXCEPTION_CAUGHT, "Unhandled Action Type: " + type.toString() + " QuestID: " + this.getId());
break;
@@ -548,9 +584,11 @@ public class MapleQuest {
}
public boolean restoreLostItem(MapleCharacter chr, int itemid) {
- ItemAction itemAct = (ItemAction) startActs.get(MapleQuestActionType.ITEM);
- if (itemAct != null) {
- return itemAct.restoreLostItem(chr, itemid);
+ if (chr.getQuest(this).equals(MapleQuestStatus.Status.STARTED)) {
+ ItemAction itemAct = (ItemAction) startActs.get(MapleQuestActionType.ITEM);
+ if (itemAct != null) {
+ return itemAct.restoreLostItem(chr, itemid);
+ }
}
return false;
@@ -561,8 +599,8 @@ public class MapleQuest {
return medalid != null ? medalid : -1;
}
- public int getNpcRequirement(boolean complete) {
- Map reqs = !complete ? startReqs : completeReqs;
+ public int getNpcRequirement(boolean checkEnd) {
+ Map reqs = !checkEnd ? startReqs : completeReqs;
MapleQuestRequirement mqr = reqs.get(MapleQuestRequirementType.NPC);
if (mqr != null) {
return ((NpcRequirement) mqr).get();
@@ -571,8 +609,8 @@ public class MapleQuest {
}
}
- public boolean hasScriptRequirement(boolean complete) {
- Map reqs = !complete ? startReqs : completeReqs;
+ public boolean hasScriptRequirement(boolean checkEnd) {
+ Map reqs = !checkEnd ? startReqs : completeReqs;
MapleQuestRequirement mqr = reqs.get(MapleQuestRequirementType.SCRIPT);
if (mqr != null) {
@@ -612,7 +650,20 @@ public class MapleQuest {
for(MapleData quest : questInfo.getChildren()) {
int questID = Integer.parseInt(quest.getName());
- quests.put(questID, new MapleQuest(questID));
+ MapleQuest q = new MapleQuest(questID);
+ quests.put(questID, q);
+
+ int infoNumber;
+
+ infoNumber = q.getInfoNumber(Status.STARTED);
+ if (infoNumber > 0) {
+ infoNumberQuests.put(infoNumber, questID);
+ }
+
+ infoNumber = q.getInfoNumber(Status.COMPLETED);
+ if (infoNumber > 0) {
+ infoNumberQuests.put(infoNumber, questID);
+ }
}
} catch (Exception ex) {
ex.printStackTrace();
diff --git a/src/server/quest/MapleQuestActionType.java b/src/server/quest/MapleQuestActionType.java
index 06721b45bd..f009d0ff21 100644
--- a/src/server/quest/MapleQuestActionType.java
+++ b/src/server/quest/MapleQuestActionType.java
@@ -26,7 +26,7 @@ package server.quest;
* @author Matze
*/
public enum MapleQuestActionType {
- UNDEFINED(-1), EXP(0), ITEM(1), NEXTQUEST(2), MESO(3), QUEST(4), SKILL(5), FAME(6), BUFF(7), PETSKILL(8), YES(9), NO(10), NPC(11), MIN_LEVEL(12), NORMAL_AUTO_START(13), PETTAMENESS(14), PETSPEED(15), ZERO(16);
+ UNDEFINED(-1), EXP(0), ITEM(1), NEXTQUEST(2), MESO(3), QUEST(4), SKILL(5), FAME(6), BUFF(7), PETSKILL(8), YES(9), NO(10), NPC(11), MIN_LEVEL(12), NORMAL_AUTO_START(13), PETTAMENESS(14), PETSPEED(15), INFO(16), ZERO(16);
final byte type;
private MapleQuestActionType(int type) {
@@ -64,6 +64,8 @@ public enum MapleQuestActionType {
return PETTAMENESS;
} else if (name.equals("petspeed")) {
return PETSPEED;
+ } else if (name.equals("info")) {
+ return INFO;
} else if (name.equals("0")) {
return ZERO;
} else {
diff --git a/scripts/quest/3345.js b/src/server/quest/actions/InfoAction.java
similarity index 52%
rename from scripts/quest/3345.js
rename to src/server/quest/actions/InfoAction.java
index def3916b24..5c5830a18a 100644
--- a/scripts/quest/3345.js
+++ b/src/server/quest/actions/InfoAction.java
@@ -17,34 +17,38 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
+package server.quest.actions;
-var status = -1;
+import client.MapleCharacter;
+import provider.MapleData;
+import provider.MapleDataTool;
+import server.quest.MapleQuest;
+import server.quest.MapleQuestActionType;
-function end(mode, type, selection) {
- if (mode == -1) {
- qm.dispose();
- } else {
- if(mode == 0 && type > 0) {
- qm.dispose();
- return;
+/**
+ *
+ * @author Ronan
+ */
+public class InfoAction extends MapleQuestAction {
+
+ private String info;
+ private int questID;
+
+ public InfoAction(MapleQuest quest, MapleData data) {
+ super(MapleQuestActionType.INFO, quest);
+ questID = quest.getId();
+ processData(data);
+ }
+
+ @Override
+ public void processData(MapleData data) {
+ info = MapleDataTool.getString(data, "");
+ }
+
+
+ @Override
+ public void run(MapleCharacter chr, Integer extSelection) {
+ chr.getAbstractPlayerInteraction().setQuestProgress(questID, info);
}
- if (mode == 1)
- status++;
- else
- status--;
-
- if (status == 0) {
- if(qm.getQuestProgress(3345, 0) == 4) {
- qm.sendNext("So, you have succeeded. With this, Magatia's upfront demise has been averted, well done brave adventurer!");
- qm.forceCompleteQuest();
-
- qm.gainExp(20000);
- } 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();
- }
- }
-}
\ No newline at end of file
+}
diff --git a/src/server/quest/actions/ItemAction.java b/src/server/quest/actions/ItemAction.java
index 600fac086b..6d701603bc 100644
--- a/src/server/quest/actions/ItemAction.java
+++ b/src/server/quest/actions/ItemAction.java
@@ -195,7 +195,7 @@ public class ItemAction extends MapleQuestAction {
if(type.equals(MapleInventoryType.EQUIP) && chr.getInventory(MapleInventoryType.EQUIPPED).countById(item.getId()) > quantity)
continue;
- chr.dropMessage(1, "Please check if you have enough items in your inventory.");
+ announceInventoryLimit(Collections.singletonList(item.getId()), chr);
return false;
} else {
int idx = type.getType() - 1; // more slots available from the given items!
@@ -217,7 +217,7 @@ public class ItemAction extends MapleQuestAction {
result = MapleInventoryManipulator.checkSpaceProgressively(c, it.getLeft().getItemId(), it.getLeft().getQuantity(), "", rndUsed.get(idx), false);
if(result % 2 == 0) {
- chr.dropMessage(1, "Please check if you have enough space in your inventory.");
+ announceInventoryLimit(Collections.singletonList(it.getLeft().getItemId()), chr);
return false;
}
@@ -231,12 +231,28 @@ public class ItemAction extends MapleQuestAction {
}
if (!canHold(chr, gainList)) {
- chr.dropMessage(1, "Please check if you have enough space in your inventory.");
+ List gainItemids = new LinkedList<>();
+ for (Pair- it : gainList) {
+ gainItemids.add(it.getLeft().getItemId());
+ }
+
+ announceInventoryLimit(gainItemids, chr);
return false;
}
return true;
}
+ private void announceInventoryLimit(List itemids, MapleCharacter chr) {
+ for (Integer id : itemids) {
+ if (MapleItemInformationProvider.getInstance().isPickupRestricted(id) && chr.haveItemWithId(id, true)) {
+ chr.dropMessage(1, "Please check if you already have a similar one-of-a-kind item in your inventory.");
+ return;
+ }
+ }
+
+ chr.dropMessage(1, "Please check if you have enough space in your inventory.");
+ }
+
private boolean canHold(MapleCharacter chr, List> gainList) {
List toAddItemids = new LinkedList<>();
List toAddQuantity = new LinkedList<>();
diff --git a/src/server/quest/actions/MapleQuestAction.java b/src/server/quest/actions/MapleQuestAction.java
index c5d70b6545..db361fb120 100644
--- a/src/server/quest/actions/MapleQuestAction.java
+++ b/src/server/quest/actions/MapleQuestAction.java
@@ -43,10 +43,8 @@ public abstract class MapleQuestAction {
public abstract void run(MapleCharacter chr, Integer extSelection);
public abstract void processData(MapleData data);
-
public boolean check(MapleCharacter chr, Integer extSelection) {
- MapleQuestStatus status = chr.getQuest(MapleQuest.getInstance(questID));
- return !(status.getStatus() == MapleQuestStatus.Status.NOT_STARTED && status.getForfeited() > 0);
+ return true;
}
public MapleQuestActionType getType() {
diff --git a/src/server/quest/actions/QuestAction.java b/src/server/quest/actions/QuestAction.java
index f132b362d4..3d86b771c8 100644
--- a/src/server/quest/actions/QuestAction.java
+++ b/src/server/quest/actions/QuestAction.java
@@ -58,7 +58,7 @@ public class QuestAction extends MapleQuestAction {
public void run(MapleCharacter chr, Integer extSelection) {
for(Integer questID : quests.keySet()) {
int stat = quests.get(questID);
- chr.updateQuest(new MapleQuestStatus(MapleQuest.getInstance(questID), MapleQuestStatus.Status.getById(stat)));
+ chr.updateQuestStatus(new MapleQuestStatus(MapleQuest.getInstance(questID), MapleQuestStatus.Status.getById(stat)));
}
}
}
diff --git a/src/server/quest/requirements/InfoExRequirement.java b/src/server/quest/requirements/InfoExRequirement.java
index 1740f918b7..ec39f0383b 100644
--- a/src/server/quest/requirements/InfoExRequirement.java
+++ b/src/server/quest/requirements/InfoExRequirement.java
@@ -22,7 +22,6 @@
package server.quest.requirements;
import client.MapleCharacter;
-import client.MapleQuestStatus;
import java.util.ArrayList;
import java.util.List;
import provider.MapleData;
@@ -41,14 +40,14 @@ public class InfoExRequirement extends MapleQuestRequirement {
public InfoExRequirement(MapleQuest quest, MapleData data) {
super(MapleQuestRequirementType.INFO_EX);
- processData(data);
questID = quest.getId();
+ processData(data);
}
@Override
public void processData(MapleData data) {
// Because we have to...
- for(MapleData infoEx : data.getChildren()) {
+ for(MapleData infoEx : data.getChildren()) {
MapleData value = infoEx.getChildByPath("value");
infoExpected.add(MapleDataTool.getString(value, ""));
}
@@ -57,15 +56,10 @@ public class InfoExRequirement extends MapleQuestRequirement {
@Override
public boolean check(MapleCharacter chr, Integer npcid) {
- MapleQuestStatus status = chr.getQuest(MapleQuest.getInstance(questID));
- return infoExpected.contains(status.getInfo());
+ return true;
}
public List getInfo() {
return infoExpected;
- }
-
- public String getFirstInfo() {
- return !infoExpected.isEmpty() ? infoExpected.get(0) : "";
- }
+ }
}
diff --git a/src/server/quest/requirements/InfoNumberRequirement.java b/src/server/quest/requirements/InfoNumberRequirement.java
new file mode 100644
index 0000000000..080176c0cf
--- /dev/null
+++ b/src/server/quest/requirements/InfoNumberRequirement.java
@@ -0,0 +1,57 @@
+/*
+ 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 server.quest.requirements;
+
+import client.MapleCharacter;
+import provider.MapleData;
+import provider.MapleDataTool;
+import server.quest.MapleQuest;
+import server.quest.MapleQuestRequirementType;
+
+/**
+ *
+ * @author Ronan
+ */
+public class InfoNumberRequirement extends MapleQuestRequirement {
+
+ private short infoNumber;
+ private int questID;
+
+ public InfoNumberRequirement(MapleQuest quest, MapleData data) {
+ super(MapleQuestRequirementType.INFO_NUMBER);
+ questID = quest.getId();
+ processData(data);
+ }
+
+ @Override
+ public void processData(MapleData data) {
+ infoNumber = (short) MapleDataTool.getIntConvert(data, 0);
+ }
+
+
+ @Override
+ public boolean check(MapleCharacter chr, Integer npcid) {
+ return true;
+ }
+
+ public short getInfoNumber() {
+ return infoNumber;
+ }
+}
diff --git a/src/server/quest/requirements/IntervalRequirement.java b/src/server/quest/requirements/IntervalRequirement.java
index 76d0645a25..e1e127a1ce 100644
--- a/src/server/quest/requirements/IntervalRequirement.java
+++ b/src/server/quest/requirements/IntervalRequirement.java
@@ -38,8 +38,8 @@ public class IntervalRequirement extends MapleQuestRequirement {
public IntervalRequirement(MapleQuest quest, MapleData data) {
super(MapleQuestRequirementType.INTERVAL);
- processData(data);
questID = quest.getId();
+ processData(data);
}
public int getInterval() {
@@ -51,11 +51,47 @@ public class IntervalRequirement extends MapleQuestRequirement {
interval = MapleDataTool.getInt(data) * 60 * 1000;
}
+ private static String getIntervalTimeLeft(MapleCharacter chr, IntervalRequirement r) {
+ StringBuilder str = new StringBuilder();
+
+ long futureTime = chr.getQuest(MapleQuest.getInstance(r.questID)).getCompletionTime() + r.getInterval();
+ long leftTime = futureTime - System.currentTimeMillis();
+
+ byte mode = 0;
+ if(leftTime / (60*1000) > 0) {
+ mode++; //counts minutes
+
+ if(leftTime / (60*60*1000) > 0)
+ mode++; //counts hours
+ }
+
+ switch(mode) {
+ case 2:
+ int hours = (int) ((leftTime / (1000*60*60)));
+ str.append(hours + " hours, ");
+
+ case 1:
+ int minutes = (int) ((leftTime / (1000*60)) % 60);
+ str.append(minutes + " minutes, ");
+
+ default:
+ int seconds = (int) (leftTime / 1000) % 60 ;
+ str.append(seconds + " seconds");
+ }
+
+ return str.toString();
+ }
@Override
public boolean check(MapleCharacter chr, Integer npcid) {
boolean check = !chr.getQuest(MapleQuest.getInstance(questID)).getStatus().equals(MapleQuestStatus.Status.COMPLETED);
boolean check2 = chr.getQuest(MapleQuest.getInstance(questID)).getCompletionTime() <= System.currentTimeMillis() - interval;
- return check || check2;
+
+ if (check || check2) {
+ return true;
+ } else {
+ chr.message("This quest will become available again in approximately " + getIntervalTimeLeft(chr, this) + ".");
+ return false;
+ }
}
}
diff --git a/src/server/quest/requirements/MesoRequirement.java b/src/server/quest/requirements/MesoRequirement.java
index 97ee20346f..7ae55d5af5 100644
--- a/src/server/quest/requirements/MesoRequirement.java
+++ b/src/server/quest/requirements/MesoRequirement.java
@@ -45,6 +45,11 @@ public class MesoRequirement extends MapleQuestRequirement {
@Override
public boolean check(MapleCharacter chr, Integer npcid) {
- return chr.getMeso() >= meso;
+ if (chr.getMeso() >= meso) {
+ return true;
+ } else {
+ chr.dropMessage(5, "You don't have enough mesos to complete this quest.");
+ return false;
+ }
}
}
diff --git a/src/server/quest/requirements/MobRequirement.java b/src/server/quest/requirements/MobRequirement.java
index 5e2a8cd3b8..8b13440a4e 100644
--- a/src/server/quest/requirements/MobRequirement.java
+++ b/src/server/quest/requirements/MobRequirement.java
@@ -42,8 +42,8 @@ public class MobRequirement extends MapleQuestRequirement {
public MobRequirement(MapleQuest quest, MapleData data) {
super(MapleQuestRequirementType.MOB);
- processData(data);
questID = quest.getId();
+ processData(data);
}
/**
diff --git a/src/server/quest/requirements/QuestRequirement.java b/src/server/quest/requirements/QuestRequirement.java
index bb142fc7d7..47bc8457db 100644
--- a/src/server/quest/requirements/QuestRequirement.java
+++ b/src/server/quest/requirements/QuestRequirement.java
@@ -58,12 +58,12 @@ public class QuestRequirement extends MapleQuestRequirement {
public boolean check(MapleCharacter chr, Integer npcid) {
for(Integer questID : quests.keySet()) {
int stateReq = quests.get(questID);
- MapleQuestStatus q = chr.getQuest(MapleQuest.getInstance(questID));
+ MapleQuestStatus qs = chr.getQuest(MapleQuest.getInstance(questID));
- if(q == null && MapleQuestStatus.Status.getById(stateReq).equals(MapleQuestStatus.Status.NOT_STARTED))
+ if(qs == null && MapleQuestStatus.Status.getById(stateReq).equals(MapleQuestStatus.Status.NOT_STARTED))
continue;
- if(q == null || !q.getStatus().equals(MapleQuestStatus.Status.getById(stateReq))) {
+ if(qs == null || !qs.getStatus().equals(MapleQuestStatus.Status.getById(stateReq))) {
return false;
}
diff --git a/src/tools/MaplePacketCreator.java b/src/tools/MaplePacketCreator.java
index a91e7db1b8..bad5a79881 100644
--- a/src/tools/MaplePacketCreator.java
+++ b/src/tools/MaplePacketCreator.java
@@ -66,6 +66,7 @@ import config.YamlConfig;
import constants.game.ExpTable;
import constants.game.GameConstants;
import constants.inventory.ItemConstants;
+import constants.net.ServerConstants;
import constants.skills.Buccaneer;
import constants.skills.Corsair;
import constants.skills.ThunderBreaker;
@@ -351,20 +352,31 @@ public class MaplePacketCreator {
}
private static void addQuestInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) {
- mplew.writeShort(chr.getStartedQuestsSize());
- for (MapleQuestStatus q : chr.getStartedQuests()) {
- mplew.writeShort(q.getQuest().getId());
- mplew.writeMapleAsciiString(q.getQuestData());
- if (q.getQuest().getInfoNumber() > 0) {
- mplew.writeShort(q.getQuest().getInfoNumber());
- mplew.writeMapleAsciiString(q.getQuestData());
+ List started = chr.getStartedQuests();
+ int startedSize = 0;
+ for (MapleQuestStatus qs : started) {
+ if (qs.getInfoNumber() > 0) {
+ startedSize++;
+ }
+ startedSize++;
+ }
+ mplew.writeShort(startedSize);
+ for (MapleQuestStatus qs : started) {
+ mplew.writeShort(qs.getQuest().getId());
+ mplew.writeMapleAsciiString(qs.getProgressData());
+
+ short infoNumber = qs.getInfoNumber();
+ if (infoNumber > 0) {
+ MapleQuestStatus iqs = chr.getQuest(infoNumber);
+ mplew.writeShort(infoNumber);
+ mplew.writeMapleAsciiString(iqs.getProgressData());
}
}
List completed = chr.getCompletedQuests();
mplew.writeShort(completed.size());
- for (MapleQuestStatus q : completed) {
- mplew.writeShort(q.getQuest().getId());
- mplew.writeLong(getTime(q.getCompletionTime()));
+ for (MapleQuestStatus qs : completed) {
+ mplew.writeShort(qs.getQuest().getId());
+ mplew.writeLong(getTime(qs.getCompletionTime()));
}
}
@@ -2839,9 +2851,9 @@ public class MaplePacketCreator {
}
ArrayList medalQuests = new ArrayList<>();
List completed = chr.getCompletedQuests();
- for (MapleQuestStatus q : completed) {
- if (q.getQuest().getId() >= 29000) { // && q.getQuest().getId() <= 29923
- medalQuests.add(q.getQuest().getId());
+ for (MapleQuestStatus qs : completed) {
+ if (qs.getQuest().getId() >= 29000) { // && q.getQuest().getId() <= 29923
+ medalQuests.add(qs.getQuest().getId());
}
}
@@ -2989,18 +3001,20 @@ public class MaplePacketCreator {
return mplew.getPacket();
}
- public static byte[] updateQuest(MapleQuestStatus q, boolean infoUpdate) {
+ public static byte[] updateQuest(MapleCharacter chr, MapleQuestStatus qs, boolean infoUpdate) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue());
mplew.write(1);
- mplew.writeShort(infoUpdate ? q.getQuest().getInfoNumber() : q.getQuest().getId());
if (infoUpdate) {
+ MapleQuestStatus iqs = chr.getQuest(qs.getInfoNumber());
+ mplew.writeShort(iqs.getQuestID());
mplew.write(1);
+ mplew.writeMapleAsciiString(iqs.getProgressData());
} else {
- mplew.write(q.getStatus().getId());
+ mplew.writeShort(qs.getQuest().getId());
+ mplew.write(qs.getStatus().getId());
+ mplew.writeMapleAsciiString(qs.getProgressData());
}
-
- mplew.writeMapleAsciiString(q.getQuestData());
mplew.skip(5);
return mplew.getPacket();
}
@@ -3194,23 +3208,23 @@ public class MaplePacketCreator {
return mplew.getPacket();
}
- public static byte[] getPlayerShopChat(MapleCharacter c, String chat, boolean owner) {
+ public static byte[] getPlayerShopChat(MapleCharacter chr, String chat, boolean owner) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
mplew.write(PlayerInteractionHandler.Action.CHAT.getCode());
mplew.write(PlayerInteractionHandler.Action.CHAT_THING.getCode());
mplew.write(owner ? 0 : 1);
- mplew.writeMapleAsciiString(c.getName() + " : " + chat);
+ mplew.writeMapleAsciiString(chr.getName() + " : " + chat);
return mplew.getPacket();
}
- public static byte[] getPlayerShopNewVisitor(MapleCharacter c, int slot) {
+ public static byte[] getPlayerShopNewVisitor(MapleCharacter chr, int slot) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
mplew.write(PlayerInteractionHandler.Action.VISIT.getCode());
mplew.write(slot);
- addCharLook(mplew, c, false);
- mplew.writeMapleAsciiString(c.getName());
+ addCharLook(mplew, chr, false);
+ mplew.writeMapleAsciiString(chr.getName());
return mplew.getPacket();
}
@@ -3224,22 +3238,22 @@ public class MaplePacketCreator {
return mplew.getPacket();
}
- public static byte[] getTradePartnerAdd(MapleCharacter c) {
+ public static byte[] getTradePartnerAdd(MapleCharacter chr) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
mplew.write(PlayerInteractionHandler.Action.VISIT.getCode());
mplew.write(1);
- addCharLook(mplew, c, false);
- mplew.writeMapleAsciiString(c.getName());
+ addCharLook(mplew, chr, false);
+ mplew.writeMapleAsciiString(chr.getName());
return mplew.getPacket();
}
- public static byte[] tradeInvite(MapleCharacter c) {
+ public static byte[] tradeInvite(MapleCharacter chr) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
mplew.write(PlayerInteractionHandler.Action.INVITE.getCode());
mplew.write(3);
- mplew.writeMapleAsciiString(c.getName());
+ mplew.writeMapleAsciiString(chr.getName());
mplew.write(new byte[]{(byte) 0xB7, (byte) 0x50, 0, 0});
return mplew.getPacket();
}
@@ -4439,15 +4453,15 @@ public class MaplePacketCreator {
return mplew.getPacket();
}
- public static byte[] showGuildInfo(MapleCharacter c) {
+ public static byte[] showGuildInfo(MapleCharacter chr) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue());
mplew.write(0x1A); //signature for showing guild info
- if (c == null) { //show empty guild (used for leaving, expelled)
+ if (chr == null) { //show empty guild (used for leaving, expelled)
mplew.write(0);
return mplew.getPacket();
}
- MapleGuild g = c.getClient().getWorldServer().getGuild(c.getMGC());
+ MapleGuild g = chr.getClient().getWorldServer().getGuild(chr.getMGC());
if (g == null) { //failed to read from DB - don't show a guild
mplew.write(0);
return mplew.getPacket();
@@ -5292,17 +5306,17 @@ public class MaplePacketCreator {
return mplew.getPacket();
}
- public static byte[] getMiniGameNewVisitor(MapleMiniGame minigame, MapleCharacter c, int slot) {
+ public static byte[] getMiniGameNewVisitor(MapleMiniGame minigame, MapleCharacter chr, int slot) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
mplew.write(PlayerInteractionHandler.Action.VISIT.getCode());
mplew.write(slot);
- addCharLook(mplew, c, false);
- mplew.writeMapleAsciiString(c.getName());
+ addCharLook(mplew, chr, false);
+ mplew.writeMapleAsciiString(chr.getName());
mplew.writeInt(1);
- mplew.writeInt(c.getMiniGamePoints(MiniGameResult.WIN, true));
- mplew.writeInt(c.getMiniGamePoints(MiniGameResult.TIE, true));
- mplew.writeInt(c.getMiniGamePoints(MiniGameResult.LOSS, true));
+ mplew.writeInt(chr.getMiniGamePoints(MiniGameResult.WIN, true));
+ mplew.writeInt(chr.getMiniGamePoints(MiniGameResult.TIE, true));
+ mplew.writeInt(chr.getMiniGamePoints(MiniGameResult.LOSS, true));
mplew.writeInt(minigame.getVisitorScore());
return mplew.getPacket();
}
@@ -5447,17 +5461,17 @@ public class MaplePacketCreator {
return mplew.getPacket();
}
- public static byte[] getMatchCardNewVisitor(MapleMiniGame minigame, MapleCharacter c, int slot) {
+ public static byte[] getMatchCardNewVisitor(MapleMiniGame minigame, MapleCharacter chr, int slot) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
mplew.write(PlayerInteractionHandler.Action.VISIT.getCode());
mplew.write(slot);
- addCharLook(mplew, c, false);
- mplew.writeMapleAsciiString(c.getName());
+ addCharLook(mplew, chr, false);
+ mplew.writeMapleAsciiString(chr.getName());
mplew.writeInt(1);
- mplew.writeInt(c.getMiniGamePoints(MiniGameResult.WIN, false));
- mplew.writeInt(c.getMiniGamePoints(MiniGameResult.TIE, false));
- mplew.writeInt(c.getMiniGamePoints(MiniGameResult.LOSS, false));
+ mplew.writeInt(chr.getMiniGamePoints(MiniGameResult.WIN, false));
+ mplew.writeInt(chr.getMiniGamePoints(MiniGameResult.TIE, false));
+ mplew.writeInt(chr.getMiniGamePoints(MiniGameResult.LOSS, false));
mplew.writeInt(minigame.getVisitorScore());
return mplew.getPacket();
}
@@ -5559,19 +5573,19 @@ public class MaplePacketCreator {
return mplew.getPacket();
}
- public static byte[] addOmokBox(MapleCharacter c, int ammount, int type) {
+ public static byte[] addOmokBox(MapleCharacter chr, int ammount, int type) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.UPDATE_CHAR_BOX.getValue());
- mplew.writeInt(c.getId());
- addAnnounceBox(mplew, c.getMiniGame(), ammount, type);
+ mplew.writeInt(chr.getId());
+ addAnnounceBox(mplew, chr.getMiniGame(), ammount, type);
return mplew.getPacket();
}
- public static byte[] addMatchCardBox(MapleCharacter c, int ammount, int type) {
+ public static byte[] addMatchCardBox(MapleCharacter chr, int ammount, int type) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.UPDATE_CHAR_BOX.getValue());
- mplew.writeInt(c.getId());
- addAnnounceBox(mplew, c.getMiniGame(), ammount, type);
+ mplew.writeInt(chr.getId());
+ addAnnounceBox(mplew, chr.getMiniGame(), ammount, type);
return mplew.getPacket();
}
@@ -5583,23 +5597,23 @@ public class MaplePacketCreator {
return mplew.getPacket();
}
- public static byte[] getPlayerShopChat(MapleCharacter c, String chat, byte slot) {
+ public static byte[] getPlayerShopChat(MapleCharacter chr, String chat, byte slot) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
mplew.write(PlayerInteractionHandler.Action.CHAT.getCode());
mplew.write(PlayerInteractionHandler.Action.CHAT_THING.getCode());
mplew.write(slot);
- mplew.writeMapleAsciiString(c.getName() + " : " + chat);
+ mplew.writeMapleAsciiString(chr.getName() + " : " + chat);
return mplew.getPacket();
}
- public static byte[] getTradeChat(MapleCharacter c, String chat, boolean owner) {
+ public static byte[] getTradeChat(MapleCharacter chr, String chat, boolean owner) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
mplew.write(PlayerInteractionHandler.Action.CHAT.getCode());
mplew.write(PlayerInteractionHandler.Action.CHAT_THING.getCode());
mplew.write(owner ? 0 : 1);
- mplew.writeMapleAsciiString(c.getName() + " : " + chat);
+ mplew.writeMapleAsciiString(chr.getName() + " : " + chat);
return mplew.getPacket();
}
diff --git a/scripts/quest/21728.js b/src/tools/exceptions/EmptyMovementException.java
similarity index 53%
rename from scripts/quest/21728.js
rename to src/tools/exceptions/EmptyMovementException.java
index 59ef6d5e4d..4e45381c71 100644
--- a/scripts/quest/21728.js
+++ b/src/tools/exceptions/EmptyMovementException.java
@@ -17,33 +17,19 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
+package tools.exceptions;
-var status = -1;
+import tools.data.input.LittleEndianAccessor;
-function end(mode, type, selection) {
- if (mode == -1) {
- qm.dispose();
- } else {
- if(mode == 0 && type > 0) {
- qm.dispose();
- return;
- }
-
- if (mode == 1)
- status++;
- else
- status--;
-
- if (status == 0) {
- if(qm.getQuestProgress(21728, 0) == 0) {
- qm.sendNext("You haven't found the #rPuppeteer's cave#k yet, did you?");
- } else {
- qm.sendNext("Hm, so the entrance is blocked by a powerful force? I see, gimme a time to think now...");
- qm.gainExp(200);
- qm.forceCompleteQuest();
- }
- } else if (status == 1) {
- qm.dispose();
- }
+
+/**
+ *
+ * @author Ronan
+ */
+public class EmptyMovementException extends Exception {
+
+ public EmptyMovementException(LittleEndianAccessor lea) {
+ super("Empty movement: " + lea);
}
-}
\ No newline at end of file
+
+}
diff --git a/tools/ScriptQuestReleaseTracker/hashset.c b/tools/ScriptQuestReleaseTracker/hashset.c
new file mode 100644
index 0000000000..71300f69f2
--- /dev/null
+++ b/tools/ScriptQuestReleaseTracker/hashset.c
@@ -0,0 +1,238 @@
+#include
+#include
+#include
+
+//NOTE: should the HASH_MAXITEM or HASH_NUMBUCK value be too small, program will crash by SIG_SEGV
+#define HASH_MAXITEM 4000
+#define HASH_NUMBUCK 1340
+#define HASH_HIVALUE 2147483647 //32-BIT integer
+
+#define HASH_REHTHRE 3.5
+#define HASH_REHRATE 5
+
+typedef struct {
+ int list[HASH_MAXITEM];
+ int first;
+
+ unsigned int count;
+} HastSetIndex;
+
+typedef struct {
+ HastSetIndex **table;
+ int *list;
+
+ unsigned int threshold;
+ unsigned int length;
+ unsigned int count;
+} HashSet;
+
+void hashset_create_table(HashSet *hs) {
+ hs->table = (HastSetIndex **)malloc(hs->length * sizeof(HastSetIndex *));
+ hs->threshold = (unsigned int)(HASH_REHTHRE * hs->length);
+
+ unsigned int i;
+ for(i = 0; i < hs->length; i++) {
+ hs->table[i] = (HastSetIndex *)malloc(sizeof(HastSetIndex));
+ hs->table[i]->count = 0;
+ hs->table[i]->first = HASH_HIVALUE;
+ }
+}
+
+HashSet* hashset_create() {
+ HashSet *hs = (HashSet *)malloc(sizeof(HashSet));
+ hs->count = 0;
+ hs->length = HASH_NUMBUCK;
+ hs->list = NULL;
+
+ hashset_create_table(hs);
+ return(hs);
+}
+
+void hashset_destroy(HashSet *hs) {
+ if(hs->list != NULL) {
+ free(hs->list);
+ }
+
+ unsigned int i;
+ for(i = 0; i < hs->length; i++)
+ free(hs->table[i]);
+
+ free(hs->table);
+ free(hs);
+}
+
+unsigned int hashset_maptable(HashSet *hs, int item) {
+ return(item % hs->length);
+}
+
+unsigned int hashset_slot(HashSet *hs, int item, unsigned int *bucket) {
+ *bucket = hashset_maptable(hs, item);
+
+ unsigned int i;
+ for(i = 0; i < hs->table[*bucket]->count; i++) {
+ if(hs->table[*bucket]->list[i] == item)
+ return(i);
+ }
+
+ return(-1);
+}
+
+short hashset_contains(HashSet *hs, int item, unsigned int *bucket) {
+ return(hashset_slot(hs, item, bucket) != -1);
+}
+
+short hashset_insertinto(HashSet *hs, int item) {
+ unsigned int bucket;
+
+ if(!hashset_contains(hs, item, &bucket)) {
+ if(hs->table[bucket]->first > item)
+ hs->table[bucket]->first = item;
+
+ hs->table[bucket]->list[hs->table[bucket]->count] = item;
+
+ (hs->count)++;
+ (hs->table[bucket]->count)++;
+ if(hs->table[bucket]->count > hs->threshold) return(1);
+ }
+
+ return(0);
+}
+
+void hashset_rehash(HashSet *hs) {
+ int *temp = (int *)malloc(hs->count * sizeof(int));
+ unsigned int temp_cursor = 0, i, j;
+
+ for(i = 0; i < hs->length; i++) {
+ for(j = 0; j < hs->table[i]->count; j++) {
+ temp[temp_cursor] = hs->table[i]->list[j];
+ temp_cursor++;
+ }
+ }
+
+ for(i = 0; i < hs->length; i++)
+ free(hs->table[i]);
+ free(hs->table);
+
+ hs->count = 0;
+ hs->length *= HASH_REHRATE;
+ hashset_create_table(hs);
+
+ for(i = 0; i < temp_cursor; i++)
+ hashset_insertinto(hs, temp[i]);
+
+ free(temp);
+}
+
+void hashset_insert(HashSet *hs, int item) {
+ if(hashset_insertinto(hs, item)) {
+ hashset_rehash(hs);
+ }
+}
+
+int hashset_recalc_first(HashSet *hs, int bucket) {
+ int i, val = HASH_HIVALUE;
+ for(i = 0; i < hs->table[bucket]->count; i++) {
+ if(val > hs->table[bucket]->list[i])
+ val = hs->table[bucket]->list[i];
+ }
+
+ return(val);
+}
+
+void hashset_remove(HashSet *hs, int item) {
+ unsigned int bucket;
+ unsigned int slot = hashset_slot(hs, item, &bucket);
+
+ if(slot != -1) {
+ (hs->count)--;
+ (hs->table[bucket]->count)--;
+ hs->table[bucket]->list[slot] = hs->table[bucket]->list[hs->table[bucket]->count];
+
+ if(item == hs->table[bucket]->first)
+ hs->table[bucket]->first = hashset_recalc_first(hs, bucket);
+ }
+}
+
+short hashset_is_empty(HashSet *hs) {
+ return(hs->count == 0);
+}
+
+void hashset_make_empty(HashSet *hs) {
+ unsigned int i;
+ for(i = 0; i < hs->length; i++) {
+ hs->table[i]->first = HASH_HIVALUE;
+ hs->table[i]->count = 0;
+ }
+
+ hs->count = 0;
+}
+
+int hashset_remove_first(HashSet *hs) {
+ int i, take = HASH_HIVALUE;
+ for(i = 0; i < hs->length; i++) {
+ if(take > hs->table[i]->first)
+ take = hs->table[i]->first;
+ }
+
+ hashset_remove(hs, take);
+ return(take);
+}
+
+void hashset_merge(HashSet *hs1, HashSet *hs2) {
+ //add values from hs2 to hs1
+
+ unsigned int i, j;
+ for(i = 0; i < hs2->length; i++) {
+ for(j = 0; j < hs2->table[i]->count; j++) {
+ hashset_insert(hs1, hs2->table[i]->list[j]);
+ }
+ }
+}
+
+void hashset_dump(HashSet *hs) {
+ printf("HASHSET v1.0 -- count: %d, buckets: %d, threshold: %d\n", hs->count, hs->length, hs->threshold);
+
+ unsigned int i, j;
+ for(i = 0; i < hs->length; i++) {
+ printf("\n%d -> ", i);
+ for(j = 0; j < hs->table[i]->count; j++) {
+ printf("%d ", hs->table[i]->list[j]);
+ }
+ printf("$");
+ }
+ printf("\n");
+}
+
+int* hashset_list(HashSet *hs) {
+ int *list = hs->list;
+ if(list != NULL) {
+ free(list);
+ }
+
+ list = (int *)malloc(hs->count * sizeof(int));
+
+ unsigned int i, j, k = 0;
+ for(i = 0; i < hs->length; i++) {
+ for(j = 0; j < hs->table[i]->count; j++) {
+ list[k] = hs->table[i]->list[j];
+ k++;
+ }
+ }
+
+ return list;
+}
+
+/*
+ HASHSET:
+
+ HashSet* hashset_create();
+ void hashset_destroy(HashSet *hs);
+ short hashset_contains(HashSet *hs, int item, unsigned int *bucket);
+ void hashset_insert(HashSet *hs, int item);
+ void hashset_remove(HashSet *hs, int item);
+ short hashset_is_empty(HashSet *hs);
+ void hashset_make_empty(HashSet *hs);
+ int hashset_remove_first(HashSet *hs);
+ void hashset_merge(HashSet *hs1, HashSet *hs2);
+ void hashset_dump(HashSet *hs);
+*/
diff --git a/tools/ScriptQuestReleaseTracker/pcre3.dll b/tools/ScriptQuestReleaseTracker/pcre3.dll
new file mode 100644
index 0000000000..b5fd2a6378
Binary files /dev/null and b/tools/ScriptQuestReleaseTracker/pcre3.dll differ
diff --git a/tools/ScriptQuestReleaseTracker/quest_diff.c b/tools/ScriptQuestReleaseTracker/quest_diff.c
new file mode 100644
index 0000000000..6e842924ea
--- /dev/null
+++ b/tools/ScriptQuestReleaseTracker/quest_diff.c
@@ -0,0 +1,85 @@
+#include
+
+// string hash version by chqrlie - https://stackoverflow.com/questions/20462826/hash-function-for-strings-in-c
+unsigned int strhash(const char *word) {
+ unsigned int hash = 0, c;
+
+ size_t i = 0;
+ for (i = 0; word[i] != '\0'; i++) {
+ c = (unsigned char)word[i];
+ hash = (hash << 3) + (hash >> (sizeof(hash) * CHAR_BIT - 3)) + c;
+ }
+ return hash % UINT_MAX;
+}
+
+/*
+ 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 "strmap.h"
+#include "hashset.c"
+
+void performQuestDiff(ScriptedQuestList *quests_then, ScriptedQuestList *quests_curr) {
+ char buf[100], bufhash[100];
+ HashSet *script_quests = hashset_create();
+
+ // bookkeep quest-script hash
+ StrMap *sm = sm_new(2000);
+
+ // insert ongoing scripts
+ resetScriptedQuestCursor(quests_curr);
+ while(true) {
+ ScriptedQuest *method = readScriptedQuest(quests_curr);
+ if (method == NULL) {
+ break;
+ }
+
+ int hash_quest = strhash(method->name);
+ sprintf(bufhash, "%d", hash_quest);
+
+ sm_put(sm, bufhash, method->name);
+ hashset_insert(script_quests, hash_quest);
+ }
+
+ // remove initial scripts
+ resetScriptedQuestCursor(quests_then);
+ while(true) {
+ ScriptedQuest *method = readScriptedQuest(quests_then);
+ if (method == NULL) {
+ break;
+ }
+
+ int hash_quest = strhash(method->name);
+ hashset_remove(script_quests, hash_quest);
+ }
+
+ int *list = hashset_list(script_quests);
+ int i;
+ for (i = 0; i < script_quests->count; i++) {
+ int hash_quest = list[i];
+ sprintf(bufhash, "%d", hash_quest);
+
+ // dump ongoing script releases
+ sm_get(sm, bufhash, buf, sizeof(buf));
+ printf("%s\n", buf);
+ }
+
+ sm_delete(sm);
+ hashset_destroy(script_quests);
+}
diff --git a/tools/ScriptQuestReleaseTracker/quest_diff.h b/tools/ScriptQuestReleaseTracker/quest_diff.h
new file mode 100644
index 0000000000..9911d581cc
--- /dev/null
+++ b/tools/ScriptQuestReleaseTracker/quest_diff.h
@@ -0,0 +1,28 @@
+/*
+ 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 QUEST_DIFF_H_
+#define QUEST_DIFF_H_
+
+void performQuestDiff(ScriptedQuestList *quests_then, ScriptedQuestList *quests_curr);
+
+#include "quest_diff.c"
+
+#endif /* QUEST_DIFF_H_ */
diff --git a/tools/ScriptQuestReleaseTracker/quest_list.c b/tools/ScriptQuestReleaseTracker/quest_list.c
new file mode 100644
index 0000000000..758bc64ab5
--- /dev/null
+++ b/tools/ScriptQuestReleaseTracker/quest_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 .
+*/
+
+ScriptedQuest* createScriptedQuest(const char *name) {
+ ScriptedQuest* method = (ScriptedQuest *)malloc(sizeof(ScriptedQuest));
+ method->name = (char *)malloc((strlen(name) + 1) * sizeof(char));
+ strcpy(method->name, name);
+ return method;
+}
+
+void freeScriptedQuest(ScriptedQuest *method) {
+ free(method->name);
+ free(method);
+}
+
+ScriptedQuestList createScriptedQuestList() {
+ ScriptedQuestList list;
+ list.size = 0;
+
+ ScriptedQuestListItem *item = (ScriptedQuestListItem *)malloc(sizeof(ScriptedQuestListItem));
+ item->prox = NULL;
+
+ list.last = item;
+ list.first = list.last;
+
+ return list;
+}
+
+void insertScriptedQuest(ScriptedQuestList *list, ScriptedQuest *method) {
+ ScriptedQuestListItem *item = (ScriptedQuestListItem *)malloc(sizeof(ScriptedQuestListItem));
+ item->prox = NULL;
+
+ list->last->method = method;
+ list->last->prox = item;
+
+ list->last = item;
+ list->size++;
+}
+
+void freeScriptedQuestList(ScriptedQuestList *list) {
+ ScriptedQuestListItem *aux = list->first;
+
+ list->first = list->last;
+ list->size = 0;
+
+ while (aux->prox != NULL) {
+ ScriptedQuestListItem *aux2 = aux;
+ aux = aux->prox;
+
+ freeScriptedQuest(aux2->method);
+ free(aux2);
+ }
+ free(aux);
+}
+
+void resetScriptedQuestCursor(ScriptedQuestList *list) {
+ list->cursor = list->first;
+}
+
+ScriptedQuest* readScriptedQuest(ScriptedQuestList *list) {
+ ScriptedQuestListItem *aux = list->cursor;
+ if (aux->prox == NULL) {
+ return NULL;
+ }
+
+ list->cursor = aux->prox;
+ return aux->method;
+}
diff --git a/tools/ScriptQuestReleaseTracker/quest_list.h b/tools/ScriptQuestReleaseTracker/quest_list.h
new file mode 100644
index 0000000000..4d6b91ef3b
--- /dev/null
+++ b/tools/ScriptQuestReleaseTracker/quest_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 QUEST_LIST_H_
+#define QUEST_LIST_H_
+
+typedef struct {
+ char *name;
+} ScriptedQuest;
+
+typedef struct ScriptedQuestListItem {
+ ScriptedQuest *method;
+ struct ScriptedQuestListItem *prox;
+} ScriptedQuestListItem;
+
+typedef struct {
+ ScriptedQuestListItem *first;
+ ScriptedQuestListItem *last;
+ ScriptedQuestListItem *cursor;
+
+ int size;
+} ScriptedQuestList;
+
+#include "quest_list.c"
+
+#endif /* QUEST_LIST_H_ */
diff --git a/tools/ScriptQuestReleaseTracker/script_tracker.c b/tools/ScriptQuestReleaseTracker/script_tracker.c
new file mode 100644
index 0000000000..4a1bb71fe0
--- /dev/null
+++ b/tools/ScriptQuestReleaseTracker/script_tracker.c
@@ -0,0 +1,159 @@
+/*
+ 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
+
+#include "strmap.c"
+#include "quest_list.h"
+#include "quest_diff.h"
+
+ScriptedQuestList getBestSubstringsFromStringList(char *aStrRegex, ScriptedQuestList *lines, int lines_size) {
+ ScriptedQuestList ret = createScriptedQuestList();
+
+ // ------------ 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++) {
+ ScriptedQuestList list = lines[i];
+
+ resetScriptedQuestCursor(&list);
+ while(true) {
+ ScriptedQuest *method = readScriptedQuest(&list);
+ if (method == NULL) {
+ break;
+ }
+
+ char *str = method->name;
+ int st = 0, en = strlen(str);
+ while(st < en) {
+ int pcreExecRet = pcre_exec(reCompiled, pcreExtra, str, en, st, 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;
+ }
+
+ 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, 1, &(psubStrMatchStr));
+
+ insertScriptedQuest(&ret, createScriptedQuest(psubStrMatchStr));
+ pcre_free_substring(psubStrMatchStr);
+
+ st = subStrVec[1];
+ }
+ }
+ }
+ }
+
+ pcre_free(reCompiled);
+
+ if(pcreExtra != NULL) {
+ pcre_free(pcreExtra);
+ }
+
+ return ret;
+}
+
+char *getContentFromFile(FILE *f) {
+ fseek(f, 0, SEEK_END); // implemented by user529758 @ StackOverflow
+ long fsize = ftell(f);
+ fseek(f, 0, SEEK_SET); /* same as rewind(f); */
+
+ char *string = malloc(fsize + 1);
+ fread(string, 1, fsize, f);
+
+ string[fsize] = 0;
+ return string;
+}
+
+ScriptedQuestList readQuestXml(char *file_path) {
+ ScriptedQuestList *file_content = (ScriptedQuestList *)malloc(sizeof(ScriptedQuestList));
+ file_content[0] = createScriptedQuestList();
+
+ FILE *f = fopen(file_path, "r+t");
+ char *content = getContentFromFile(f);
+
+ char *tok = strtok(content, "\n");
+ int i = 0;
+ while (tok != NULL) {
+ insertScriptedQuest(&(file_content[0]), createScriptedQuest(tok));
+ tok = strtok(NULL, "\n");
+ i++;
+ }
+
+ free(content);
+ fclose(f);
+
+ ScriptedQuestList ret = getBestSubstringsFromStringList("script\" value=\"(.+)\"", file_content, 1);
+
+ freeScriptedQuestList(&file_content[0]);
+ free(file_content);
+
+ return ret;
+}
+
+void trackScriptQuestReleases() {
+ ScriptedQuestList quests_then = readQuestXml("Check2.img.xml");
+ ScriptedQuestList quests_curr = readQuestXml("Check.img.xml");
+
+ performQuestDiff(&quests_then, &quests_curr);
+
+ freeScriptedQuestList(&quests_curr);
+ freeScriptedQuestList(&quests_then);
+}
+
+int main() {
+ trackScriptQuestReleases();
+ return 0;
+}
diff --git a/tools/ScriptQuestReleaseTracker/strmap.c b/tools/ScriptQuestReleaseTracker/strmap.c
new file mode 100644
index 0000000000..6111209abe
--- /dev/null
+++ b/tools/ScriptQuestReleaseTracker/strmap.c
@@ -0,0 +1,515 @@
+/*
+ * strmap version 2.0.1
+ *
+ * ANSI C hash table for strings.
+ *
+ * Version history:
+ * 1.0.0 - initial release
+ * 2.0.0 - changed function prefix from strmap to sm to ensure
+ * ANSI C compatibility
+ * 2.0.1 - improved documentation
+ *
+ * strmap.c
+ *
+ * Copyright (c) 2009, 2011, 2013 Per Ola Kristensson.
+ *
+ * Per Ola Kristensson
+ * Inference Group, Department of Physics
+ * University of Cambridge
+ * Cavendish Laboratory
+ * JJ Thomson Avenue
+ * CB3 0HE Cambridge
+ * United Kingdom
+ *
+ * strmap is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * strmap is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with strmap. If not, see .
+ */
+#include "strmap.h"
+
+typedef struct Pair Pair;
+
+typedef struct Bucket Bucket;
+
+struct Pair {
+ char *key;
+ char *value;
+};
+
+struct Bucket {
+ unsigned int count;
+ Pair *pairs;
+};
+
+struct StrMap {
+ unsigned int count;
+ Bucket *buckets;
+};
+
+static Pair * get_pair(Bucket *bucket, const char *key);
+static unsigned long hash(const char *str);
+
+StrMap * sm_new(unsigned int capacity)
+{
+ StrMap *map;
+
+ map = malloc(sizeof(StrMap));
+ if (map == NULL) {
+ return NULL;
+ }
+ map->count = capacity;
+ map->buckets = malloc(map->count * sizeof(Bucket));
+ if (map->buckets == NULL) {
+ free(map);
+ return NULL;
+ }
+ memset(map->buckets, 0, map->count * sizeof(Bucket));
+ return map;
+}
+
+void sm_delete(StrMap *map)
+{
+ unsigned int i, j, n, m;
+ Bucket *bucket;
+ Pair *pair;
+
+ if (map == NULL) {
+ return;
+ }
+ n = map->count;
+ bucket = map->buckets;
+ i = 0;
+ while (i < n) {
+ m = bucket->count;
+ pair = bucket->pairs;
+ j = 0;
+ while(j < m) {
+ free(pair->key);
+ free(pair->value);
+ pair++;
+ j++;
+ }
+ free(bucket->pairs);
+ bucket++;
+ i++;
+ }
+ free(map->buckets);
+ free(map);
+}
+
+int sm_get(const StrMap *map, const char *key, char *out_buf, unsigned int n_out_buf)
+{
+ unsigned int index;
+ Bucket *bucket;
+ Pair *pair;
+
+ if (map == NULL) {
+ return 0;
+ }
+ if (key == NULL) {
+ return 0;
+ }
+ index = hash(key) % map->count;
+ bucket = &(map->buckets[index]);
+ pair = get_pair(bucket, key);
+ if (pair == NULL) {
+ return 0;
+ }
+ if (out_buf == NULL && n_out_buf == 0) {
+ return strlen(pair->value) + 1;
+ }
+ if (out_buf == NULL) {
+ return 0;
+ }
+ if (strlen(pair->value) >= n_out_buf) {
+ return 0;
+ }
+ strcpy(out_buf, pair->value);
+ return 1;
+}
+
+int sm_exists(const StrMap *map, const char *key)
+{
+ unsigned int index;
+ Bucket *bucket;
+ Pair *pair;
+
+ if (map == NULL) {
+ return 0;
+ }
+ if (key == NULL) {
+ return 0;
+ }
+ index = hash(key) % map->count;
+ bucket = &(map->buckets[index]);
+ pair = get_pair(bucket, key);
+ if (pair == NULL) {
+ return 0;
+ }
+ return 1;
+}
+
+int sm_put(StrMap *map, const char *key, const char *value)
+{
+ unsigned int key_len, value_len, index;
+ Bucket *bucket;
+ Pair *tmp_pairs, *pair;
+ char *tmp_value;
+ char *new_key, *new_value;
+
+ if (map == NULL) {
+ return 0;
+ }
+ if (key == NULL || value == NULL) {
+ return 0;
+ }
+ key_len = strlen(key);
+ value_len = strlen(value);
+ /* Get a pointer to the bucket the key string hashes to */
+ index = hash(key) % map->count;
+ bucket = &(map->buckets[index]);
+ /* Check if we can handle insertion by simply replacing
+ * an existing value in a key-value pair in the bucket.
+ */
+ if ((pair = get_pair(bucket, key)) != NULL) {
+ /* The bucket contains a pair that matches the provided key,
+ * change the value for that pair to the new value.
+ */
+ if (strlen(pair->value) < value_len) {
+ /* If the new value is larger than the old value, re-allocate
+ * space for the new larger value.
+ */
+ tmp_value = realloc(pair->value, (value_len + 1) * sizeof(char));
+ if (tmp_value == NULL) {
+ return 0;
+ }
+ pair->value = tmp_value;
+ }
+ /* Copy the new value into the pair that matches the key */
+ strcpy(pair->value, value);
+ return 1;
+ }
+ /* Allocate space for a new key and value */
+ new_key = malloc((key_len + 1) * sizeof(char));
+ if (new_key == NULL) {
+ return 0;
+ }
+ new_value = malloc((value_len + 1) * sizeof(char));
+ if (new_value == NULL) {
+ free(new_key);
+ return 0;
+ }
+ /* Create a key-value pair */
+ if (bucket->count == 0) {
+ /* The bucket is empty, lazily allocate space for a single
+ * key-value pair.
+ */
+ bucket->pairs = malloc(sizeof(Pair));
+ if (bucket->pairs == NULL) {
+ free(new_key);
+ free(new_value);
+ return 0;
+ }
+ bucket->count = 1;
+ }
+ else {
+ /* The bucket wasn't empty but no pair existed that matches the provided
+ * key, so create a new key-value pair.
+ */
+ tmp_pairs = realloc(bucket->pairs, (bucket->count + 1) * sizeof(Pair));
+ if (tmp_pairs == NULL) {
+ free(new_key);
+ free(new_value);
+ return 0;
+ }
+ bucket->pairs = tmp_pairs;
+ bucket->count++;
+ }
+ /* Get the last pair in the chain for the bucket */
+ pair = &(bucket->pairs[bucket->count - 1]);
+ pair->key = new_key;
+ pair->value = new_value;
+ /* Copy the key and its value into the key-value pair */
+ strcpy(pair->key, key);
+ strcpy(pair->value, value);
+ return 1;
+}
+
+int sm_get_count(const StrMap *map)
+{
+ unsigned int i, j, n, m;
+ unsigned int count;
+ Bucket *bucket;
+ Pair *pair;
+
+ if (map == NULL) {
+ return 0;
+ }
+ bucket = map->buckets;
+ n = map->count;
+ i = 0;
+ count = 0;
+ while (i < n) {
+ pair = bucket->pairs;
+ m = bucket->count;
+ j = 0;
+ while (j < m) {
+ count++;
+ pair++;
+ j++;
+ }
+ bucket++;
+ i++;
+ }
+ return count;
+}
+
+int sm_enum(const StrMap *map, sm_enum_func enum_func, const void *obj)
+{
+ unsigned int i, j, n, m;
+ Bucket *bucket;
+ Pair *pair;
+
+ if (map == NULL) {
+ return 0;
+ }
+ if (enum_func == NULL) {
+ return 0;
+ }
+ bucket = map->buckets;
+ n = map->count;
+ i = 0;
+ while (i < n) {
+ pair = bucket->pairs;
+ m = bucket->count;
+ j = 0;
+ while (j < m) {
+ enum_func(pair->key, pair->value, obj);
+ pair++;
+ j++;
+ }
+ bucket++;
+ i++;
+ }
+ return 1;
+}
+
+/*
+ * Returns a pair from the bucket that matches the provided key,
+ * or null if no such pair exist.
+ */
+static Pair * get_pair(Bucket *bucket, const char *key)
+{
+ unsigned int i, n;
+ Pair *pair;
+
+ n = bucket->count;
+ if (n == 0) {
+ return NULL;
+ }
+ pair = bucket->pairs;
+ i = 0;
+ while (i < n) {
+ if (pair->key != NULL && pair->value != NULL) {
+ if (strcmp(pair->key, key) == 0) {
+ return pair;
+ }
+ }
+ pair++;
+ i++;
+ }
+ return NULL;
+}
+
+/*
+ * Returns a hash code for the provided string.
+ */
+static unsigned long hash(const char *str)
+{
+ unsigned long hash = 5381;
+ int c;
+
+ while (c = *str++) {
+ hash = ((hash << 5) + hash) + c;
+ }
+ return hash;
+}
+
+/*
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
+
+*/
\ No newline at end of file
diff --git a/tools/ScriptQuestReleaseTracker/strmap.h b/tools/ScriptQuestReleaseTracker/strmap.h
new file mode 100644
index 0000000000..b0ff19cbc5
--- /dev/null
+++ b/tools/ScriptQuestReleaseTracker/strmap.h
@@ -0,0 +1,356 @@
+/*
+ * strmap version 2.0.1
+ *
+ * ANSI C hash table for strings.
+ *
+ * Version history:
+ * 1.0.0 - initial release
+ * 2.0.0 - changed function prefix from strmap to sm to ensure
+ * ANSI C compatibility
+ * 2.0.1 - improved documentation
+ *
+ * strmap.h
+ *
+ * Copyright (c) 2009, 2011, 2013 Per Ola Kristensson.
+ *
+ * Per Ola Kristensson
+ * Inference Group, Department of Physics
+ * University of Cambridge
+ * Cavendish Laboratory
+ * JJ Thomson Avenue
+ * CB3 0HE Cambridge
+ * United Kingdom
+ *
+ * strmap is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * strmap is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with strmap. If not, see .
+ */
+#ifndef _STRMAP_H_
+#define _STRMAP_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include
+#include
+
+typedef struct StrMap StrMap;
+
+/*
+ * This callback function is called once per key-value when iterating over
+ * all keys associated to values.
+ *
+ * Parameters:
+ *
+ * key: A pointer to a null-terminated C string. The string must not
+ * be modified by the client.
+ *
+ * value: A pointer to a null-terminated C string. The string must
+ * not be modified by the client.
+ *
+ * obj: A pointer to a client-specific object. This parameter may be
+ * null.
+ *
+ * Return value: None.
+ */
+typedef void(*sm_enum_func)(const char *key, const char *value, const void *obj);
+
+/*
+ * Creates a string map.
+ *
+ * Parameters:
+ *
+ * capacity: The number of top-level slots this string map
+ * should allocate. This parameter must be > 0.
+ *
+ * Return value: A pointer to a string map object,
+ * or null if a new string map could not be allocated.
+ */
+StrMap * sm_new(unsigned int capacity);
+
+/*
+ * Releases all memory held by a string map object.
+ *
+ * Parameters:
+ *
+ * map: A pointer to a string map. This parameter cannot be null.
+ * If the supplied string map has been previously released, the
+ * behaviour of this function is undefined.
+ *
+ * Return value: None.
+ */
+void sm_delete(StrMap *map);
+
+/*
+ * Returns the value associated with the supplied key.
+ *
+ * Parameters:
+ *
+ * map: A pointer to a string map. This parameter cannot be null.
+ *
+ * key: A pointer to a null-terminated C string. This parameter cannot
+ * be null.
+ *
+ * out_buf: A pointer to an output buffer which will contain the value,
+ * if it exists and fits into the buffer.
+ *
+ * n_out_buf: The size of the output buffer in bytes.
+ *
+ * Return value: If out_buf is set to null and n_out_buf is set to 0 the return
+ * value will be the number of bytes required to store the value (if it exists)
+ * and its null-terminator. For all other parameter configurations the return value
+ * is 1 if an associated value was found and completely copied into the output buffer,
+ * 0 otherwise.
+ */
+int sm_get(const StrMap *map, const char *key, char *out_buf, unsigned int n_out_buf);
+
+/*
+ * Queries the existence of a key.
+ *
+ * Parameters:
+ *
+ * map: A pointer to a string map. This parameter cannot be null.
+ *
+ * key: A pointer to a null-terminated C string. This parameter cannot
+ * be null.
+ *
+ * Return value: 1 if the key exists, 0 otherwise.
+ */
+int sm_exists(const StrMap *map, const char *key);
+
+/*
+ * Associates a value with the supplied key. If the key is already
+ * associated with a value, the previous value is replaced.
+ *
+ * Parameters:
+ *
+ * map: A pointer to a string map. This parameter cannot be null.
+ *
+ * key: A pointer to a null-terminated C string. This parameter
+ * cannot be null. The string must have a string length > 0. The
+ * string will be copied.
+ *
+ * value: A pointer to a null-terminated C string. This parameter
+ * cannot be null. The string must have a string length > 0. The
+ * string will be copied.
+ *
+ * Return value: 1 if the association succeeded, 0 otherwise.
+ */
+int sm_put(StrMap *map, const char *key, const char *value);
+
+/*
+ * Returns the number of associations between keys and values.
+ *
+ * Parameters:
+ *
+ * map: A pointer to a string map. This parameter cannot be null.
+ *
+ * Return value: The number of associations between keys and values.
+ */
+int sm_get_count(const StrMap *map);
+
+/*
+ * An enumerator over all associations between keys and values.
+ *
+ * Parameters:
+ *
+ * map: A pointer to a string map. This parameter cannot be null.
+ *
+ * enum_func: A pointer to a callback function that will be
+ * called by this procedure once for every key associated
+ * with a value. This parameter cannot be null.
+ *
+ * obj: A pointer to a client-specific object. This parameter will be
+ * passed back to the client's callback function. This parameter can
+ * be null.
+ *
+ * Return value: 1 if enumeration completed, 0 otherwise.
+ */
+int sm_enum(const StrMap *map, sm_enum_func enum_func, const void *obj);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/*
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
+
+*/
\ No newline at end of file
diff --git a/tools/ScriptStaticMethodTracker/method_tracker.c b/tools/ScriptStaticMethodTracker/method_tracker.c
index 63af248dec..5a23d0f23e 100644
--- a/tools/ScriptStaticMethodTracker/method_tracker.c
+++ b/tools/ScriptStaticMethodTracker/method_tracker.c
@@ -24,8 +24,6 @@
#include
#include
-#define SCRIPT_FILES_MAX_CONTENT_SIZE 1777777
-
#include "method_list.h"
#include "script_path.h"
@@ -63,29 +61,36 @@ JavaMethodList getBestSubstringsFromStringList(char *aStrRegex, JavaMethodList *
}
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;
- }
+ int st = 0, en = strlen(str);
+ while (st < en) {
+ int pcreExecRet = pcre_exec(reCompiled, pcreExtra, str, en, st, 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;
+ }
- const char *psubStrMatchStr;
- pcre_get_substring(str, subStrVec, pcreExecRet, 0, &(psubStrMatchStr));
+ break; // no more matches found
+ } 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;
+ }
- insertJavaMethod(&ret, createJavaMethod(psubStrMatchStr));
- pcre_free_substring(psubStrMatchStr);
+ const char *psubStrMatchStr;
+ pcre_get_substring(str, subStrVec, pcreExecRet, 0, &(psubStrMatchStr));
+
+ insertJavaMethod(&ret, createJavaMethod(psubStrMatchStr));
+ pcre_free_substring(psubStrMatchStr);
+
+ st = subStrVec[1];
+ }
}
}
}
@@ -204,7 +209,6 @@ JavaMethodList trackerFindSourceStaticMethods(JavaMethodList *lines, int lines_s
continue;
}
- //printf("Java Method: %s\n", method->name);
insertJavaMethod(&ret, createJavaMethod(method->name));
}
@@ -214,17 +218,15 @@ JavaMethodList trackerFindSourceStaticMethods(JavaMethodList *lines, int lines_s
}
char *getContentFromFile(FILE *f) {
- char str[10240];
+ fseek(f, 0, SEEK_END); // implemented by user529758 @ StackOverflow
+ long fsize = ftell(f);
+ fseek(f, 0, SEEK_SET); /* same as rewind(f); */
- char *content = (char *)malloc(SCRIPT_FILES_MAX_CONTENT_SIZE * sizeof(char));
- content[0] = 0;
+ char *string = malloc(fsize + 1);
+ fread(string, 1, fsize, f);
- while (!feof(f)) {
- fgets(str, 10240, f);
- strcat(content, str);
- }
-
- return content;
+ string[fsize] = 0;
+ return string;
}
bool locateMethodCall(const char *method_name, char *file_path) {
@@ -246,6 +248,7 @@ bool locateMethodCall(const char *method_name, char *file_path) {
JavaMethodList list = getBestSubstringsFromStringList(aStrRegex, file_content, 1);
bool found = (list.size > 0);
+ freeJavaMethodList(&(file_content[0]));
free(file_content);
fclose(f);
@@ -263,7 +266,7 @@ void locateMethodCalls(const char *method_name, char **file_paths, int file_path
}
int trackerLocateScriptsStaticCalls(JavaMethodList method_names) {
- ScriptFiles *files = createScriptFiles("../../HeavenMS/scripts");
+ ScriptFiles *files = createScriptFiles("../../scripts");
if (files == NULL) {
printf("ERROR: Could not initialize script files.\n");
return -1;
@@ -289,7 +292,7 @@ typedef struct {
} SourceFilesContent;
SourceFilesContent* readSourceFileContents() {
- ScriptFiles *srcFilePaths = createScriptFiles("../../HeavenMS/src");
+ ScriptFiles *srcFilePaths = createScriptFiles("../../src");
SourceFilesContent *files = (SourceFilesContent *)malloc(sizeof(SourceFilesContent));
files->file_content = (JavaMethodList *)malloc(srcFilePaths->file_paths_size * sizeof(JavaMethodList));
@@ -311,7 +314,6 @@ SourceFilesContent* readSourceFileContents() {
insertJavaMethod(&(files->file_content[i]), createJavaMethod(content));
}
- //printf("len: %d\n", max_len);
freeScriptFiles(srcFilePaths);
return files;
diff --git a/tools/ScriptStaticMethodTracker/script_path.h b/tools/ScriptStaticMethodTracker/script_path.h
index 553d28d260..cd2452a517 100644
--- a/tools/ScriptStaticMethodTracker/script_path.h
+++ b/tools/ScriptStaticMethodTracker/script_path.h
@@ -21,8 +21,8 @@
#ifndef SCRIPT_PATH_H_
#define SCRIPT_PATH_H_
-#define SCRIPT_FILES_MAX_COUNT 20000
-#define SCRIPT_FILES_MAX_PATH_SIZE 1000
+#define SCRIPT_FILES_MAX_COUNT 70000
+#define SCRIPT_FILES_MAX_PATH_SIZE 40000
typedef struct {
char **file_paths;
diff --git a/wz/Quest.wz/Act.img.xml b/wz/Quest.wz/Act.img.xml
index e612835194..647b53de72 100644
--- a/wz/Quest.wz/Act.img.xml
+++ b/wz/Quest.wz/Act.img.xml
@@ -12775,8 +12775,16 @@
+
+
+
+
+
+
+
+
@@ -20077,6 +20085,7 @@
+
diff --git a/wz/Quest.wz/Check.img.xml b/wz/Quest.wz/Check.img.xml
index d19084770e..f94af3a935 100644
--- a/wz/Quest.wz/Check.img.xml
+++ b/wz/Quest.wz/Check.img.xml
@@ -20136,6 +20136,12 @@
+
+
+
+
+
+
@@ -22133,7 +22139,12 @@
-
+
+
+
+
+
+
@@ -22309,6 +22320,12 @@
+
+
+
+
+
+
@@ -23461,7 +23478,7 @@
-
+
@@ -24184,12 +24201,17 @@
-
+
+
+
+
+
+
@@ -39696,7 +39718,11 @@
-
+
+
+
+
+
@@ -40748,7 +40774,6 @@
-
@@ -41038,7 +41063,11 @@
-
+
+
+
+
+
@@ -41728,7 +41757,11 @@
-
+
+
+
+
+
@@ -42046,7 +42079,11 @@
-
+
+
+
+
+
@@ -48377,7 +48414,11 @@
-
+
+
+
+
+
@@ -48393,7 +48434,11 @@
-
+
+
+
+
+
@@ -48443,7 +48488,11 @@
-
+
+
+
+
+
@@ -50105,6 +50154,12 @@
+
+
+
+
+
+
@@ -56931,6 +56986,11 @@
+
+
+
+
+
@@ -60034,7 +60094,12 @@
-
+
+
+
+
+
+
diff --git a/wz/Quest.wz/QuestInfo.img.xml b/wz/Quest.wz/QuestInfo.img.xml
index d89f6d0f96..1c5d858e44 100644
--- a/wz/Quest.wz/QuestInfo.img.xml
+++ b/wz/Quest.wz/QuestInfo.img.xml
@@ -6467,7 +6467,7 @@ Once there, talk to #b#p1200003##k to board the ship.
-
+
diff --git a/wz/Quest.wz/Say.img.xml b/wz/Quest.wz/Say.img.xml
index 5eb5b41717..c22151a4e9 100644
--- a/wz/Quest.wz/Say.img.xml
+++ b/wz/Quest.wz/Say.img.xml
@@ -30134,6 +30134,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+