diff --git a/.gitignore b/.gitignore
index 32140893ac..db23594d4c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -103,6 +103,10 @@
/tools/MapleReactorDropFetcher/dist/
/tools/MapleReactorDropFetcher/nbproject/
+/tools/MapleSkillbookStackUpdate/build/
+/tools/MapleSkillbookStackUpdate/dist/
+/tools/MapleSkillbookStackUpdate/nbproject/
+
/tools/MapleSkillMakerFetcher/build/
/tools/MapleSkillMakerFetcher/dist/
/tools/MapleSkillMakerFetcher/nbproject/
diff --git a/README.md b/README.md
index bcb558c73f..f20ff2a3da 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-
+
## Head developer: Ronan C. P. Lana
@@ -56,7 +56,7 @@ Java7 SDK: https://www.oracle.com/technetwork/java/javase/downloads/java-archive
---
### Open-source client development - HeavenClient
-Continuing from where **SYJourney**'s JourneyClient has finished contributions (as of 5 Jul 2016), an open-source delevopment of a software artifact designed to handle both gaming operations and interactions with the server is being conducted.
+Continuing from where **SYJourney**'s JourneyClient has finished contributions (as of 5 Jul 2016), an open-source development of a software artifact designed to handle both gaming operations and interactions with the server is being conducted.
Newer implementations are being maintained by **頼晏 (ryantpayton)** and aims to offer higher display resolution, bring recent UI contents for the pre-BB gameplay and incremental support on overall gaming perspective.
@@ -84,16 +84,20 @@ By taking the v83 MapleStory as the angular stone, incrementally look forward to
#### Announcements
-HeavenMS development achieved an acceptable state-of-the-art and will get into a halt. A heartfelt thanks for everyone that contributed in some way for the progress of this server!
+HeavenMS development as we can see right now achieved an acceptable state-of-the-art. A heartfelt thanks for everyone that contributed in some way for the progress of this server!
-Although development is halted, support for fixing features that were implemented here is still up. You can still actively help us improve the server by issuing pull requests with informative details about what's changing.
+As development and support for fixing features that were implemented here is still up, with **your** help we can improve it even further! Please help where you can to better the server for everyone.
+
+Furthermore, you can actively help improving the server by issuing pull requests with informative details about what's changing.
+
+Note for anyone up to contribute further pull requests: make awareness to use __english language__ in codes and messages, as usage of any other languages will render it open to faculty of whether this content will be ready to be accepted or *further changes are going to be requested* before it becomes apt to merge.
+
+#### Support HeavenMS
If you liked this project, please don't forget to __star__ the repo ;) .
It's never enough to tell this, thanks to everyone that have been contributing something for the continuous improvement of the server! Be it through bug reports, donation, code snippets and/or pull requests.
-Note for anyone up to contribute further pull requests: make awareness to use __english language__ in codes and messages, as usage of any other languages will render it open to faculty of whether this content will be ready to be accepted or *further changes are going to be requested* before it becomes apt to merge.
-
Our Discord channel is still available on: https://discord.gg/Q7wKxHX
@@ -110,7 +114,7 @@ Paypal: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3K8
* HeavenMS staff has __no current intention__ to publicly open a server with this source, if that ever comes to happen this note will be lifted. __Don't be scammed!__
-* This server source is __NOT intended to be stable__ as is. Proper deadlock review and other maintenance checks are needed in order to make it suitable for production use.
+* This server source is __NOT intended to be stable__ as is. Proper deadlock review and other maintenance contributions are needed in order to make it steps ahead on viability.
---
### Preparing the ambient
diff --git a/docs/mychanges_ptbr.txt b/docs/mychanges_ptbr.txt
index f8373a83fe..bdb3c8686e 100644
--- a/docs/mychanges_ptbr.txt
+++ b/docs/mychanges_ptbr.txt
@@ -1798,10 +1798,18 @@ Corrigido cooldown de skills de mob não atuando adequadamente.
08 - 09 Abril 2019,
Resolvido problema de deadlock envolvendo acesso a valores de stats de jogadores e diversas operações de despacho de update de stats.
+Implementado envio de desafio na CPQ utilizando o sistema de matching.
+Corrigido LanguageConstants atuando estaticamente para todos os jogadores.
Corrigido mob skills que não se encontram disponíveis sendo passados para o cliente para serem usados. Resultado disso era efeito visual de skill sendo mostrado ao usuário, habilidade sem ser aplicada em sequência.
+Corrigido portais do stage "" da OPQ levando jogadores incorretamente para a próxima plataforma.
+Corrigido portais do stage "" da OPQ retornando jogadores à plataforma inicial, ao invés de retornar a uma plataforma "checkpoint".
+Corrigido fonte da EllinPQ não atribuindo corretamente "Altaire Fragment" aos jogadores.
+Implementado geração de sequências com relação entre as mesmas, utilizadas no estágio "Lab - Unit" da RnJPQ.
12 Abril 2019,
+Corrigido limites de mapas nos eventos de RockSpirit.
Corrigido ganho visual do EXP de party ocasionalmente mostrando EXP em amarelo ao jogador em party solo.
+Corrigido battleship setando HP inicial menor que o esperado pela skill para jogadores de nível menor que 120.
15 Abril 2019,
Iniciado operação de introdução da AriantPQ no fonte, a partir do pull request feito pelo Dragohe4rt.
@@ -1817,7 +1825,26 @@ Ajustado drops de mobs, agora sendo buscado na DB.
Ajustado diversas mecânicas da AriantPQ, tais como update visual da pontuação de jogadores (ao dropar itens, ganhar itens, acessar mapa de evento), pontos de batalha persistindo na DB, etc.
21 Abril 2019,
-Adicionado debug de packets descrito pelo Atoot.Adicionado debug de packets descrito pelo Atoot.
+Adicionado debug de packets descrito pelo Atoot.
22 Abril 2019,
-Revisado refatoração recente em acesso a valores de stats de jogadores levando a inconsistência nos valores dos mesmos ao colocá-los para rodar em uma nova thread sem proteção concorrente.
\ No newline at end of file
+Corrigido Fredrick retornando valores negativos de mesos ao retornar espólios de mercantes aos jogadores.
+Adicionado informação aprimorada em comando "goto".
+Adicionado contagem de quests completadas de mesmo id.
+Corrigido problema de visibilidade latente com mobs que já foram derrotados aparecendo num flicker ao realizar certas ações (tal como mudar de mapas).
+Nova ferramenta: MapleSkillbookStackUpdate. Livros de skill e melhorias agora levam quantidade de stack padrão (100 unidades).
+Protegido concorrentemente adição de itens ao inventário. Checagens de posição e inserção ocorrem atomicamente.
+Protegido concorrentemente e revisado módulos de ganho de EXP do Writs of Solomon (gachapon EXP).
+Revisado refatoração recente em acesso a valores de stats de jogadores levando a inconsistência nos valores dos mesmos ao colocá-los para rodar em uma nova thread sem proteção concorrente.
+
+24 - 26 Abril 2019,
+Ajustado levemente taxa de respawn de mobs quando não se está usando a flag de respawn completo.
+Ajustado ganhos de stats de ataque ao passar de nível weapons, ganha-se menos do stat que não é a afinidade (watk/matk).
+Corrigido drops de mesos sendo bloqueados para drops rápidos de mesos, indevidamente dificultando jogabilidade para certas classes.
+Corrigido caso de XML parser em MapleSkillBookInformationParser não lidando com terminadores "/>" corretamente.
+
+01 - 02 Maio 2019,
+Corrigido jogadores podendo explorar mecânica de checagem de match, não respondendo ao match e sendo permitido se registrar em um novo sem ter respondido ao anterior.
+Corrigido caso de dupe com itens ao serem colocados no storage.
+Adicionado sistema de "qualquer NPC scriptável", com apoio do GabrielSin.
+Adicionado server flag para checagem de IP's ao logar jogadores.
\ No newline at end of file
diff --git a/scripts/event/3rdJob_mount.js b/scripts/event/3rdJob_mount.js
index b3f4bc0f7a..cd366824ed 100644
--- a/scripts/event/3rdJob_mount.js
+++ b/scripts/event/3rdJob_mount.js
@@ -92,7 +92,7 @@ function playerEntry(eim, player) {
function playerUnregistered(eim, player) {}
function playerExit(eim, player) {
- var api = player.getClient().getAbstractPlayerInteraction();
+ var api = player.getAbstractPlayerInteraction();
api.removeAll(4031507);
api.removeAll(4031508);
diff --git a/scripts/event/GuildQuest.js b/scripts/event/GuildQuest.js
index 8f3c755643..d4d3fa00f8 100644
--- a/scripts/event/GuildQuest.js
+++ b/scripts/event/GuildQuest.js
@@ -237,7 +237,7 @@ function changedMap(eim, player, mapid) {
function afterChangedMap(eim, player, mapid) {
if (mapid == 990000100) {
var texttt = "So, here is the brief. You guys should be warned that, once out on the fortress outskirts, anyone that would not be equipping the #b#t1032033##k will die instantly due to the deteriorated state of the air around there. That being said, once your team moves out, make sure to #bhit the glowing rocks#k in that region and #bequip the dropped item#k before advancing stages. That will protect you thoroughly from the air sickness. Good luck!";
- player.getClient().getAbstractPlayerInteraction().npcTalk(9040000, texttt);
+ player.getAbstractPlayerInteraction().npcTalk(9040000, texttt);
}
}
diff --git a/scripts/event/MK_PrimeMinister.js b/scripts/event/MK_PrimeMinister.js
index c61f7b7a0d..01ddf963f9 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.getClient().getAbstractPlayerInteraction().getQuestProgress(2333, mobId) == 0) {
+ if (player.getQuestStatus(2333) == 1 && player.getAbstractPlayerInteraction().getQuestProgress(2333, mobId) == 0) {
return true;
}
}
diff --git a/scripts/event/MagatiaPQ_A.js b/scripts/event/MagatiaPQ_A.js
index b26b7376ac..312980d2a8 100644
--- a/scripts/event/MagatiaPQ_A.js
+++ b/scripts/event/MagatiaPQ_A.js
@@ -176,6 +176,33 @@ function shuffle(array) {
return array;
}
+function generateStg6Combo(eim) { // thanks Chloek3, seth1 for stating generated sequences are supposed to be linked
+ var matrix = [];
+
+ for (var i = 0; i < 4; i++) {
+ matrix.push([]);
+ }
+
+ for (var j = 0; j < 10; j++) {
+ var array = [0, 1, 2, 3];
+ array = shuffle(array);
+
+ for (var i = 0; i < 4; i++) {
+ matrix[i].push(array[i]);
+ }
+ }
+
+ for (var i = 0; i < 4; i++) {
+ var comb = "";
+ for(var j = 0; j < 10; j++) {
+ var r = matrix[i][j];
+ comb += r.toString();
+ }
+
+ eim.setProperty("stage6_comb" + (i + 1), comb);
+ }
+}
+
function afterSetup(eim) {
eim.setIntProperty("escortFail", 0); // refresh friendly status
@@ -390,6 +417,7 @@ function monsterKilled(mob, eim) {
eim.showClearEffect();
eim.giveEventPlayersStageReward(5);
+ generateStg6Combo(eim);
map.getReactorByName("jnr6_out").forceHitReactor(1);
}
} else if(mob.getId() == 9300151 || mob.getId() == 9300152) {
diff --git a/scripts/event/MagatiaPQ_Z.js b/scripts/event/MagatiaPQ_Z.js
index ca62cb3fcc..fe88d4af3d 100644
--- a/scripts/event/MagatiaPQ_Z.js
+++ b/scripts/event/MagatiaPQ_Z.js
@@ -176,6 +176,33 @@ function shuffle(array) {
return array;
}
+function generateStg6Combo(eim) {
+ var matrix = [];
+
+ for (var i = 0; i < 4; i++) {
+ matrix.push([]);
+ }
+
+ for (var j = 0; j < 10; j++) {
+ var array = [0, 1, 2, 3];
+ array = shuffle(array);
+
+ for (var i = 0; i < 4; i++) {
+ matrix[i].push(array[i]);
+ }
+ }
+
+ for (var i = 0; i < 4; i++) {
+ var comb = "";
+ for(var j = 0; j < 10; j++) {
+ var r = matrix[i][j];
+ comb += r.toString();
+ }
+
+ eim.setProperty("stage6_comb" + (i + 1), comb);
+ }
+}
+
function afterSetup(eim) {
eim.setIntProperty("escortFail", 0); // refresh friendly status
@@ -390,6 +417,7 @@ function monsterKilled(mob, eim) {
eim.showClearEffect();
eim.giveEventPlayersStageReward(5);
+ generateStg6Combo(eim);
map.getReactorByName("rnj6_out").forceHitReactor(1);
}
} else if(mob.getId() == 9300139 || mob.getId() == 9300140) {
diff --git a/scripts/event/OrbisPQ.js b/scripts/event/OrbisPQ.js
index 2d11c2c409..397e205a5b 100644
--- a/scripts/event/OrbisPQ.js
+++ b/scripts/event/OrbisPQ.js
@@ -180,7 +180,7 @@ function playerEntry(eim, player) {
player.changeMap(map, map.getPortal(0));
var texttt = "Hi, my name is Eak, the Chamberlain of the Goddess. Don't be alarmed; you won't be able to see me right now. Back when the Goddess turned into a block of stone, I simultaneously lost my own power. If you gather up the power of the Magic Cloud of Orbis, however, then I'll be able to recover my body and re-transform back to my original self. Please collect #b20#k Magic Clouds and bring them back to me. Right now, you'll only see me as a tiny, flickering light.";
- player.getClient().getAbstractPlayerInteraction().npcTalk(2013001, texttt);
+ player.getAbstractPlayerInteraction().npcTalk(2013001, texttt);
}
function scheduledTimeout(eim) {
diff --git a/scripts/event/RockSpirit.js b/scripts/event/RockSpirit.js
index fe043ad251..149ced9bd1 100644
--- a/scripts/event/RockSpirit.js
+++ b/scripts/event/RockSpirit.js
@@ -21,9 +21,13 @@
importPackage(Packages.tools);
-var exitMap;
var entryMap;
+var exitMap;
var otherMap;
+
+var minMapId = 103040410;
+var maxMapId = 103040460;
+
var minPlayers = 1;
var fightTime = 60;
var timer = 1000 * 60 * fightTime;
@@ -80,7 +84,7 @@ function playerDisconnected(eim, player) {
}
function changedMap(eim, player, mapid) {
- if(mapid == exitMap.getId()) {
+ if (mapid < minMapId || mapid > maxMapId) {
if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
eim.unregisterPlayer(player);
end(eim);
diff --git a/scripts/event/RockSpiritVIP.js b/scripts/event/RockSpiritVIP.js
index 4de76839c1..0d2ecba425 100644
--- a/scripts/event/RockSpiritVIP.js
+++ b/scripts/event/RockSpiritVIP.js
@@ -21,9 +21,13 @@
importPackage(Packages.tools);
-var exitMap;
var entryMap;
+var exitMap;
var otherMap;
+
+var minMapId = 103040410;
+var maxMapId = 103040460;
+
var minPlayers = 1;
var fightTime = 30;
var timer = 1000 * 60 * fightTime;
@@ -80,7 +84,7 @@ function playerDisconnected(eim, player) {
}
function changedMap(eim, player, mapid) {
- if(mapid == exitMap.getId()) {
+ if (mapid < minMapId || mapid > maxMapId) {
if (eim.isEventTeamLackingNow(true, minPlayers, player)) {
eim.unregisterPlayer(player);
end(eim);
diff --git a/scripts/event/WeddingCathedral.js b/scripts/event/WeddingCathedral.js
index 7d811fac40..2bf92e039a 100644
--- a/scripts/event/WeddingCathedral.js
+++ b/scripts/event/WeddingCathedral.js
@@ -110,7 +110,7 @@ function respawnStages(eim) {
function playerEntry(eim, player) {
eim.setProperty("giftedItemG" + player.getId(), "0");
eim.setProperty("giftedItemB" + player.getId(), "0");
- player.getClient().getAbstractPlayerInteraction().gainItem(4000313, 1);
+ player.getAbstractPlayerInteraction().gainItem(4000313, 1);
var map = eim.getMapInstance(entryMap);
player.changeMap(map, map.getPortal(0));
diff --git a/scripts/event/WeddingChapel.js b/scripts/event/WeddingChapel.js
index 259e790c32..37a44bd953 100644
--- a/scripts/event/WeddingChapel.js
+++ b/scripts/event/WeddingChapel.js
@@ -110,7 +110,7 @@ function respawnStages(eim) {
function playerEntry(eim, player) {
eim.setProperty("giftedItemG" + player.getId(), "0");
eim.setProperty("giftedItemB" + player.getId(), "0");
- player.getClient().getAbstractPlayerInteraction().gainItem(4000313, 1);
+ player.getAbstractPlayerInteraction().gainItem(4000313, 1);
var map = eim.getMapInstance(entryMap);
player.changeMap(map, map.getPortal(0));
diff --git a/scripts/npc/2042004.js b/scripts/npc/2042004.js
index 84801867a7..d9cf1d2b6e 100644
--- a/scripts/npc/2042004.js
+++ b/scripts/npc/2042004.js
@@ -8,9 +8,23 @@ function start() {
function action(mode, type, selection) {
- cm.warpParty(980000000);
- cm.cancelCPQLobby();
- cm.dispose();
+ if (mode == -1) {
+ cm.dispose();
+ } else {
+ if (mode == 0 && status == 0) {
+ cm.dispose();
+ return;
+ }
+ if (mode == 1)
+ status++;
+ else
+ status--;
+ if (status == 0) {
+ cm.warpParty(980000000);
+ cm.cancelCPQLobby();
+ cm.dispose();
+ }
+ }
}
diff --git a/scripts/npc/2112000.js b/scripts/npc/2112000.js
index 552e9c968d..71a0f0755a 100644
--- a/scripts/npc/2112000.js
+++ b/scripts/npc/2112000.js
@@ -69,9 +69,13 @@ function action(mode, type, selection) {
if(state == -1) {
cm.sendOk("Heh, it seems you guys have company. Have fun with them, as I politely request my leave.");
- } else if (playersTooClose() || eim.getIntProperty("npcShocked") == 0) {
+ } else if (playersTooClose()) {
cm.sendOk("Oh, hello there. I have been #bmonitoring your moves#k since you guys entered this perimeter. Quite the feat reaching here, I commend all of you. Now, now, look at the time, I've got an appointment right now, I'm afraid I will need to request my leave. But worry not, my #raccessors#k will deal with all of you. Now, if you permit me, I'm leaving now.");
+ eim.setIntProperty("yuleteTalked", -1);
+ } else if (eim.getIntProperty("npcShocked") == 0) {
+ cm.sendOk("Ho~ Aren't you quite the sneaky one? Well, it matters not. I have been #bmonitoring your moves#k since you guys entered this perimeter. Quite the feat reaching here, I commend all of you. Now, now, look at the time, I've got an appointment right now, I'm afraid I will need to request my leave. But worry not, my #raccessors#k will deal with all of you. Now, if you permit me, I'm leaving now.");
+
eim.setIntProperty("yuleteTalked", -1);
} else {
cm.sendOk("... Hah! What, wh-- How did you get here?! I though I had sealed all paths here! No matter, this situation will be resolved soon. Guys: DEPLOY the #rmaster weapon#k!! You! Yes, you. Don't you think this ends here, look back at your companions, they need some help! I'll be retreating for now.");
diff --git a/scripts/npc/2112010.js b/scripts/npc/2112010.js
index ea52077fb4..3d6d4cb895 100644
--- a/scripts/npc/2112010.js
+++ b/scripts/npc/2112010.js
@@ -69,9 +69,13 @@ function action(mode, type, selection) {
if(state == -1) {
cm.sendOk("Heh, it seems you guys have company. Have fun with them, as I politely request my leave.");
- } else if (playersTooClose() || eim.getIntProperty("npcShocked") == 0) {
+ } else if (playersTooClose()) {
cm.sendOk("Oh, hello there. I have been #bmonitoring your moves#k since you guys entered this perimeter. Quite the feat reaching here, I commend all of you. Now, now, look at the time, I've got an appointment right now, I'm afraid I will need to request my leave. But worry not, my #raccessors#k will deal with all of you. Now, if you permit me, I'm leaving now.");
+ eim.setIntProperty("yuleteTalked", -1);
+ } else if (eim.getIntProperty("npcShocked") == 0) {
+ cm.sendOk("Ho~ Aren't you quite the sneaky one? Well, it matters not. I have been #bmonitoring your moves#k since you guys entered this perimeter. Quite the feat reaching here, I commend all of you. Now, now, look at the time, I've got an appointment right now, I'm afraid I will need to request my leave. But worry not, my #raccessors#k will deal with all of you. Now, if you permit me, I'm leaving now.");
+
eim.setIntProperty("yuleteTalked", -1);
} else {
cm.sendOk("... Hah! What, wh-- How did you get here?! I though I had sealed all paths here! No matter, this situation will be resolved soon. Guys: DEPLOY the #rmaster weapon#k!! You! Yes, you. Don't you think this ends here, look back at your companions, they need some help! I'll be retreating for now.");
diff --git a/scripts/npc/9201002.js b/scripts/npc/9201002.js
index aa7e970fee..8a9341aa87 100644
--- a/scripts/npc/9201002.js
+++ b/scripts/npc/9201002.js
@@ -344,7 +344,7 @@ function action(mode, type, selection) {
cm.sendOk("You have already confirmed your vows. All that is left is for your partner to confirm now.");
} else {
eim.setIntProperty("weddingStage", 3);
- var cmPartner = partner.getClient().getAbstractPlayerInteraction();
+ var cmPartner = partner.getAbstractPlayerInteraction();
var playerItemId = detectPlayerItemid(player);
var partnerItemId = (playerItemId % 2 == 1) ? playerItemId + 1 : playerItemId - 1;
diff --git a/scripts/npc/9201005.js b/scripts/npc/9201005.js
index 5785d6d2f4..354076b112 100644
--- a/scripts/npc/9201005.js
+++ b/scripts/npc/9201005.js
@@ -159,7 +159,7 @@ function action(mode, type, selection) {
return;
}
- if(!cm.getUnclaimedMarriageGifts().isEmpty() || !partner.getClient().getAbstractPlayerInteraction().getUnclaimedMarriageGifts().isEmpty()) {
+ if(!cm.getUnclaimedMarriageGifts().isEmpty() || !partner.getAbstractPlayerInteraction().getUnclaimedMarriageGifts().isEmpty()) {
cm.sendOk("Eerhm... I'm sorry, something doesn't seem right according to the Amoria's Wedding Gift Registry reserve. Please check in the situation with #b#p9201014##k.");
cm.dispose();
return;
@@ -178,7 +178,7 @@ function action(mode, type, selection) {
var expirationTime = cserv.getRelativeWeddingTicketExpireTime(resStatus);
cm.gainItem(weddingSendTicket,15,false,true,expirationTime);
- partner.getClient().getAbstractPlayerInteraction().gainItem(weddingSendTicket,15,false,true,expirationTime);
+ partner.getAbstractPlayerInteraction().gainItem(weddingSendTicket,15,false,true,expirationTime);
var placeTime = cserv.getWeddingReservationTimeLeft(weddingId);
diff --git a/scripts/npc/9201007.js b/scripts/npc/9201007.js
index 0e879780e8..077c98b2b4 100644
--- a/scripts/npc/9201007.js
+++ b/scripts/npc/9201007.js
@@ -111,7 +111,7 @@ function action(mode, type, selection) {
} else if (status == 1) {
var cmPartner;
try {
- cmPartner = cm.getMap().getCharacterById(cm.getPlayer().getPartnerId()).getClient().getAbstractPlayerInteraction();
+ cmPartner = cm.getMap().getCharacterById(cm.getPlayer().getPartnerId()).getAbstractPlayerInteraction();
} catch(err) {
cmPartner = null;
}
diff --git a/scripts/npc/9201008.js b/scripts/npc/9201008.js
index e3dee07937..b13337fc78 100644
--- a/scripts/npc/9201008.js
+++ b/scripts/npc/9201008.js
@@ -159,7 +159,7 @@ function action(mode, type, selection) {
return;
}
- if(!cm.getUnclaimedMarriageGifts().isEmpty() || !partner.getClient().getAbstractPlayerInteraction().getUnclaimedMarriageGifts().isEmpty()) {
+ if(!cm.getUnclaimedMarriageGifts().isEmpty() || !partner.getAbstractPlayerInteraction().getUnclaimedMarriageGifts().isEmpty()) {
cm.sendOk("Eerhm... I'm sorry, something doesn't seem right according to the Amoria's Wedding Gift Registry reserve. Please check in the situation with #b#p9201014##k.");
cm.dispose();
return;
@@ -178,7 +178,7 @@ function action(mode, type, selection) {
var expirationTime = cserv.getRelativeWeddingTicketExpireTime(resStatus);
cm.gainItem(weddingSendTicket,15,false,true,expirationTime);
- partner.getClient().getAbstractPlayerInteraction().gainItem(weddingSendTicket,15,false,true,expirationTime);
+ partner.getAbstractPlayerInteraction().gainItem(weddingSendTicket,15,false,true,expirationTime);
var placeTime = cserv.getWeddingReservationTimeLeft(weddingId);
diff --git a/scripts/npc/9201009.js b/scripts/npc/9201009.js
index 601d7489be..815aa0ad92 100644
--- a/scripts/npc/9201009.js
+++ b/scripts/npc/9201009.js
@@ -111,7 +111,7 @@ function action(mode, type, selection) {
} else if (status == 1) {
var cmPartner;
try {
- cmPartner = cm.getMap().getCharacterById(cm.getPlayer().getPartnerId()).getClient().getAbstractPlayerInteraction();
+ cmPartner = cm.getMap().getCharacterById(cm.getPlayer().getPartnerId()).getAbstractPlayerInteraction();
} catch(err) {
cmPartner = null;
}
diff --git a/scripts/npc/9201011.js b/scripts/npc/9201011.js
index 01fbba44d1..b81902eab3 100644
--- a/scripts/npc/9201011.js
+++ b/scripts/npc/9201011.js
@@ -214,7 +214,7 @@ function action(mode, type, selection) {
cm.sendOk("You have already confirmed your vows. All that is left is for your partner to confirm now.");
} else {
eim.setIntProperty("weddingStage", 3);
- var cmPartner = partner.getClient().getAbstractPlayerInteraction();
+ var cmPartner = partner.getAbstractPlayerInteraction();
var playerItemId = detectPlayerItemid(player);
var partnerItemId = (playerItemId % 2 == 1) ? playerItemId + 1 : playerItemId - 1;
diff --git a/scripts/npc/9977777.js b/scripts/npc/9977777.js
index 7692ad766e..ab64b59dad 100644
--- a/scripts/npc/9977777.js
+++ b/scripts/npc/9977777.js
@@ -47,7 +47,7 @@ function writeFeatureTab_PQs() {
addFeature("Brand-new PQs: BossRushPQ, CafePQ.");
addFeature("Mu Lung Dojo.");
addFeature("Monster Carnival 1 & 2 - thanks Dragohe4rt & Jayd!");
- addFeature("AriantPQ - thanks Dragohe4rt!");
+ addFeature("AriantPQ - thanks Dragohe4rt & Jayd!");
addFeature("Capt. Latanica with party fighting the boss.");
addFeature("Filled up missing obligatory event script methods.");
addFeature("Secured uniquety of active lobby-name instances.");
@@ -222,6 +222,7 @@ function writeFeatureTab_Serverpotentials() {
addFeature("SP cap past tier-level, recovered after job upgrade.");
addFeature("Bypassable PIN/PIC system for authenticated users.");
addFeature("Automatic account registration - thanks shavit!");
+ addFeature("Any NPC scriptable - thanks GabrielSin!");
}
function writeFeatureTab_Commands() {
diff --git a/scripts/npc/cpqchallenge.js b/scripts/npc/cpqchallenge.js
index ab5f3ff5cf..1be873d469 100644
--- a/scripts/npc/cpqchallenge.js
+++ b/scripts/npc/cpqchallenge.js
@@ -18,10 +18,12 @@ function start(chrs) {
function action(mode, type, selection) {
if (mode == -1) {
+ cm.answerCPQChallenge(false);
cm.getChar().setChallenged(false);
cm.dispose();
} else {
if (mode == 0) {
+ cm.answerCPQChallenge(false);
cm.getChar().setChallenged(false);
cm.dispose();
return;
@@ -43,16 +45,16 @@ function action(mode, type, selection) {
snd += "#bName: " + party.get(i).getName() + " / (Level: " + party.get(i).getLevel() + ") / " + GameConstants.getJobName(party.get(i).getJobId()) + "#k\r\n\r\n";
cm.sendAcceptDecline(snd + "Would you like to fight this party at the Monster Carnival?");
} else {
- return;
+ cm.answerCPQChallenge(false);
+ cm.getChar().setChallenged(false);
+ cm.dispose();
}
} else if (status == 1) {
- var ch = cm.getChrById(party.get(0).getId());
if (party.size() == cm.getParty().getMembers().size()) {
- cm.startCPQ(ch, ch.getMapId() + 1);
- ch.getParty().setEnemy(cm.getPlayer().getParty());
- cm.getChar().getParty().setEnemy(ch.getParty());
- cm.getChar().setChallenged(false);
+ cm.answerCPQChallenge(true);
} else {
+ cm.answerCPQChallenge(false);
+ cm.getChar().setChallenged(false);
cm.sendOk("The number of players between the teams is not the same.");
}
cm.dispose();
diff --git a/scripts/npc/cpqchallenge2.js b/scripts/npc/cpqchallenge2.js
index d8454eb4f4..1be873d469 100644
--- a/scripts/npc/cpqchallenge2.js
+++ b/scripts/npc/cpqchallenge2.js
@@ -18,11 +18,12 @@ function start(chrs) {
function action(mode, type, selection) {
if (mode == -1) {
+ cm.answerCPQChallenge(false);
cm.getChar().setChallenged(false);
cm.dispose();
} else {
if (mode == 0) {
- cm.sendOk("Come back once you have thought about it some more.");
+ cm.answerCPQChallenge(false);
cm.getChar().setChallenged(false);
cm.dispose();
return;
@@ -44,14 +45,18 @@ function action(mode, type, selection) {
snd += "#bName: " + party.get(i).getName() + " / (Level: " + party.get(i).getLevel() + ") / " + GameConstants.getJobName(party.get(i).getJobId()) + "#k\r\n\r\n";
cm.sendAcceptDecline(snd + "Would you like to fight this party at the Monster Carnival?");
} else {
- return;
+ cm.answerCPQChallenge(false);
+ cm.getChar().setChallenged(false);
+ cm.dispose();
}
} else if (status == 1) {
- var ch = cm.getChrById(party.get(0).getId());
- cm.startCPQ2(ch, ch.getMapId() + 1);
- ch.getParty().setEnemy(cm.getPlayer().getParty());
- cm.getChar().getParty().setEnemy(ch.getParty());
- cm.getChar().setChallenged(false);
+ if (party.size() == cm.getParty().getMembers().size()) {
+ cm.answerCPQChallenge(true);
+ } else {
+ cm.answerCPQChallenge(false);
+ cm.getChar().setChallenged(false);
+ cm.sendOk("The number of players between the teams is not the same.");
+ }
cm.dispose();
}
}
diff --git a/scripts/portal/TD_MC_enterboss2.js b/scripts/portal/TD_MC_enterboss2.js
index 066ea6e26e..be984738d4 100644
--- a/scripts/portal/TD_MC_enterboss2.js
+++ b/scripts/portal/TD_MC_enterboss2.js
@@ -35,7 +35,7 @@ function enter(pi) {
return false;
}
} else {
- if (em.startInstance(pi.getPlayer(), pi.getMap())) {
+ if (em.startInstance(pi.getPlayer())) { // thanks RedHat for noticing an issue here
pi.playPortalSound();
return true;
} else {
@@ -57,7 +57,7 @@ function enter(pi) {
return false;
}
} else {
- if (em.startInstance(pi.getPlayer(), pi.getMap())) {
+ if (em.startInstance(pi.getPlayer())) {
pi.playPortalSound();
return true;
} else {
diff --git a/scripts/portal/party3_r6pt.js b/scripts/portal/party3_r6pt.js
index 5498ab4b50..b9d7a2a5d4 100644
--- a/scripts/portal/party3_r6pt.js
+++ b/scripts/portal/party3_r6pt.js
@@ -43,11 +43,11 @@ function enter(pi) {
var pRow = Math.floor(portalId / 10);
var pCol = portalId % 10;
-
if (pCol == parseInt(comb.substring(pRow, pRow + 1), 10)) { //climb
pi.playPortalSound(); pi.warp(pi.getMapId(), (pRow % 4 != 0) ? pi.getPortal().getId() + 4 : (pRow / 4));
} else { //fail
- pi.playPortalSound(); pi.warp(pi.getMapId(), 5);
+ pRow--;
+ pi.playPortalSound(); pi.warp(pi.getMapId(), (pRow / 4) > 1 ? (pRow / 4) : 5); // thanks Chloek3, seth1 for noticing next plaform issues
}
return true;
diff --git a/scripts/portal/party6_stage800.js b/scripts/portal/party6_stage800.js
index 7aa55ca09b..e80f27a744 100644
--- a/scripts/portal/party6_stage800.js
+++ b/scripts/portal/party6_stage800.js
@@ -5,7 +5,8 @@ function enter(pi) {
pi.removeAll(4001169);
pi.removeAll(2270004);
- if(pi.getMap().getReactorByName("") != null && pi.getMap().getReactorByName("").getState() == 1) {
+ var spring = pi.getMap().getReactorById(3008000); // thanks Chloek3, seth1 for noticing fragments not being awarded properly
+ if(spring != null && spring.getState() > 0) {
if(!pi.canHold(4001198, 1)) {
pi.playerMessage(5, "Check for a free space on your ETC inventory before entering this portal.");
return false;
diff --git a/scripts/portal/rnj5_rp.js b/scripts/portal/rnj5_rp.js
index e97a5a8d45..3dbaf07121 100644
--- a/scripts/portal/rnj5_rp.js
+++ b/scripts/portal/rnj5_rp.js
@@ -25,17 +25,6 @@ function enter(pi) {
var mapplayer = "stage6_comb" + (pi.getMapId() % 10);
var eim = pi.getEventInstance();
- if(eim.getProperty(mapplayer) == null) {
- var comb = "";
-
- for(var i = 0; i < 10; i++) {
- var r = Math.floor((Math.random() * 4));
- comb += r.toString();
- }
-
- eim.setProperty(mapplayer, comb);
- }
-
var comb = eim.getProperty(mapplayer);
var name = pi.getPortal().getName().substring(2, 4);
diff --git a/scripts/quest/21703.js b/scripts/quest/21703.js
index e597d4190c..d6116bd8c2 100644
--- a/scripts/quest/21703.js
+++ b/scripts/quest/21703.js
@@ -67,10 +67,9 @@ function end(mode, type, selection) {
qm.teachSkill(21000000, qm.getPlayer().getSkillLevel(21000000), 10, -1); // Combo Ability Skill
qm.gainExp(2800);
}
- qm.sendNext("(You remembered the #bCombo Ability#k skill! You were skeptical of the training at first, since the old man suffers from Alzheimer's and all, but boy, was it effective!)", 2);
- qm.showInfo("Effect/BasicEff.img/AranGetSkill");
+ qm.sendNext("(You remembered the #bCombo Ability#k skill! You were skeptical of the training at first, since the old man suffers from Alzheimer's and all, but boy, was it effective!)", 2);
} else if (status == 4) {
- qm.sendPrev("Now report back to #p1201000#. I know she'll be ecstatic when she sees the progress you've made!");
- qm.dispose();
+ qm.sendPrev("Now report back to #p1201000#. I know she'll be ecstatic when she sees the progress you've made!");
+ qm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/quest/21720.js b/scripts/quest/21720.js
index e8039917d6..e054020f21 100644
--- a/scripts/quest/21720.js
+++ b/scripts/quest/21720.js
@@ -39,7 +39,6 @@ function end(mode, type, selection) {
qm.teachSkill(21001003, qm.getPlayer().getSkillLevel(21001003), 20, -1);
qm.gainExp(3900);
}
- qm.showIntro("Effect/BasicEff.img/AranGetSkill");
qm.sendNext('#b(You remembered the Polearm Booster skill!)#k', 2);
} else if (status == 8) {
qm.sendNextPrev("This skill was found in an ancient incomprehensible script. I had a hunch it might be a skill you used in the past, and I think I was right. You're not as strong as you used to be, but you'll get there, in time.", 8);
diff --git a/sql/db_database.sql b/sql/db_database.sql
index eab384ba11..888edc4d4b 100644
--- a/sql/db_database.sql
+++ b/sql/db_database.sql
@@ -12794,7 +12794,8 @@ INSERT INTO `drop_data_global` (`id`, `continent`, `itemid`, `minimum_quantity`,
(2, -1, 4031866, 1, 1, 0, 20000, 'NX Card 250 PTS'),
(3, -1, 4001126, 1, 2, 0, 8000, 'Maple Leaves'),
(4, -1, 2049100, 1, 1, 0, 1200, 'Chaos Scroll 60%'),
-(5, -1, 4001006, 1, 1, 0, 10000, 'Flaming Feather');
+(5, -1, 2340000, 1, 1, 0, 1200, 'White Scroll'),
+(6, -1, 4001006, 1, 1, 0, 10000, 'Flaming Feather');
CREATE TABLE IF NOT EXISTS `dueyitems` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
@@ -16461,7 +16462,6 @@ INSERT INTO `nxcoupons` (`id`, `couponid`, `rate`, `activeday`, `starthour`, `en
(39,5360008,2,254,6,10),
(40,5360042,2,254,0,24);
-
CREATE TABLE IF NOT EXISTS `pets` (
`petid` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(13) DEFAULT NULL,
@@ -16583,6 +16583,7 @@ CREATE TABLE IF NOT EXISTS `queststatus` (
`time` int(11) NOT NULL DEFAULT '0',
`expires` bigint(20) NOT NULL DEFAULT '0',
`forfeited` int(11) NOT NULL DEFAULT '0',
+ `completed` int(11) NOT NULL DEFAULT '0',
`info` tinyint(3) NOT NULL DEFAULT '0',
PRIMARY KEY (`queststatusid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
diff --git a/src/client/MapleCharacter.java b/src/client/MapleCharacter.java
index 5e0d36d712..1181238342 100644
--- a/src/client/MapleCharacter.java
+++ b/src/client/MapleCharacter.java
@@ -64,6 +64,7 @@ import net.server.world.MapleParty;
import net.server.world.MaplePartyCharacter;
import net.server.world.PartyOperation;
import net.server.world.World;
+import scripting.AbstractPlayerInteraction;
import scripting.event.EventInstanceManager;
import server.CashShop;
import server.MapleItemInformationProvider;
@@ -199,7 +200,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
private int expRate = 1, mesoRate = 1, dropRate = 1, expCoupon = 1, mesoCoupon = 1, dropCoupon = 1;
private int omokwins, omokties, omoklosses, matchcardwins, matchcardties, matchcardlosses;
private int owlSearch;
- private long lastfametime, lastUsedCashItem, lastExpression = 0, lastHealed, lastBuyback = 0, lastDeathtime, lastMesoDrop = -1, jailExpiration = -1;
+ private long lastfametime, lastUsedCashItem, lastExpression = 0, lastHealed, lastBuyback = 0, lastDeathtime, jailExpiration = -1;
private transient int localstr, localdex, localluk, localint_, localmagic, localwatk;
private transient int equipmaxhp, equipmaxmp, equipstr, equipdex, equipluk, equipint_, equipmagic, equipwatk, localchairhp, localchairmp;
private int localchairrate;
@@ -2954,22 +2955,24 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
public void gainGachaExp() {
int expgain = 0;
- int currentgexp = gachaexp.get();
+ long currentgexp = gachaexp.get();
if ((currentgexp + exp.get()) >= ExpTable.getExpNeededForLevel(level)) {
expgain += ExpTable.getExpNeededForLevel(level) - exp.get();
+
int nextneed = ExpTable.getExpNeededForLevel(level + 1);
- if ((currentgexp - expgain) >= nextneed) {
+ if (currentgexp - expgain >= nextneed) {
expgain += nextneed;
}
- this.gachaexp.set(currentgexp - expgain);
+
+ this.gachaexp.set((int) (currentgexp - expgain));
} else {
expgain = this.gachaexp.getAndSet(0);
}
- gainExp(expgain, false, false);
+ gainExp(expgain, false, true);
updateSingleStat(MapleStat.GACHAEXP, this.gachaexp.get());
}
- public void gainGachaExp(int gain) {
+ public void addGachaExp(int gain) {
updateSingleStat(MapleStat.GACHAEXP, gachaexp.addAndGet(gain));
}
@@ -4296,6 +4299,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
return client;
}
+ public AbstractPlayerInteraction getAbstractPlayerInteraction() {
+ return client.getAbstractPlayerInteraction();
+ }
+
public final List getCompletedQuests() {
synchronized (quests) {
List ret = new LinkedList<>();
@@ -4930,8 +4937,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
if (elapsedDays > 100) elapsedDays = 100;
- int netMeso = (merchantmeso * (100 - elapsedDays)) / 100;
- return netMeso;
+ long netMeso = (long) merchantmeso; // negative mesos issues found thanks to Flash, Vcoc
+ netMeso = (netMeso * (100 - elapsedDays)) / 100;
+ return (int) netMeso;
}
public int getMesosTraded() {
@@ -6906,6 +6914,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
status.setForfeited(rs.getInt("forfeited"));
+ status.setCompleted(rs.getInt("completed"));
ret.quests.put(q.getId(), status);
loadedQuestStatus.put(rs.getInt("queststatusid"), status);
}
@@ -7665,7 +7674,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public void resetBattleshipHp() {
- this.battleshipHp = 400 * getSkillLevel(SkillFactory.getSkill(Corsair.BATTLE_SHIP)) + ((getLevel() - 120) * 200);
+ int bshipLevel = Math.max(getLevel() - 120, 0); // thanks alex12 for noticing battleship HP issues for low-level players
+ this.battleshipHp = 400 * getSkillLevel(SkillFactory.getSkill(Corsair.BATTLE_SHIP)) + (bshipLevel * 200);
}
public void resetEnteredScript() {
@@ -8254,7 +8264,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
deleteQuestProgressWhereCharacterId(con, id);
- ps = con.prepareStatement("INSERT INTO queststatus (`queststatusid`, `characterid`, `quest`, `status`, `time`, `expires`, `forfeited`) VALUES (DEFAULT, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS);
+ ps = con.prepareStatement("INSERT INTO queststatus (`queststatusid`, `characterid`, `quest`, `status`, `time`, `expires`, `forfeited`, `completed`) VALUES (DEFAULT, ?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS);
PreparedStatement psf;
try (PreparedStatement pse = con.prepareStatement("INSERT INTO questprogress VALUES (DEFAULT, ?, ?, ?, ?)")) {
psf = con.prepareStatement("INSERT INTO medalmaps VALUES (DEFAULT, ?, ?, ?)");
@@ -8267,6 +8277,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
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();
@@ -8549,8 +8560,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
public synchronized void withdrawMerchantMesos() {
int merchantMeso = this.getMerchantNetMeso();
+ int playerMeso = this.getMeso();
+
if (merchantMeso > 0) {
- int possible = Integer.MAX_VALUE - merchantMeso;
+ int possible = Integer.MAX_VALUE - playerMeso;
if (possible > 0) {
if (possible < merchantMeso) {
@@ -8562,7 +8575,6 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
} else {
- int playerMeso = this.getMeso();
int nextMeso = playerMeso + merchantMeso;
if (nextMeso < 0) {
@@ -9401,9 +9413,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
} else if (quest.getStatus().equals(MapleQuestStatus.Status.COMPLETED)) {
MapleQuest mquest = quest.getQuest();
short questid = mquest.getId();
- if(!mquest.isSameDayRepeatable() && !MapleQuest.isExploitableQuest(questid)) {
+ if (!mquest.isSameDayRepeatable() && !MapleQuest.isExploitableQuest(questid)) {
awardQuestPoint(ServerConstants.QUEST_POINT_PER_QUEST_COMPLETE);
}
+ quest.setCompleted(quest.getCompleted() + 1); // count quest completed Jayd's idea
announce(MaplePacketCreator.completeQuest(questid, quest.getCompletionTime()));
} else if (quest.getStatus().equals(MapleQuestStatus.Status.NOT_STARTED)) {
@@ -10040,14 +10053,6 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
whiteChat = !whiteChat;
}
- public boolean canDropMeso() {
- if (System.currentTimeMillis() - lastMesoDrop >= 200 || lastMesoDrop == -1) { //About 200 meso drops a minute
- lastMesoDrop = System.currentTimeMillis();
- return true;
- }
- return false;
- }
-
// These need to be renamed, but I am too lazy right now to go through the scripts and rename them...
public String getPartyQuestItems() {
return dataString;
diff --git a/src/client/MapleClient.java b/src/client/MapleClient.java
index 66d36d4956..4af9f01cb3 100644
--- a/src/client/MapleClient.java
+++ b/src/client/MapleClient.java
@@ -888,7 +888,6 @@ public class MapleClient {
player.cancelAllBuffs(true);
player.closePlayerInteractions();
- QuestScriptManager.getInstance().dispose(this);
if (!serverTransition) { // thanks MedicOP for detecting an issue with party leader change on changing channels
removePartyPlayer(wserv);
@@ -1463,18 +1462,8 @@ public class MapleClient {
return;
}
- if (player.getTrade() != null) {
- MapleTrade.cancelTrade(getPlayer(), MapleTrade.TradeResult.PARTNER_CANCEL);
- }
-
- MapleHiredMerchant merchant = player.getHiredMerchant();
- if (merchant != null) {
- if (merchant.isOwner(getPlayer())) {
- merchant.setOpen(true);
- } else {
- merchant.removeVisitor(getPlayer());
- }
- }
+ player.closePlayerInteractions();
+
player.unregisterChairBuff();
server.getPlayerBuffStorage().addBuffsToStorage(player.getId(), player.getAllBuffs());
server.getPlayerBuffStorage().addDiseasesToStorage(player.getId(), player.getAllDiseases());
@@ -1540,6 +1529,7 @@ public class MapleClient {
public void closePlayerScriptInteractions() {
this.removeClickedNPC();
NPCScriptManager.getInstance().dispose(this);
+ QuestScriptManager.getInstance().dispose(this);
}
public boolean attemptCsCoupon() {
diff --git a/src/client/MapleQuestStatus.java b/src/client/MapleQuestStatus.java
index 4eb31ce1fc..9e0ccc9dd1 100644
--- a/src/client/MapleQuestStatus.java
+++ b/src/client/MapleQuestStatus.java
@@ -65,7 +65,7 @@ public class MapleQuestStatus {
private final List medalProgress = new LinkedList();
private int npc;
private long completionTime, expirationTime;
- private int forfeited = 0;
+ private int forfeited = 0, completed = 0;
private String customData;
public MapleQuestStatus(MapleQuest quest, Status status) {
@@ -214,6 +214,10 @@ public class MapleQuestStatus {
return forfeited;
}
+ public int getCompleted() {
+ return completed;
+ }
+
public String getInfo() {
if(!progress.containsKey(0) && !getMedalMaps().isEmpty()) {
return Integer.toString(getMedalProgress());
@@ -233,6 +237,14 @@ public class MapleQuestStatus {
throw new IllegalArgumentException("Can't set forfeits to something lower than before.");
}
}
+
+ public void setCompleted(int completed) {
+ if (completed >= this.completed) {
+ this.completed = completed;
+ } else {
+ throw new IllegalArgumentException("Can't set completes to something lower than before.");
+ }
+ }
public final void setCustomData(final String customData) {
this.customData = customData;
diff --git a/src/client/command/CommandsExecutor.java b/src/client/command/CommandsExecutor.java
index daf53a4f4d..98be594909 100644
--- a/src/client/command/CommandsExecutor.java
+++ b/src/client/command/CommandsExecutor.java
@@ -204,6 +204,8 @@ public class CommandsExecutor {
addCommand("enableauth", EnableAuthCommand.class);
addCommand("toggleexp", ToggleExpCommand.class);
addCommand("mylawn", MapOwnerClaimCommand.class);
+ addCommand("bosshp", BossHpCommand.class);
+ addCommand("mobhp", MobHpCommand.class);
commandsNameDesc.add(levelCommandsCursor);
}
@@ -212,8 +214,6 @@ public class CommandsExecutor {
private void registerLv1Commands() {
levelCommandsCursor = new Pair<>((List) new ArrayList(), (List) new ArrayList());
- addCommand("bosshp", 1, BossHpCommand.class);
- addCommand("mobhp", 1, MobHpCommand.class);
addCommand("whatdropsfrom", 1, WhatDropsFromCommand.class);
addCommand("whodrops", 1, WhoDropsCommand.class);
addCommand("buffme", 1, BuffMeCommand.class);
@@ -291,7 +291,6 @@ public class CommandsExecutor {
addCommand("givevp", 3, GiveVpCommand.class);
addCommand("givems", 3, GiveMesosCommand.class);
addCommand("giverp", 3, GiveRpCommand.class);
- addCommand("id", 3, IdCommand.class);
addCommand("expeds", 3, ExpedsCommand.class);
addCommand("kill", 3, KillCommand.class);
addCommand("seed", 3, SeedCommand.class);
@@ -307,7 +306,6 @@ public class CommandsExecutor {
addCommand("startmapevent", 3, StartMapEventCommand.class);
addCommand("stopmapevent", 3, StopMapEventCommand.class);
addCommand("online2", 3, OnlineTwoCommand.class);
- addCommand("warpsnowball", 3, WarpSnowBallCommand.class);
addCommand("ban", 3, BanCommand.class);
addCommand("unban", 3, UnBanCommand.class);
addCommand("healmap", 3, HealMapCommand.class);
@@ -339,6 +337,7 @@ public class CommandsExecutor {
addCommand("exprate", 4, ExpRateCommand.class);
addCommand("mesorate", 4, MesoRateCommand.class);
addCommand("droprate", 4, DropRateCommand.class);
+ addCommand("bossdroprate", 4, BossDropRateCommand.class);
addCommand("questrate", 4, QuestRateCommand.class);
addCommand("travelrate", 4, TravelRateCommand.class);
addCommand("fishrate", 4, FishingRateCommand.class);
diff --git a/src/client/command/commands/gm1/GotoCommand.java b/src/client/command/commands/gm1/GotoCommand.java
index 72445d122b..2824929435 100644
--- a/src/client/command/commands/gm1/GotoCommand.java
+++ b/src/client/command/commands/gm1/GotoCommand.java
@@ -27,23 +27,64 @@ import client.MapleCharacter;
import client.command.Command;
import client.MapleClient;
import constants.GameConstants;
+import java.util.ArrayList;
+import java.util.Collections;
+import net.server.Server;
import server.MaplePortal;
import server.maps.FieldLimit;
import server.maps.MapleMap;
+import server.maps.MapleMapFactory;
import server.maps.MapleMiniDungeonInfo;
+import java.util.Comparator;
import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
public class GotoCommand extends Command {
+
{
setDescription("");
+
+ MapleMapFactory mapFactory = Server.getInstance().getWorlds().get(0).getChannels().get(0).getMapFactory();
+
+ List> towns = new ArrayList<>(GameConstants.GOTO_TOWNS.entrySet());
+ sortGotoEntries(towns);
+ for (Map.Entry e : towns) {
+ GOTO_TOWNS_INFO += ("'" + e.getKey() + "' - #b" + (mapFactory.getMap(e.getValue()).getMapName()) + "#k\r\n");
+ }
+
+ List> areas = new ArrayList<>(GameConstants.GOTO_AREAS.entrySet());
+ sortGotoEntries(areas);
+ for (Map.Entry e : areas) {
+ GOTO_AREAS_INFO += ("'" + e.getKey() + "' - #b" + (mapFactory.getMap(e.getValue()).getMapName()) + "#k\r\n");
+ }
+ }
+
+ public static String GOTO_TOWNS_INFO = "";
+ public static String GOTO_AREAS_INFO = "";
+
+ private static void sortGotoEntries(List> listEntries) {
+ Collections.sort(listEntries, new Comparator>() {
+ @Override
+ public int compare(Entry e1, Entry e2)
+ {
+ return e1.getValue().compareTo(e2.getValue());
+ }
+ });
}
@Override
public void execute(MapleClient c, String[] params) {
MapleCharacter player = c.getPlayer();
if (params.length < 1){
- player.yellowMessage("Syntax: @goto