Persistent diseases + PQ request system + GuildPQ fix

Implemented persistent diseases. Players now keep their disease status when logging out the game.
Solved several concurrent access issues in MapleMap and MapleMonster.
Implemented an option where an account's character slots can be accounted either by each world or all-server range.
Fixed some issues with character slot count when entering/exiting Cash Shop.
Fixed an exploit with Papulatus, on where players could create cracks of dimension infinitely.
Solved an issue with the "reach" command not working properly when the targeted player is on an event instance.
Devised an advanced and secure "PQ request" system. The service revolves around expecting massive number of players requesting a "pass" simultaneously, and fairly & swiftly responsing as much people as possible.
Improved overall Whisper handler performance.
Fixed GPQ Stage 1 statues not working as expected, which rendered the instance unplayable until now.
Added commands for start, complete and reset quests.
This commit is contained in:
ronancpl
2018-08-18 11:38:55 -03:00
parent cda4433d99
commit 0d47edf1a7
116 changed files with 1596 additions and 703 deletions
+1 -1
View File
@@ -59,7 +59,7 @@ Although development is halted, support for fixing features that were implemente
If you liked this project, please don't forget to __star__ the repo ;) .
It's never too much to tell this, even still thanks to everyone that have been contributing something for the continuous improvement of the server! Be it through bug reports, donation, code snippets and/or pull requests.
It's never enough to tell this, thanks to everyone that have been contributing something for the continuous improvement of the server! Be it through bug reports, donation, code snippets and/or pull requests.
Our Discord channel is still available on: https://discord.gg/Q7wKxHX
+3
View File
@@ -116,6 +116,7 @@ Monsters, Maps & Reactors:
PQ potentials:
* Advanced synchronization and smart management of the PQ registration system, as expected for a core server mechanic that is largely used by the players.
* Lobby system - Multiple PQ instances on same channel.
* Expedition system - Multiples parties can attempt on a same instance (lobbies and expeds are mutually-exclusive).
* Guild queue system - Guilds can register themselves on a queue for the GPQ.
@@ -129,6 +130,7 @@ Player potentials:
* Gain fame by quests.
* Pet evolutions functional (not GMS-like).
* Reviewed keybinding system.
* Account's Character slots: either each world has it's own count or there's a shared value between all worlds.
Server potentials:
@@ -147,6 +149,7 @@ Server potentials:
* Pet item pickup now gives preference to player attacks rather than forcing attack disables when automatically picking up.
* Channel capacity bar functional and world servers with max capacity checks.
* Disease status are now visible for other players, even when changing maps.
* Players keep their current disease status saved when exiting the game, returning with them on login.
* Poison damage value are now visible for other players.
* Mastery book announcer displays droppers of needed books of a player, by reading underlying DB.
* Custom jail system (needs provided custom wz).
+20
View File
@@ -1227,3 +1227,23 @@ Modificado algumas tabelas em ThreadTracker e World para usar Integer ao invés
07 Agosto 2018,
Corrigido um bug na fase de login que nao construia corretamente overview de characters sem itens equipados, lancando excecoes posteriormente.
Revisado alguns casos de borda com doors levando as mesmas a nao sumirem imediatamente em certos cenarios.
08 - 10 Agosto 2018,
Adicionado registro de diseases na DB. Agora jogadores continuam com diseases ao voltar a logar no jogo.
Corrigido exploit com jogadores podendo visitar sua propria loja via owl.
Corrigido varios problemas de acesso concorrente e deadlocks em recursos do MapleMap e MapleMonster.
Implementado character slots para cobrir limite de personagens por conta (ao inves de 3 em cada mundo).
Corrigido diversos problemas com character slots ao entrar/sair do cash shop (erro ligado a alternancia de MapleClients).
Corrigido exploit com quest de Papulatus, onde jogadores poderiam gerar cracks of dimension por desistir de quests.
Corrigido jogadores podendo ser registrados em event instances mesmo quando estas ja estao liberadas (disposed).
Corrigido comando "reach" nao funcionando corretamente para casos que envolvam event instances.
Implementado um sistema avancado e seguro de escalonamento de requisicoes delegadas com iniciar nova PQs.
13 - 14 Agosto 2018,
Corrigido quest "Revealed Identity" erroneamente requisitando itens de quest anteriores de jogadores, impossibilitando jogadores de comecar quests em certos casos.
Melhorado handler de whisper, agora buscando referencias a DB somente em casos onde o jogador eh GM.
Retirado campo de GM da tabela "accounts".
Corrigido estatuas do stage1 da GuildPQ nao funcionando corretamente.
Alterado varias strings de NPCs e de mensagens utilizando a palavra "evento" querendo dizer instancias (julgamento subjetivo).
Adicionado comandos para start, complete e reset quests.
Adicionado scripts para meteoritos de Omega Sector.
+4 -4
View File
@@ -30,10 +30,10 @@ endorsed.classpath=
excludes=
file.reference.HikariCP-java7-2.4.12.jar=cores/HikariCP-java7-2.4.12.jar
file.reference.MapleSolaxia-src=src
file.reference.mina-core-2.0.7.jar=C:\\Users\\Tyler\\Desktop\\MoopleDev\\dist\\mina-core-2.0.7.jar
file.reference.mysql-connector-java-bin.jar=C:\\Users\\Tyler\\Desktop\\MoopleDev\\dist\\mysql-connector-java-bin.jar
file.reference.slf4j-api-1.6.6.jar=C:\\Users\\Tyler\\Desktop\\MoopleDev\\dist\\slf4j-api-1.6.6.jar
file.reference.slf4j-jdk14-1.7.5.jar=C:\\Users\\Tyler\\Desktop\\MoopleDev\\dist\\slf4j-jdk14-1.7.5.jar
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-jdk14-1.7.5.jar=cores\\slf4j-jdk14-1.7.5.jar
includes=**
jar.archive.disabled=${jnlp.enabled}
jar.compress=true
+3 -3
View File
@@ -247,7 +247,7 @@ function changedMap(eim, player, mapid) {
end(eim);
}
else {
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the event.");
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the instance.");
eim.unregisterPlayer(player);
}
} else {
@@ -303,7 +303,7 @@ function playerRevive(eim, player) {
end(eim);
}
else {
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the event.");
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the instance.");
eim.unregisterPlayer(player);
}
}
@@ -315,7 +315,7 @@ function playerDisconnected(eim, player) {
end(eim);
}
else {
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the event.");
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the instance.");
eim.unregisterPlayer(player);
}
}
+1 -1
View File
@@ -236,7 +236,7 @@ function changedMap(eim, player, mapid) {
function afterChangedMap(eim, player, mapid) {
if (mapid == 990000100) {
var texttt = "So, here is the brief. You guys should be warned that, once out on the fortress outskirts, anyone that would not be equipping the #b#t1032033##k will die instantly due to the deteriorated state of the air around there. That being said, once your team moves out to the next stage, make sure to #bhit the glowing rocks#k in that region and #bequip the dropped item#k before advancing stages. That will protect you thoroughly from the air sickness. Good luck!";
var texttt = "So, here is the brief. You guys should be warned that, once out on the fortress outskirts, anyone that would not be equipping the #b#t1032033##k will die instantly due to the deteriorated state of the air around there. That being said, once your team moves out, make sure to #bhit the glowing rocks#k in that region and #bequip the dropped item#k before advancing stages. That will protect you thoroughly from the air sickness. Good luck!";
player.getClient().getSession().write(Packages.tools.MaplePacketCreator.getNPCTalk(9040000, /*(byte)*/ 0, texttt, "00 00", /*(byte)*/ 0));
}
}
+3 -3
View File
@@ -132,7 +132,7 @@ function changedMap(eim, player, mapid) {
end(eim);
}
else {
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the event.");
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the instance.");
eim.unregisterPlayer(player);
}
}
@@ -149,7 +149,7 @@ function playerRevive(eim, player) {
end(eim);
}
else {
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the event.");
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the instance.");
eim.unregisterPlayer(player);
}
}
@@ -161,7 +161,7 @@ function playerDisconnected(eim, player) {
end(eim);
}
else {
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the event.");
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the instance.");
eim.unregisterPlayer(player);
}
}
+3 -3
View File
@@ -118,7 +118,7 @@ function changedMap(eim, player, mapid) {
end(eim);
}
else {
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the event.");
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the instance.");
eim.unregisterPlayer(player);
}
}
@@ -135,7 +135,7 @@ function playerRevive(eim, player) {
end(eim);
}
else {
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the event.");
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the instance.");
eim.unregisterPlayer(player);
}
}
@@ -147,7 +147,7 @@ function playerDisconnected(eim, player) {
end(eim);
}
else {
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the event.");
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the instance.");
eim.unregisterPlayer(player);
}
}
+3 -3
View File
@@ -125,7 +125,7 @@ function changedMap(eim, player, mapid) {
end(eim);
}
else {
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the event.");
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the instance.");
eim.unregisterPlayer(player);
}
}
@@ -144,7 +144,7 @@ function playerRevive(eim, player) {
end(eim);
}
else {
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the event.");
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the instance.");
eim.unregisterPlayer(player);
}
}
@@ -156,7 +156,7 @@ function playerDisconnected(eim, player) {
end(eim);
}
else {
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the event.");
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the instance.");
eim.unregisterPlayer(player);
}
}
+3 -3
View File
@@ -120,7 +120,7 @@ function changedMap(eim, player, mapid) {
end(eim);
}
else {
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the event.");
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the instance.");
eim.unregisterPlayer(player);
}
}
@@ -137,7 +137,7 @@ function playerRevive(eim, player) {
end(eim);
}
else {
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the event.");
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the instance.");
eim.unregisterPlayer(player);
}
}
@@ -149,7 +149,7 @@ function playerDisconnected(eim, player) {
end(eim);
}
else {
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the event.");
eim.dropMessage(5, "[Expedition] " + player.getName() + " has left the instance.");
eim.unregisterPlayer(player);
}
}
+2 -2
View File
@@ -58,7 +58,7 @@ function action(mode, type, selection) {
return;
}
cm.sendSimple("#e#b<Party Quest: Primrose Hill>\r\n#k#n" + em.getProperty("party") + "\r\n\r\nI'm Tory. Inside here is a beautiful hill where the primrose blooms. There's a tiger that lives in the hill, Growlie, and he seems to be looking for something to eat. Would you like to head over to the hill of primrose and join forces with your party members to help Growlie out?#b\r\n#L0#I want to participate in the party quest.\r\n#L1#I want to find party members.\r\n#L2#I would like to hear more details.\r\n#L3#I would like to redeem an event hat.");
cm.sendSimple("#e#b<Party Quest: Primrose Hill>\r\n#k#n" + em.getProperty("party") + "\r\n\r\nI'm Tory. Inside here is a beautiful hill where the primrose blooms. There's a tiger that lives in the hill, Growlie, and he seems to be looking for something to eat. Would you like to head over to the hill of primrose and join forces with your party members to help Growlie out?#b\r\n#L0#I want to participate in the party quest.\r\n#L1#I want to find party members.\r\n#L2#I would like to hear more details.\r\n#L3#I would like to redeem an instance hat.");
} else if (status == 1) {
if (selection == 0) {
if (cm.getParty() == null) {
@@ -87,7 +87,7 @@ function action(mode, type, selection) {
cm.sendOk("#e#b<Party Quest: Primrose Hill>#k#n\r\nCollect primrose seeds from the flowers at the bottom part of the map and drop them by the platforms above the stage. Primrose seed color must match to grow the seeds, so test until you find the correct combination. When all the seeds have been planted, that is, starting second part of the mission, scout the Moon Bunny while it prepares Rice Cakes for the hungry Growlie. Once Growlie becomes satisfied, your mission is complete.");
cm.dispose();
} else {
cm.sendYesNo("So you want to exchange #b20 #b#t4001158##k for the event-designed hat?");
cm.sendYesNo("So you want to exchange #b20 #b#t4001158##k for the instance-designed hat?");
}
} else {
if(cm.hasItem(4001158, 20)) {
+4 -6
View File
@@ -22,18 +22,16 @@ function action(mode, type, selection) {
cm.sendOk("This training ground is available only for those under level 20.");
cm.dispose();
return;
}
if (cm.isQuestActive(22515) || cm.isQuestActive(22516) || cm.isQuestActive(22517) || cm.isQuestActive(22518)) {
cm.sendYesNo("Would you like to go in the special Spore Training Center?");
} else if (cm.isQuestActive(22515) || cm.isQuestActive(22516) || cm.isQuestActive(22517) || cm.isQuestActive(22518)) {
cm.sendYesNo("Would you like to go in the special Training Center?");
status = 1;
}
} else {
var selStr = "Would you like to go into the Training Center?";
for (var i = 0; i < num; i++) {
selStr += "\r\n#b#L" + i + "#Training Center " + i + " (" + cm.getPlayerCount(map + i) + "/" + maxp + ")#l#k";
}
cm.sendSimple(selStr);
}
} else if (status == 1) {
if (selection < 0 || selection >= num) {
cm.dispose();
+2 -7
View File
@@ -22,15 +22,10 @@ function action(mode, type, selection) {
cm.sendOk("This training ground is available only for those under level 20.");
cm.dispose();
return;
}
else if (cm.isQuestActive(22515) || cm.isQuestActive(22516) || cm.isQuestActive(22517) || cm.isQuestActive(22518)) {
} else if (cm.isQuestActive(22515) || cm.isQuestActive(22516) || cm.isQuestActive(22517) || cm.isQuestActive(22518)) {
cm.sendYesNo("Would you like to enter the special Training Center?");
status = 1;
}
else {
} else {
var selStr = "Would you like to go into the Training Center?";
for (var i = 0; i < num; i++) {
selStr += "\r\n#b#L" + i + "#Training Center " + i + " (" + cm.getPlayerCount(map + i) + "/" + maxp + ")#l#k";
+1 -1
View File
@@ -20,7 +20,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Shane 1032004
* By Moogra
* @Author Moogra
*/
function start() {
+2 -2
View File
@@ -61,10 +61,10 @@ function action(mode, type, selection) {
cm.dispose();
return;
} else {
cm.sendYesNo("Your team must collect #r" + couponsNeeded + "#k coupons to complete this event. Talk to me when you have the right amount in hands... Or you want to #bquit now#k? Note that if you quit now #ryour team will be forced to quit#k as well.");
cm.sendYesNo("Your team must collect #r" + couponsNeeded + "#k coupons to complete this instance. Talk to me when you have the right amount in hands... Or you want to #bquit now#k? Note that if you quit now #ryour team will be forced to quit#k as well.");
}
} else {
cm.sendYesNo("Your team must collect #r" + couponsNeeded + "#k coupons to complete this event. Let your leader talk to me with the right amount in hands... Or you want to #bquit now#k? Note that if you quit now your team #rmay become undermanned#k to complete this event.");
cm.sendYesNo("Your team must collect #r" + couponsNeeded + "#k coupons to complete this instance. Let your leader talk to me with the right amount in hands... Or you want to #bquit now#k? Note that if you quit now your team #rmay become undermanned#k to further continue this instance.");
}
} else {
if(!eim.giveEventReward(cm.getPlayer())) {
+1 -1
View File
@@ -25,7 +25,7 @@ function start() {
var eli = em.getEligibleParty(cm.getParty());
if(eli.size() > 0) {
if(!em.startInstance(cm.getParty(), cm.getPlayer().getMap(), 1)) {
cm.sendOk("A party in your name is already registered in this event.");
cm.sendOk("A party in your name is already registered in this instance.");
}
} else {
cm.sendOk("You cannot start this party quest yet, because either your party is not in the range size, some of your party members are not eligible to attempt it or they are not in this map. If you're having trouble finding party members, try Party Search.");
+1 -1
View File
@@ -24,7 +24,7 @@
* @ID: 1103005
* @Map Id: 913040006
* @Function: Cygnus Creator
* @Author Jay (text)
* @Author Jay <text>
* @Author David
*/
+1 -1
View File
@@ -20,7 +20,7 @@
*/
/*Adobis
*
*@author SharpAceX (Alan)
*@author Alan (SharpAceX)
*@author Ronan
*/
importPackage(Packages.server.expeditions);
+2 -2
View File
@@ -20,7 +20,7 @@
*/
/*
* @Authors Stereo, xQuasar, <<XkelvinchiaX@Kelvin(For make it Fully Working.)>>
* @Author Stereo, xQuasar, <<XkelvinchiaX@Kelvin(For make it Fully Working.)>>
*
* Adobis - El Nath: Entrance to Zakum Altar (211042400)
*
@@ -80,7 +80,7 @@ function action(mode, type, selection) {
else { // start Zakum Battle
var eim = em.newInstance("Zakum" + passwd);
if(!em.startInstance(eim,cm.getPlayer().getName())) {
cm.sendOk("A party in your name is already registered in this event.");
cm.sendOk("A party in your name is already registered in this instance.");
cm.dispose();
return;
}
+2 -1
View File
@@ -1,4 +1,4 @@
/* Author: aaroncsn(MapleSea Like)(Need to add creation of minigame)
/* Author: aaroncsn <(MapleSea Like)(Need to add creation of minigame)>
NPC Name: Wisp
Map(s): Ludibrium: Eos Tower Entrance(220000400)
Description: Pet Master
@@ -22,6 +22,7 @@ function action(mode, type, selection) {
status++;
else
status--;
if(status == 0){
cm.sendSimple("Hello there, I'm #bMar the Fairy#k of Victoria Island's main disciple. Mar the Fairy summoned me here to see if the pets are being taken care of here in Ludibrium. What can I do for you? \r\n#L0##bMy pet has turned back into a doll\r\nPlease help me make it move again!#k#l \r\n#L1##bTell me more about Pets.#k#l \r\n#L2##bHow do I raise Pets?#k#l \r\n#L3##bDo Pets die too?#k#l \r\n#L4##bWhat are the commands for brown and black kitty?#k#l \r\n#L5##bWhat are the commands for brown puppy?#k#l \r\n#L6##bWhat are the commands for pink and white bunny?#k#l \r\n#L7##bWhat are the commands for Mini Cargo?#k#l \r\n#L8##bWhat are the commands for Husky?#k#l \r\n#L9##bWhat are the commands for Black Pig?#k#l \r\n#L10##bWhat are the commands for Panda#k#l \r\n#L11##bWhat are the commands for Dino Boy & Girl?#k#l \r\n#L12##bWhat are the commands for Rudolph?#k#l \r\n#L13##bWhat are the commands for Monkey?#k#l \r\n#L14##bWhat are the commands for Robot?#k#l \r\n#L15##bWhat are the commands for Elephant?#k#l \r\n#L16##bWhat are the commands for Golden Pig?#k#l \r\n#L17##bWhat are the commands for Penguin?#k#l \r\n#L18##bWhat are the commands for Mini Yeti?#k#l \r\n#L19##bWhat are the commands for Jr. Balrog? \r\n#L20##bWhat are the commands for Baby Dragon?#k#l \r\n#L21##bWhat are the commands for Green/Red/Blue Dragon?#k#l \r\n#L22##bWhat are the commands for Black Dragon?#k#l \r\n#L23##bWhat are the commands for Snowman?#k#l \r\n#L24##bWhat are the commands for Sun Wu Kong?#k#l \r\n#L25##bWhat are the commands for Jr. Reaper?#k#l \r\n#L26##bWhat are the commands for Crystal Rudolph?#k#l \r\n#L27##bWhat are the commands for Kino?#k#l \r\n#L28##bWhat are the commands for White Duck?#k#l \r\n#L29##bWhat are the commands for Pink Bean?#k#l \r\n#L30##bWhat are the commands for Porcupine?#k#l");
}
+1 -1
View File
@@ -19,7 +19,7 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//First version by Moogra
//First version thanks to Moogra
/**
* @author: Ronan
+60
View File
@@ -0,0 +1,60 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/* Meteorite
@Author RonanLana (Ronan)
*/
var status;
function start() {
status = -1;
action(1, 0, 0);
}
function action(mode, type, selection) {
if (mode == -1) {
cm.dispose();
} else {
if (mode == 0 && type > 0) {
cm.dispose();
return;
}
if (mode == 1)
status++;
else
status--;
if(status == 0) {
if(cm.isQuestStarted(3421)) {
var meteoriteId = cm.getNpc() - 2050014;
var progress = cm.getQuestProgress(3421, 0);
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
progress |= (1 << meteoriteId);
cm.gainItem(4031117, 1);
cm.setQuestProgress(3421, 0, progress);
}
}
cm.dispose();
}
}
}
+60
View File
@@ -0,0 +1,60 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/* Meteorite
@Author RonanLana (Ronan)
*/
var status;
function start() {
status = -1;
action(1, 0, 0);
}
function action(mode, type, selection) {
if (mode == -1) {
cm.dispose();
} else {
if (mode == 0 && type > 0) {
cm.dispose();
return;
}
if (mode == 1)
status++;
else
status--;
if(status == 0) {
if(cm.isQuestStarted(3421)) {
var meteoriteId = cm.getNpc() - 2050014;
var progress = cm.getQuestProgress(3421, 0);
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
progress |= (1 << meteoriteId);
cm.gainItem(4031117, 1);
cm.setQuestProgress(3421, 0, progress);
}
}
cm.dispose();
}
}
}
+60
View File
@@ -0,0 +1,60 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/* Meteorite
@Author RonanLana (Ronan)
*/
var status;
function start() {
status = -1;
action(1, 0, 0);
}
function action(mode, type, selection) {
if (mode == -1) {
cm.dispose();
} else {
if (mode == 0 && type > 0) {
cm.dispose();
return;
}
if (mode == 1)
status++;
else
status--;
if(status == 0) {
if(cm.isQuestStarted(3421)) {
var meteoriteId = cm.getNpc() - 2050014;
var progress = cm.getQuestProgress(3421, 0);
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
progress |= (1 << meteoriteId);
cm.gainItem(4031117, 1);
cm.setQuestProgress(3421, 0, progress);
}
}
cm.dispose();
}
}
}
+60
View File
@@ -0,0 +1,60 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/* Meteorite
@Author RonanLana (Ronan)
*/
var status;
function start() {
status = -1;
action(1, 0, 0);
}
function action(mode, type, selection) {
if (mode == -1) {
cm.dispose();
} else {
if (mode == 0 && type > 0) {
cm.dispose();
return;
}
if (mode == 1)
status++;
else
status--;
if(status == 0) {
if(cm.isQuestStarted(3421)) {
var meteoriteId = cm.getNpc() - 2050014;
var progress = cm.getQuestProgress(3421, 0);
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
progress |= (1 << meteoriteId);
cm.gainItem(4031117, 1);
cm.setQuestProgress(3421, 0, progress);
}
}
cm.dispose();
}
}
}
+60
View File
@@ -0,0 +1,60 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/* Meteorite
@Author RonanLana (Ronan)
*/
var status;
function start() {
status = -1;
action(1, 0, 0);
}
function action(mode, type, selection) {
if (mode == -1) {
cm.dispose();
} else {
if (mode == 0 && type > 0) {
cm.dispose();
return;
}
if (mode == 1)
status++;
else
status--;
if(status == 0) {
if(cm.isQuestStarted(3421)) {
var meteoriteId = cm.getNpc() - 2050014;
var progress = cm.getQuestProgress(3421, 0);
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
progress |= (1 << meteoriteId);
cm.gainItem(4031117, 1);
cm.setQuestProgress(3421, 0, progress);
}
}
cm.dispose();
}
}
}
+60
View File
@@ -0,0 +1,60 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/* Meteorite
@Author RonanLana (Ronan)
*/
var status;
function start() {
status = -1;
action(1, 0, 0);
}
function action(mode, type, selection) {
if (mode == -1) {
cm.dispose();
} else {
if (mode == 0 && type > 0) {
cm.dispose();
return;
}
if (mode == 1)
status++;
else
status--;
if(status == 0) {
if(cm.isQuestStarted(3421)) {
var meteoriteId = cm.getNpc() - 2050014;
var progress = cm.getQuestProgress(3421, 0);
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
progress |= (1 << meteoriteId);
cm.gainItem(4031117, 1);
cm.setQuestProgress(3421, 0, progress);
}
}
cm.dispose();
}
}
}
+1 -1
View File
@@ -19,7 +19,7 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//Fixed by Moogra, Ronan
//@Author Moogra, Ronan
//Fixed grammar, javascript syntax
importPackage(Packages.client);
+1 -1
View File
@@ -96,7 +96,7 @@ function action(mode, type, selection) {
}
} else {
if(!cm.isEventLeader()) {
cm.sendOk("Only your event leader is allowed to interact with the Schedule.");
cm.sendOk("Only your party leader is allowed to interact with the Schedule.");
} else if(cm.getMapId() == 240050100) {
if(cm.haveItem(4001087) && cm.haveItem(4001088) && cm.haveItem(4001089) && cm.haveItem(4001090) && cm.haveItem(4001091)) {
cm.gainItem(4001087, -1);
+1 -1
View File
@@ -20,7 +20,7 @@
*/
/*Mark of the Squad
*
*@author SharpAceX (Alan)
*@author Alan (SharpAceX)
*@author Ronan
*/
importPackage(Packages.server.expeditions);
+1 -1
View File
@@ -1,4 +1,4 @@
/* @author aaroncsn(MapleSea Like)
/* @author aaroncsn <MapleSea Like>
* @author Ronan
NPC Name: Mr. Do
Map(s): Mu Lung: Mu Lung(2500000000)
+1 -1
View File
@@ -29,7 +29,7 @@ function action(mode, type, selection) {
var eim = cm.getEventInstance();
if (eim == null) {
cm.warp(251010404,0);
cm.sendNext("How are you even here without being registered on an event?");
cm.sendNext("How are you even here without being registered on an instance?");
cm.dispose();
return;
}
+1 -1
View File
@@ -1,4 +1,4 @@
/* Author: aaroncsn (MapleSea Like)
/* Author: aaroncsn <MapleSea Like>
NPC Name: Muhammad
Map(s): Ariant:The Town of Ariant(260000200)
Description: Jewel Refiner
+1 -1
View File
@@ -1,4 +1,4 @@
/* Author: aaroncsn (MapleSea Like)
/* Author: aaroncsn <MapleSea Like>
NPC Name: Shati
Map(s): The Burning Road: Ariant(2600000000)
Description: Assistant Hairdresser
+1 -1
View File
@@ -1,4 +1,4 @@
/* Author: aaroncsn (MapleSea Like)
/* Author: aaroncsn <MapleSea Like>
NPC Name: Mazra
Map(s): The Burning Road: Ariant(2600000000)
Description: Hair Salon Owner
+1 -1
View File
@@ -1,4 +1,4 @@
/* Author: aaroncsn (MapleSea Like)(Incomplete- Needs skin id)
/* Author: aaroncsn <(MapleSea Like)(Incomplete- Needs skin id)>
NPC Name: Laila
Map(s): The Burning Road: Ariant(2600000000)
Description: Skin Care Specialist
+1 -1
View File
@@ -1,4 +1,4 @@
/* Author: aaroncsn (MapleSea Like)
/* Author: aaroncsn <MapleSea Like>
NPC Name: Badr
Map(s): The Burning Road: Ariant(2600000000)
Description: Ariant Plastic Surgery
+1 -1
View File
@@ -1,4 +1,4 @@
/* Author: aaroncsn (MapleSea Like)
/* Author: aaroncsn <MapleSea Like>
NPC Name: Aldin
Map(s): The Burning Road: Ariant(2600000000)
Description: Ariant Plastic Surgery
+1 -1
View File
@@ -1,4 +1,4 @@
/* Author: aaroncsn(MapleSea Like)
/* Author: aaroncsn <MapleSea Like>
NPC Name: Karcasa
Map(s): The Burning Sands: Tents of the Entertainers(260010600)
Description: Warps to Victoria Island
+1 -1
View File
@@ -23,7 +23,7 @@
-- Odin JavaScript --------------------------------------------------------------------------------
Camel Cab - Magatia (GMS Like)
-- Version Info -----------------------------------------------------------------------------------
1.3 - Actually fixed by SharpAceX (Alan)
1.3 - Actually fixed by Alan (SharpAceX)
1.2 - Fixed and recoded by Moogra
1.1 - Shortened by Moogra
1.0 - First Version by Maple4U, who actually can't code at all
+1 -1
View File
@@ -1,4 +1,4 @@
/* Author: aaroncsn(MapleSea Like)(Incomplete)
/* Author: aaroncsn <(MapleSea Like)(Incomplete)>
NPC Name: Athena Pierce
Map(s): Altair Camp: Conference Hall(300000010)
Description: Unknown
+1 -1
View File
@@ -1,4 +1,4 @@
/* Author: aaroncsn(MapleSea Like)(Incomplete)
/* Author: aaroncsn <(MapleSea Like)(Incomplete)>
NPC Name: Euryth
Map(s): Elin Forest:Altair Camp(300000000)
Description: Unknown
+1 -1
View File
@@ -1,4 +1,4 @@
/* Author: aaroncsn(MapleSea Like)(Incomplete)
/* Author: aaroncsn <(MapleSea Like)(Incomplete)>
NPC Name: Kanderun
Map(s): Elin Forest:Entrance to Rocky Mountain(300010400)
Description: Unknown
+1 -1
View File
@@ -43,7 +43,7 @@ function action(mode, type, selection) {
cm.warp(270050000);
}
else {
cm.sendOk("You cannot receive an event prize without having an empty room in your EQUIP, USE, SET-UP and ETC inventory.");
cm.sendOk("You cannot receive an instance prize without having an empty room in your EQUIP, USE, SET-UP and ETC inventory.");
}
cm.dispose();
+3 -3
View File
@@ -89,7 +89,7 @@ function action(mode, type, selection) {
cm.sendOk("Your party completed such an astounding feat coming this far, #byou have defeated all the bosses#k, congratulations! Now I will be handing your reward as you are being transported out...");
}
else {
cm.sendOk("For #bdefeating all bosses#k in this event, congratulations! You will now receive a prize that matches your performance here as I warp you out.");
cm.sendOk("For #bdefeating all bosses#k in this instance, congratulations! You will now receive a prize that matches your performance here as I warp you out.");
}
}
else if(state == 2) {
@@ -109,7 +109,7 @@ function action(mode, type, selection) {
return;
}
} else if(state == 1) {
cm.sendYesNo("Do you wish to abandon this event?");
cm.sendYesNo("Do you wish to abandon this instance?");
}
else {
em = cm.getEventManager("BossRushPQ");
@@ -174,7 +174,7 @@ function action(mode, type, selection) {
cm.sendOk("Try using a Super Megaphone or asking your buddies or guild to join!");
cm.dispose();
} else {
cm.sendOk("#e#b<Party Quest: Boss Rush>#k#n\r\nBrave adventurers from all over the places travels here to test their skills and abilities in combat, as they face even more powerful bosses from MapleStory. Join forces with fellow adventurers or face all the burden by yourself and receive all the glory, it is up to you. REWARDS are given accordingly to how far the adventurers reach and extra prizes may are given to a random member of the party, all attributed at the end of an expedition.\r\n\r\nThis event also supports #bmultiple lobbies for matchmaking several ranges of team levels#k at once: team up with players with lower level if you want better chances to swiftly set up a boss rush for your team.");
cm.sendOk("#e#b<Party Quest: Boss Rush>#k#n\r\nBrave adventurers from all over the places travels here to test their skills and abilities in combat, as they face even more powerful bosses from MapleStory. Join forces with fellow adventurers or face all the burden by yourself and receive all the glory, it is up to you. REWARDS are given accordingly to how far the adventurers reach and extra prizes may are given to a random member of the party, all attributed at the end of an expedition.\r\n\r\nThis instance also supports #bmultiple lobbies for matchmaking several ranges of team levels#k at once: team up with players with lower level if you want better chances to swiftly set up a boss rush for your team.");
cm.dispose();
}
}
+1 -1
View File
@@ -20,7 +20,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @Author : iAkira/Kevintjuh93
* @Author : iAkira, Kevintjuh93
**/
var status = 0;
var selected = 0;
+5 -7
View File
@@ -66,14 +66,13 @@ function action(mode, type, selection) {
} else {
stage = parseInt(eim.getProperty("stage1phase"));
}
if (stage == 1) {
cm.sendOk("In this challenge, I shall show a pattern on the statues around me. When I give the word, repeat the pattern to me to proceed.");
}
else {
} else {
cm.sendOk("I shall now present a more difficult puzzle for you. Good luck.");
}
}
else if (eim.getProperty("stage1status").equals("active")) {
} else if (eim.getProperty("stage1status").equals("active")) {
stage = parseInt(eim.getProperty("stage1phase"));
if (eim.getProperty("stage1combo").equals(eim.getProperty("stage1guess"))) {
@@ -97,8 +96,7 @@ function action(mode, type, selection) {
}
eim.setProperty("stage1status", "waiting");
cm.dispose();
}
else {
} else {
cm.sendOk("The statues are working on the pattern. Please wait.");
cm.dispose();
}
@@ -116,7 +114,7 @@ function action(mode, type, selection) {
cm.dispose();
}
} else {
cm.sendOk("I need the leader of this event to speak with me, nobody else.");
cm.sendOk("I need the leader of this instance to speak with me, nobody else.");
cm.dispose();
}
}
+1 -1
View File
@@ -43,7 +43,7 @@ function start() {
}
}
else {
cm.sendOk("This is your final challenge. Defeat the evil lurking within the Rubian and let your event leader return it to me. That is all.");
cm.sendOk("This is your final challenge. Defeat the evil lurking within the Rubian and let your instance leader return it to me. That is all.");
}
}
else
+1 -1
View File
@@ -54,7 +54,7 @@ function action(mode, type, selection) {
if (status == 0) {
if(cm.isEventLeader()) {
if(!cm.getEventInstance().isEventTeamTogether()) {
cm.sendOk("One or more event team members is missing, please wait for them to reach here first.");
cm.sendOk("One or more instance team members is missing, please wait for them to reach here first.");
cm.dispose();
}
else if(cm.hasItem(4001106, 30)) {
+1 -1
View File
@@ -74,7 +74,7 @@ function action(mode, type, selection) {
advance = true;
if(status == 0) {
cm.sendNext("Hi there, how is it going? Since you're passing by Amoria, have you heard about the event my brother Amos is hosting? It is the #bAmorian Challenge#k, an event for everyone above level 40.\r\n\r\nThere, you may find the #i4031543# #i4031544# #i4031545# #bWish Tickets#k that can be brought here to redeem prizes.");
cm.sendNext("Hi there, how is it going? Since you're passing by Amoria, have you heard about the instance my brother Amos is hosting? It is the #bAmorian Challenge#k, an instance for everyone above level 40.\r\n\r\nThere, you may find the #i4031543# #i4031544# #i4031545# #bWish Tickets#k that can be brought here to redeem prizes.");
} else if(status == 1) {
var listStr = "";
for(var i = 0; i < wishPrizes.length; i++) {
+1 -1
View File
@@ -83,7 +83,7 @@ function action(mode, type, selection) {
cm.sendOk("Try using a Super Megaphone or asking your buddies or guild to join!");
cm.dispose();
} else {
cm.sendOk("#e#b<Party Quest: Amorian Challenge>#k#n\r\nI am Amos, hoster of the well-round famed Amorian Challenge. The event consist of many team puzzles, where cooperation is the fundamental key for progress. Team up with other players to attempt for the bonus stage, where many goodies can be obtained at the end of the event. If an all-couple party is formed, they can get even better prizes on the extra bonus stage.");
cm.sendOk("#e#b<Party Quest: Amorian Challenge>#k#n\r\nI am Amos, hoster of the well-round famed Amorian Challenge. The instance consist of many team puzzles, where cooperation is the fundamental key for progress. Team up with other players to attempt for the bonus stage, where many goodies can be obtained at the end of the instance. If an all-couple party is formed, they can get even better prizes on the extra bonus stage.");
cm.dispose();
}
}
+1 -1
View File
@@ -20,7 +20,7 @@
*/
/*Jack
*
*@author SharpAceX (Alan)
*@author Alan (SharpAceX)
*@author Ronan
*/
importPackage(Packages.server.expeditions);
+7
View File
@@ -23,11 +23,13 @@
Version
|- 1.0 by Jayd
|- 1.1 by Ronan (check job requirements)
*/
var status;
var map = 102000003;
var job = "Warrior";
var jobType = 1;
var no = "Come back to me if you decided to be a #b"+job+"#k.";
function start() {
@@ -52,7 +54,12 @@ function action(mode, type, selection) {
if(status == 0) {
if (cm.getJob() == "BEGINNER") {
if (cm.getLevel() >= 10 && cm.canGetFirstJob(jobType)) {
cm.sendYesNo("Hey #h #, I can send you to #b#m"+map+"##k if you want to be a #b"+job+"#k. Do you want to go now?");
} else {
cm.sendOk("If you want to be a #b"+job+"#k, train yourself further until you reach #blevel 10, " + cm.getFirstJobStatRequirement(jobType) + "#k.");
cm.dispose();
}
} else {
cm.sendOk("You're much stronger now. Keep training!");
cm.dispose();
+10 -1
View File
@@ -23,11 +23,14 @@
Version
|- 1.0 by Jayd
|- 1.1 by Ronan (check job requirements)
*/
var status;
var map = 100000201;
var job = "Bowman";
var jobType = 3;
var no = "Come back to me if you decided to be a #b"+job+"#k.";
function start() {
status = -1;
@@ -36,10 +39,11 @@ function start() {
function action(mode, type, selection) {
if (mode == -1) {
cm.sendOk(no);
cm.dispose();
} else {
if (mode == 0 && type > 0) {
cm.sendOk("Come back to me if you decided to be a #b"+job+"#k.");
cm.sendOk(no);
cm.dispose();
}
@@ -50,7 +54,12 @@ function action(mode, type, selection) {
if(status == 0) {
if (cm.getJob() == "BEGINNER") {
if (cm.getLevel() >= 10 && cm.canGetFirstJob(jobType)) {
cm.sendYesNo("Hey #h #, I can send you to #b#m"+map+"##k if you want to be a #b"+job+"#k. Do you want to go now?");
} else {
cm.sendOk("If you want to be a #b"+job+"#k, train yourself further until you reach #blevel 10, " + cm.getFirstJobStatRequirement(jobType) + "#k.");
cm.dispose();
}
} else {
cm.sendOk("You're much stronger now. Keep training!");
cm.dispose();
+7
View File
@@ -23,11 +23,13 @@
Version
|- 1.0 by Jayd
|- 1.1 by Ronan (check job requirements)
*/
var status;
var map = 101000003;
var job = "Magician";
var jobType = 2;
var no = "Come back to me if you decided to be a #b"+job+"#k.";
function start() {
@@ -52,7 +54,12 @@ function action(mode, type, selection) {
if(status == 0) {
if (cm.getJob() == "BEGINNER") {
if (cm.getLevel() >= 8 && cm.canGetFirstJob(jobType)) {
cm.sendYesNo("Hey #h #, I can send you to #b#m"+map+"##k if you want to be a #b"+job+"#k. Do you want to go now?");
} else {
cm.sendOk("If you want to be a #b"+job+"#k, train yourself further until you reach #blevel 8, " + cm.getFirstJobStatRequirement(jobType) + "#k.");
cm.dispose();
}
} else {
cm.sendOk("You're much stronger now. Keep training!");
cm.dispose();
+7
View File
@@ -23,11 +23,13 @@
Version
|- 1.0 by Jayd
|- 1.1 by Ronan (check job requirements)
*/
var status;
var map = 103000003;
var job = "Thief";
var jobType = 4;
var no = "Come back to me if you decided to be a #b"+job+"#k.";
function start() {
@@ -52,7 +54,12 @@ function action(mode, type, selection) {
if(status == 0) {
if (cm.getJob() == "BEGINNER") {
if (cm.getLevel() >= 10 && cm.canGetFirstJob(jobType)) {
cm.sendYesNo("Hey #h #, I can send you to #b#m"+map+"##k if you want to be a #b"+job+"#k. Do you want to go now?");
} else {
cm.sendOk("If you want to be a #b"+job+"#k, train yourself further until you reach #blevel 10, " + cm.getFirstJobStatRequirement(jobType) + "#k.");
cm.dispose();
}
} else {
cm.sendOk("You're much stronger now. Keep training!");
cm.dispose();
+7
View File
@@ -23,11 +23,13 @@
Version
|- 1.0 by Jayd
|- 1.1 by Ronan (check job requirements)
*/
var status;
var map = 120000101;
var job = "Pirate";
var jobType = 5;
var no = "Come back to me if you decided to be a #b"+job+"#k.";
function start() {
@@ -52,7 +54,12 @@ function action(mode, type, selection) {
if(status == 0) {
if (cm.getJob() == "BEGINNER") {
if (cm.getLevel() >= 10 && cm.canGetFirstJob(jobType)) {
cm.sendYesNo("Hey #h #, I can send you to #b#m"+map+"##k if you want to be a #b"+job+"#k. Do you want to go now?");
} else {
cm.sendOk("If you want to be a #b"+job+"#k, train yourself further until you reach #blevel 10, " + cm.getFirstJobStatRequirement(jobType) + "#k.");
cm.dispose();
}
} else {
cm.sendOk("You're much stronger now. Keep training!");
cm.dispose();
+1 -1
View File
@@ -20,7 +20,7 @@
*/
/*Aldol
*
*@author SharpAceX (Alan)
*@author Alan (SharpAceX)
*@author Ronan
*/
importPackage(Packages.server.expeditions);
+4 -1
View File
@@ -41,7 +41,7 @@ function addFeature(feature) {
function writeFeatureTab_PQs() {
addFeature("HPQ/KPQ/LPQ/LMPQ/OPQ/APQ/EllinPQ/PiratePQ.");
addFeature("RnJPQ/HorntailPQ/TreasurePQ/ElnathPQ/HolidayPQ.");
addFeature("CWKPQ as Expedition-based event.");
addFeature("CWKPQ as Expedition-based instance.");
addFeature("Scarga/Horntail/Showa/Balrog/Zakum/Pinkbean.");
addFeature("GuildPQ & queue with multi-lobby systems available.");
addFeature("Brand-new PQs: BossRushPQ, CafePQ.");
@@ -131,6 +131,7 @@ function writeFeatureTab_MonstersMapsReactors() {
}
function writeFeatureTab_PQpotentials() {
addFeature("Advanced and well-safe PQ registration system.");
addFeature("Lobby system: Same channel, multiple PQ instances.");
addFeature("Exped system: Many parties can join a same instance.");
addFeature("Guild queue: guild registration for the GPQ.");
@@ -144,6 +145,7 @@ function writeFeatureTab_Playerpotentials() {
addFeature("Gain fame by quests.");
addFeature("Pet evolutions functional (not GMS-like).");
addFeature("Reviewed keybinding system.");
addFeature("Character slots per world/server-wide.");
}
function writeFeatureTab_Serverpotentials() {
@@ -162,6 +164,7 @@ function writeFeatureTab_Serverpotentials() {
addFeature("Pet pickup gives preference to player attacks.");
addFeature("Channel capacity bar and worlds with capacity check.");
addFeature("Diseases visible for others, even after changing maps.");
addFeature("Persistent diseases. Players keep their status on login.");
addFeature("Poison damage value visible for other players.");
addFeature("M. book announcer displays info based on demand.");
addFeature("Custom jail system.");
+3
View File
@@ -162,6 +162,9 @@ function writeHeavenMSCommandsLv3() { //GM
addCommand("npc", "");
addCommand("face", "");
addCommand("hair", "");
addCommand("startquest", "");
addCommand("completequest", "");
addCommand("resetquest", "");
}
function writeHeavenMSCommandsLv2() { //JrGM
+1
View File
@@ -36,6 +36,7 @@ function writeServerStaff_MapleNext() {
function writeServerStaff_HeavenMS() {
addPerson("Ronan", "Developer");
addPerson("Vcoc", "Freelance Developer");
addPerson("Thora", "Contributor");
setHistory(2015, 2018);
}
+1 -1
View File
@@ -1,7 +1,7 @@
function enter(pi) {
var nex = pi.getEventManager("GuardianNex");
if(nex == null) {
pi.message("Guardian Nex event encontered an error and is unavailable.");
pi.message("Guardian Nex challenge encountered an error and is unavailable.");
return false;
}
+1 -1
View File
@@ -37,7 +37,7 @@ function enter(pi) {
return true;
}
else {
pi.message("Make a room available on all EQUIP, USE, SET-UP and ETC inventory to claim an event prize.");
pi.message("Make a room available on all EQUIP, USE, SET-UP and ETC inventory to claim an instance prize.");
return false;
}
}
+1 -1
View File
@@ -19,7 +19,7 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Author: Xterminator (Modified by XxOsirisxX)
/* Author: Xterminator <Modified by XxOsirisxX>
NPC Name: Roger
Map(s): Maple Road : Lower level of the Training Camp (2)
Description: Quest - Roger's Apple
+64
View File
@@ -0,0 +1,64 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/* Papulatus - 7103
*/
var status = -1;
function start(mode, type, selection) {
if (mode == -1) {
qm.sendOk("Oh really. Do you need more time? I'm fully confident that you'll help me out before the Time Sphere is formed.");
qm.dispose();
} else {
if(mode == 0 && type > 0) {
qm.sendOk("Oh really. Do you need more time? I'm fully confident that you'll help me out before the Time Sphere is formed.");
qm.dispose();
return;
}
if (mode == 1)
status++;
else
status--;
if (status == 0) {
qm.sendYesNo("Only thing we have to do now ...is to make #o8500002# disappear forever... are you ready?");
} else if (status == 1) {
qm.sendNext("I'll explain to you what you need to do from here on out. \r\nTo enter the power-generating room, you'll need to pass either #bForgotten Passage#k or the #bWarped Passage#k. Once you defeat whichever monster that is guarding the passage, you can obtain #b#t4031172:##k, which is needed to enter the power-generating room.");
} else if (status == 2) {
qm.sendNextPrev("Then enter the room through the door in the middle. It's going to be MUCH quieter than you imagined. The Time Sphere should be hidden in a state undetectable in our eyes... but if you seal up the crack in dimension, the #o8500002#, panicking because its exit route is sealed up, will make its appearance there.");
} else if (status == 3) {
if (!qm.haveItem(4031179, 1)) {
if (!qm.canHold(4031179, 1)) {
qm.sendOk("Please have an #rETC slot available#k to start this quest.");
qm.dispose();
return;
}
qm.gainItem(4031179, 1);
}
qm.sendAcceptDecline("Drop the #b#t4031179:##k that I returned to you to seal up whatever crack you see that #o8500002# may have used to enter this dimension in the first place. Then it'll come out of the Time Sphere and show everyone its true appearance. Please, please kill it and then come back. \r\n\r\nCollect #r1 #t4031172:##k\r\nEliminate #r#o8500001##k");
} else if (status == 4) {
qm.forceStartQuest();
qm.dispose();
}
}
}
+2 -2
View File
@@ -40,7 +40,7 @@ function act() {
if(!rm.getReactor().isRecentHitFromAttack()) {
var prevCombo = eim.getProperty("stage1combo");
var n = "" + rm.getReactor().getObjectId();
var n = "" + (rm.getReactor().getObjectId() % 1000);
prevCombo += padWithZeroes(n, 3);
eim.setProperty("stage1combo",prevCombo);
@@ -53,7 +53,7 @@ function act() {
} else { //active
var prevGuess = "" + eim.getProperty("stage1guess");
if (prevGuess.length != (3 * (stage + 3))) {
var n = "" + rm.getReactor().getObjectId();
var n = "" + (rm.getReactor().getObjectId() % 1000);
prevGuess += padWithZeroes(n, 3);
eim.setProperty("stage1guess",prevGuess);
+2 -2
View File
@@ -42,7 +42,7 @@ function act() {
if(!rm.getReactor().isRecentHitFromAttack()) {
var prevCombo = eim.getProperty("stage1combo");
var n = "" + rm.getReactor().getObjectId();
var n = "" + (rm.getReactor().getObjectId() % 1000);
prevCombo += padWithZeroes(n, 3);
eim.setProperty("stage1combo",prevCombo);
@@ -55,7 +55,7 @@ function act() {
} else { //active
var prevGuess = "" + eim.getProperty("stage1guess");
if (prevGuess.length != (3 * (stage + 3))) {
var n = "" + rm.getReactor().getObjectId();
var n = "" + (rm.getReactor().getObjectId() % 1000);
prevGuess += padWithZeroes(n, 3);
eim.setProperty("stage1guess",prevGuess);
+2 -2
View File
@@ -39,7 +39,7 @@ function act() {
if (status.equals("display")) {
if(!rm.getReactor().isRecentHitFromAttack()) {
var prevCombo = eim.getProperty("stage1combo");
var n = "" + rm.getReactor().getObjectId();
var n = "" + (rm.getReactor().getObjectId() % 1000);
prevCombo += padWithZeroes(n, 3);
eim.setProperty("stage1combo",prevCombo);
@@ -52,7 +52,7 @@ function act() {
} else { //active
var prevGuess = "" + eim.getProperty("stage1guess");
if (prevGuess.length != (3 * (stage + 3))) {
var n = "" + rm.getReactor().getObjectId();
var n = "" + (rm.getReactor().getObjectId() % 1000);
prevGuess += padWithZeroes(n, 3);
eim.setProperty("stage1guess",prevGuess);
+10 -1
View File
@@ -25,7 +25,6 @@ CREATE TABLE IF NOT EXISTS `accounts` (
`birthday` date NOT NULL DEFAULT '0000-00-00',
`banned` tinyint(1) NOT NULL DEFAULT '0',
`banreason` text,
`gm` tinyint(1) NOT NULL DEFAULT '0',
`macs` tinytext,
`nxCredit` int(11) DEFAULT NULL,
`maplePoint` int(11) DEFAULT NULL,
@@ -16474,6 +16473,16 @@ CREATE TABLE IF NOT EXISTS `petignores` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `playerdiseases` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`charid` int(11) NOT NULL,
`disease` int(11) NOT NULL,
`mobskillid` int(11) NOT NULL,
`mobskilllv` int(11) NOT NULL,
`length` int(11) NOT NULL DEFAULT '1',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `playernpcs` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(13) NOT NULL,
+5
View File
@@ -19823,6 +19823,11 @@ USE `heavenms`;
(1110100, 4001369, 1, 1, 28259, 40000),
(1210101, 4001370, 1, 1, 28260, 40000),
(1110101, 4001371, 1, 1, 28261, 40000),
(2130100, 4001368, 1, 1, 28262, 40000),
(2110200, 4001369, 1, 1, 28262, 40000),
(1110100, 4001370, 1, 1, 28262, 40000),
(1210101, 4001371, 1, 1, 28262, 40000),
(1110101, 4001367, 1, 1, 28262, 40000),
(3300003, 4001317, 1, 1, 2326, 20000),
(1210102, 4001364, 1, 1, 28192, 80000),
(1120100, 4001365, 1, 1, 28192, 80000),
+106 -19
View File
@@ -155,6 +155,7 @@ import constants.skills.Swordsman;
import constants.skills.ThunderBreaker;
import net.server.channel.handlers.PartyOperationHandler;
import scripting.item.ItemScriptManager;
import server.life.MobSkillFactory;
import server.maps.MapleMapItem;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
@@ -1370,6 +1371,35 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
eventAfterChangedMap(this.getMapId());
}
public void forceChangeMap(final MapleMap target, final MaplePortal pto) {
// will actually enter the map given as parameter, regardless of being an eventmap or whatnot
canWarpCounter++;
eventChangedMap(999999999);
EventInstanceManager mapEim = target.getEventInstance();
if(mapEim != null) {
EventInstanceManager playerEim = this.getEventInstance();
if(playerEim != null) {
playerEim.exitPlayer(this);
if(playerEim.getPlayerCount() == 0) {
playerEim.dispose();
}
}
mapEim.registerPlayer(this);
}
MapleMap to = getWarpMap(target.getId());
changeMapInternal(to, pto.getPosition(), MaplePacketCreator.getWarpToMap(to, pto.getId(), this));
canWarpMap = false;
canWarpCounter--;
if(canWarpCounter == 0) canWarpMap = true;
eventAfterChangedMap(this.getMapId());
}
private boolean buffMapProtection() {
effLock.lock();
chrLock.lock();
@@ -2073,6 +2103,10 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
ps.setInt(1, cid);
ps.executeUpdate();
}
try (PreparedStatement ps = con.prepareStatement("DELETE FROM playerdiseases WHERE charid = ?")) {
ps.setInt(1, cid);
ps.executeUpdate();
}
try (PreparedStatement ps = con.prepareStatement("DELETE FROM area_info WHERE charid = ?")) {
ps.setInt(1, cid);
ps.executeUpdate();
@@ -2359,30 +2393,33 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
long expTime = curTime + di.getValue().getLeft();
diseaseExpires.put(di.getKey(), expTime);
diseases.put(di.getKey(), new Pair<>(new MapleDiseaseValueHolder(curTime, expTime), di.getValue().getRight()));
diseases.put(di.getKey(), new Pair<>(new MapleDiseaseValueHolder(curTime, di.getValue().getLeft()), di.getValue().getRight()));
}
} finally {
chrLock.unlock();
}
}
public void announceDiseases(MapleClient c) {
public void announceDiseases() {
Set<Entry<MapleDisease, Pair<MapleDiseaseValueHolder, MobSkill>>> chrDiseases;
chrLock.lock();
try {
// Poison damage visibility and diseases status visibility, extended through map transitions thanks to Ronan
if(!this.isLoggedinWorld()) return;
for(Entry<MapleDisease, Pair<MapleDiseaseValueHolder, MobSkill>> di : diseases.entrySet()) {
chrDiseases = new LinkedHashSet<>(diseases.entrySet());
} finally {
chrLock.unlock();
}
for(Entry<MapleDisease, Pair<MapleDiseaseValueHolder, MobSkill>> di : chrDiseases) {
MapleDisease disease = di.getKey();
MobSkill skill = di.getValue().getRight();
final List<Pair<MapleDisease, Integer>> debuff = Collections.singletonList(new Pair<>(disease, Integer.valueOf(skill.getX())));
if(disease != MapleDisease.SLOW) c.announce(MaplePacketCreator.giveForeignDebuff(id, debuff, skill));
else c.announce(MaplePacketCreator.giveForeignSlowDebuff(id, debuff, skill));
}
} finally {
chrLock.unlock();
if(disease != MapleDisease.SLOW) map.broadcastMessage(MaplePacketCreator.giveForeignDebuff(id, debuff, skill));
else map.broadcastMessage(MaplePacketCreator.giveForeignSlowDebuff(id, debuff, skill));
}
}
@@ -6276,11 +6313,14 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
rs.close();
ps.close();
ps = con.prepareStatement("SELECT name FROM accounts WHERE id = ?", Statement.RETURN_GENERATED_KEYS);
ps = con.prepareStatement("SELECT name, characterslots FROM accounts WHERE id = ?", Statement.RETURN_GENERATED_KEYS);
ps.setInt(1, ret.accountid);
rs = ps.executeQuery();
if (rs.next()) {
ret.getClient().setAccountName(rs.getString("name"));
MapleClient retClient = ret.getClient();
retClient.setAccountName(rs.getString("name"));
retClient.setCharacterSlots(rs.getByte("characterslots"));
}
rs.close();
ps.close();
@@ -6348,20 +6388,24 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
try (ResultSet rsProgress = pse.executeQuery()) {
while(rsProgress.next()) {
MapleQuestStatus status = loadedQuestStatus.get(rsProgress.getInt("queststatusid"));
if(status != null) {
status.setProgress(rsProgress.getInt("progressid"), rsProgress.getString("progress"));
}
}
}
}
try (PreparedStatement pse = con.prepareStatement("SELECT * FROM medalmaps WHERE characterid = ?")) {
pse.setInt(1, charid);
try (ResultSet rsMedalMaps = pse.executeQuery()) {
while(rsMedalMaps.next()) {
MapleQuestStatus status = loadedQuestStatus.get(rsMedalMaps.getInt("queststatusid"));
if(status != null) {
status.addMedalMap(rsMedalMaps.getInt("mapid"));
}
}
}
}
loadedQuestStatus.clear();
@@ -6391,6 +6435,29 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
ps.setInt(1, ret.getId());
ps.executeUpdate();
ps.close();
Map<MapleDisease, Pair<Long, MobSkill>> loadedDiseases = new LinkedHashMap<>();
ps = con.prepareStatement("SELECT * FROM playerdiseases WHERE charid = ?");
ps.setInt(1, ret.getId());
rs = ps.executeQuery();
while (rs.next()) {
final MapleDisease disease = MapleDisease.ordinal(rs.getInt("disease"));
if(disease == MapleDisease.NULL) continue;
final int skillid = rs.getInt("mobskillid"), skilllv = rs.getInt("mobskilllv");
final long length = rs.getInt("length");
MobSkill ms = MobSkillFactory.getMobSkill(skillid, skilllv);
if(ms != null) {
loadedDiseases.put(disease, new Pair<>(length, ms));
}
}
rs.close();
ps.close();
ps = con.prepareStatement("DELETE FROM playerdiseases WHERE charid = ?");
ps.setInt(1, ret.getId());
ps.executeUpdate();
ps.close();
if(!loadedDiseases.isEmpty()) Server.getInstance().getPlayerBuffStorage().addDiseasesToStorage(ret.id, loadedDiseases);
ps = con.prepareStatement("SELECT * FROM skillmacros WHERE characterid = ?");
ps.setInt(1, charid);
rs = ps.executeQuery();
@@ -6922,7 +6989,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
public synchronized void saveCooldowns() {
List<PlayerCoolDownValueHolder> listcd = getAllCooldowns();
if (listcd.size() > 0) {
if (!listcd.isEmpty()) {
try {
Connection con = DatabaseConnection.getConnection();
deleteWhereCharacterId(con, "DELETE FROM cooldowns WHERE charid = ?");
@@ -6942,6 +7009,33 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
se.printStackTrace();
}
}
Map<MapleDisease, Pair<Long, MobSkill>> listds = getAllDiseases();
if (!listds.isEmpty()) {
try {
Connection con = DatabaseConnection.getConnection();
deleteWhereCharacterId(con, "DELETE FROM playerdiseases WHERE charid = ?");
try (PreparedStatement ps = con.prepareStatement("INSERT INTO playerdiseases (charid, disease, mobskillid, mobskilllv, length) VALUES (?, ?, ?, ?, ?)")) {
ps.setInt(1, getId());
for (Entry<MapleDisease, Pair<Long, MobSkill>> e : listds.entrySet()) {
ps.setInt(2, e.getKey().ordinal());
MobSkill ms = e.getValue().getRight();
ps.setInt(3, ms.getSkillId());
ps.setInt(4, ms.getSkillLevel());
ps.setInt(5, e.getValue().getLeft().intValue());
ps.addBatch();
}
ps.executeBatch();
}
con.close();
} catch (SQLException se) {
se.printStackTrace();
}
}
}
public void saveGuildStatus() {
@@ -7454,13 +7548,6 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
psf.close();
ps.close();
ps = con.prepareStatement("UPDATE accounts SET gm = ? WHERE id = ?");
ps.setInt(1, gmLevel > 1 ? 1 : 0);
ps.setInt(2, client.getAccID());
ps.executeUpdate();
ps.close();
con.commit();
con.setAutoCommit(true);
+17 -3
View File
@@ -516,13 +516,13 @@ public class MapleClient {
ResultSet rs = null;
try {
con = DatabaseConnection.getConnection();
ps = con.prepareStatement("SELECT id, password, salt, gender, banned, gm, pin, pic, characterslots, tos FROM accounts WHERE name = ?");
ps = con.prepareStatement("SELECT id, password, salt, gender, banned, pin, pic, characterslots, tos FROM accounts WHERE name = ?");
ps.setString(1, login);
rs = ps.executeQuery();
if (rs.next()) {
boolean banned = (rs.getByte("banned") == 1);
accId = rs.getInt("id");
gmlevel = rs.getInt("gm");
gmlevel = 0;
pin = rs.getString("pin");
pic = rs.getString("pic");
gender = rs.getByte("gender");
@@ -796,7 +796,6 @@ public class MapleClient {
player.setDisconnectedFromChannelWorld();
player.notifyMapTransferToPartner(-1);
player.cancelAllBuffs(true);
player.cancelAllDebuffs();
player.closePlayerInteractions();
QuestScriptManager.getInstance().dispose(this);
@@ -845,6 +844,7 @@ public class MapleClient {
removePlayer();
player.saveCooldowns();
player.cancelAllDebuffs();
player.saveCharToDB(true);
clear();
@@ -927,6 +927,7 @@ public class MapleClient {
//getChannelServer().removePlayer(player); already being done
player.saveCooldowns();
player.cancelAllDebuffs();
player.saveCharToDB(true);
if (player != null) {//no idea, occur :(
player.empty(false);
@@ -936,6 +937,7 @@ public class MapleClient {
getChannelServer().removePlayer(player);
player.saveCooldowns();
player.cancelAllDebuffs();
player.saveCharToDB();
}
}
@@ -1191,10 +1193,22 @@ public class MapleClient {
}
}
public short getAvailableCharacterSlots() {
return (short) Math.max(0, characterSlots - Server.getInstance().getAccountCharacterCount(accId));
}
public short getAvailableCharacterWorldSlots() {
return (short) Math.max(0, characterSlots - Server.getInstance().getAccountWorldCharacterCount(accId, world));
}
public short getCharacterSlots() {
return characterSlots;
}
public void setCharacterSlots(byte slots) {
characterSlots = slots;
}
public synchronized boolean gainCharacterSlot() {
if (characterSlots < 15) {
Connection con = null;
+10
View File
@@ -21,6 +21,9 @@
*/
package client;
import java.util.ArrayList;
import java.util.List;
public enum MapleDisease {
NULL(0x0),
SLOW(0x1),
@@ -56,4 +59,11 @@ public enum MapleDisease {
return first;
}
public static MapleDisease ordinal(int ord) {
try {
return MapleDisease.values()[ord];
} catch (IndexOutOfBoundsException io) {
return NULL;
}
}
}
+67 -1
View File
@@ -1201,7 +1201,7 @@ public class Commands {
player.dropMessage(5, "Player '" + victim.getName() + "' is at channel " + victim.getClient().getChannel() + ".");
} else {
MapleMap map = victim.getMap();
player.changeMap(map, map.findClosestPortal(victim.getPosition()));
player.forceChangeMap(map, map.findClosestPortal(victim.getPosition()));
}
} else {
player.dropMessage(6, "Unknown player.");
@@ -2417,6 +2417,72 @@ public class Commands {
} catch(Exception e) {}
break;
case "startquest":
if (sub.length < 2){
player.yellowMessage("Syntax: !startquest <questid>");
break;
}
int questid = Integer.parseInt(sub[1]);
if (player.getQuestStatus(questid) == 0) {
MapleQuest quest = MapleQuest.getInstance(questid);
if (quest != null) {
int npcid = quest.getNpcRequirement(false);
quest.forceStart(player, npcid);
player.dropMessage(5, "QUEST " + questid + " started.");
} else {
player.dropMessage(5, "QUESTID " + questid + " is invalid.");
}
} else {
player.dropMessage(5, "QUESTID " + questid + " already started/completed.");
}
break;
case "completequest":
if (sub.length < 2){
player.yellowMessage("Syntax: !completequest <questid>");
break;
}
int questId = Integer.parseInt(sub[1]);
if (player.getQuestStatus(questId) == 1) {
MapleQuest quest = MapleQuest.getInstance(questId);
if (quest != null) {
int npcid = quest.getNpcRequirement(true);
quest.forceComplete(player, npcid);
player.dropMessage(5, "QUEST " + questId + " completed.");
} else { // should not occur
player.dropMessage(5, "QUESTID " + questId + " is invalid.");
}
} else {
player.dropMessage(5, "QUESTID " + questId + " not started or already completed.");
}
break;
case "resetquest":
if (sub.length < 2){
player.yellowMessage("Syntax: !resetquest <questid>");
break;
}
int questid_ = Integer.parseInt(sub[1]);
if (player.getQuestStatus(questid_) != 0) {
MapleQuest quest = MapleQuest.getInstance(questid_);
if (quest != null) {
quest.reset(player);
player.dropMessage(5, "QUEST " + questid_ + " reseted.");
} else { // should not occur
player.dropMessage(5, "QUESTID " + questid_ + " is invalid.");
}
}
break;
default:
return false;
}
+5
View File
@@ -25,6 +25,7 @@ import client.MapleSkinColor;
import client.inventory.Item;
import client.inventory.MapleInventory;
import client.inventory.MapleInventoryType;
import constants.ServerConstants;
import net.server.Server;
import server.MapleItemInformationProvider;
import tools.MaplePacketCreator;
@@ -36,6 +37,10 @@ import tools.MaplePacketCreator;
public abstract class CharacterFactory {
protected synchronized static int createNewCharacter(MapleClient c, String name, int face, int hair, int skin, int gender, CharacterFactoryRecipe recipe) {
if (ServerConstants.COLLECTIVE_CHARSLOT ? c.getAvailableCharacterSlots() <= 0 : c.getAvailableCharacterWorldSlots() <= 0) {
return -3;
}
if (!MapleCharacter.canCreateChar(name)) {
return -1;
}
+1 -1
View File
@@ -470,7 +470,7 @@ public class Equip extends Item {
lvupStr += "+UPGSLOT ";
}
showLevelupMessage(showStr, c); // thx to Polaris dev team !
showLevelupMessage(showStr, c); // thanks to Polaris dev team !
c.getPlayer().dropMessage(6, lvupStr);
c.announce(MaplePacketCreator.showEquipmentLevelUp());
+1
View File
@@ -32,6 +32,7 @@ public class ServerConstants {
public static final boolean AUTOMATIC_REGISTER = true; //Automatically register players when they login with a nonexistent username.
public static final boolean BCRYPT_MIGRATION = true; //Performs a migration from old SHA-1 and SHA-512 password to bcrypt.
public static final boolean COLLECTIVE_CHARSLOT = false; //Available character slots are contabilized globally rather than per world server.
//Ip Configuration
public static String HOST;
+44 -7
View File
@@ -100,6 +100,7 @@ public class Server {
private final Properties subnetInfo = new Properties();
private static Server instance = null;
private final Map<Integer, Set<Integer>> accountChars = new HashMap<>();
private final Map<Integer, Short> accountCharacterCount = new HashMap<>();
private final Map<Integer, Integer> worldChars = new HashMap<>();
private final Map<String, Integer> transitioningChars = new HashMap<>();
private List<Pair<Integer, String>> worldRecommendedList = new LinkedList<>();
@@ -601,9 +602,7 @@ public class Server {
MapleClient c = processDiseaseAnnounceClients.remove(0);
MapleCharacter player = c.getPlayer();
if(player != null && player.isLoggedinWorld()) {
for(MapleCharacter chr : player.getMap().getCharacters()) {
chr.announceDiseases(c);
}
player.announceDiseases();
}
}
@@ -1089,6 +1088,32 @@ public class Server {
}
}
public short getAccountCharacterCount(Integer accountid) {
lgnRLock.lock();
try {
return accountCharacterCount.get(accountid);
} finally {
lgnRLock.unlock();
}
}
public short getAccountWorldCharacterCount(Integer accountid, Integer worldid) {
lgnRLock.lock();
try {
short count = 0;
for(Integer chr : accountChars.get(accountid)) {
if(worldChars.get(chr).equals(worldid)) {
count++;
}
}
return count;
} finally {
lgnRLock.unlock();
}
}
private Set<Integer> getAccountCharacterEntries(Integer accountid) {
lgnRLock.lock();
try {
@@ -1115,6 +1140,8 @@ public class Server {
lgnWLock.lock();
try {
accountCharacterCount.put(accountid, (short)(accountCharacterCount.get(accountid) + 1));
Set<Integer> accChars = accountChars.get(accountid);
accChars.add(chrid);
@@ -1132,6 +1159,8 @@ public class Server {
public void deleteCharacterEntry(Integer accountid, Integer chrid) {
lgnWLock.lock();
try {
accountCharacterCount.put(accountid, (short)(accountCharacterCount.get(accountid) - 1));
Set<Integer> accChars = accountChars.get(accountid);
accChars.remove(chrid);
@@ -1169,6 +1198,7 @@ public class Server {
public void deleteAccountEntry(Integer accountid) { is this even a thing?
lgnWLock.lock();
try {
accountCharacterCount.remove(accountid);
accountChars.remove(accountid);
} finally {
lgnWLock.unlock();
@@ -1190,6 +1220,7 @@ public class Server {
List<MapleCharacter> wchars = w.getAccountCharactersView(accountId);
if(wchars == null) {
if(!accountChars.containsKey(accountId)) {
accountCharacterCount.put(accountId, (short) 0);
accountChars.put(accountId, new HashSet<Integer>()); // not advisable at all to write on the map on a read-protected environment
} // yet it's known there's no problem since no other point in the source does
} else if(!wchars.isEmpty()) { // this action.
@@ -1206,7 +1237,8 @@ public class Server {
return new Pair<>(new Pair<>(chrTotal, lastwchars), accChars);
}
private static List<List<MapleCharacter>> loadAccountCharactersViewFromDb(int accId, int wlen) {
private static Pair<Short, List<List<MapleCharacter>>> loadAccountCharactersViewFromDb(int accId, int wlen) {
short characterCount = 0;
List<List<MapleCharacter>> wchars = new ArrayList<>(wlen);
for(int i = 0; i < wlen; i++) wchars.add(i, new LinkedList<MapleCharacter>());
@@ -1231,8 +1263,10 @@ public class Server {
ps.setInt(1, accId);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
characterCount++;
int cworld = rs.getByte("world");
if(cworld >= wlen) break;
if(cworld >= wlen) continue;
if(cworld > curWorld) {
wchars.add(curWorld, chars);
@@ -1253,7 +1287,7 @@ public class Server {
sqle.printStackTrace();
}
return wchars;
return new Pair<>(characterCount, wchars);
}
public void loadAccountCharacters(MapleClient c) {
@@ -1300,10 +1334,13 @@ public class Server {
private int loadAccountCharactersView(Integer accId, int gmLevel, int fromWorldid) { // returns the maximum gmLevel found
List<World> wlist = this.getWorlds();
List<List<MapleCharacter>> accChars = loadAccountCharactersViewFromDb(accId, wlist.size());
Pair<Short, List<List<MapleCharacter>>> accCharacters = loadAccountCharactersViewFromDb(accId, wlist.size());
lgnWLock.lock();
try {
List<List<MapleCharacter>> accChars = accCharacters.getRight();
accountCharacterCount.put(accId, accCharacters.getLeft());
Set<Integer> chars = accountChars.get(accId);
if(chars == null) {
chars = new HashSet<>(5);
@@ -75,6 +75,7 @@ public enum MonitoredLockType {
EM_LOBBY,
EM_QUEUE,
EM_SCHDL,
EM_START,
CASHSHOP,
VISITOR_PSHOP,
STORAGE,
@@ -37,6 +37,11 @@ public final class OwlWarpHandler extends AbstractMaplePacketHandler {
int ownerid = slea.readInt();
int mapid = slea.readInt();
if(ownerid == c.getPlayer().getId()) {
c.announce(MaplePacketCreator.serverNotice(1, "You cannot visit your own shop."));
return;
}
MapleHiredMerchant hm = c.getWorldServer().getHiredMerchant(ownerid); // if both hired merchant and player shop is on the same map
MaplePlayerShop ps;
if(hm == null || hm.getMapId() != mapid || !hm.hasItem(c.getPlayer().getOwlSearch())) {
@@ -27,6 +27,7 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import net.AbstractMaplePacketHandler;
import net.server.PlayerBuffValueHolder;
@@ -90,6 +91,7 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
e.printStackTrace();
}
} else {
c.setCharacterSlots((byte) player.getClient().getCharacterSlots());
player.newClient(c);
}
if (player == null) { //If you are still getting null here then please just uninstall the game >.>, we dont need you fucking with the logs
@@ -275,16 +277,6 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
c.announce(MaplePacketCreator.enableReport());
player.changeSkillLevel(SkillFactory.getSkill(10000000 * player.getJobType() + 12), (byte) (player.getLinkedLevel() / 10), 20, -1);
player.checkBerserk(player.isHidden());
player.buffExpireTask();
player.diseaseExpireTask();
player.skillCooldownTask();
player.expirationTask();
player.questExpirationTask();
if (GameConstants.hasSPTable(player.getJob()) && player.getJob().getId() != 2001) {
player.createDragon();
}
player.commitExcludedItems();
if (newcomer){
/*
@@ -295,12 +287,31 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
if (player.isGM()){
Server.getInstance().broadcastGMMessage(c.getWorld(), MaplePacketCreator.earnTitleMessage((player.gmLevel() < 6 ? "GM " : "Admin ") + player.getName() + " has logged in"));
}
if(diseases != null) {
for(Entry<MapleDisease, Pair<Long, MobSkill>> e : diseases.entrySet()) {
final List<Pair<MapleDisease, Integer>> debuff = Collections.singletonList(new Pair<>(e.getKey(), Integer.valueOf(e.getValue().getRight().getX())));
c.announce(MaplePacketCreator.giveDebuff(debuff, e.getValue().getRight()));
}
player.announceDiseases();
}
} else {
if(player.isRidingBattleship()) {
player.announceBattleshipHp();
}
}
player.buffExpireTask();
player.diseaseExpireTask();
player.skillCooldownTask();
player.expirationTask();
player.questExpirationTask();
if (GameConstants.hasSPTable(player.getJob()) && player.getJob().getId() != 2001) {
player.createDragon();
}
player.commitExcludedItems();
showDueyNotification(c, player);
if (player.getMap().getHPDec() > 0) player.resetHpDecreaseTask();
@@ -39,8 +39,8 @@ public final class ScriptedItemHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
slea.readInt(); // trash stamp (thx rmzero)
short itemSlot = slea.readShort(); // item sl0t (thx rmzero)
slea.readInt(); // trash stamp (thanks rmzero)
short itemSlot = slea.readShort(); // item slot (thanks rmzero)
int itemId = slea.readInt(); // itemId
scriptedItem info = ii.getScriptedItemInfo(itemId);
if (info == null) return;
@@ -34,6 +34,7 @@ import client.inventory.ModifyInventory;
import constants.ItemConstants;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import net.AbstractMaplePacketHandler;
import client.inventory.manipulator.MapleInventoryManipulator;
import server.MapleItemInformationProvider;
@@ -72,10 +73,17 @@ public final class ScrollHandler extends AbstractMaplePacketHandler {
Item scroll = useInventory.getItem(slot);
Item wscroll = null;
if (((Equip) toScroll).getUpgradeSlots() < 1 && !ItemConstants.isCleanSlate(scroll.getItemId())) {
if (ItemConstants.isCleanSlate(scroll.getItemId())) {
Map<String, Integer> eqStats = ii.getEquipStats(scroll.getItemId());
if (eqStats == null || eqStats.get("tuc") == 0) {
c.announce(MaplePacketCreator.getInventoryFull());
return;
}
} else if (((Equip) toScroll).getUpgradeSlots() < 1) {
c.announce(MaplePacketCreator.getInventoryFull());
return;
}
List<Integer> scrollReqs = ii.getScrollReqs(scroll.getItemId());
if (scrollReqs.size() > 0 && !scrollReqs.contains(toScroll.getItemId())) {
c.announce(MaplePacketCreator.getInventoryFull());
@@ -27,7 +27,6 @@ import java.sql.SQLException;
import net.AbstractMaplePacketHandler;
import net.server.world.World;
import tools.LogHelper;
import tools.DatabaseConnection;
import tools.FilePrinter;
import tools.MaplePacketCreator;
@@ -43,6 +42,7 @@ import java.sql.Connection;
*/
public final class WhisperHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
byte mode = slea.readByte();
if (mode == 6) { // whisper
@@ -92,7 +92,7 @@ public final class WhisperHandler extends AbstractMaplePacketHandler {
} else {
c.announce(MaplePacketCreator.getFindReply(victim.getName(), victim.getMap().getId(), 1));
}
} else { // not found
} else if (c.getPlayer().gmLevel() > 1) { // not found
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT gm FROM characters WHERE name = ?");
@@ -116,6 +116,8 @@ public final class WhisperHandler extends AbstractMaplePacketHandler {
} catch (SQLException e) {
e.printStackTrace();
}
} else {
c.announce(MaplePacketCreator.getWhisperReply(recipient, (byte) 0));
}
} else if (mode == 0x44) {
//Buddy find?
+12 -1
View File
@@ -117,6 +117,7 @@ public class MapleGuild {
return;
}
Set<Integer> chs = Server.getInstance().getOpenChannels(world);
synchronized (notifications) {
if (notifications.keySet().size() != chs.size()) {
notifications.clear();
for (Integer ch : chs) {
@@ -127,6 +128,7 @@ public class MapleGuild {
l.clear();
}
}
}
membersLock.lock();
try {
@@ -134,7 +136,11 @@ public class MapleGuild {
if (!mgc.isOnline()) {
continue;
}
List<Integer> chl = notifications.get(mgc.getChannel());
List<Integer> chl;
synchronized (notifications) {
chl = notifications.get(mgc.getChannel());
}
if (chl != null) chl.add(mgc.getId());
//Unable to connect to Channel... error was here
}
@@ -279,6 +285,8 @@ public class MapleGuild {
}
public void broadcast(final byte[] packet, int exceptionId, BCOp bcop) {
membersLock.lock(); // membersLock awareness thanks to ProjectNano dev team
try {
synchronized (notifications) {
if (bDirty) {
buildNotifications();
@@ -300,6 +308,9 @@ public class MapleGuild {
System.out.println("Failed to contact channel(s) for broadcast.");//fu?
}
}
} finally {
membersLock.unlock();
}
}
public void guildMessage(final byte[] serverNotice) {
+10 -6
View File
@@ -224,14 +224,18 @@ public class EventInstanceManager {
}
public void registerPlayer(MapleCharacter chr) {
if (chr == null || !chr.isLoggedin()){
public synchronized void registerPlayer(MapleCharacter chr) {
if (chr == null || !chr.isLoggedinWorld() || disposed) {
return;
}
try {
wL.lock();
try {
if(chars.containsKey(chr.getId())) {
return;
}
chars.put(chr.getId(), chr);
chr.setEventInstance(this);
} finally {
@@ -249,7 +253,7 @@ public class EventInstanceManager {
}
}
public void exitPlayer(MapleCharacter chr) { //unused
public void exitPlayer(MapleCharacter chr) {
if (chr == null || !chr.isLoggedin()){
return;
}
@@ -299,7 +303,7 @@ public class EventInstanceManager {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, "Event '" + em.getName() + "' does not implement scheduledTimeout function.", ex);
}
}
}, time);
@@ -324,7 +328,7 @@ public class EventInstanceManager {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, "Event '" + em.getName() + "' does not implement scheduledTimeout function.", ex);
}
}
}, nextTime);
@@ -397,7 +401,7 @@ public class EventInstanceManager {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, "Event '" + em.getName() + "' does not implement playerUnregistered function.", ex);
}
wL.lock();
+114 -4
View File
@@ -48,10 +48,14 @@ import server.life.MapleMonster;
import server.life.MapleLifeFactory;
import server.quest.MapleQuest;
import java.util.List;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import net.server.audit.LockCollector;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReentrantLock;
@@ -74,11 +78,15 @@ public class EventManager {
private final Map<Integer, Integer> queuedGuildLeaders = new HashMap<>();
private List<Boolean> openedLobbys;
private List<EventInstanceManager> readyInstances = new LinkedList<>();
private Integer readyId = 0;
private Integer readyId = 0, onLoadInstances = 0;
private Properties props = new Properties();
private String name;
private MonitoredReentrantLock lobbyLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.EM_LOBBY);
private MonitoredReentrantLock queueLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.EM_QUEUE);
private MonitoredReentrantLock startLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.EM_START);
private Set<Integer> playerPermit = new HashSet<>();
private Semaphore startSemaphore = new Semaphore(7);
private static final int maxLobbys = 8; // an event manager holds up to this amount of concurrent lobbys
@@ -114,6 +122,7 @@ public class EventManager {
try {
readyEims = new ArrayList<>(readyInstances);
readyInstances.clear();
onLoadInstances = Integer.MIN_VALUE / 2;
} finally {
queueLock.unlock();
}
@@ -143,6 +152,7 @@ public class EventManager {
private void emptyLocks() {
lobbyLock = lobbyLock.dispose();
queueLock = queueLock.dispose();
startLock = startLock.dispose();
}
private static List<Integer> convertToIntegerArray(List<Double> list) {
@@ -332,6 +342,12 @@ public class EventManager {
//Expedition method: starts an expedition
public boolean startInstance(int lobbyId, MapleExpedition exped, MapleCharacter leader) {
try {
if(!playerPermit.contains(leader.getId()) && startSemaphore.tryAcquire(7777, TimeUnit.MILLISECONDS)) {
playerPermit.add(leader.getId());
startLock.lock();
try {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
@@ -360,6 +376,17 @@ public class EventManager {
}
return true;
} finally {
startLock.unlock();
playerPermit.remove(leader.getId());
startSemaphore.release();
}
}
} catch(InterruptedException ie) {
playerPermit.remove(leader.getId());
}
return false;
}
//Regular method: player
@@ -372,6 +399,12 @@ public class EventManager {
}
public boolean startInstance(int lobbyId, MapleCharacter chr, MapleCharacter leader, int difficulty) {
try {
if(!playerPermit.contains(leader.getId()) && startSemaphore.tryAcquire(7777, TimeUnit.MILLISECONDS)) {
playerPermit.add(leader.getId());
startLock.lock();
try {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
@@ -403,6 +436,17 @@ public class EventManager {
}
return true;
} finally {
startLock.unlock();
playerPermit.remove(leader.getId());
startSemaphore.release();
}
}
} catch(InterruptedException ie) {
playerPermit.remove(leader.getId());
}
return false;
}
//PQ method: starts a PQ
@@ -415,6 +459,12 @@ public class EventManager {
}
public boolean startInstance(int lobbyId, MapleParty party, MapleMap map, MapleCharacter leader) {
try {
if(!playerPermit.contains(leader.getId()) && startSemaphore.tryAcquire(7777, TimeUnit.MILLISECONDS)) {
playerPermit.add(leader.getId());
startLock.lock();
try {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
@@ -443,6 +493,17 @@ public class EventManager {
}
return true;
} finally {
startLock.unlock();
playerPermit.remove(leader.getId());
startSemaphore.release();
}
}
} catch(InterruptedException ie) {
playerPermit.remove(leader.getId());
}
return false;
}
//PQ method: starts a PQ with a difficulty level, requires function setup(difficulty, leaderid) instead of setup()
@@ -455,6 +516,12 @@ public class EventManager {
}
public boolean startInstance(int lobbyId, MapleParty party, MapleMap map, int difficulty, MapleCharacter leader) {
try {
if(!playerPermit.contains(leader.getId()) && startSemaphore.tryAcquire(7777, TimeUnit.MILLISECONDS)) {
playerPermit.add(leader.getId());
startLock.lock();
try {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
@@ -483,6 +550,17 @@ public class EventManager {
}
return true;
} finally {
startLock.unlock();
playerPermit.remove(leader.getId());
startSemaphore.release();
}
}
} catch(InterruptedException ie) {
playerPermit.remove(leader.getId());
}
return false;
}
//non-PQ method for starting instance
@@ -499,6 +577,12 @@ public class EventManager {
}
public boolean startInstance(int lobbyId, EventInstanceManager eim, String ldr, MapleCharacter leader) {
try {
if(!playerPermit.contains(leader.getId()) && startSemaphore.tryAcquire(7777, TimeUnit.MILLISECONDS)) {
playerPermit.add(leader.getId());
startLock.lock();
try {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
@@ -526,6 +610,17 @@ public class EventManager {
}
return true;
} finally {
startLock.unlock();
playerPermit.remove(leader.getId());
startSemaphore.release();
}
}
} catch(InterruptedException ie) {
playerPermit.remove(leader.getId());
}
return false;
}
public List<MaplePartyCharacter> getEligibleParty(MapleParty party) {
@@ -713,16 +808,31 @@ public class EventManager {
}
private void instantiateQueuedInstance() {
int nextEventId;
queueLock.lock();
try {
if(readyInstances.size() >= Math.ceil((double)maxLobbys / 3.0)) return;
if(onLoadInstances <= -1000 || readyInstances.size() + onLoadInstances >= Math.ceil((double)maxLobbys / 3.0)) return;
readyInstances.add(new EventInstanceManager(this, "sampleName" + readyId));
onLoadInstances++;
nextEventId = readyId;
readyId++;
} finally {
queueLock.unlock();
}
EventInstanceManager eim = new EventInstanceManager(this, "sampleName" + nextEventId);
queueLock.lock();
try {
if(onLoadInstances <= -1000) { // EM already disposed
return;
}
readyInstances.add(eim);
onLoadInstances--;
} finally {
queueLock.unlock();
}
instantiateQueuedInstance(); // keep filling the queue until reach threshold.
}
@@ -344,7 +344,9 @@ public class NPCConversationManager extends AbstractPlayerInteraction {
public void gainCloseness(int closeness) {
for (MaplePet pet : getPlayer().getPets()) {
if(pet != null) pet.gainClosenessFullness(getPlayer(), closeness, 0, 0);
if(pet != null) {
pet.gainClosenessFullness(getPlayer(), closeness, 0, 0);
}
}
}
+1 -1
View File
@@ -38,7 +38,7 @@ import client.MapleCharacter;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public class MapleExpedition {
@@ -26,7 +26,7 @@ import constants.ServerConstants;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public enum MapleExpeditionType {
+1 -1
View File
@@ -2,7 +2,7 @@ package server.gachapon;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public class Ellinia extends GachaponItems {
+1 -1
View File
@@ -24,7 +24,7 @@ package server.gachapon;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public abstract class GachaponItems {
+1 -1
View File
@@ -2,7 +2,7 @@ package server.gachapon;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public class Global extends GachaponItems {
+1 -1
View File
@@ -2,7 +2,7 @@ package server.gachapon;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public class Henesys extends GachaponItems {
+1 -1
View File
@@ -2,7 +2,7 @@ package server.gachapon;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public class KerningCity extends GachaponItems {
+1 -1
View File
@@ -25,7 +25,7 @@ import tools.Randomizer;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public class MapleGachapon {
+1 -1
View File
@@ -2,7 +2,7 @@ package server.gachapon;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public class MushroomShrine extends GachaponItems {
+1 -1
View File
@@ -2,7 +2,7 @@ package server.gachapon;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public class NautilusHarbor extends GachaponItems {
+1 -1
View File
@@ -2,7 +2,7 @@ package server.gachapon;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public class NewLeafCity extends GachaponItems {
+1 -1
View File
@@ -2,7 +2,7 @@ package server.gachapon;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public class Perion extends GachaponItems {

Some files were not shown because too many files have changed in this diff Show More