diff --git a/docs/issues.txt b/docs/issues.txt
index 86ca538bf4..abb0fd94ed 100644
--- a/docs/issues.txt
+++ b/docs/issues.txt
@@ -20,6 +20,7 @@ Missing features list:
- Change name/World transfer.
- Some pirate skills doesn't work for 3rd parties.
- Medal quests.
+- Cache frequently used SQL data.
---------------------------
diff --git a/docs/mychanges_ptbr.txt b/docs/mychanges_ptbr.txt
index 9200ba06ea..2b9d973b38 100644
--- a/docs/mychanges_ptbr.txt
+++ b/docs/mychanges_ptbr.txt
@@ -1039,4 +1039,14 @@ Corrigido battleship não dando buffs na defesa corretamente.
11 - 12 Junho 2018,
Adicionado efeito do usável Happy Birthday pra todos no mapa.
Implementado HolidayPQ.
-Adicionado sistema de sandbox para itens.
\ No newline at end of file
+Adicionado sistema de sandbox para itens.
+
+13 - 14 Junho 2018,
+Adicionado novo server flag para permitir criar expedições solo.
+Adicionado novo server flag para cooldown reduzido no Hero's Will.
+Adicionado recipes para forjar Mob Crystal lv120 e 130 pelo Maker, usando Maple Leaf e versão de cristal anterior.
+Corrigido Heaven's Hammer e Combo Tempest não mostrando dano aos jogadores.
+Corrigido exploit onde jogadores poderiam criar minirooms em certos casos onde os mesmos não poderiam fazê-lo.
+Quest itens dropados de mobs que não visíveis pelo jogador atacante agora são mostrados mais nas pontas, de forma que o conjunto de drops agora aparente não ter espaço com itens invisíveis no meio.
+Corrigido Horntail não atruibuindo quest progress corretamente para a quest The Last Hour of Horntail.
+Removido skill books agora desnecessários do drop data, uma vez que já foi implementado as quests para conseguir elas.
\ No newline at end of file
diff --git a/scripts/event/Aran_3rdmount.js b/scripts/event/Aran_3rdmount.js
index fce9b80a16..b85b44aef9 100644
--- a/scripts/event/Aran_3rdmount.js
+++ b/scripts/event/Aran_3rdmount.js
@@ -92,7 +92,11 @@ function clearPQ(eim) {
em.setProperty("noEntry","false");
}
-function monsterKilled(mob, eim) {}
+function monsterKilled(mob, eim) {
+ if(eim.getInstanceMap(entryMap).countMonsters() == 0) {
+ eim.showClearEffect();
+ }
+}
function monsterValue(eim, mobId) {
return 1;
diff --git a/scripts/event/HorntailBattle.js b/scripts/event/HorntailBattle.js
index 8805e159b6..732015e7bb 100644
--- a/scripts/event/HorntailBattle.js
+++ b/scripts/event/HorntailBattle.js
@@ -214,6 +214,7 @@ function monsterKilled(mob, eim) {
eim.showClearEffect(mob.getMap().getId());
eim.clearPQ();
+ eim.dispatchUpdateQuestMobCount(8810018, 240060200);
mob.getMap().broadcastHorntailVictory();
} else if(isHorntailHead(mob)) {
var killed = eim.getIntProperty("defeatedHead");
diff --git a/scripts/npc/2020008.js b/scripts/npc/2020008.js
index 41d3e34039..41f43aa71e 100644
--- a/scripts/npc/2020008.js
+++ b/scripts/npc/2020008.js
@@ -54,7 +54,15 @@ function start() {
return;
}
- if (!(cm.getPlayer().getLevel() >= 70 && parseInt(cm.getJobId() / 100) == 1)){
+ var jobBase = parseInt(cm.getJobId() / 100);
+ var jobStyle = 1;
+ if (!(cm.getPlayer().getLevel() >= 70 && jobBase == jobStyle)){
+ if(cm.getPlayer().getLevel() >= 70 && jobBase % 10 == jobStyle) {
+ status++;
+ action(1, 0, 1);
+ return;
+ }
+
cm.sendNext("Hi there.");
cm.dispose();
return;
@@ -134,6 +142,7 @@ function action(mode, type, selection){
if (cm.getPlayer().getLevel() >= 50){
cm.sendNext("Ok, go.");
if(!cm.isQuestStarted(100200)) cm.startQuest(100200);
+ if(Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
}else
cm.sendNext("You're weak.");
cm.dispose();
diff --git a/scripts/npc/2020009.js b/scripts/npc/2020009.js
index a7855aba82..a118b1a7b9 100644
--- a/scripts/npc/2020009.js
+++ b/scripts/npc/2020009.js
@@ -26,11 +26,19 @@ var sel;
actionx = {"Mental" : false, "Physical" : false};
function start() {
- if (!(cm.getPlayer().getLevel() >= 70 && parseInt(cm.getJobId() / 100) == 2)){
- cm.sendNext("Hi there.");
- cm.dispose();
- return;
- }
+ var jobBase = parseInt(cm.getJobId() / 100);
+ var jobStyle = 2;
+ if (!(cm.getPlayer().getLevel() >= 70 && jobBase == jobStyle)){
+ if(cm.getPlayer().getLevel() >= 70 && jobBase % 10 == jobStyle) {
+ status++;
+ action(1, 0, 1);
+ return;
+ }
+
+ cm.sendNext("Hi there.");
+ cm.dispose();
+ return;
+ }
if (cm.haveItem(4031058))
actionx["Mental"] = true;
else if (cm.haveItem(4031057))
@@ -106,6 +114,7 @@ function action(mode, type, selection){
if (cm.getPlayer().getLevel() >= 50){
cm.sendNext("Ok, go.");
if(!cm.isQuestStarted(100200)) cm.startQuest(100200);
+ if(Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
}else
cm.sendNext("You're weak.");
cm.dispose();
diff --git a/scripts/npc/2020010.js b/scripts/npc/2020010.js
index 5481ba5a1d..ad882702c6 100644
--- a/scripts/npc/2020010.js
+++ b/scripts/npc/2020010.js
@@ -28,11 +28,19 @@ var sel;
actionx = {"Mental" : false, "Physical" : false};
function start() {
- if (!(cm.getPlayer().getLevel() >= 70 && parseInt(cm.getJobId() / 100) == 3)){
- cm.sendNext("Hi there.");
- cm.dispose();
- return;
- }
+ var jobBase = parseInt(cm.getJobId() / 100);
+ var jobStyle = 3;
+ if (!(cm.getPlayer().getLevel() >= 70 && jobBase == jobStyle)){
+ if(cm.getPlayer().getLevel() >= 70 && jobBase % 10 == jobStyle) {
+ status++;
+ action(1, 0, 1);
+ return;
+ }
+
+ cm.sendNext("Hi there.");
+ cm.dispose();
+ return;
+ }
if (cm.haveItem(4031058))
actionx["Mental"] = true;
else if (cm.haveItem(4031057))
@@ -107,6 +115,7 @@ function action(mode, type, selection){
if (cm.getPlayer().getLevel() >= 50){
cm.sendNext("Ok, go.");
if(!cm.isQuestStarted(100200)) cm.startQuest(100200);
+ if(Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
}else
cm.sendNext("You're weak.");
cm.dispose();
diff --git a/scripts/npc/2020011.js b/scripts/npc/2020011.js
index 0787818cab..44d0e62032 100644
--- a/scripts/npc/2020011.js
+++ b/scripts/npc/2020011.js
@@ -26,7 +26,15 @@ var sel;
actionx = {"Mental" : false, "Physical" : false};
function start() {
- if (!(cm.getPlayer().getLevel() >= 70 && parseInt(cm.getJobId() / 100) == 4)){
+ var jobBase = parseInt(cm.getJobId() / 100);
+ var jobStyle = 4;
+ if (!(cm.getPlayer().getLevel() >= 70 && jobBase == jobStyle)){
+ if(cm.getPlayer().getLevel() >= 70 && jobBase % 10 == jobStyle) {
+ status++;
+ action(1, 0, 1);
+ return;
+ }
+
cm.sendNext("Hi there.");
cm.dispose();
return;
@@ -106,6 +114,7 @@ function action(mode, type, selection){
if (cm.getPlayer().getLevel() >= 50){
cm.sendNext("Ok, go.");
if(!cm.isQuestStarted(100200)) cm.startQuest(100200);
+ if(Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
}else
cm.sendNext("You're weak.");
cm.dispose();
diff --git a/scripts/npc/2020013.js b/scripts/npc/2020013.js
index ee61e8e256..7658c22e94 100644
--- a/scripts/npc/2020013.js
+++ b/scripts/npc/2020013.js
@@ -26,7 +26,15 @@ var sel;
actionx = {"Mental" : false, "Physical" : false};
function start() {
- if (!(cm.getPlayer().getLevel() >= 70 && parseInt(cm.getJobId() / 100) == 5)){
+ var jobBase = parseInt(cm.getJobId() / 100);
+ var jobStyle = 5;
+ if (!(cm.getPlayer().getLevel() >= 70 && jobBase == jobStyle)){
+ if(cm.getPlayer().getLevel() >= 70 && jobBase % 10 == jobStyle) {
+ status++;
+ action(1, 0, 1);
+ return;
+ }
+
cm.sendNext("Hi there.");
cm.dispose();
return;
@@ -105,6 +113,7 @@ function action(mode, type, selection){
if (cm.getPlayer().getLevel() >= 50){
cm.sendNext("Ok, go.");
if(!cm.isQuestStarted(100200)) cm.startQuest(100200);
+ if(Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
}else
cm.sendNext("You're weak.");
cm.dispose();
diff --git a/scripts/npc/2042001.js b/scripts/npc/2042001.js
new file mode 100644
index 0000000000..7488954c21
--- /dev/null
+++ b/scripts/npc/2042001.js
@@ -0,0 +1,226 @@
+/*
+ This file is part of the HeavenMS MapleStory Server
+ Copyleft (L) 2016 - 2018 RonanLana
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation version 3 as published by
+ the Free Software Foundation. You may not use, modify or distribute
+ this program under any other version of the GNU Affero General Public
+ License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+/* Spiegelmann
+ Refining NPC:
+ * Auto ore refiner
+ *
+ * @author RonanLana
+*/
+
+var status;
+var refineRocks = true; // enables moon rock, star rock
+var refineCrystals = true; // enables common crystals
+var refineSpecials = true; // enables lithium, special crystals
+var feeMultiplier = 7.0;
+
+function start() {
+ status = -1;
+ action(1, 0, 0);
+}
+
+function action(mode, type, selection) {
+ if (mode == -1) {
+ cm.dispose();
+ } else {
+ if (mode == 0 && type > 0) {
+ cm.dispose();
+ return;
+ }
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if(status == 0) {
+ var selStr = "The Monster Carnival is currently unavailable, but instead I offer a steadfast #bore refining#k service for you, taxing #r" + ((feeMultiplier * 100) | 0) + "%#k over the usual fee to synthetize them. What will you do?#b";
+
+ var options = new Array("Refine mineral ores","Refine jewel ores");
+ if(refineCrystals) {
+ options.push("Refine crystal ores");
+ }
+ if(refineRocks) {
+ options.push("Refine plates/jewels");
+ }
+
+ for (var i = 0; i < options.length; i++){
+ selStr += "\r\n#L" + i + "# " + options[i] + "#l";
+ }
+
+ cm.sendSimple(selStr);
+ } else if(status == 1) {
+ var allDone;
+
+ if (selection == 0) {
+ allDone = refineItems(0); // minerals
+ } else if (selection == 1) {
+ allDone = refineItems(1); // jewels
+ } else if (selection == 2 && refineCrystals) {
+ allDone = refineItems(2); // crystals
+ } else if (selection == 2 && !refineCrystals || selection == 3) {
+ allDone = refineRockItems(); // moon/star rock
+ }
+
+ if(allDone) {
+ cm.sendOk("Done. Thanks for showing up~.");
+ } else {
+ cm.sendOk("Done. Be aware some of the items could not be synthetized because either you have a lack of space on your ETC inventory or there's not enough mesos to cover the fee.");
+ }
+ cm.dispose();
+ }
+ }
+}
+
+function getRefineFee(fee) {
+ return ((feeMultiplier * fee) | 0);
+}
+
+function isRefineTarget(refineType, refineItemid) {
+ if(refineType == 0) { //mineral refine
+ return refineItemid >= 4010000 && refineItemid <= 4010007 && !(refineItemid == 4010007 && !refineSpecials);
+ } else if(refineType == 1) { //jewel refine
+ return refineItemid >= 4020000 && refineItemid <= 4020008 && !(refineItemid == 4020008 && !refineSpecials);
+ } else if(refineType == 2) { //crystal refine
+ return refineItemid >= 4004000 && refineItemid <= 4004004 && !(refineItemid == 4004004 && !refineSpecials);
+ }
+
+ return false;
+}
+
+function getRockRefineTarget(refineItemid) {
+ if(refineItemid >= 4011000 && refineItemid <= 4011006) {
+ return 0;
+ } else if(refineItemid >= 4021000 && refineItemid <= 4021008) {
+ return 1;
+ }
+
+ return -1;
+}
+
+function refineItems(refineType) {
+ var allDone = true;
+
+ var refineFees = [[300,300,300,500,500,500,800,270],[500,500,500,500,500,500,500,1000,3000],[5000,5000,5000,5000,1000000]];
+ var itemCount = {};
+
+ var iter = cm.getPlayer().getInventory(Packages.client.inventory.MapleInventoryType.ETC).iterator();
+ while (iter.hasNext()) {
+ var it = iter.next();
+ var itemid = it.getItemId();
+
+ if(isRefineTarget(refineType, itemid)) {
+ var ic = itemCount[itemid];
+
+ if(ic != undefined) {
+ itemCount[itemid] += it.getQuantity();
+ } else {
+ itemCount[itemid] = it.getQuantity();
+ }
+ }
+ }
+
+ for(var key in itemCount) {
+ var itemqty = itemCount[key];
+ var itemid = parseInt(key);
+
+ var refineQty = ((itemqty / 10) | 0);
+ if(refineQty <= 0) continue;
+
+ while(true) {
+ itemqty = refineQty * 10;
+
+ var fee = getRefineFee(refineFees[refineType][(itemid % 100) | 0] * refineQty);
+ if(cm.canHold(itemid + 1000, refineQty) && cm.getMeso() >= fee) {
+ cm.gainMeso(-fee);
+ cm.gainItem(itemid, -itemqty);
+ cm.gainItem(itemid + (itemid != 4010007 ? 1000 : 1001), refineQty);
+
+ break;
+ } else if(refineQty <= 1) {
+ allDone = false;
+ break;
+ } else {
+ refineQty--;
+ }
+ }
+ }
+
+ return allDone;
+}
+
+function refineRockItems() {
+ var allDone = true;
+ var minItems = [[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0]];
+ var minRocks = [2147483647, 2147483647];
+
+ var rockItems = [4011007, 4021009];
+ var rockFees = [10000, 15000];
+
+ var iter = cm.getPlayer().getInventory(Packages.client.inventory.MapleInventoryType.ETC).iterator();
+ while (iter.hasNext()) {
+ var it = iter.next();
+ var itemid = it.getItemId();
+ var rockRefine = getRockRefineTarget(itemid);
+ if(rockRefine >= 0) {
+ var rockItem = ((itemid % 100) | 0);
+ var itemqty = it.getQuantity();
+
+ minItems[rockRefine][rockItem] += itemqty;
+ }
+ }
+
+ for(var i = 0; i < minRocks.length; i++) {
+ for(var j = 0; j < minItems[i].length; j++) {
+ if(minRocks[i] > minItems[i][j]) {
+ minRocks[i] = minItems[i][j];
+ }
+ }
+ if(minRocks[i] <= 0 || minRocks[i] == 2147483647) continue;
+
+ var refineQty = minRocks[i];
+ while(true) {
+ var fee = getRefineFee(rockFees[i] * refineQty);
+ if(cm.canHold(rockItems[i], refineQty) && cm.getMeso() >= fee) {
+ cm.gainMeso(-fee);
+
+ var j;
+ if(i == 0) {
+ for(j = 4011000; j < 4011007; j++) {
+ cm.gainItem(j, -refineQty);
+ }
+ cm.gainItem(j, refineQty);
+ } else {
+ for(j = 4021000; j < 4021009; j++) {
+ cm.gainItem(j, -refineQty);
+ }
+ cm.gainItem(j, refineQty);
+ }
+
+ break;
+ } else if(refineQty <= 1) {
+ allDone = false;
+ break;
+ } else {
+ refineQty--;
+ }
+ }
+ }
+
+ return allDone;
+}
diff --git a/scripts/npc/2042002.js b/scripts/npc/2042002.js
new file mode 100644
index 0000000000..7488954c21
--- /dev/null
+++ b/scripts/npc/2042002.js
@@ -0,0 +1,226 @@
+/*
+ This file is part of the HeavenMS MapleStory Server
+ Copyleft (L) 2016 - 2018 RonanLana
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation version 3 as published by
+ the Free Software Foundation. You may not use, modify or distribute
+ this program under any other version of the GNU Affero General Public
+ License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+/* Spiegelmann
+ Refining NPC:
+ * Auto ore refiner
+ *
+ * @author RonanLana
+*/
+
+var status;
+var refineRocks = true; // enables moon rock, star rock
+var refineCrystals = true; // enables common crystals
+var refineSpecials = true; // enables lithium, special crystals
+var feeMultiplier = 7.0;
+
+function start() {
+ status = -1;
+ action(1, 0, 0);
+}
+
+function action(mode, type, selection) {
+ if (mode == -1) {
+ cm.dispose();
+ } else {
+ if (mode == 0 && type > 0) {
+ cm.dispose();
+ return;
+ }
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if(status == 0) {
+ var selStr = "The Monster Carnival is currently unavailable, but instead I offer a steadfast #bore refining#k service for you, taxing #r" + ((feeMultiplier * 100) | 0) + "%#k over the usual fee to synthetize them. What will you do?#b";
+
+ var options = new Array("Refine mineral ores","Refine jewel ores");
+ if(refineCrystals) {
+ options.push("Refine crystal ores");
+ }
+ if(refineRocks) {
+ options.push("Refine plates/jewels");
+ }
+
+ for (var i = 0; i < options.length; i++){
+ selStr += "\r\n#L" + i + "# " + options[i] + "#l";
+ }
+
+ cm.sendSimple(selStr);
+ } else if(status == 1) {
+ var allDone;
+
+ if (selection == 0) {
+ allDone = refineItems(0); // minerals
+ } else if (selection == 1) {
+ allDone = refineItems(1); // jewels
+ } else if (selection == 2 && refineCrystals) {
+ allDone = refineItems(2); // crystals
+ } else if (selection == 2 && !refineCrystals || selection == 3) {
+ allDone = refineRockItems(); // moon/star rock
+ }
+
+ if(allDone) {
+ cm.sendOk("Done. Thanks for showing up~.");
+ } else {
+ cm.sendOk("Done. Be aware some of the items could not be synthetized because either you have a lack of space on your ETC inventory or there's not enough mesos to cover the fee.");
+ }
+ cm.dispose();
+ }
+ }
+}
+
+function getRefineFee(fee) {
+ return ((feeMultiplier * fee) | 0);
+}
+
+function isRefineTarget(refineType, refineItemid) {
+ if(refineType == 0) { //mineral refine
+ return refineItemid >= 4010000 && refineItemid <= 4010007 && !(refineItemid == 4010007 && !refineSpecials);
+ } else if(refineType == 1) { //jewel refine
+ return refineItemid >= 4020000 && refineItemid <= 4020008 && !(refineItemid == 4020008 && !refineSpecials);
+ } else if(refineType == 2) { //crystal refine
+ return refineItemid >= 4004000 && refineItemid <= 4004004 && !(refineItemid == 4004004 && !refineSpecials);
+ }
+
+ return false;
+}
+
+function getRockRefineTarget(refineItemid) {
+ if(refineItemid >= 4011000 && refineItemid <= 4011006) {
+ return 0;
+ } else if(refineItemid >= 4021000 && refineItemid <= 4021008) {
+ return 1;
+ }
+
+ return -1;
+}
+
+function refineItems(refineType) {
+ var allDone = true;
+
+ var refineFees = [[300,300,300,500,500,500,800,270],[500,500,500,500,500,500,500,1000,3000],[5000,5000,5000,5000,1000000]];
+ var itemCount = {};
+
+ var iter = cm.getPlayer().getInventory(Packages.client.inventory.MapleInventoryType.ETC).iterator();
+ while (iter.hasNext()) {
+ var it = iter.next();
+ var itemid = it.getItemId();
+
+ if(isRefineTarget(refineType, itemid)) {
+ var ic = itemCount[itemid];
+
+ if(ic != undefined) {
+ itemCount[itemid] += it.getQuantity();
+ } else {
+ itemCount[itemid] = it.getQuantity();
+ }
+ }
+ }
+
+ for(var key in itemCount) {
+ var itemqty = itemCount[key];
+ var itemid = parseInt(key);
+
+ var refineQty = ((itemqty / 10) | 0);
+ if(refineQty <= 0) continue;
+
+ while(true) {
+ itemqty = refineQty * 10;
+
+ var fee = getRefineFee(refineFees[refineType][(itemid % 100) | 0] * refineQty);
+ if(cm.canHold(itemid + 1000, refineQty) && cm.getMeso() >= fee) {
+ cm.gainMeso(-fee);
+ cm.gainItem(itemid, -itemqty);
+ cm.gainItem(itemid + (itemid != 4010007 ? 1000 : 1001), refineQty);
+
+ break;
+ } else if(refineQty <= 1) {
+ allDone = false;
+ break;
+ } else {
+ refineQty--;
+ }
+ }
+ }
+
+ return allDone;
+}
+
+function refineRockItems() {
+ var allDone = true;
+ var minItems = [[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0]];
+ var minRocks = [2147483647, 2147483647];
+
+ var rockItems = [4011007, 4021009];
+ var rockFees = [10000, 15000];
+
+ var iter = cm.getPlayer().getInventory(Packages.client.inventory.MapleInventoryType.ETC).iterator();
+ while (iter.hasNext()) {
+ var it = iter.next();
+ var itemid = it.getItemId();
+ var rockRefine = getRockRefineTarget(itemid);
+ if(rockRefine >= 0) {
+ var rockItem = ((itemid % 100) | 0);
+ var itemqty = it.getQuantity();
+
+ minItems[rockRefine][rockItem] += itemqty;
+ }
+ }
+
+ for(var i = 0; i < minRocks.length; i++) {
+ for(var j = 0; j < minItems[i].length; j++) {
+ if(minRocks[i] > minItems[i][j]) {
+ minRocks[i] = minItems[i][j];
+ }
+ }
+ if(minRocks[i] <= 0 || minRocks[i] == 2147483647) continue;
+
+ var refineQty = minRocks[i];
+ while(true) {
+ var fee = getRefineFee(rockFees[i] * refineQty);
+ if(cm.canHold(rockItems[i], refineQty) && cm.getMeso() >= fee) {
+ cm.gainMeso(-fee);
+
+ var j;
+ if(i == 0) {
+ for(j = 4011000; j < 4011007; j++) {
+ cm.gainItem(j, -refineQty);
+ }
+ cm.gainItem(j, refineQty);
+ } else {
+ for(j = 4021000; j < 4021009; j++) {
+ cm.gainItem(j, -refineQty);
+ }
+ cm.gainItem(j, refineQty);
+ }
+
+ break;
+ } else if(refineQty <= 1) {
+ allDone = false;
+ break;
+ } else {
+ refineQty--;
+ }
+ }
+ }
+
+ return allDone;
+}
diff --git a/scripts/npc/2083000.js b/scripts/npc/2083000.js
index 20e50edf9c..f59c817e1e 100644
--- a/scripts/npc/2083000.js
+++ b/scripts/npc/2083000.js
@@ -24,10 +24,6 @@
*/
var status = 0;
-var minLevel = 80;
-var maxLevel = 255;
-var minPlayers = 1;
-var maxPlayers = 6;
function start() {
status = -1;
@@ -49,6 +45,13 @@ function action(mode, type, selection) {
if (status == 0) {
if(cm.haveItem(4001086)) {
cm.sendYesNo("Do you want to access #b#m240050400##k right now?");
+ } else if(Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS) {
+ if(canBypassHTPQ()) {
+ cm.sendYesNo("Do you want to access #b#m240050400##k right now?");
+ } else {
+ cm.sendOk("Those who don't have the #r#t4001086##k must prove their valor before challenging #bHorntail#k. Come here holding the #r3 certificates#k that proves you're worthy to || the task."); // NPC picture is so long it goes through some section of text, || to fill up that space
+ cm.dispose();
+ }
} else {
cm.sendOk("Those who don't have the #r#t4001086##k must prove their valor before challenging #bHorntail#k.");
cm.dispose();
@@ -60,5 +63,7 @@ function action(mode, type, selection) {
}
}
}
-
-
+
+function canBypassHTPQ() {
+ return cm.haveItem(4001083) && cm.haveItem(4001084) && cm.haveItem(4001085);
+}
\ No newline at end of file
diff --git a/scripts/npc/9000037.js b/scripts/npc/9000037.js
index 8822be13df..e3c805a0d9 100644
--- a/scripts/npc/9000037.js
+++ b/scripts/npc/9000037.js
@@ -136,7 +136,7 @@ function action(mode, type, selection) {
cm.dispose();
} else if(state == 2) {
var restSpot = ((cm.getMapId() - 1) % 5) + 1;
- cm.getPlayer().getEventInstance().addEventTimer(restSpot * 4 * 60000); // adds (restspot number * 4) minutes
+ cm.getPlayer().getEventInstance().restartEventTimer(restSpot * 4 * 60000); // adds (restspot number * 4) minutes
cm.getPlayer().getEventInstance().warpEventTeam(970030100 + cm.getEventInstance().getIntProperty("lobby") + (500 * restSpot));
cm.dispose();
diff --git a/scripts/quest/3514.js b/scripts/quest/3514.js
index 98ed1d529c..3da41bc370 100644
--- a/scripts/quest/3514.js
+++ b/scripts/quest/3514.js
@@ -25,6 +25,8 @@
importPackage(Packages.client);
+var status = -1;
+
function start(mode, type, selection) {
if(qm.getPlayer().getMeso() >= 1000000) {
if(qm.canHold(2022337, 1)) {
@@ -48,21 +50,36 @@ function usedPotion(ch) {
}
function end(mode, type, selection) {
- if(!usedPotion(qm.getPlayer())) {
- if(qm.haveItem(2022337)) {
- qm.sendOk("Are you scared to drink the potion? I can assure you it has only a minor #rside effect#k.");
- } else {
- if(qm.canHold(2022337)) {
- qm.gainItem(2022337, 1);
- qm.sendOk("Lost it? Luckily for you I managed to recover it back. Take it.");
- } else {
- qm.sendOk("Lost it? Luckily for you I managed to recover it back. Make a room to get it.");
- }
- }
+ if (mode == 0 && type == 0) {
+ status--;
+ } else if (mode == -1) {
+ qm.dispose();
+ return;
} else {
- qm.sendOk("It seems the potion worked and your emotions are no longer frozen. And, oh, my... You're ailing bad, #bpurge#k that out quickly.");
- qm.gainExp(891500 * qm.getPlayer().getExpRate());
- qm.completeQuest(3514);
+ status++;
}
- qm.dispose();
+
+ if(status == 0) {
+ if(!usedPotion(qm.getPlayer())) {
+ if(qm.haveItem(2022337)) {
+ qm.sendOk("Are you scared to drink the potion? I can assure you it has only a minor #rside effect#k.");
+ } else {
+ if(qm.canHold(2022337)) {
+ qm.gainItem(2022337, 1);
+ qm.sendOk("Lost it? Luckily for you I managed to recover it back. Take it.");
+ } else {
+ qm.sendOk("Lost it? Luckily for you I managed to recover it back. Make a room to get it.");
+ }
+ }
+
+ qm.dispose();
+ return;
+ } else {
+ qm.sendOk("It seems the potion worked and your emotions are no longer frozen. And, oh, my... You're ailing bad, #bpurge#k that out quickly.");
+ }
+ } else if(status == 1) {
+ qm.gainExp(891500 * qm.getPlayer().getExpRate());
+ qm.completeQuest(3514);
+ qm.dispose();
+ }
}
\ No newline at end of file
diff --git a/sql/db_drops.sql b/sql/db_drops.sql
index 76915e3ac7..b8f54aa314 100644
--- a/sql/db_drops.sql
+++ b/sql/db_drops.sql
@@ -19546,19 +19546,6 @@ USE `heavenms`;
(9500319, 2020019, 5, 20, 0, 40000),
(9500319, 2020020, 5, 20, 0, 40000),
(9500319, 1052166, 1, 1, 0, 4000),
-(9500319, 2280000, 1, 1, 0, 4000),
-(9500319, 2280001, 1, 1, 0, 4000),
-(9500319, 2280002, 1, 1, 0, 4000),
-(9500319, 2280003, 1, 1, 0, 4000),
-(9500319, 2280004, 1, 1, 0, 4000),
-(9500319, 2280005, 1, 1, 0, 4000),
-(9500319, 2280006, 1, 1, 0, 4000),
-(9500319, 2280007, 1, 1, 0, 4000),
-(9500319, 2280008, 1, 1, 0, 4000),
-(9500319, 2280009, 1, 1, 0, 4000),
-(9500319, 2280010, 1, 1, 0, 4000),
-(9500319, 2280011, 1, 1, 0, 4000),
-(9500319, 2280012, 1, 1, 0, 4000),
(9500319, 2044712, 1, 1, 0, 4000),
(9500319, 2044612, 1, 1, 0, 4000),
(9500319, 2044512, 1, 1, 0, 4000),
@@ -20293,12 +20280,6 @@ USE `heavenms`;
# add more skill/mastery books
INSERT IGNORE INTO temp_data (`dropperid`, `itemid`, `minimum_quantity`, `maximum_quantity`, `questid`, `chance`) VALUES
-(9400014, 2280000, 1, 1, 0, 40000),
-(8150000, 2280001, 1, 1, 0, 40000),
-(9400121, 2280002, 1, 1, 0, 40000),
-(9300028, 2280003, 1, 1, 0, 100000),
-(8150100, 2280011, 1, 1, 0, 1000),
-(8220009, 2280012, 1, 1, 0, 40000),
(8150000, 2280013, 1, 1, 0, 40000),
(8200005, 2280014, 1, 1, 0, 1000),
(9300028, 2280015, 1, 1, 0, 100000),
@@ -20372,12 +20353,6 @@ USE `heavenms`;
(9400582, 2290135, 1, 1, 0, 1000),
(9400593, 2290138, 1, 1, 0, 40000),
(8200002, 2290139, 1, 1, 0, 1000),
-(8190004, 2280000, 1, 1, 0, 1000),
-(9400300, 2280001, 1, 1, 0, 100000),
-(8200012, 2280002, 1, 1, 0, 1000),
-(8140511, 2280003, 1, 1, 0, 1000),
-(8200005, 2280011, 1, 1, 0, 1000),
-(9420513, 2280012, 1, 1, 0, 40000),
(8190003, 2280013, 1, 1, 0, 1000),
(9400121, 2280014, 1, 1, 0, 40000),
(8200001, 2280015, 1, 1, 0, 1000),
diff --git a/src/client/MapleCharacter.java b/src/client/MapleCharacter.java
index fcce53ed94..d29aa46de1 100644
--- a/src/client/MapleCharacter.java
+++ b/src/client/MapleCharacter.java
@@ -198,7 +198,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
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, lastHealed, lastBuyback, lastDeathtime, lastMesoDrop = -1, jailExpiration = -1;
+ private long lastfametime, lastUsedCashItem, lastHealed, lastBuyback = 0, lastDeathtime, lastMesoDrop = -1, jailExpiration = -1;
private transient int localmaxhp, localmaxmp, localstr, localdex, localluk, localint_, magic, watk;
private boolean hidden, canDoor = true, berserk, hasMerchant, hasSandboxItem = false, whiteChat = false;
private int linkedLevel = 0;
@@ -1729,14 +1729,17 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
if (mesosamm > 50000 * this.getMesoRate()) {
return;
}
+
+ MapleMap thisMap = this.getMap();
int partynum = 0;
- for (MaplePartyCharacter partymem : this.party.getMembers()) {
- if (partymem.isOnline() && partymem.getMapId() == this.getMap().getId() && partymem.getChannel() == client.getChannel()) {
+ Collection mpcs = this.party.getMembers();
+ for (MaplePartyCharacter partymem : mpcs) {
+ if (partymem.getPlayer().isLoggedinWorld() && partymem.getMapId() == thisMap.getId() && partymem.getChannel() == client.getChannel()) {
partynum++;
}
}
- for (MaplePartyCharacter partymem : this.party.getMembers()) {
- if (partymem.isOnline() && partymem.getMapId() == this.getMap().getId()) {
+ for (MaplePartyCharacter partymem : mpcs) {
+ if (partymem.getPlayer().isLoggedinWorld() && partymem.getMapId() == thisMap.getId()) {
MapleCharacter somecharacter = client.getChannelServer().getPlayerStorage().getCharacterById(partymem.getId());
if (somecharacter != null) {
somecharacter.gainMeso(mesosamm / partynum, true, true, false);
@@ -5213,6 +5216,10 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
}
+ private long getNextBuybackTime() {
+ return lastBuyback + ServerConstants.BUYBACK_COOLDOWN_MINUTES * 60 * 1000;
+ }
+
public boolean couldBuyback() { // Ronan's buyback system
long timeNow = System.currentTimeMillis();
@@ -5221,7 +5228,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
return false;
}
- long nextBuybacktime = lastBuyback + ServerConstants.BUYBACK_COOLDOWN_MINUTES * 60 * 1000;
+ long nextBuybacktime = getNextBuybackTime();
if(timeNow < nextBuybacktime) {
long timeLeft = nextBuybacktime - timeNow;
int seconds = (int) Math.floor(timeLeft / 1000) % 60;
@@ -5840,14 +5847,15 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
ret.mgc = new MapleGuildCharacter(ret);
int buddyCapacity = rs.getInt("buddyCapacity");
ret.buddylist = new BuddyList(buddyCapacity);
+
ret.getInventory(MapleInventoryType.EQUIP).setSlotLimit(rs.getByte("equipslots"));
ret.getInventory(MapleInventoryType.USE).setSlotLimit(rs.getByte("useslots"));
ret.getInventory(MapleInventoryType.SETUP).setSlotLimit(rs.getByte("setupslots"));
ret.getInventory(MapleInventoryType.ETC).setSlotLimit(rs.getByte("etcslots"));
+
+ byte sandboxCheck = 0x0;
for (Pair- item : ItemFactory.INVENTORY.loadItems(ret.id, !channelserver)) {
- if(MapleInventoryManipulator.isSandboxItem(item.getLeft())) {
- ret.setHasSandboxItem();
- }
+ sandboxCheck |= item.getLeft().getFlag();
ret.getInventory(item.getRight()).addFromDB(item.getLeft());
Item itemz = item.getLeft();
@@ -5872,6 +5880,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
}
}
+ if((sandboxCheck & ItemConstants.SANDBOX) == ItemConstants.SANDBOX) ret.setHasSandboxItem();
World wserv = Server.getInstance().getWorld(ret.world);
@@ -6072,10 +6081,11 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
ps = con.prepareStatement("SELECT SkillID,StartTime,length FROM cooldowns WHERE charid = ?");
ps.setInt(1, ret.getId());
rs = ps.executeQuery();
+ long curTime = System.currentTimeMillis();
while (rs.next()) {
final int skillid = rs.getInt("SkillID");
final long length = rs.getLong("length"), startTime = rs.getLong("StartTime");
- if (skillid != 5221999 && (length + startTime < System.currentTimeMillis())) {
+ if (skillid != 5221999 && (length + startTime < curTime)) {
continue;
}
ret.giveCoolDowns(skillid, startTime, length);
diff --git a/src/constants/ServerConstants.java b/src/constants/ServerConstants.java
index 3e4704406a..435bb8894c 100644
--- a/src/constants/ServerConstants.java
+++ b/src/constants/ServerConstants.java
@@ -75,6 +75,7 @@ public class ServerConstants {
public static final boolean USE_MULTIPLE_SAME_EQUIP_DROP = true;//Enables multiple drops by mobs of the same equipment, number of possible drops based on the quantities provided at the drop data.
public static final boolean USE_BANISHABLE_TOWN_SCROLL = true; //Enables town scrolls to act as if it's a "player banish", rendering the antibanish scroll effect available.
public static final boolean USE_OLD_GMS_STYLED_PQ_NPCS = true; //Enables PQ NPCs with similar behaviour to old GMS style, that skips info about the PQs and immediately tries to register the party in.
+ public static final boolean USE_ENABLE_SOLO_EXPEDITIONS = true; //Enables start expeditions with any number of players. This will also bypass all the Zakum prequest.
//Announcement Configuration
public static final boolean USE_ANNOUNCE_SHOPITEMSOLD = false; //Automatic message sent to owner when an item from the Player Shop or Hired Merchant is sold.
@@ -137,6 +138,9 @@ public class ServerConstants {
public static final boolean USE_ULTRA_RECOVERY = true; //Massive recovery amounts overtime.
public static final boolean USE_ULTRA_THREE_SNAILS = true; //Massive damage on shell toss.
+ //Other Skills Configuration
+ public static final boolean USE_FAST_REUSE_HERO_WILL = true;//Greatly reduce cooldown on Hero's Will.
+
//Character Configuration
public static final boolean USE_ADD_SLOTS_BY_LEVEL = true; //Slots are added each 20 levels.
public static final boolean USE_ADD_RATES_BY_LEVEL = true; //Rates are added each 20 levels.
diff --git a/src/net/server/channel/handlers/AbstractDealDamageHandler.java b/src/net/server/channel/handlers/AbstractDealDamageHandler.java
index a331393ffc..99210b695e 100644
--- a/src/net/server/channel/handlers/AbstractDealDamageHandler.java
+++ b/src/net/server/channel/handlers/AbstractDealDamageHandler.java
@@ -487,17 +487,17 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
}
if (attack.skill == Paladin.HEAVENS_HAMMER) {
if(!monster.isBoss()) {
- map.damageMonster(player, monster, monster.getHp() - 1);
+ damageMonsterWithSkill(player, map, monster, monster.getHp() - 1, attack.skill, 1777);
} else {
int HHDmg = (player.calculateMaxBaseDamage(player.getTotalWatk()) * (SkillFactory.getSkill(Paladin.HEAVENS_HAMMER).getEffect(player.getSkillLevel(SkillFactory.getSkill(Paladin.HEAVENS_HAMMER))).getDamage() / 100));
- map.damageMonster(player, monster, (int) (Math.floor(Math.random() * (HHDmg / 5) + HHDmg * .8)));
+ damageMonsterWithSkill(player, map, monster, (int) (Math.floor(Math.random() * (HHDmg / 5) + HHDmg * .8)), attack.skill, 1777);
}
} else if (attack.skill == Aran.COMBO_TEMPEST) {
if(!monster.isBoss()) {
- map.damageMonster(player, monster, monster.getHp());
+ damageMonsterWithSkill(player, map, monster, monster.getHp(), attack.skill, 0);
} else {
int TmpDmg = (player.calculateMaxBaseDamage(player.getTotalWatk()) * (SkillFactory.getSkill(Aran.COMBO_TEMPEST).getEffect(player.getSkillLevel(SkillFactory.getSkill(Aran.COMBO_TEMPEST))).getDamage() / 100));
- map.damageMonster(player, monster, (int) (Math.floor(Math.random() * (TmpDmg / 5) + TmpDmg * .8)));
+ damageMonsterWithSkill(player, map, monster, (int) (Math.floor(Math.random() * (TmpDmg / 5) + TmpDmg * .8)), attack.skill, 0);
}
} else {
if(attack.skill == Aran.BODY_PRESSURE) {
@@ -534,6 +534,26 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
}
}
+ private static void damageMonsterWithSkill(final MapleCharacter attacker, final MapleMap map, final MapleMonster monster, final int damage, int skillid, int fixedTime) {
+ int animationTime;
+
+ if(fixedTime == 0) animationTime = SkillFactory.getSkill(skillid).getAnimationTime();
+ else animationTime = fixedTime;
+
+ if(animationTime > 0) { // be sure to only use LIMITED ATTACKS with animation time here
+ TimerManager.getInstance().schedule(new Runnable() {
+ @Override
+ public void run() {
+ map.broadcastMessage(MaplePacketCreator.damageMonster(monster.getObjectId(), damage), monster.getPosition());
+ map.damageMonster(attacker, monster, damage);
+ }
+ }, animationTime);
+ } else {
+ map.broadcastMessage(MaplePacketCreator.damageMonster(monster.getObjectId(), damage), monster.getPosition());
+ map.damageMonster(attacker, monster, damage);
+ }
+ }
+
protected AttackInfo parseDamage(LittleEndianAccessor lea, MapleCharacter chr, boolean ranged, boolean magic) {
//2C 00 00 01 91 A1 12 00 A5 57 62 FC E2 75 99 10 00 47 80 01 04 01 C6 CC 02 DD FF 5F 00
AttackInfo ret = new AttackInfo();
diff --git a/src/net/server/channel/handlers/PlayerInteractionHandler.java b/src/net/server/channel/handlers/PlayerInteractionHandler.java
index 6886a1649d..728292d783 100644
--- a/src/net/server/channel/handlers/PlayerInteractionHandler.java
+++ b/src/net/server/channel/handlers/PlayerInteractionHandler.java
@@ -117,6 +117,16 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
final MapleCharacter chr = c.getPlayer();
if (mode == Action.CREATE.getCode()) {
+ if(!chr.isAlive()) { // thanks GabrielSin for pointing this
+ chr.getClient().announce(MaplePacketCreator.getMiniRoomError(4));
+ return;
+ }
+
+ if(chr.getEventInstance() != null) {
+ chr.getClient().announce(MaplePacketCreator.getMiniRoomError(5));
+ return;
+ }
+
byte createType = slea.readByte();
if (createType == 3) {// trade
MapleTrade.startTrade(chr);
@@ -585,8 +595,9 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
} else if (mode == Action.BAN_PLAYER.getCode()) {
slea.skip(1);
- if (chr.getPlayerShop() != null && chr.getPlayerShop().isOwner(chr)) {
- chr.getPlayerShop().banPlayer(slea.readMapleAsciiString());
+ MaplePlayerShop shop = chr.getPlayerShop();
+ if (shop != null && shop.isOwner(chr)) {
+ shop.banPlayer(slea.readMapleAsciiString());
}
} else if (mode == Action.EXPEL.getCode()) {
MapleMiniGame miniGame = chr.getMiniGame();
diff --git a/src/net/server/channel/handlers/SpecialMoveHandler.java b/src/net/server/channel/handlers/SpecialMoveHandler.java
index df6be698bf..b9483ac934 100644
--- a/src/net/server/channel/handlers/SpecialMoveHandler.java
+++ b/src/net/server/channel/handlers/SpecialMoveHandler.java
@@ -36,6 +36,7 @@ import client.MapleStat;
import client.Skill;
import client.SkillFactory;
import constants.GameConstants;
+import constants.ServerConstants;
import constants.skills.Brawler;
import constants.skills.Corsair;
import constants.skills.DarkKnight;
@@ -82,8 +83,13 @@ public final class SpecialMoveHandler extends AbstractMaplePacketHandler {
if (chr.skillIsCooling(skillid)) {
return;
} else if (skillid != Corsair.BATTLE_SHIP) {
- c.announce(MaplePacketCreator.skillCooldown(skillid, effect.getCooldown()));
- chr.addCooldown(skillid, System.currentTimeMillis(), effect.getCooldown() * 1000);
+ int cooldownTime = effect.getCooldown();
+ if(MapleStatEffect.isHerosWill(skillid) && ServerConstants.USE_FAST_REUSE_HERO_WILL) {
+ cooldownTime /= 60;
+ }
+
+ c.announce(MaplePacketCreator.skillCooldown(skillid, cooldownTime));
+ chr.addCooldown(skillid, System.currentTimeMillis(), cooldownTime * 1000);
}
}
if (skillid == Hero.MONSTER_MAGNET || skillid == Paladin.MONSTER_MAGNET || skillid == DarkKnight.MONSTER_MAGNET) { // Monster Magnet
diff --git a/src/server/MapleStatEffect.java b/src/server/MapleStatEffect.java
index 93f222621a..7ca91b32ed 100644
--- a/src/server/MapleStatEffect.java
+++ b/src/server/MapleStatEffect.java
@@ -1444,27 +1444,32 @@ public class MapleStatEffect {
private boolean isCureAllAbnormalStatus() {
if (skill) {
- switch (sourceid) {
- case Hero.HEROS_WILL:
- case Paladin.HEROS_WILL:
- case DarkKnight.HEROS_WILL:
- case FPArchMage.HEROS_WILL:
- case ILArchMage.HEROS_WILL:
- case Bishop.HEROS_WILL:
- case Bowmaster.HEROS_WILL:
- case Marksman.HEROS_WILL:
- case NightLord.HEROS_WILL:
- case Shadower.HEROS_WILL:
- case Buccaneer.PIRATES_RAGE:
- case Aran.HEROS_WILL:
- return true;
- default:
- return false;
- }
+ return isHerosWill(sourceid);
} else if (sourceid == 2022544) return true;
return false;
}
+
+ public static boolean isHerosWill(int skillid) {
+ switch(skillid) {
+ case Hero.HEROS_WILL:
+ case Paladin.HEROS_WILL:
+ case DarkKnight.HEROS_WILL:
+ case FPArchMage.HEROS_WILL:
+ case ILArchMage.HEROS_WILL:
+ case Bishop.HEROS_WILL:
+ case Bowmaster.HEROS_WILL:
+ case Marksman.HEROS_WILL:
+ case NightLord.HEROS_WILL:
+ case Shadower.HEROS_WILL:
+ case Buccaneer.PIRATES_RAGE:
+ case Aran.HEROS_WILL:
+ return true;
+
+ default:
+ return false;
+ }
+ }
private boolean isDash() {
return skill && (sourceid == Pirate.DASH || sourceid == ThunderBreaker.DASH || sourceid == Beginner.SPACE_DASH || sourceid == Noblesse.SPACE_DASH);
diff --git a/src/server/expeditions/MapleExpeditionType.java b/src/server/expeditions/MapleExpeditionType.java
index 291a258c43..eaa664689d 100644
--- a/src/server/expeditions/MapleExpeditionType.java
+++ b/src/server/expeditions/MapleExpeditionType.java
@@ -22,6 +22,8 @@
package server.expeditions;
+import constants.ServerConstants;
+
/**
*
* @author SharpAceX(Alan)
@@ -55,7 +57,7 @@ public enum MapleExpeditionType {
}
public int getMinSize() {
- return minSize;
+ return !ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS ? minSize : 1;
}
public int getMaxSize() {
diff --git a/src/server/maps/MapleMap.java b/src/server/maps/MapleMap.java
index d8e2f619e9..4e37f71fcd 100644
--- a/src/server/maps/MapleMap.java
+++ b/src/server/maps/MapleMap.java
@@ -583,14 +583,18 @@ public class MapleMap {
return new Pair<>(getRoundedCoordinate(angle), Integer.valueOf((int)distn));
}
- private static void sortDropEntries(List from, List item, List quest) {
+ private static void sortDropEntries(List from, List item, List visibleQuest, List otherQuest, MapleCharacter chr) {
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
for(MonsterDropEntry mde : from) {
if(!ii.isQuestItem(mde.itemId)) {
item.add(mde);
} else {
- quest.add(mde);
+ if(chr.needQuestItem(mde.questid, mde.itemId)) {
+ visibleQuest.add(mde);
+ } else {
+ otherQuest.add(mde);
+ }
}
}
}
@@ -690,8 +694,9 @@ public class MapleMap {
final MapleMonsterInformationProvider mi = MapleMonsterInformationProvider.getInstance();
final List dropEntry = new ArrayList<>();
- final List questEntry = new ArrayList<>();
- sortDropEntries(mi.retrieveEffectiveDrop(mob.getId()), dropEntry, questEntry);
+ final List visibleQuestEntry = new ArrayList<>();
+ final List otherQuestEntry = new ArrayList<>();
+ sortDropEntries(mi.retrieveEffectiveDrop(mob.getId()), dropEntry, visibleQuestEntry, otherQuestEntry, chr);
// Normal Drops
d = dropItemsFromMonsterOnMap(dropEntry, pos, d, chRate, droptype, mobpos, chr, mob);
@@ -701,7 +706,8 @@ public class MapleMap {
d = dropGlobalItemsFromMonsterOnMap(globalEntry, pos, d, droptype, mobpos, chr, mob);
// Quest Drops
- dropItemsFromMonsterOnMap(questEntry, pos, d, chRate, droptype, mobpos, chr, mob);
+ d = dropItemsFromMonsterOnMap(visibleQuestEntry, pos, d, chRate, droptype, mobpos, chr, mob);
+ dropItemsFromMonsterOnMap(otherQuestEntry, pos, d, chRate, droptype, mobpos, chr, mob);
}
public void dropItemsFromMonster(List list, final MapleCharacter chr, final MapleMonster mob) {
diff --git a/wz/Etc.wz/ItemMake.img.xml b/wz/Etc.wz/ItemMake.img.xml
index 498a33ef8b..5a6e886d8d 100644
--- a/wz/Etc.wz/ItemMake.img.xml
+++ b/wz/Etc.wz/ItemMake.img.xml
@@ -1573,6 +1573,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/wz/Quest.wz/Check.img.xml b/wz/Quest.wz/Check.img.xml
index c38df3af54..0eba3c7ddd 100644
--- a/wz/Quest.wz/Check.img.xml
+++ b/wz/Quest.wz/Check.img.xml
@@ -27173,6 +27173,8 @@
+
+
diff --git a/wz/Quest.wz/Say.img.xml b/wz/Quest.wz/Say.img.xml
index 916ef0ff2a..28760b3886 100644
--- a/wz/Quest.wz/Say.img.xml
+++ b/wz/Quest.wz/Say.img.xml
@@ -3455,7 +3455,7 @@
-
+
@@ -3467,6 +3467,11 @@
+
+
+
+
+
diff --git a/wz/String.wz/Npc.img.xml b/wz/String.wz/Npc.img.xml
index c2a12efe7b..8a32ff461b 100644
--- a/wz/String.wz/Npc.img.xml
+++ b/wz/String.wz/Npc.img.xml
@@ -5354,6 +5354,7 @@
+
@@ -5498,16 +5499,19 @@
+
+
+
@@ -5539,21 +5543,25 @@
+
+
+
+