diff --git a/README.md b/README.md
index f82f4bf60a..df258ac230 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ Besides myself for maintaining this repository, credits are to be given to Wizet
Regarding distributability and usage of the code presented here: like it was before, this MapleStory server is open-source. By that, it is meant that anyone is **free to install, use, modify and redistribute the contents**, as long as there is **no kind of commercial trading involved** and the **credits to the original creators are maintained** within the codes.
-This is a NetBeans 8.0.2 Project, that MUST be built and run under JDK/JRE 7 (1.7.0_79+) in order to run properly. This means that it's easier to install the project via opening the server project folder inside NetBeans' IDE. Once installed, build this project on your machine and run the server using the "launch.bat" application.
+This is a NetBeans 8.0.2 Project, that MUST be built and run on Java 7 (JDK/JRE 1.7.0_79+) in order to run properly. This means that it's easier to install the project via opening the server project folder inside NetBeans' IDE. Once installed, build this project on your machine and run the server using the "launch.bat" application.
In this project, many gameplay-wise issues generated from either the original WZ files and the server source have been partially or completely solved. Considering the use of the provided edited WZ's and server-side wz.xml files should be of the greatest importance when dealing with this instance of server source, in order to perceive it at it's full potential. My opinion, though!
@@ -19,6 +19,8 @@ Server files: https://github.com/ronancpl/HeavenMS
Client files & general tools: https://drive.google.com/drive/folders/0BzDsHSr-0V4MYVJ0TWIxd05hYUk
+Java7 SDK: https://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase7-521261.html
+
**Important note about localhosts**: these executables are red-flagged by antivirus tools as __potentially malicious softwares__, this happens due to the reverse engineering methods that were applied onto these software artifacts. Those depicted here have been put to use for years already and posed no harm so far, so they are soundly assumed to be safe.
Latest localhost: https://hostr.co/m2bVtnizCtmD
@@ -81,6 +83,7 @@ It's never enough to tell this, thanks to everyone that have been contributing s
Our Discord channel is still available on: https://discord.gg/Q7wKxHX
+
### Donation
If you REALLY liked what you have seen on the project, please feel free to donate a little something as a helping hand for my contributions towards Maple development. Also remember to **support Nexon**!
diff --git a/cores/HikariCP-java7-2.4.12.jar b/cores/HikariCP-java7-2.4.12.jar
deleted file mode 100644
index 792b690564..0000000000
Binary files a/cores/HikariCP-java7-2.4.12.jar and /dev/null differ
diff --git a/cores/HikariCP-java7-2.4.13.jar b/cores/HikariCP-java7-2.4.13.jar
new file mode 100644
index 0000000000..6506cbac92
Binary files /dev/null and b/cores/HikariCP-java7-2.4.13.jar differ
diff --git a/cores/slf4j-api-1.6.6.jar b/cores/slf4j-api-1.6.6.jar
deleted file mode 100644
index 4c03fa6bb2..0000000000
Binary files a/cores/slf4j-api-1.6.6.jar and /dev/null differ
diff --git a/cores/slf4j-api-1.7.21.jar b/cores/slf4j-api-1.7.21.jar
new file mode 100644
index 0000000000..2a5c33ec55
Binary files /dev/null and b/cores/slf4j-api-1.7.21.jar differ
diff --git a/docs/mychanges_ptbr.txt b/docs/mychanges_ptbr.txt
index 3f09112e5e..25788d0a90 100644
--- a/docs/mychanges_ptbr.txt
+++ b/docs/mychanges_ptbr.txt
@@ -1573,4 +1573,50 @@ Protegido concorrentemente sistema de comandos, assim evitando processamento em
16 Janeiro 2019,
Revisado login handler, trazendo métodos de desconexão para antes de checar LoginState, e não permitindo reatribuição de objeto-cliente para jogador já logado em canal.
-Revisado disconnect no login handler, agora devidamente finalizando sessões recém-criadas que falham em conectar jogador ao mundo.
\ No newline at end of file
+Revisado disconnect no login handler, agora devidamente finalizando sessões recém-criadas que falham em conectar jogador ao mundo.
+Revisado skill Monster Magnet, agora devidamente mostrando efeitos de skill.
+Mais uma tentativa de proteção contra acesso concorrente no login handler, buscando evitar múltiplas requisições concorrente por um accountId durante processo e múltiplas requisições de mesmo objeto de cliente.
+Revisado objeto das expedições, não mais permitindo armazenar objetos de jogadores (que já podem ter sido desativados).
+Corrigido expedições enviando pacotes para jogadores que estão fora de jogo.
+Normalizado mensagens de 1o job de NPCs explorers, com afirmação de mínimo de stats antes de checar requerimentos.
+
+18 Janeiro 2019,
+Corrigido dispose de interação com NPCs não devolvendo controle de certas ações ao jogador, mais notável quando a interação ocorreu automaticamente (jogador caminhou pra área de atuação).
+Removido pigs de Maple Island, já que o quiz de 3rd job sugere não há os mesmos lá. Cynical Orange Mushrooms passam a ocupar posições dos mesmos.
+Editado "launch.bat" para somente usar Java7, assim permitindo usuários a não terem que especificar preferência de uso de Java7 nas variáveis de ambiente PATH.
+
+20 Janeiro 2019,
+Corrigido necessidade de repetir aprovação dos mestres para realizar expedições de Zakum.
+Revisado comando goto. Jogadores tem acesso somente a mapas de cidade, GMs tem acesso a areas também.
+Implementado EXP rate específico para novatos de nível menor que 11.
+Revisado petid sendo setado fora de área de atuação (até então não compete setar isso após criado objeto de Item).
+
+21 - 24 Janeiro 2019,
+Corrigido sistema de guilds não atualizando corretamente tooltips de informação de guild de jogadores no mapa, para ampla quantidade de eventos com guilds (adicionar player na guild, trocar emblema, remover player, etc).
+Corrigido sistema de eventos permitindo entrada duplicada de eventos com mesmo nome nos registros do gerenciador de eventos, potencialmente levando a nulos em EIMs.
+Corrigido skill Hyper Body cancelando efeito do buff anterior ao reutilizar a skill, levando valores suficientemente grandes de HP corrente do jogador ao MaxHP base (MaxHP antes de utilizar a skill).
+Refatorado uso de evtLock para métodos que gerenciam expiração de quests, possívelmente resolvendo caso de deadlock no método de desistência de quests expiráveis.
+Revisado MoveLifeHandler, não mais propagando pacotes de movimentação de mobs vindas de jogadores que não são controladores.
+Refatorado completamente o sistema de aggro de mobs. Agora, métodos que atuam na atualização de aggros de mobs usam funções comuns.
+
+25 - 26 Janeiro 2019,
+Corrigido problema de acesso a ponteiro nulo ao realizar dispose no sistema de mapas das instâncias de eventos. Referência ao gerenciador de eventos já era nulo ao atingir tal método.
+Implementado retorno de estado de aggro para "sem aggro" se não houveram atividades de aggro num mob por algum tempo.
+Implementado checagem de aniversário ao adicionar itens de cash às lojas de player.
+Corrigido Hired Merchants não fechando devidamente ao abrir loja com itens de cash.
+Corrigido tooltip de Hired Merchant não atualizando para "indisponível" quando a loja está em manutenção.
+Corrigido tooltip de Player Shops não fechando corretamente se ainda havia visitantes na loja.
+Mais alguns ajustes no novo sistema de aggros. Nesta implementação aparentemente somente controladores processam ataques do tipo "areaWarning" de mobs.
+Corrigido função forceChangeMap não levando devidamente jogadores para o mapa dado como parâmetro, quando tal mapa é de instância de evento.
+Revisado comando de summon de jogadores, agora utilizando função padrão forceChangeMap, que lida com registro de jogadores em instâncias e coloca jogador no mapa alvo.
+Adicionado, no comando de summon de jogadores, habilidade de colocar jogadores em outros canais dentro do mapa de evento.
+
+27 - 29 Janeiro 2019,
+Corrigido custom AP autoassigner não utilizando devidamente os caps definidos no escopo do handler.
+Revisado custom AP autoassigner. Classes que usam DEX como atributo secundário para STR foram rebalanceados, de forma que o aumento no uso do atributo secundário permita melhores condições de ataque no jogo.
+Adicionado checagem de mesos em transações entre jogadores, lojas de jogador, ao receber itens de Duey e Fredrick.
+Adicionado checagem em quantidade de itens nas lojas e mercantes de jogadores, assim evitando bugs quando há mais itens a serem vendidos do que o esperado.
+Corrigido um exploit com mercantes, envolvendo chamada à DB antes de retirar item (que está sendo inserido na loja) do inventário do jogador.
+
+30 Janeiro 2019,
+Corrigido chamadas irregulares a "qm/cm" em scripts.
\ No newline at end of file
diff --git a/launch.bat b/launch.bat
index 9f87e29e73..076a28d634 100644
--- a/launch.bat
+++ b/launch.bat
@@ -1,5 +1,6 @@
@echo off
@title HeavenMS
+set PATH=C:\Program Files\Java\jdk1.7.0_79\bin;%PATH%
set CLASSPATH=.;dist\*
java -Xmx2048m -Dwzpath=wz\ net.server.Server
pause
\ No newline at end of file
diff --git a/nbproject/project.properties b/nbproject/project.properties
index 62e82d2465..3c19c318ab 100644
--- a/nbproject/project.properties
+++ b/nbproject/project.properties
@@ -28,21 +28,21 @@ dist.jar=${dist.dir}/HeavenMS.jar
dist.javadoc.dir=${dist.dir}/javadoc
endorsed.classpath=
excludes=
-file.reference.HikariCP-java7-2.4.12.jar=cores/HikariCP-java7-2.4.12.jar
+file.reference.HikariCP-java7-2.4.13.jar=cores/HikariCP-java7-2.4.13.jar
file.reference.MapleSolaxia-src=src
file.reference.mina-core-2.0.7.jar=cores/mina-core-2.0.7.jar
file.reference.mysql-connector-java-bin.jar=cores/mysql-connector-java-bin.jar
-file.reference.slf4j-api-1.6.6.jar=cores/slf4j-api-1.6.6.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
includes=**
jar.archive.disabled=${jnlp.enabled}
jar.compress=true
jar.index=${jnlp.enabled}
javac.classpath=\
- ${file.reference.HikariCP-java7-2.4.12.jar}:\
${file.reference.mina-core-2.0.7.jar}:\
+ ${file.reference.slf4j-api-1.7.21.jar}:\
+ ${file.reference.HikariCP-java7-2.4.13.jar}:\
${file.reference.mysql-connector-java-bin.jar}:\
- ${file.reference.slf4j-api-1.6.6.jar}:\
${file.reference.slf4j-jdk14-1.7.5.jar}
# Space-separated list of extra javac options
javac.compilerargs=
diff --git a/scripts/npc/1012100.js b/scripts/npc/1012100.js
index a132cfce17..abebcb671a 100644
--- a/scripts/npc/1012100.js
+++ b/scripts/npc/1012100.js
@@ -46,12 +46,7 @@ function start() {
} else {
if (cm.getJobId() == 0) {
actionx["1stJob"] = true;
- if (cm.getLevel() >= 10 && cm.canGetFirstJob(jobType))
- cm.sendNext("So you decided to become a #rBowman#k?");
- else {
- cm.sendOk("Train a bit more until you reach #blevel 10, " + cm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rBowman#k.");
- cm.dispose();
- }
+ cm.sendNext("So you decided to become a #rbowman#k? There are some standards to meet, y'know... #bYour level should be at least 10, with at least " + cm.getFirstJobStatRequirement(jobType) + "#k. Let's see."); // thanks Vcoc for noticing a need to state and check requirements on first job adv starting message
} else if (cm.getLevel() >= 30 && cm.getJobId() == 300) {
actionx["2ndJob"] = true;
if (cm.haveItem(4031012))
@@ -79,8 +74,13 @@ function start() {
function action(mode, type, selection) {
status++;
- if (mode == 0 && type != 1)
+ if (mode == -1 && selection == -1) {
+ cm.dispose();
+ return;
+ } else if (mode == 0 && type != 1) {
status -= 2;
+ }
+
if (status == -1){
start();
return;
@@ -116,10 +116,15 @@ function action(mode, type, selection) {
}
if (actionx["1stJob"]){
- if (status == 0)
- cm.sendNextPrev("It is an important and final choice. You will not be able to turn back.");
- else if (status == 1){
- if (cm.canHold(1452051) && cm.canHold(2060000)){
+ if (status == 0) {
+ if (cm.getLevel() >= 10 && cm.canGetFirstJob(jobType)) {
+ cm.sendNextPrev("It is an important and final choice. You will not be able to turn back.");
+ } else {
+ cm.sendOk("Train a bit more until you reach the base requirements and I can show you the way of the #rBowman#k.");
+ cm.dispose();
+ }
+ } else if (status == 1){
+ if (cm.canHold(1452051) && cm.canHold(2070000)){
if (cm.getJobId() == 0){
cm.changeJobById(300);
cm.gainItem(1452051, 1);
diff --git a/scripts/npc/1013001.js b/scripts/npc/1013001.js
index 89c035317c..ba4813df37 100644
--- a/scripts/npc/1013001.js
+++ b/scripts/npc/1013001.js
@@ -8,7 +8,7 @@ function action(mode, type, selection) {
if (mode == 0 && type == 0) {
status--;
} else if (mode == -1) {
- qm.dispose();
+ cm.dispose();
return;
} else {
status++;
diff --git a/scripts/npc/1022000.js b/scripts/npc/1022000.js
index a112e93b0c..4d4aaeae59 100644
--- a/scripts/npc/1022000.js
+++ b/scripts/npc/1022000.js
@@ -47,12 +47,7 @@ function start() {
} else {
if (cm.getJobId() == 0) {
actionx["1stJob"] = true;
- if (cm.getLevel() >= 10 && cm.canGetFirstJob(jobType))
- cm.sendNext("Do you want to become a Warrior? You need to meet some criteria in order to do so.#b You should be at least in level 10, with at least 35 in STR#k. Let's see...");
- else {
- cm.sendOk("Train a bit more until you reach #blevel 10, " + cm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rWarrior#k.");
- cm.dispose();
- }
+ cm.sendNext("Do you want to become a #rwarrior#k? You need to meet some criteria in order to do so.#b You should be at least in level 10, and at least " + cm.getFirstJobStatRequirement(jobType) + "#k. Let's see..."); // thanks Vcoc for noticing a need to state and check requirements on first job adv starting message
} else if (cm.getLevel() >= 30 && cm.getJobId() == 100) {
actionx["2ndJob"] = true;
if (cm.haveItem(4031012))
@@ -80,8 +75,13 @@ function start() {
function action(mode, type, selection) {
status++;
- if (mode == 0 && type != 1)
+ if (mode == -1 && selection == -1) {
+ cm.dispose();
+ return;
+ } else if (mode == 0 && type != 1) {
status -= 2;
+ }
+
if (status == -1){
start();
return;
@@ -117,9 +117,14 @@ function action(mode, type, selection) {
}
if (actionx["1stJob"]){
- if (status == 0)
- cm.sendNextPrev("It is an important and final choice. You will not be able to turn back.");
- else if (status == 1){
+ if (status == 0) {
+ if (cm.getLevel() >= 10 && cm.canGetFirstJob(jobType)) {
+ cm.sendNextPrev("It is an important and final choice. You will not be able to turn back.");
+ } else {
+ cm.sendOk("Train a bit more until you reach the base requirements and I can show you the way of the #rWarrior#k.");
+ cm.dispose();
+ }
+ } else if (status == 1){
if (cm.canHold(1302077)){
if (cm.getJobId() == 0){
cm.changeJobById(100);
diff --git a/scripts/npc/1032001.js b/scripts/npc/1032001.js
index 1d501ebf8c..98bb35d84a 100644
--- a/scripts/npc/1032001.js
+++ b/scripts/npc/1032001.js
@@ -47,12 +47,7 @@ function start() {
} else {
if (cm.getJobId() == 0) {
actionx["1stJob"] = true;
- if (cm.getLevel() >= 8 && cm.canGetFirstJob(jobType))
- cm.sendNext("Want to be a magician? There are some standards to meet. because we can't just accept EVERYONE in... #bYour level should be at least 8#k, with getting INT as your top priority. Let's see.");
- else {
- cm.sendOk("Train a bit more until you reach #blevel 8, " + cm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rMagician#k.");
- cm.dispose();
- }
+ cm.sendNext("Want to be a #rmagician#k? There are some standards to meet. because we can't just accept EVERYONE in... #bYour level should be at least 8#k, with getting " + cm.getFirstJobStatRequirement(jobType) + " as your top priority. Let's see."); // thanks Vcoc for noticing a need to state and check requirements on first job adv starting message
} else if (cm.getLevel() >= 30 && cm.getJobId() == 200) {
actionx["2ndJob"] = true;
if (cm.haveItem(4031012))
@@ -80,8 +75,13 @@ function start() {
function action(mode, type, selection) {
status++;
- if (mode == 0 && type == 0)
+ if (mode == -1 && selection == -1) {
+ cm.dispose();
+ return;
+ } else if (mode == 0 && type == 0) {
status -= 2;
+ }
+
if (status == -1){
start();
return;
@@ -117,9 +117,14 @@ function action(mode, type, selection) {
}
if (actionx["1stJob"]){
- if (status == 0)
- cm.sendYesNo("Oh...! You look like someone that can definitely be a part of us... all you need is a little sinister mind, and... yeah... so, what do you think? Wanna be the Magician?");
- else if (status == 1){
+ if (status == 0) {
+ if (cm.getLevel() >= 8 && cm.canGetFirstJob(jobType)) {
+ cm.sendYesNo("Oh...! You look like someone that can definitely be a part of us... all you need is a little sinister mind, and... yeah... so, what do you think? Wanna be the Magician?");
+ } else {
+ cm.sendOk("Train a bit more until you reach the base requirements and I can show you the way of the #rMagician#k.");
+ cm.dispose();
+ }
+ } else if (status == 1){
if (cm.canHold(1372043)){
if (cm.getJobId() == 0){
cm.changeJobById(200);
diff --git a/scripts/npc/1052001.js b/scripts/npc/1052001.js
index 3f76c7fb14..a9ae74c161 100644
--- a/scripts/npc/1052001.js
+++ b/scripts/npc/1052001.js
@@ -46,12 +46,7 @@ function start() {
} else {
if (cm.getJobId() == 0) {
actionx["1stJob"] = true;
- if (cm.getLevel() >= 10 && cm.canGetFirstJob(jobType))
- cm.sendNext("Want to be a thief? There are some standards to meet. because we can't just accept EVERYONE in... #bYour level should be at least 10, with your DEX over 25#k. Let's see.");
- else {
- cm.sendOk("Train a bit more until you reach #blevel 10, " + cm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rThief#k.");
- cm.dispose();
- }
+ cm.sendNext("Want to be a #rthief#k? There are some standards to meet. because we can't just accept EVERYONE in... #bYour level should be at least 10, with at least your " + cm.getFirstJobStatRequirement(jobType) + "#k. Let's see."); // thanks Vcoc for noticing a need to state and check requirements on first job adv starting message
} else if (cm.getLevel() >= 30 && cm.getJobId() == 400) {
actionx["2ndJob"] = true;
if (cm.haveItem(4031012))
@@ -81,8 +76,13 @@ function start() {
function action(mode, type, selection) {
status++;
- if (mode == 0 && type != 1)
+ if (mode == -1 && selection == -1) {
+ cm.dispose();
+ return;
+ } else if (mode == 0 && type != 1) {
status -= 2;
+ }
+
if (status == -1){
start();
return;
@@ -118,14 +118,20 @@ function action(mode, type, selection) {
}
if (actionx["1stJob"]){
- if (status == 0)
- cm.sendYesNo("Oh...! You look like someone that can definitely be a part of us... all you need is a little sinister mind, and... yeah... so, what do you think? Wanna be the Rogue?");
- else if (status == 1){
- if (cm.canHold(2070000) && cm.canHold(1472061)){
+ if (status == 0) {
+ if (cm.getLevel() >= 10 && cm.canGetFirstJob(jobType))
+ cm.sendYesNo("Oh...! You look like someone that can definitely be a part of us... all you need is a little sinister mind, and... yeah... so, what do you think? Wanna be the Rogue?");
+ else {
+ cm.sendOk("Train a bit more until you reach the base requirements and I can show you the way of the #rThief#k.");
+ cm.dispose();
+ }
+ } else if (status == 1){
+ if (cm.canHold(2070000) && cm.canHoldAll([1472061, 1332063])){
if (cm.getJobId() == 0){
cm.changeJobById(400);
- cm.gainItem(2070000, 500);
+ cm.gainItem(2070015, 500);
cm.gainItem(1472061, 1);
+ cm.gainItem(1332063, 1);
cm.resetStats();
}
cm.sendNext("Alright, from here out, you are a part of us! You'll be living the life of a wanderer at ..., but just be patient as soon, you'll be living the high life. Alright, it ain't much, but I'll give you some of my abilities... HAAAHHH!!!");
diff --git a/scripts/npc/1061014.js b/scripts/npc/1061014.js
index 8d6e5b4932..b7c51c4891 100644
--- a/scripts/npc/1061014.js
+++ b/scripts/npc/1061014.js
@@ -29,6 +29,7 @@ importPackage(Packages.scripting.event);
var status = 0;
var expedition;
+var expedMembers;
var player;
var em;
var exped = MapleExpeditionType.BALROG_NORMAL;
@@ -68,7 +69,7 @@ function action(mode, type, selection) {
status = 2;
} else if (expedition.isRegistering()) { //If the expedition is registering
if (expedition.contains(player)) { //If you're in it but it hasn't started, be patient
- cm.sendOk("You have already registered for the expedition. Please wait for #r" + expedition.getLeader().getName() + "#k to begin the expedition.");
+ cm.sendOk("You have already registered for the expedition. Please wait for #r" + expedition.getLeader().getName() + "#k to begin it.");
cm.dispose();
} else { //If you aren't in it, you're going to get added
cm.sendOk(expedition.addMember(cm.getPlayer()));
@@ -120,7 +121,8 @@ function action(mode, type, selection) {
cm.dispose();
return;
}
- var size = expedition.getMembers().size();
+ expedMembers = expedition.getMemberList();
+ var size = expedMembers.size();
if (size == 1) {
cm.sendOk("You are the only member of the expedition.");
cm.dispose();
@@ -129,13 +131,13 @@ function action(mode, type, selection) {
var text = "The following members make up your expedition (Click on them to expel them):\r\n";
text += "\r\n\t\t1." + expedition.getLeader().getName();
for (var i = 1; i < size; i++) {
- text += "\r\n#b#L" + (i + 1) + "#" + (i + 1) + ". " + expedition.getMembers().get(i).getName() + "#l\n";
+ text += "\r\n#b#L" + (i + 1) + "#" + (i + 1) + ". " + expedMembers.get(i).getValue() + "#l\n";
}
cm.sendSimple(text);
status = 6;
} else if (selection == 2) {
var min = exped.getMinSize();
- var size = expedition.getMembers().size();
+ var size = expedition.getMemberList().size();
if (size < min) {
cm.sendOk("You need at least " + min + " players registered in your expedition.");
cm.dispose();
@@ -170,7 +172,7 @@ function action(mode, type, selection) {
return;
} else if (status == 6) {
if (selection > 0) {
- var banned = expedition.getMembers().get(selection - 1);
+ var banned = expedMembers.get(selection - 1);
expedition.ban(banned);
cm.sendOk("You have banned " + banned.getName() + " from the expedition.");
cm.dispose();
diff --git a/scripts/npc/1090000.js b/scripts/npc/1090000.js
index 8595f29c3f..60b573219d 100644
--- a/scripts/npc/1090000.js
+++ b/scripts/npc/1090000.js
@@ -77,12 +77,7 @@ function start() {
} else {
if (cm.getJobId() == 0) {
actionx["1stJob"] = true;
- if (cm.getLevel() >= 10 && cm.canGetFirstJob(jobType))
- cm.sendNext("Want to be a pirate? There are some standards to meet. because we can't just accept EVERYONE in... #bYour level should be at least 10#k. Let's see.");
- else {
- cm.sendOk("Train a bit more until you reach #blevel 10, " + cm.getFirstJobStatRequirement(jobType) + "#k and I can show you the way of the #rPirate#k.");
- cm.dispose();
- }
+ cm.sendNext("Want to be a #rpirate#k? There are some standards to meet. because we can't just accept EVERYONE in... #bYour level should be at least 10, with " + cm.getFirstJobStatRequirement(jobType) + " minimum#k. Let's see."); // thanks Vcoc for noticing a need to state and check requirements on first job adv starting message
} else if (cm.getLevel() >= 30 && cm.getJobId() == 500) {
actionx["2ndJob"] = true;
if (cm.isQuestCompleted(2191) || cm.isQuestCompleted(2192))
@@ -107,8 +102,13 @@ function start() {
function action(mode, type, selection) {
status++;
- if (mode == 0 && type != 1)
+ if (mode == -1 && selection == -1) {
+ cm.dispose();
+ return;
+ } else if (mode == 0 && type != 1) {
status -= 2;
+ }
+
if (status == -1){
start();
return;
@@ -161,10 +161,15 @@ function action(mode, type, selection) {
}
if (actionx["1stJob"]){
- if (status == 0)
- cm.sendYesNo("Oh...! You look like someone that can definitely be a part of us... all you need is a little slang, and... yeah... so, what do you think? Wanna be the Pirate?");
- else if (status == 1){
- if (cm.canHold(2070000) && cm.canHold(1472061)){
+ if (status == 0) {
+ if (cm.getLevel() >= 10 && cm.canGetFirstJob(jobType)) {
+ cm.sendYesNo("Oh...! You look like someone that can definitely be a part of us... all you need is a little slang, and... yeah... so, what do you think? Wanna be the Pirate?");
+ } else {
+ cm.sendOk("Train a bit more until you reach the base requirements and I can show you the way of the #rPirate#k.");
+ cm.dispose();
+ }
+ } else if (status == 1){
+ if (cm.canHold(2070000) && cm.canHoldAll([1482000, 1492000])){
if (cm.getJobId() == 0){
cm.changeJobById(500);
cm.gainItem(1492000, 1);
diff --git a/scripts/npc/2020008.js b/scripts/npc/2020008.js
index 2ce3f079ad..bfe4b52f82 100644
--- a/scripts/npc/2020008.js
+++ b/scripts/npc/2020008.js
@@ -141,7 +141,7 @@ function action(mode, type, selection){
} else {
if (cm.getPlayer().getLevel() >= 50){
cm.sendNext("Ok, go.");
- if(!cm.isQuestStarted(100200)) cm.startQuest(100200);
+ if(!(cm.isQuestStarted(100200) || cm.isQuestCompleted(100200))) cm.startQuest(100200);
if(Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
}else
cm.sendNext("You're weak.");
diff --git a/scripts/npc/2020009.js b/scripts/npc/2020009.js
index 39ab767c6c..a44bdcf957 100644
--- a/scripts/npc/2020009.js
+++ b/scripts/npc/2020009.js
@@ -113,7 +113,7 @@ function action(mode, type, selection){
} else {
if (cm.getPlayer().getLevel() >= 50){
cm.sendNext("Ok, go.");
- if(!cm.isQuestStarted(100200)) cm.startQuest(100200);
+ if(!(cm.isQuestStarted(100200) || cm.isQuestCompleted(100200))) cm.startQuest(100200);
if(Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
}else
cm.sendNext("You're weak.");
diff --git a/scripts/npc/2020010.js b/scripts/npc/2020010.js
index cab227ff6f..6c51b76405 100644
--- a/scripts/npc/2020010.js
+++ b/scripts/npc/2020010.js
@@ -114,7 +114,7 @@ function action(mode, type, selection){
} else {
if (cm.getPlayer().getLevel() >= 50){
cm.sendNext("Ok, go.");
- if(!cm.isQuestStarted(100200)) cm.startQuest(100200);
+ if(!(cm.isQuestStarted(100200) || cm.isQuestCompleted(100200))) cm.startQuest(100200);
if(Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
}else
cm.sendNext("You're weak.");
diff --git a/scripts/npc/2020011.js b/scripts/npc/2020011.js
index a85730f09d..850b295c62 100644
--- a/scripts/npc/2020011.js
+++ b/scripts/npc/2020011.js
@@ -113,7 +113,7 @@ function action(mode, type, selection){
} else {
if (cm.getPlayer().getLevel() >= 50){
cm.sendNext("Ok, go.");
- if(!cm.isQuestStarted(100200)) cm.startQuest(100200);
+ if(!(cm.isQuestStarted(100200) || cm.isQuestCompleted(100200))) cm.startQuest(100200);
if(Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
}else
cm.sendNext("You're weak.");
diff --git a/scripts/npc/2020013.js b/scripts/npc/2020013.js
index edec8efb1a..1521740211 100644
--- a/scripts/npc/2020013.js
+++ b/scripts/npc/2020013.js
@@ -112,7 +112,7 @@ function action(mode, type, selection){
} else {
if (cm.getPlayer().getLevel() >= 50){
cm.sendNext("Ok, go.");
- if(!cm.isQuestStarted(100200)) cm.startQuest(100200);
+ if(!(cm.isQuestStarted(100200) || cm.isQuestCompleted(100200))) cm.startQuest(100200);
if(Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
}else
cm.sendNext("You're weak.");
diff --git a/scripts/npc/2030006.js b/scripts/npc/2030006.js
index 6cc117e1e1..f05dfb3945 100644
--- a/scripts/npc/2030006.js
+++ b/scripts/npc/2030006.js
@@ -32,14 +32,14 @@ var questionTree = [
//Questions Related to ITEMS
["Which of following monsters got CORRECT item corresponding to the monster?", ["Royal cactus - Needle", "Wild Boar - Boar fang", "Lazy Buffy - Buffy hat", "Chipmunk - Nut", "Stirge - Stirge's wing"], 4],
["Which of following monsters got WRONG item corresponding to the monster?", ["Greatest Oldies - Greatest oldies", "Nependeath - Nependeath's leaf", "Ghost stump - Seedling", "Sparker - Seal tooth", "Miner Zombie - Zombie's lost tooth"], 1],
- ["In GM Event, how many FRUIT CAKE you can get as reward?", ["20", "200", "5", "25", "100"], 2],
+ //["In GM Event, how many FRUIT CAKE you can get as reward?", ["20", "200", "5", "25", "100"], 2],
["Which of following potions got CORRECT info.?", ["Warrior Elixir - Attack +5 for 3 minutes", "Pure Water - Recover 700 MP", "Cake - Recover 150 HP & MP", "Salad - Recover 300 MP", "Pizza - Recover 400 HP"], 4],
["Which of following potions got WRONG info.?", ["Mana Elixir - Recover 300 MP", "Tonic - Cures state of weakness", "Apple - Recover 30 HP", "Sunrise Dew - Recover 3000 MP", "Ramen - Recover 1000 HP"], 3],
//Questions Related to MONSTERS
["Green Mushroom, Tree Stump, Bubbling, Axe Stump, Octopus, which is highest level of all?", ["Tree Stump", "Bubbling", "Axe Stump", "Octopus", "Green Mushroom"], 2],
["Which monster will be seen during the ship trip to Orbis/Ellinia?", ["Werewolf", "Slime", "Crimson Balrog", "Zakum", "Star Pixie"], 2],
- ["Maple Island doesn't have which following monsters?", ["Green Mushroom", "Blue Snail", "Orange Mushroom", "Red Snail", "Pig"], 0],
+ ["Maple Island doesn't have which following monsters?", ["Shroom", "Blue Snail", "Slime", "Red Snail", "Pig"], 4], // to get conformant with website answers, thanks to Vcoc
["Which monster is not at Victoria Island and Sleepywood?", ["Evil Eye", "Sentinel", "Jr. Balrog", "Ghost Stump", "Snail"], 1],
["El Nath doesn't have which following monsters?", ["Dark Yeti", "Dark Ligator", "Yeti & Pepe", "Bain", "Coolie Zombie"], 1],
["Which of following monsters can fly?", ["Malady", "Ligator", "Cold Eye", "Meerkat", "Alishar"], 0],
diff --git a/scripts/npc/2030008.js b/scripts/npc/2030008.js
index 31a3afa6f4..c836e0234d 100644
--- a/scripts/npc/2030008.js
+++ b/scripts/npc/2030008.js
@@ -58,7 +58,7 @@ function action(mode, type, selection) {
return;
}
- if(!cm.isQuestStarted(100200)) {
+ if(!(cm.isQuestStarted(100200) || cm.isQuestCompleted(100200))) { // thanks Vcoc for finding out a need of reapproval from the masters for Zakum expeditions
cm.sendOk("Beware, for the power of olde has not been forgotten... ");
cm.dispose();
return;
diff --git a/scripts/npc/2030013.js b/scripts/npc/2030013.js
index 77d0586a59..ef61b1d339 100644
--- a/scripts/npc/2030013.js
+++ b/scripts/npc/2030013.js
@@ -29,6 +29,7 @@ importPackage(Packages.scripting.event);
var status = 0;
var expedition;
+var expedMembers;
var player;
var em;
var exped = MapleExpeditionType.ZAKUM;
@@ -69,7 +70,7 @@ function action(mode, type, selection) {
status = 2;
} else if (expedition.isRegistering()) { //If the expedition is registering
if (expedition.contains(player)) { //If you're in it but it hasn't started, be patient
- cm.sendOk("You have already registered for the expedition. Please wait for #r" + expedition.getLeader().getName() + "#k to begin the expedition.");
+ cm.sendOk("You have already registered for the expedition. Please wait for #r" + expedition.getLeader().getName() + "#k to begin it.");
cm.dispose();
} else { //If you aren't in it, you're going to get added
cm.sendOk(expedition.addMember(cm.getPlayer()));
@@ -121,7 +122,8 @@ function action(mode, type, selection) {
cm.dispose();
return;
}
- var size = expedition.getMembers().size();
+ expedMembers = expedition.getMemberList();
+ var size = expedMembers.size();
if (size == 1) {
cm.sendOk("You are the only member of the expedition.");
cm.dispose();
@@ -130,14 +132,14 @@ function action(mode, type, selection) {
var text = "The following members make up your expedition (Click on them to expel them):\r\n";
text += "\r\n\t\t1." + expedition.getLeader().getName();
for (var i = 1; i < size; i++) {
- text += "\r\n#b#L" + (i + 1) + "#" + (i + 1) + ". " + expedition.getMembers().get(i).getName() + "#l\n";
+ text += "\r\n#b#L" + (i + 1) + "#" + (i + 1) + ". " + expedMembers.get(i).getValue() + "#l\n";
}
cm.sendSimple(text);
status = 6;
} else if (selection == 2) {
var min = exped.getMinSize();
- var size = expedition.getMembers().size();
+ var size = expedition.getMemberList().size();
if (size < min) {
cm.sendOk("You need at least " + min + " players registered in your expedition.");
cm.dispose();
@@ -172,7 +174,7 @@ function action(mode, type, selection) {
return;
} else if (status == 6) {
if (selection > 0) {
- var banned = expedition.getMembers().get(selection - 1);
+ var banned = expedMembers.get(selection - 1);
expedition.ban(banned);
cm.sendOk("You have banned " + banned.getName() + " from the expedition.");
cm.dispose();
diff --git a/scripts/npc/2083004.js b/scripts/npc/2083004.js
index 6194b60125..17520857e5 100644
--- a/scripts/npc/2083004.js
+++ b/scripts/npc/2083004.js
@@ -29,6 +29,7 @@ importPackage(Packages.scripting.event);
var status = 0;
var expedition;
+var expedMembers;
var player;
var em;
var exped = MapleExpeditionType.HORNTAIL;
@@ -67,7 +68,7 @@ function action(mode, type, selection) {
status = 2;
} else if (expedition.isRegistering()) { //If the expedition is registering
if (expedition.contains(player)) { //If you're in it but it hasn't started, be patient
- cm.sendOk("You have already registered for the expedition. Please wait for #r" + expedition.getLeader().getName() + "#k to begin the expedition.");
+ cm.sendOk("You have already registered for the expedition. Please wait for #r" + expedition.getLeader().getName() + "#k to begin it.");
cm.dispose();
} else { //If you aren't in it, you're going to get added
cm.sendOk(expedition.addMember(cm.getPlayer()));
@@ -113,7 +114,8 @@ function action(mode, type, selection) {
cm.dispose();
return;
}
- var size = expedition.getMembers().size();
+ expedMembers = expedition.getMemberList();
+ var size = expedMembers.size();
if (size == 1) {
cm.sendOk("You are the only member of the expedition.");
cm.dispose();
@@ -122,14 +124,14 @@ function action(mode, type, selection) {
var text = "The following members make up your expedition (Click on them to expel them):\r\n";
text += "\r\n\t\t1." + expedition.getLeader().getName();
for (var i = 1; i < size; i++) {
- text += "\r\n#b#L" + (i + 1) + "#" + (i + 1) + ". " + expedition.getMembers().get(i).getName() + "#l\n";
+ text += "\r\n#b#L" + (i + 1) + "#" + (i + 1) + ". " + expedMembers.get(i).getValue() + "#l\n";
}
cm.sendSimple(text);
status = 6;
} else if (selection == 2) {
var min = exped.getMinSize();
- var size = expedition.getMembers().size();
+ var size = expedition.getMemberList().size();
if (size < min) {
cm.sendOk("You need at least " + min + " players registered in your expedition.");
cm.dispose();
@@ -164,7 +166,7 @@ function action(mode, type, selection) {
return;
} else if (status == 6) {
if (selection > 0) {
- var banned = expedition.getMembers().get(selection - 1);
+ var banned = expedMembers.get(selection - 1);
expedition.ban(banned);
cm.sendOk("You have banned " + banned.getName() + " from the expedition.");
cm.dispose();
diff --git a/scripts/npc/2141001.js b/scripts/npc/2141001.js
index 210faf5fa7..9772b05adc 100644
--- a/scripts/npc/2141001.js
+++ b/scripts/npc/2141001.js
@@ -31,6 +31,7 @@ importPackage(Packages.scripting.event);
var status = 0;
var expedition;
+var expedMembers;
var player;
var em;
var exped = MapleExpeditionType.PINKBEAN;
@@ -70,7 +71,7 @@ function action(mode, type, selection) {
status = 2;
} else if (expedition.isRegistering()) { //If the expedition is registering
if (expedition.contains(player)) { //If you're in it but it hasn't started, be patient
- cm.sendOk("You have already registered for the expedition. Please wait for #r" + expedition.getLeader().getName() + "#k to begin the expedition.");
+ cm.sendOk("You have already registered for the expedition. Please wait for #r" + expedition.getLeader().getName() + "#k to begin it.");
cm.dispose();
} else { //If you aren't in it, you're going to get added
cm.sendOk(expedition.addMember(cm.getPlayer()));
@@ -116,7 +117,8 @@ function action(mode, type, selection) {
cm.dispose();
return;
}
- var size = expedition.getMembers().size();
+ expedMembers = expedition.getMemberList();
+ var size = expedMembers.size();
if (size == 1) {
cm.sendOk("You are the only member of the expedition.");
cm.dispose();
@@ -125,14 +127,14 @@ function action(mode, type, selection) {
var text = "The following members make up your expedition (Click on them to expel them):\r\n";
text += "\r\n\t\t1." + expedition.getLeader().getName();
for (var i = 1; i < size; i++) {
- text += "\r\n#b#L" + (i + 1) + "#" + (i + 1) + ". " + expedition.getMembers().get(i).getName() + "#l\n";
+ text += "\r\n#b#L" + (i + 1) + "#" + (i + 1) + ". " + expedMembers.get(i).getValue() + "#l\n";
}
cm.sendSimple(text);
status = 6;
} else if (selection == 2) {
var min = exped.getMinSize();
- var size = expedition.getMembers().size();
+ var size = expedition.getMemberList().size();
if (size < min) {
cm.sendOk("You need at least " + min + " players registered in your expedition.");
cm.dispose();
@@ -167,7 +169,7 @@ function action(mode, type, selection) {
return;
} else if (status == 6) {
if (selection > 0) {
- var banned = expedition.getMembers().get(selection - 1);
+ var banned = expedMembers.get(selection - 1);
expedition.ban(banned);
cm.sendOk("You have banned " + banned.getName() + " from the expedition.");
cm.dispose();
diff --git a/scripts/npc/9120201.js b/scripts/npc/9120201.js
index 09e41bf0db..4f3b233776 100644
--- a/scripts/npc/9120201.js
+++ b/scripts/npc/9120201.js
@@ -28,6 +28,7 @@ importPackage(Packages.scripting.event);
var status = 0;
var expedition;
+var expedMembers;
var player;
var em;
var exped = MapleExpeditionType.SHOWA;
@@ -68,7 +69,7 @@ function action(mode, type, selection) {
status = 2;
} else if (expedition.isRegistering()) { //If the expedition is registering
if (expedition.contains(player)) { //If you're in it but it hasn't started, be patient
- cm.sendOk("You have already registered for the expedition. Please wait for #r" + expedition.getLeader().getName() + "#k to begin the expedition.");
+ cm.sendOk("You have already registered for the expedition. Please wait for #r" + expedition.getLeader().getName() + "#k to begin it.");
cm.dispose();
} else { //If you aren't in it, you're going to get added
cm.sendOk(expedition.addMember(cm.getPlayer()));
@@ -120,7 +121,8 @@ function action(mode, type, selection) {
cm.dispose();
return;
}
- var size = expedition.getMembers().size();
+ expedMembers = expedition.getMemberList();
+ var size = expedMembers.size();
if (size == 1) {
cm.sendOk("You are the only member of the expedition.");
cm.dispose();
@@ -129,14 +131,14 @@ function action(mode, type, selection) {
var text = "The following members make up your expedition (Click on them to expel them):\r\n";
text += "\r\n\t\t1." + expedition.getLeader().getName();
for (var i = 1; i < size; i++) {
- text += "\r\n#b#L" + (i + 1) + "#" + (i + 1) + ". " + expedition.getMembers().get(i).getName() + "#l\n";
+ text += "\r\n#b#L" + (i + 1) + "#" + (i + 1) + ". " + expedMembers.get(i).getValue() + "#l\n";
}
cm.sendSimple(text);
status = 6;
} else if (selection == 2) {
var min = exped.getMinSize();
- var size = expedition.getMembers().size();
+ var size = expedition.getMemberList().size();
if (size < min) {
cm.sendOk("You need at least " + min + " players registered in your expedition.");
cm.dispose();
@@ -171,7 +173,7 @@ function action(mode, type, selection) {
return;
} else if (status == 6) {
if (selection > 0) {
- var banned = expedition.getMembers().get(selection - 1);
+ var banned = expedMembers.get(selection - 1);
expedition.ban(banned);
cm.sendOk("You have banned " + banned.getName() + " from the expedition.");
cm.dispose();
diff --git a/scripts/npc/9201014.js b/scripts/npc/9201014.js
index 6713b15fcf..9fd36866af 100644
--- a/scripts/npc/9201014.js
+++ b/scripts/npc/9201014.js
@@ -61,7 +61,7 @@ function action(mode, type, selection) {
} else if (status == 1) {
if (selection == 0) {
if (cm.haveItem(4031424)) {
- if (cm.isMarried()) {
+ if (cm.getPlayer().isMarried()) { // thanks MedicOP for solving an issue here
if(cm.getInventory(2).getNextFreeSlot() >= 0) {
var rand = Math.floor(Math.random() * bgPrizes.length);
cm.gainItem(bgPrizes[rand][0], bgPrizes[rand][1]);
diff --git a/scripts/npc/9201113.js b/scripts/npc/9201113.js
index d513e4e4fb..4cd1baca90 100644
--- a/scripts/npc/9201113.js
+++ b/scripts/npc/9201113.js
@@ -29,6 +29,7 @@ importPackage(Packages.scripting.event);
var status = 0;
var expedition;
+var expedMembers;
var player;
var em;
var cwkpq = MapleExpeditionType.CWKPQ;
@@ -64,7 +65,7 @@ function action(mode, type, selection) {
status = 2;
} else if (expedition.isRegistering()) { //If the expedition is registering
if (expedition.contains(player)) { //If you're in it but it hasn't started, be patient
- cm.sendOk("You have already registered for the expedition. Please wait for #r" + expedition.getLeader().getName() + "#k to begin the expedition.");
+ cm.sendOk("You have already registered for the expedition. Please wait for #r" + expedition.getLeader().getName() + "#k to begin it.");
cm.dispose();
} else { //If you aren't in it, you're going to get added
cm.sendOk(expedition.addMember(cm.getPlayer()));
@@ -104,7 +105,8 @@ function action(mode, type, selection) {
cm.dispose();
return;
}
- var size = expedition.getMembers().size();
+ expedMembers = expedition.getMemberList();
+ var size = expedMembers.size();
if (size == 1) {
cm.sendOk("You are the only member of the expedition.");
cm.dispose();
@@ -113,13 +115,13 @@ function action(mode, type, selection) {
var text = "The following members make up your expedition (Click on them to expel them):\r\n";
text += "\r\n\t\t1." + expedition.getLeader().getName();
for (var i = 1; i < size; i++) {
- text += "\r\n#b#L" + (i + 1) + "#" + (i + 1) + ". " + expedition.getMembers().get(i).getName() + "#l\n";
+ text += "\r\n#b#L" + (i + 1) + "#" + (i + 1) + ". " + expedMembers.get(i).getValue() + "#l\n";
}
cm.sendSimple(text);
status = 6;
} else if (selection == 2) {
var min = cwkpq.getMinSize();
- var size = expedition.getMembers().size();
+ var size = expedition.getMemberList().size();
if (size < min) {
cm.sendOk("You need at least " + min + " players registered in your expedition.");
cm.dispose();
@@ -154,7 +156,7 @@ function action(mode, type, selection) {
return;
} else if (status == 6) {
if (selection > 0) {
- var banned = expedition.getMembers().get(selection - 1);
+ var banned = expedMembers.get(selection - 1);
expedition.ban(banned);
cm.sendOk("You have banned " + banned.getName() + " from the expedition.");
cm.dispose();
diff --git a/scripts/npc/9270047.js b/scripts/npc/9270047.js
index a84ced3482..4d7288d24e 100644
--- a/scripts/npc/9270047.js
+++ b/scripts/npc/9270047.js
@@ -29,6 +29,7 @@ importPackage(Packages.scripting.event);
var status = 0;
var expedition;
+var expedMembers;
var player;
var em;
var exped = MapleExpeditionType.SCARGA;
@@ -69,7 +70,7 @@ function action(mode, type, selection) {
status = 2;
} else if (expedition.isRegistering()) { //If the expedition is registering
if (expedition.contains(player)) { //If you're in it but it hasn't started, be patient
- cm.sendOk("You have already registered for the expedition. Please wait for #r" + expedition.getLeader().getName() + "#k to begin the expedition.");
+ cm.sendOk("You have already registered for the expedition. Please wait for #r" + expedition.getLeader().getName() + "#k to begin it.");
cm.dispose();
} else { //If you aren't in it, you're going to get added
cm.sendOk(expedition.addMember(cm.getPlayer()));
@@ -121,7 +122,8 @@ function action(mode, type, selection) {
cm.dispose();
return;
}
- var size = expedition.getMembers().size();
+ expedMembers = expedition.getMemberList();
+ var size = expedMembers.size();
if (size == 1) {
cm.sendOk("You are the only member of the expedition.");
cm.dispose();
@@ -130,13 +132,13 @@ function action(mode, type, selection) {
var text = "The following members make up your expedition (Click on them to expel them):\r\n";
text += "\r\n\t\t1." + expedition.getLeader().getName();
for (var i = 1; i < size; i++) {
- text += "\r\n#b#L" + (i + 1) + "#" + (i + 1) + ". " + expedition.getMembers().get(i).getName() + "#l\n";
+ text += "\r\n#b#L" + (i + 1) + "#" + (i + 1) + ". " + expedMembers.get(i).getValue() + "#l\n";
}
cm.sendSimple(text);
status = 6;
} else if (selection == 2) {
var min = exped.getMinSize();
- var size = expedition.getMembers().size();
+ var size = expedition.getMemberList().size();
if (size < min) {
cm.sendOk("You need at least " + min + " players registered in your expedition.");
cm.dispose();
@@ -171,7 +173,7 @@ function action(mode, type, selection) {
return;
} else if (status == 6) {
if (selection > 0) {
- var banned = expedition.getMembers().get(selection - 1);
+ var banned = expedMembers.get(selection - 1);
expedition.ban(banned);
cm.sendOk("You have banned " + banned.getName() + " from the expedition.");
cm.dispose();
diff --git a/scripts/npc/9977777.js b/scripts/npc/9977777.js
index d0136b8e9c..e3c07313a7 100644
--- a/scripts/npc/9977777.js
+++ b/scripts/npc/9977777.js
@@ -77,6 +77,7 @@ function writeFeatureTab_PlayerSocialNetwork() {
addFeature("P. members' HPBar accounts HP gain on equips.");
addFeature("Thoroughly reviewed P. Shops and H. Merchants.");
addFeature("Transactions on Merchs instantly announced to owner.");
+ addFeature("Proper meso space check on player transactions.");
addFeature("Game minirooms with functional pw system.");
addFeature("Proper item pickup cooldown on non-owned items.");
addFeature("Improved ranking system, with daily movement.");
@@ -121,6 +122,7 @@ function writeFeatureTab_MonstersMapsReactors() {
addFeature("Added meso drop data for many missing mobs.");
addFeature("Monsterbook displays updated drop data info.");
addFeature("Every skill/mastery book is now obtainable.");
+ addFeature("Enhanced aggro system: real-time DPS aggro detection.");
addFeature("Mobs now can drop more than one of the same equip.");
addFeature("Mobs only drop items collectable by the player/party.");
addFeature("Mobs shouldn't fall from foothold too often now.");
@@ -146,6 +148,7 @@ function writeFeatureTab_MonstersMapsReactors() {
addFeature("Added world maps for M. Castle, W. Tour & Ellin areas.");
addFeature("Added W. Tour & Masteria continents in the world map.");
addFeature("Reviewed several issues with W. Map tooltips & links.");
+ addFeature("Continent separated global drops.");
addFeature("Giant Cake boss drops s. bags and Maple items.");
}
diff --git a/scripts/portal/Zakum05.js b/scripts/portal/Zakum05.js
index 1afbeb322c..7f0f674aab 100644
--- a/scripts/portal/Zakum05.js
+++ b/scripts/portal/Zakum05.js
@@ -24,7 +24,7 @@
*/
function enter(pi) {
- if (!pi.isQuestStarted(100200)) {
+ if (!(pi.isQuestStarted(100200) || pi.isQuestCompleted(100200))) {
pi.getPlayer().dropMessage(5,"You need approval from the masters to battle. You may not attempt the boss right now.");
return false;
}
diff --git a/scripts/quest/20101.js b/scripts/quest/20101.js
index f6d2107782..9af9d25a2f 100644
--- a/scripts/quest/20101.js
+++ b/scripts/quest/20101.js
@@ -27,6 +27,12 @@ function end(mode, type, selection) {
return;
}
+ 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);
diff --git a/scripts/quest/20102.js b/scripts/quest/20102.js
index f4bd37ddcb..cbdf5aee82 100644
--- a/scripts/quest/20102.js
+++ b/scripts/quest/20102.js
@@ -27,6 +27,12 @@ function end(mode, type, selection) {
return;
}
+ 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);
diff --git a/scripts/quest/20103.js b/scripts/quest/20103.js
index 03d54ab4e8..9d603bf429 100644
--- a/scripts/quest/20103.js
+++ b/scripts/quest/20103.js
@@ -27,6 +27,12 @@ function end(mode, type, selection) {
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.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);
diff --git a/scripts/quest/20104.js b/scripts/quest/20104.js
index a0fc3311a0..232a97ad5d 100644
--- a/scripts/quest/20104.js
+++ b/scripts/quest/20104.js
@@ -27,11 +27,16 @@ function end(mode, type, selection) {
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.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(2070015, 800);
- qm.gainItem(2070015, 800);
+ qm.gainItem(2070000, 800);
qm.gainItem(1142066, 1);
qm.changeJob(MapleJob.NIGHTWALKER1);
qm.getPlayer().resetStats();
diff --git a/scripts/quest/20105.js b/scripts/quest/20105.js
index 5de72b98f4..6580c083c4 100644
--- a/scripts/quest/20105.js
+++ b/scripts/quest/20105.js
@@ -27,6 +27,12 @@ function end(mode, type, selection) {
return;
}
+ 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);
diff --git a/scripts/quest/21101.js b/scripts/quest/21101.js
index 74815877db..e59c0bb9a6 100644
--- a/scripts/quest/21101.js
+++ b/scripts/quest/21101.js
@@ -39,7 +39,7 @@ function start(mode, type, selection) {
} else if (status == 1) {
if (qm.getPlayer().getJob().getId() == 2000) {
if(!qm.canHold(1142129)) {
- cm.sendOk("Wow, your #bequip#k inventory is full. You need to make at least 1 empty slot to complete this quest.");
+ qm.sendOk("Wow, your #bequip#k inventory is full. You need to make at least 1 empty slot to complete this quest.");
qm.dispose();
return;
}
diff --git a/scripts/quest/21201.js b/scripts/quest/21201.js
index da8713a1cd..4d8f0f8d06 100644
--- a/scripts/quest/21201.js
+++ b/scripts/quest/21201.js
@@ -59,7 +59,7 @@ function end(mode, type, selection) {
else if (status == 8) {
if(!qm.isQuestCompleted(21201)) {
if(!qm.canHold(1142130)) {
- cm.sendOk("Wow, your #bequip#k inventory is full. I need you to make at least 1 empty slot to complete this quest.");
+ qm.sendOk("Wow, your #bequip#k inventory is full. I need you to make at least 1 empty slot to complete this quest."); // thanks MedicOP for finding an issue here
qm.dispose();
return;
}
diff --git a/scripts/quest/21302.js b/scripts/quest/21302.js
index 0d3e60695c..35556f9587 100644
--- a/scripts/quest/21302.js
+++ b/scripts/quest/21302.js
@@ -39,7 +39,7 @@ function end(mode, type, selection) {
} else if (status == 2) {
if(!qm.isQuestCompleted(21302)) {
if(!qm.canHold(1142131)) {
- cm.sendOk("Wow, your #bequip#k inventory is full. I need you to make at least 1 empty slot to complete this quest.");
+ qm.sendOk("Wow, your #bequip#k inventory is full. I need you to make at least 1 empty slot to complete this quest.");
qm.dispose();
return;
}
diff --git a/sql/db_database.sql b/sql/db_database.sql
index fc3c325ec5..aae28570c9 100644
--- a/sql/db_database.sql
+++ b/sql/db_database.sql
@@ -12776,8 +12776,7 @@ INSERT IGNORE INTO `temp_data` (`id`, `dropperid`, `itemid`, `minimum_quantity`,
CREATE TABLE IF NOT EXISTS `drop_data_global` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
- `continent` int(11) NOT NULL,
- `dropType` tinyint(1) NOT NULL DEFAULT '0',
+ `continent` tinyint(1) NOT NULL DEFAULT '-1',
`itemid` int(11) NOT NULL DEFAULT '0',
`minimum_quantity` int(11) NOT NULL DEFAULT '1',
`maximum_quantity` int(11) NOT NULL DEFAULT '1',
@@ -12788,12 +12787,12 @@ CREATE TABLE IF NOT EXISTS `drop_data_global` (
KEY `mobid` (`continent`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC AUTO_INCREMENT=5 ;
-INSERT INTO `drop_data_global` (`id`, `continent`, `dropType`, `itemid`, `minimum_quantity`, `maximum_quantity`, `questid`, `chance`, `comments`) VALUES
-(1, 0, 0, 4031865, 1, 1, 0, 35000, 'NX Card 100 PTS'),
-(2, 0, 0, 4031866, 1, 1, 0, 20000, 'NX Card 250 PTS'),
-(3, 0, 0, 4001126, 1, 2, 0, 8000, 'Maple Leaves'),
-(4, 0, 0, 2049100, 1, 1, 0, 1200, 'Chaos Scroll 60%'),
-(5, 0, 0, 4001006, 1, 1, 0, 10000, 'Flaming Feather');
+INSERT INTO `drop_data_global` (`id`, `continent`, `itemid`, `minimum_quantity`, `maximum_quantity`, `questid`, `chance`, `comments`) VALUES
+(1, -1, 4031865, 1, 1, 0, 35000, 'NX Card 100 PTS'),
+(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');
CREATE TABLE IF NOT EXISTS `dueyitems` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
diff --git a/sql/db_drops.sql b/sql/db_drops.sql
index 6b906b2ba7..23e0864ebe 100644
--- a/sql/db_drops.sql
+++ b/sql/db_drops.sql
@@ -6719,8 +6719,8 @@ USE `heavenms`;
(4220000, 4010002, 1, 1, 0, 7000),
(4220001, 4010002, 1, 1, 0, 7000),
(9303014, 4010002, 1, 1, 0, 7000),
-(4220000, 1442018, 1, 1, 0, 40000),
-(4220001, 1442018, 1, 1, 0, 40000),
+(4220000, 1442018, 1, 1, 0, 25000),
+(4220001, 1442018, 1, 1, 0, 25000),
(9303014, 1442018, 1, 1, 0, 700),
(4220000, 1302010, 1, 1, 0, 40000),
(4220001, 1302010, 1, 1, 0, 40000),
diff --git a/src/client/MapleCharacter.java b/src/client/MapleCharacter.java
index d32325605e..1c077d6024 100644
--- a/src/client/MapleCharacter.java
+++ b/src/client/MapleCharacter.java
@@ -273,7 +273,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
private ScheduledFuture> pendantOfSpirit = null; //1122017
private Lock chrLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_CHR, true);
private Lock evtLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_EVT, true);
- private Lock petLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_PET, true); // for meso & quest tasks as well
+ private Lock petLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_PET, true);
private Lock prtLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_PRT);
private Lock cpnLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_CPN);
private Map> excluded = new LinkedHashMap<>();
@@ -852,17 +852,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
List> ldsstat = Collections.singletonList(new Pair(MapleBuffStat.DARKSIGHT, 0));
getMap().broadcastGMMessage(this, MaplePacketCreator.giveForeignBuff(id, ldsstat), false);
- for (MapleMonster mon : this.getControlledMonsters()) {
- mon.lockMonster();
- try {
- mon.setController(null);
- mon.setControllerHasAggro(false);
- mon.setControllerKnowsAboutAggro(false);
- mon.getMap().updateMonsterController(mon);
- } finally {
- mon.unlockMonster();
- }
- }
+ this.releaseControlledMonsters();
}
announce(MaplePacketCreator.enableActions());
}
@@ -1356,7 +1346,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
- mapEim.registerPlayer(this);
+ // thanks Thora for finding an issue with players not being actually warped into the target event map (rather sent to the event starting map)
+ mapEim.registerPlayer(this, false);
}
MapleMap to = target; // warps directly to the target intead of the target's map id, this allows GMs to patrol players inside instances.
@@ -1708,29 +1699,48 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
- public void checkMonsterAggro(MapleMonster monster) {
- monster.lockMonster();
- try {
- if (!monster.isControllerHasAggro()) {
- if (monster.getController() == this) {
- monster.setControllerHasAggro(true);
- } else {
- monster.switchController(this, true);
- }
+ public void controlMonster(MapleMonster monster) {
+ if (cpnLock.tryLock()) {
+ try {
+ controlled.add(monster);
+ } finally {
+ cpnLock.unlock();
}
- } finally {
- monster.unlockMonster();
}
}
-
- public void controlMonster(MapleMonster monster, boolean aggro) {
- monster.lockMonster();
+
+ public void stopControllingMonster(MapleMonster monster) {
+ if (cpnLock.tryLock()) {
+ try {
+ controlled.remove(monster);
+ } finally {
+ cpnLock.unlock();
+ }
+ }
+ }
+
+ public int getNumControlledMonsters() {
+ cpnLock.lock();
try {
- monster.setController(this);
- controlled.add(monster);
- client.announce(MaplePacketCreator.controlMonster(monster, false, aggro));
+ return controlled.size();
} finally {
- monster.unlockMonster();
+ cpnLock.unlock();
+ }
+ }
+
+ public void releaseControlledMonsters() {
+ Collection controlledMonsters;
+
+ cpnLock.lock();
+ try {
+ controlledMonsters = new ArrayList<>(controlled);
+ controlled.clear();
+ } finally {
+ cpnLock.unlock();
+ }
+
+ for (MapleMonster monster : controlledMonsters) {
+ monster.aggroRedirectController();
}
}
@@ -2967,6 +2977,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
+ public boolean canHoldMeso(int gain) { // thanks lucasziron found pointing out a need to check space availability for mesos on player transactions
+ long nextMeso = (long) meso.get() + gain;
+ return nextMeso <= Integer.MAX_VALUE;
+ }
+
public void gainMeso(int gain) {
gainMeso(gain, true, false, true);
}
@@ -4124,11 +4139,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
return Collections.unmodifiableList(ret);
}
}
-
- public Collection getControlledMonsters() {
- return Collections.unmodifiableCollection(controlled);
- }
-
+
public List getCrushRings() {
Collections.sort(crushRings);
return crushRings;
@@ -4343,7 +4354,15 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
return gachaexp.get();
}
+ public boolean hasNoviceExpRate() {
+ return ServerConstants.USE_ENFORCE_NOVICE_EXPRATE && isBeginnerJob() && level < 11;
+ }
+
public int getExpRate() {
+ if (hasNoviceExpRate()) { // base exp rate 1x for early levels idea thanks to Vcoc
+ return 1;
+ }
+
return expRate;
}
@@ -4383,7 +4402,17 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
public int getRawMesoRate() {
return mesoRate / (mesoCoupon * getWorldServer().getMesoRate());
}
-
+
+ public int getQuestExpRate() {
+ World w = getWorldServer();
+ return w.getExpRate() * w.getQuestRate();
+ }
+
+ public int getQuestMesoRate() {
+ World w = getWorldServer();
+ return w.getMesoRate() * w.getQuestRate();
+ }
+
public int getFace() {
return face;
}
@@ -4829,10 +4858,6 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
- public int getNumControlledMonsters() {
- return controlled.size();
- }
-
public MapleParty getParty() {
prtLock.lock();
try {
@@ -5635,9 +5660,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
public boolean isGuildLeader() { // true on guild master or jr. master
return guildid > 0 && guildRank < 3;
}
-
+
public void leaveMap() {
- controlled.clear();
+ releaseControlledMonsters();
visibleMapObjects.clear();
setChair(0);
if (hpDecreaseTask != null) {
@@ -7772,17 +7797,22 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
throw new RuntimeException("Character not in database (" + id + ")");
}
+ List petList = new LinkedList<>();
petLock.lock();
try {
for (int i = 0; i < 3; i++) {
if (pets[i] != null) {
- pets[i].saveToDb();
+ petList.add(pets[i]);
}
}
} finally {
petLock.unlock();
}
+ for (MaplePet pet : petList) {
+ pet.saveToDb();
+ }
+
for(Entry> es: getExcluded().entrySet()) { // this set is already protected
try (PreparedStatement ps2 = con.prepareStatement("DELETE FROM petignores WHERE petid=?")) {
ps2.setInt(1, es.getKey());
@@ -8912,11 +8942,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}, duration);
}
-
- public void stopControllingMonster(MapleMonster monster) {
- controlled.remove(monster);
- }
-
+
public void unequipAllPets() {
for (int i = 0; i < 3; i++) {
MaplePet pet = getPet(i);
@@ -9046,19 +9072,19 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public void cancelQuestExpirationTask() {
- petLock.lock();
+ evtLock.lock();
try {
if (questExpireTask != null) {
questExpireTask.cancel(false);
questExpireTask = null;
}
} finally {
- petLock.unlock();
+ evtLock.unlock();
}
}
public void forfeitExpirableQuests() {
- petLock.lock();
+ evtLock.lock();
try {
for(MapleQuest quest : questExpirations.keySet()) {
quest.forfeit(this);
@@ -9066,12 +9092,12 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
questExpirations.clear();
} finally {
- petLock.unlock();
+ evtLock.unlock();
}
}
public void questExpirationTask() {
- petLock.lock();
+ evtLock.lock();
try {
if(!questExpirations.isEmpty()) {
if(questExpireTask == null) {
@@ -9084,12 +9110,12 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
} finally {
- petLock.unlock();
+ evtLock.unlock();
}
}
private void runQuestExpireTask() {
- petLock.lock();
+ evtLock.lock();
try {
long timeNow = Server.getInstance().getCurrentTime();
List expireList = new LinkedList<>();
@@ -9110,12 +9136,12 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
} finally {
- petLock.unlock();
+ evtLock.unlock();
}
}
private void registerQuestExpire(MapleQuest quest, long time) {
- petLock.lock();
+ evtLock.lock();
try {
if(questExpireTask == null) {
questExpireTask = TimerManager.getInstance().register(new Runnable() {
@@ -9128,7 +9154,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
questExpirations.put(quest, Server.getInstance().getCurrentTime() + time);
} finally {
- petLock.unlock();
+ evtLock.unlock();
}
}
@@ -9671,7 +9697,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
if (pendantOfSpirit != null) { pendantOfSpirit.cancel(true); }
pendantOfSpirit = null;
- petLock.lock();
+ evtLock.lock();
try {
if (questExpireTask != null) {
questExpireTask.cancel(false);
@@ -9681,7 +9707,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
questExpirations = null;
}
} finally {
- petLock.unlock();
+ evtLock.unlock();
}
if (maplemount != null) {
diff --git a/src/client/MapleClient.java b/src/client/MapleClient.java
index 50f77e86aa..4e5acbe135 100644
--- a/src/client/MapleClient.java
+++ b/src/client/MapleClient.java
@@ -175,22 +175,22 @@ public class MapleClient {
return chars;
}
- public List loadCharacterNames(int serverId) {
+ public List loadCharacterNames(int worldId) {
List chars = new ArrayList<>(15);
- for (CharNameAndId cni : loadCharactersInternal(serverId)) {
+ for (CharNameAndId cni : loadCharactersInternal(worldId)) {
chars.add(cni.name);
}
return chars;
}
- private List loadCharactersInternal(int serverId) {
+ private List loadCharactersInternal(int worldId) {
PreparedStatement ps;
List chars = new ArrayList<>(15);
try {
Connection con = DatabaseConnection.getConnection();
ps = con.prepareStatement("SELECT id, name FROM characters WHERE accountid = ? AND world = ?");
ps.setInt(1, this.getAccID());
- ps.setInt(2, serverId);
+ ps.setInt(2, worldId);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
chars.add(new CharNameAndId(rs.getString("name"), rs.getInt("id")));
@@ -882,7 +882,7 @@ public class MapleClient {
}
public final void disconnect(final boolean shutdown, final boolean cashshop) {
- if (isDisconnecting()) {
+ if (canDisconnect()) {
ThreadManager.getInstance().newTask(new Runnable() {
@Override
public void run() {
@@ -893,12 +893,12 @@ public class MapleClient {
}
public final void forceDisconnect() {
- if (isDisconnecting()) {
+ if (canDisconnect()) {
disconnectInternal(true, false);
}
}
- private synchronized boolean isDisconnecting() {
+ private synchronized boolean canDisconnect() {
if (disconnecting) {
return false;
}
diff --git a/src/client/command/commands/gm0/RatesCommand.java b/src/client/command/commands/gm0/RatesCommand.java
index 4ae23dc779..378923e632 100644
--- a/src/client/command/commands/gm0/RatesCommand.java
+++ b/src/client/command/commands/gm0/RatesCommand.java
@@ -39,7 +39,7 @@ public class RatesCommand extends Command {
// travel rates not applicable since it's intrinsically a server/environment rate rather than a character rate
String showMsg_ = "#eCHARACTER RATES#n" + "\r\n\r\n";
- showMsg_ += "EXP Rate: #e#b" + player.getExpRate() + "x#k#n" + "\r\n";
+ showMsg_ += "EXP Rate: #e#b" + player.getExpRate() + "x#k#n" + (player.hasNoviceExpRate() ? " - novice rate" : "") + "\r\n";
showMsg_ += "MESO Rate: #e#b" + player.getMesoRate() + "x#k#n" + "\r\n";
showMsg_ += "DROP Rate: #e#b" + player.getDropRate() + "x#k#n" + "\r\n";
showMsg_ += "BOSS DROP Rate: #e#b" + player.getBossDropRate() + "x#k#n" + "\r\n";
diff --git a/src/client/command/commands/gm0/ShowRatesCommand.java b/src/client/command/commands/gm0/ShowRatesCommand.java
index e1bf006477..0db9088efd 100644
--- a/src/client/command/commands/gm0/ShowRatesCommand.java
+++ b/src/client/command/commands/gm0/ShowRatesCommand.java
@@ -40,7 +40,7 @@ public class ShowRatesCommand extends Command {
showMsg += "World EXP Rate: #k" + c.getWorldServer().getExpRate() + "x#k" + "\r\n";
showMsg += "Player EXP Rate: #k" + player.getRawExpRate() + "x#k" + "\r\n";
if(player.getCouponExpRate() != 1) showMsg += "Coupon EXP Rate: #k" + player.getCouponExpRate() + "x#k" + "\r\n";
- showMsg += "EXP Rate: #e#b" + player.getExpRate() + "x#k#n" + "\r\n";
+ showMsg += "EXP Rate: #e#b" + player.getExpRate() + "x#k#n" + (player.hasNoviceExpRate() ? " - novice rate" : "") + "\r\n";
showMsg += "\r\n" + "#eMESO RATE#n" + "\r\n";
showMsg += "World MESO Rate: #k" + c.getWorldServer().getMesoRate() + "x#k" + "\r\n";
@@ -66,7 +66,7 @@ public class ShowRatesCommand extends Command {
}
showMsg += "\r\n";
- showMsg += "World TRAVEL Rate: #e#b" + c.getWorldServer().getTravelRate() + "x#k#n" + "\r\nServer\r\nPlayer";
+ showMsg += "World TRAVEL Rate: #e#b" + c.getWorldServer().getTravelRate() + "x#k#n" + "\r\n";
player.showHint(showMsg, 300);
}
diff --git a/src/client/command/commands/gm1/GotoCommand.java b/src/client/command/commands/gm1/GotoCommand.java
index f39df86498..3e1a816449 100644
--- a/src/client/command/commands/gm1/GotoCommand.java
+++ b/src/client/command/commands/gm1/GotoCommand.java
@@ -41,8 +41,6 @@ public class GotoCommand extends Command {
@Override
public void execute(MapleClient c, String[] params) {
- final HashMap gotomaps = GameConstants.GOTO_MAPS;
-
MapleCharacter player = c.getPlayer();
if (params.length < 1){
player.yellowMessage("Syntax: @goto