Using Java ThreadPool + Mob Skills & Event Instance patch + Eqp Merge
Server source now uses Java ThreadPool, recycling used thread resources for next uses. Added Grenade visual effect for other players. Implemented an attempt towards unsynced mob behavior, where reportedly players were able to pin same mob in different sections of the map. Solved several deadlock issues, mostly regarding character synchronized methods, event instance scripts and player/item vision-unvision. Solved an issue where mobs would not cast some skills of it's skillset. Frequent behavior on low-leveled mobs. Fixed a bug on 2nd Maker quest where players could complete it by merely disassembling an equipment. New custom mechanic: equipment merge. Similarly to the Bazaar NPC, every equipment after the selected one is used up, and a fraction of their stat amounts are used as stat gains on the currently equipped items. If restrictions are enabled, players must be high-leveled and Maker lv3 to use it. Skill Storm Break no longer uses up arrows. Added a server flag to allow access for all Aran job skills from the beginning. Implemented Battleship and Super Transformation questline scripts. Fixed a desynchronization within pet position and cash inventory position, that could potentially lead to some inventory issues until relogin. Improved timestamp handling in some handler classes. Spam detection is entirely a server-side matter, hence removed usage of client-sided timestamp content. Refactored some pet response packets, improving some of their behaviors. Fixed some quest issues: Maker lv1 and Omega Sector meteorite one.
This commit is contained in:
@@ -9,7 +9,7 @@ Regarding distributability and usage of the code presented here: like it was bef
|
||||
|
||||
This is a NetBeans 8.0.2 Project, that MUST be built and run under JDK/JRE 7 (1.7.0_79+) in order to run properly. This means that it's easier to install the project via opening the server project folder inside NetBeans' IDE. Once installed, build this project on your machine and run the server using the "launch.bat" application.
|
||||
|
||||
In this project, many gameplay-wise issues generated from either the original WZ files and the server source have been partially or completely solved. Considering the use of the provided edited WZ's and server-side wz.xml files should be of the greatest importance when dealing with this instance of server source, in order to perceive it at it's full potential. My opinion, though! Refer to "README_wzchanges.txt" for more information on what has been changed from Nexon's v83 WZ files.
|
||||
In this project, many gameplay-wise issues generated from either the original WZ files and the server source have been partially or completely solved. Considering the use of the provided edited WZ's and server-side wz.xml files should be of the greatest importance when dealing with this instance of server source, in order to perceive it at it's full potential. My opinion, though!
|
||||
|
||||
The main objective of this project is to try as best as possible to recreate what once was the original MapleStory v83, while adding up some flavors that spices up the gameplay. In other words, aim to get the best of the MapleStory of that era.
|
||||
|
||||
@@ -48,7 +48,7 @@ Client files & general tools: https://drive.google.com/drive/folders/0BzDsHSr-0V
|
||||
|
||||
* Fraysa's https://hostr.co/gJbLZITRVHmv
|
||||
|
||||
* MapleSilver's starting on window-mode.
|
||||
* Eric's MapleSilver starting on window-mode.
|
||||
|
||||
---
|
||||
### Development information
|
||||
@@ -175,7 +175,7 @@ Finally, select "Clean and Build project" to build the JAR file for the MapleSto
|
||||
The client's set-up is quite straightforward:
|
||||
|
||||
1. From "ManagerMsv83.exe", install MapleStory on your folder of preference (e.g. "C:\Nexon\MapleStory") and follow their instructions.
|
||||
2. Once done, erase these files: "HShield" (folder), "ASPLauncher.exe", "MapleStory.exe" and "patcher.exe".
|
||||
2. Once done, erase these files: "HShield" (folder), "ASPLnchr.exe", "MapleStory.exe" and "Patcher.exe".
|
||||
3. Extract into the client folder the "localhost.exe" from the provided link.
|
||||
4. Overwrite the original WZ files with the ones provided from either one of those folders on the Google Drive:
|
||||
- "commit???_wz" (last published RELEASE, referring to commit of same number).
|
||||
|
||||
@@ -89,6 +89,7 @@ Cash & Items:
|
||||
* Storage with "Arrange Items" feature functional.
|
||||
* Close-quarters evaluation mode for items (sandbox).
|
||||
* Further improved Karma scissors & Untradeable items mechanics.
|
||||
* Reviewed pet/item position data inconsistency within CASH inventory.
|
||||
* Spikes on shoes.
|
||||
* Vega's spell.
|
||||
* Owl of Minerva.
|
||||
@@ -175,6 +176,7 @@ Server potentials:
|
||||
* Delete Character (requires ENABLE_PIC activated).
|
||||
* Smoothed up view-all-char feature, now showing properly all available characters and not disconnecting players too often.
|
||||
* Centralized getcurrenttime throughout several server handlers, boosting it's performance overall.
|
||||
* Centralized server timestamping, several timestamps received from clients are now unused, preventing some spammable exploits.
|
||||
* Autosaver (periodically saves on DB current state of every player in-game).
|
||||
* Both fixed and randomized versions of HP/MP growth rate available, regarding player job (enable one at ServerConstants). Placeholder for HP/MP washing feature.
|
||||
* Implemented methods to get the current Players' MaxHP/MaxMP method with equipment HP/MP gains already summed up.
|
||||
@@ -191,6 +193,7 @@ Custom NPCs:
|
||||
* Asia: scroll & rarities shop NPC.
|
||||
* Abdula: lists droppers of needed skill/mastery books.
|
||||
* Agent E: accessory crafter.
|
||||
* Dalair: automatized equipment-merger.
|
||||
* Donation Box: automatized item-buyer.
|
||||
* Coco & Ace of Hearts: C. scroll crafters.
|
||||
|
||||
@@ -239,6 +242,7 @@ Project:
|
||||
* Reviewed SQL data, eliminating duplicated entries on the tables.
|
||||
* Improved login phase, using cache over DB queries.
|
||||
* Usage of HikariCP to improve the DB connection management.
|
||||
* Usage of Java Threadpool to improve runnable call management.
|
||||
* Developed many survey tools for content profiling.
|
||||
* Developed a robust anti-exploit login coordinator system.
|
||||
* Protected many flaws with login management system.
|
||||
|
||||
+43
-4
@@ -2,12 +2,15 @@
|
||||
Spiegelmann -> 2042000
|
||||
Coco -> 9000017
|
||||
Agent E -> 9000036
|
||||
Dalair -> 9000040
|
||||
Donation Box -> 9000041
|
||||
Abdula -> 9209000
|
||||
Abdula -> 9209000 *
|
||||
|
||||
CUSTOM NPC SHOPS:
|
||||
Asia -> 2082014
|
||||
T-1337 -> 9201101
|
||||
CUSTOM NPC SHOPS (db_shopupdate.sql):
|
||||
Asia -> 2082014 *
|
||||
T-1337 -> 9201101 *
|
||||
|
||||
* : those won't get disabled when USE_ENABLE_CUSTOM_NPC_SCRIPTS = false
|
||||
|
||||
LOGS:
|
||||
|
||||
@@ -1415,3 +1418,39 @@ Removido possibilidade de preparar engagements enquanto segurando aneis de casam
|
||||
|
||||
23 Outubro 2018,
|
||||
Adicionado script para quest de 4o job de Cygnus Knights.
|
||||
|
||||
25 - 27 Outubro 2018,
|
||||
Scripts de eventos agora executam em uma thread separada, assim resolvendo possíveis problemas de deadlocks.
|
||||
Realizada tentativa de solução para casos onde jogadores percebem mobs em pontos diferentes do mapa em certas situações.
|
||||
Clareado um problema de deadlock relacionado a packets de visão/desaparecimento de jogadores e mobs.
|
||||
Resolvido diversos problemas de deadlocks relacionados com event instances.
|
||||
Implementado ThreadManager. Este sistema utiliza a abordagem de ThreadPool para reciclagem de threads utilizadas, assim eliminando realização de overhead ao criar novas threads a todo uso.
|
||||
Resolvido certos casos onde requisição de item pickup de jogador não era devidamente registrado pelo servidor como ação válida.
|
||||
|
||||
29 - 31 Outubro 2018,
|
||||
Corrigido mobs não lançando skills em determinados casos. Comportamento notável era mobs de nível baixo utilizando nenhuma skill.
|
||||
Skill Storm Break não mais remove flechas ao ser utilizada.
|
||||
Implementado método que força alteração na posição atual de mobs no mapa.
|
||||
Mobs que forem atacados de muito longe terão suas posições atualizadas para todos os jogadores no mapa, buscando assim evitar dessincronizações entre clientes.
|
||||
Adicionado drops de red bean porridge em alguns mobs de El Nath.
|
||||
Implementado flag para opção de aquisição de belts de Dojo regular ou fácil.
|
||||
Corrigido map banish de mobs não funcionando corretamente após as últimas atualizações do MoveLifeHandler.
|
||||
Corrigido bug na quest do 2nd Maker que permitia conclusão de quest ao realizar disassemble em equipamentos.
|
||||
Adicionado nova mecânica custom: amalgama de equipamentos. Jogadores acima do nível 160, que possuem Maker level 3, poderão utilizar esta mecânica para alavancar atributos dos itens equipados.
|
||||
Refatorado método de ganho de fama para não mais usar modificador synchronized, assim evitando possível caso de deadlock.
|
||||
Adicionado server flag que permite acesso a todas as skills de job de Aran ao iniciar novo job.
|
||||
Corrigido horário irregular no sistema do servidor.
|
||||
Adicionado scripts para skill quests de Battleship e Super Transformation.
|
||||
|
||||
03 Novembro 2018,
|
||||
Corrigido caso onde pets estavam com posições de inventário desatualizadas, levando a certas inconsistências com evoluir/administrar pets.
|
||||
|
||||
05 Novembro 2018,
|
||||
Alterado administração de timestamp nos handlers. Agora detecção de spam é inteiramente responsabilidade do servidor, onde a detecção de spam ocorre de acordo com quantidade de vezes que um pacote é recebido num dado intervalo de tempo estipulado internamente.
|
||||
Refatorado packets que lidam com respostas a comandos de pets.
|
||||
|
||||
07 - 09 Novembro 2018,
|
||||
Corrigido drop data de Ultra Gray com item inexistente.
|
||||
Corrigido quest de meteoritos mudando estado da quest mesmo quando jogador não recebe o item devido a inventário cheio.
|
||||
Corrigido quest de Maker lv1 retirando mesos além da quantidade esperada, ao realizar ações da quest.
|
||||
Adicionado server flag que lida com utilização de features NPCs custom.
|
||||
@@ -0,0 +1,28 @@
|
||||
Source: http://metropi.forumotion.net/t32-npc-scripting-guide-from-ragezone
|
||||
|
||||
NPC Markups:
|
||||
#b = Blue text.
|
||||
#c[itemid]# Shows how many [itemid] the player has in their inventory.
|
||||
#d = Purple text.
|
||||
#e = Bold text.
|
||||
#f[imagelocation]# - Shows an image inside the .wz files.
|
||||
#g = Green text.
|
||||
#h # - Shows the name of the player.
|
||||
#i[itemid]# - Shows a picture of the item.
|
||||
#k = Black text.
|
||||
#l - Selection close.
|
||||
#m[mapid]# - Shows the name of the map.
|
||||
#n = Normal text (removes bold).
|
||||
#o[mobid]# - Shows the name of the mob.
|
||||
#p[npcid]# - Shows the name of the NPC.
|
||||
#q[skillid]# - Shows the name of the skill.
|
||||
#r = Red text.
|
||||
#s[skillid]# - Shows the image of the skill.
|
||||
#t[itemid]# - Shows the name of the item.
|
||||
#v[itemid]# - Shows a picture of the item.
|
||||
#x - Returns "0%" (need more information on this).
|
||||
#z[itemid]# - Shows the name of the item.
|
||||
#B[%]# - Shows a 'progress' bar.
|
||||
#F[imagelocation]# - Shows an image inside the .wz files.
|
||||
#L[number]# Selection open.
|
||||
\r\n - Moves down a line.
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
/**
|
||||
* @Author Ronan
|
||||
* Event - Kyrin's Test Quest
|
||||
**/
|
||||
|
||||
var entryMap = 912010000;
|
||||
var exitMap = 120000101;
|
||||
|
||||
var minMapId = 912010000;
|
||||
var maxMapId = 912010200;
|
||||
|
||||
var eventTime = 4; //4 minutes
|
||||
|
||||
var lobbyRange = [0, 0];
|
||||
|
||||
function setLobbyRange() {
|
||||
return lobbyRange;
|
||||
}
|
||||
|
||||
function init() {
|
||||
em.setProperty("noEntry","false");
|
||||
}
|
||||
|
||||
function setup(level, lobbyid) {
|
||||
var eim = em.newInstance("4jship_" + lobbyid);
|
||||
eim.setProperty("level", level);
|
||||
eim.setProperty("boss", "0");
|
||||
eim.setProperty("canLeave", "0");
|
||||
|
||||
eim.getInstanceMap(entryMap).resetPQ(level);
|
||||
|
||||
respawnStages(eim);
|
||||
eim.startEventTimer(eventTime * 60000);
|
||||
eim.schedule("playerCanLeave", 1 * 60000);
|
||||
eim.schedule("playerSurvived", 2 * 60000);
|
||||
return eim;
|
||||
}
|
||||
|
||||
function afterSetup(eim) {}
|
||||
|
||||
function respawnStages(eim) {}
|
||||
|
||||
function playerCanLeave(eim) {
|
||||
eim.setIntProperty("canLeave", 1);
|
||||
}
|
||||
|
||||
function playerSurvived(eim) {
|
||||
if (eim.getLeader().isAlive()) {
|
||||
eim.setIntProperty("canLeave", 2);
|
||||
eim.dropMessage(5, "Kyrin: You have passed the test. Now for the closing part... Are you able reach the exit over there?");
|
||||
} else {
|
||||
eim.dropMessage(5, "Kyrin: You have failed the test. Aww, don't have such a sad face, just try it again later, ok?");
|
||||
}
|
||||
}
|
||||
|
||||
function playerEntry(eim, player) {
|
||||
var map = eim.getMapInstance(entryMap);
|
||||
player.changeMap(map, map.getPortal(0));
|
||||
}
|
||||
|
||||
function playerUnregistered(eim, player) {}
|
||||
|
||||
function playerExit(eim, player) {
|
||||
eim.unregisterPlayer(player);
|
||||
eim.dispose();
|
||||
em.setProperty("noEntry","false");
|
||||
}
|
||||
|
||||
function playerLeft(eim, player) {}
|
||||
|
||||
function scheduledTimeout(eim) {
|
||||
var player = eim.getPlayers().get(0);
|
||||
playerExit(eim, player);
|
||||
player.changeMap(exitMap);
|
||||
}
|
||||
|
||||
function playerDisconnected(eim, player) {
|
||||
playerExit(eim, player);
|
||||
}
|
||||
|
||||
function changedMap(eim, chr, mapid) {
|
||||
if(mapid < minMapId || mapid > maxMapId) playerExit(eim, chr);
|
||||
}
|
||||
|
||||
function clearPQ(eim) {
|
||||
eim.stopEventTimer();
|
||||
eim.setEventCleared();
|
||||
|
||||
var player = eim.getPlayers().get(0);
|
||||
eim.unregisterPlayer(player);
|
||||
player.changeMap(exitMap);
|
||||
|
||||
eim.dispose();
|
||||
em.setProperty("noEntry","false");
|
||||
}
|
||||
|
||||
function monsterKilled(mob, eim) {}
|
||||
|
||||
function leftParty(eim, player) {}
|
||||
|
||||
function disbandParty(eim) {}
|
||||
|
||||
function monsterValue(eim, mobId) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
function friendlyKilled(mob, eim) {
|
||||
if(em.getProperty("noEntry") != "false") {
|
||||
var player = eim.getPlayers().get(0);
|
||||
playerExit(eim, player);
|
||||
player.changeMap(exitMap);
|
||||
}
|
||||
}
|
||||
|
||||
function allMonstersDead(eim) {}
|
||||
|
||||
function cancelSchedule() {}
|
||||
|
||||
function dispose() {}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
/**
|
||||
* @Author Ronan
|
||||
* Event - Kyrin's Test Quest
|
||||
**/
|
||||
|
||||
var entryMap = 912010100;
|
||||
var exitMap = 120000101;
|
||||
|
||||
var minMapId = 912010100;
|
||||
var maxMapId = 912010200;
|
||||
|
||||
var eventTime = 4; //4 minutes
|
||||
|
||||
var lobbyRange = [0, 0];
|
||||
|
||||
function setLobbyRange() {
|
||||
return lobbyRange;
|
||||
}
|
||||
|
||||
function init() {
|
||||
em.setProperty("noEntry","false");
|
||||
}
|
||||
|
||||
function setup(level, lobbyid) {
|
||||
var eim = em.newInstance("4jsuper_" + lobbyid);
|
||||
eim.setProperty("level", level);
|
||||
eim.setProperty("boss", "0");
|
||||
eim.setProperty("canLeave", "0");
|
||||
|
||||
eim.getInstanceMap(entryMap).resetPQ(level);
|
||||
|
||||
respawnStages(eim);
|
||||
eim.startEventTimer(eventTime * 60000);
|
||||
eim.schedule("playerCanLeave", 1 * 60000);
|
||||
eim.schedule("playerSurvived", 2 * 60000);
|
||||
return eim;
|
||||
}
|
||||
|
||||
function afterSetup(eim) {}
|
||||
|
||||
function respawnStages(eim) {}
|
||||
|
||||
function playerCanLeave(eim) {
|
||||
eim.setIntProperty("canLeave", 1);
|
||||
}
|
||||
|
||||
function playerSurvived(eim) {
|
||||
if (eim.getLeader().isAlive()) {
|
||||
eim.setIntProperty("canLeave", 2);
|
||||
eim.dropMessage(5, "Kyrin: You have passed the test. Now for the closing part... Are you able reach the exit over there?");
|
||||
} else {
|
||||
eim.dropMessage(5, "Kyrin: You have failed the test. Aww, don't have such a sad face, just try it again later, ok?");
|
||||
}
|
||||
}
|
||||
|
||||
function playerEntry(eim, player) {
|
||||
var map = eim.getMapInstance(entryMap);
|
||||
player.changeMap(map, map.getPortal(0));
|
||||
}
|
||||
|
||||
function playerUnregistered(eim, player) {}
|
||||
|
||||
function playerExit(eim, player) {
|
||||
eim.unregisterPlayer(player);
|
||||
eim.dispose();
|
||||
em.setProperty("noEntry","false");
|
||||
}
|
||||
|
||||
function playerLeft(eim, player) {}
|
||||
|
||||
function scheduledTimeout(eim) {
|
||||
var player = eim.getPlayers().get(0);
|
||||
playerExit(eim, player);
|
||||
player.changeMap(exitMap);
|
||||
}
|
||||
|
||||
function playerDisconnected(eim, player) {
|
||||
playerExit(eim, player);
|
||||
}
|
||||
|
||||
function changedMap(eim, chr, mapid) {
|
||||
if(mapid < minMapId || mapid > maxMapId) playerExit(eim, chr);
|
||||
}
|
||||
|
||||
function changedLeader(eim, leader) {}
|
||||
|
||||
function clearPQ(eim) {
|
||||
eim.stopEventTimer();
|
||||
eim.setEventCleared();
|
||||
|
||||
var player = eim.getPlayers().get(0);
|
||||
eim.unregisterPlayer(player);
|
||||
player.changeMap(exitMap);
|
||||
|
||||
eim.dispose();
|
||||
em.setProperty("noEntry","false");
|
||||
}
|
||||
|
||||
function monsterKilled(mob, eim) {}
|
||||
|
||||
function leftParty(eim, player) {}
|
||||
|
||||
function disbandParty(eim) {}
|
||||
|
||||
function monsterValue(eim, mobId) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
function friendlyKilled(mob, eim) {
|
||||
if(em.getProperty("noEntry") != "false") {
|
||||
var player = eim.getPlayers().get(0);
|
||||
playerExit(eim, player);
|
||||
player.changeMap(exitMap);
|
||||
}
|
||||
}
|
||||
|
||||
function allMonstersDead(eim) {}
|
||||
|
||||
function cancelSchedule() {}
|
||||
|
||||
function dispose() {}
|
||||
+23
-11
@@ -3,6 +3,7 @@ var maps = [104000000, 102000000, 100000000, 103000000, 120000000];
|
||||
var cost = [1000, 1000, 1000, 1000, 800];
|
||||
var selectedMap = -1;
|
||||
var mesos;
|
||||
var hasCoupon = false;
|
||||
|
||||
function start() {
|
||||
cm.sendNext("Hello, I drive the Regular Cab. If you want to go from town to town safely and fast, then ride our cab. We'll glady take you to your destination with an affordable price.");
|
||||
@@ -33,22 +34,33 @@ function action(mode, type, selection) {
|
||||
selStr += "\r\n#L" + i + "##m" + maps[i] + "# (" + (cm.getJobId() == 0 ? cost[i] / 10 : cost[i]) + " mesos)#l";
|
||||
cm.sendSimple(selStr);
|
||||
} else if (status == 2) {
|
||||
cm.sendYesNo("You don't have anything else to do here, huh? Do you really want to go to #b#m" + maps[selection] + "##k? It'll cost you #b"+ (cm.getJobId() == 0 ? cost[selection] / 10 : cost[selection]) + " mesos#k.");
|
||||
if (maps[selection] == 100000000 && cm.getMapId() == 101000000 && cm.haveItem(4032288)) {
|
||||
cm.sendYesNo("Hmm, I see you have been recommended by Neinheart to come to Victoria Island to improve your knightly skills. Well, just this time the ride will be free of charges. Will you take the ride?");
|
||||
hasCoupon = true;
|
||||
} else {
|
||||
cm.sendYesNo("You don't have anything else to do here, huh? Do you really want to go to #b#m" + maps[selection] + "##k? It'll cost you #b"+ (cm.getJobId() == 0 ? cost[selection] / 10 : cost[selection]) + " mesos#k.");
|
||||
}
|
||||
|
||||
selectedMap = selection;
|
||||
} else if (status == 3) {
|
||||
if (cm.getJobId() == 0) {
|
||||
mesos = cost[selectedMap] / 10;
|
||||
if (!hasCoupon) {
|
||||
if (cm.getJobId() == 0) {
|
||||
mesos = cost[selectedMap] / 10;
|
||||
} else {
|
||||
mesos = cost[selectedMap];
|
||||
}
|
||||
|
||||
if (cm.getMeso() < mesos) {
|
||||
cm.sendNext("You don't have enough mesos. Sorry to say this, but without them, you won't be able to ride the cab.");
|
||||
cm.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
cm.gainMeso(-mesos);
|
||||
} else {
|
||||
mesos = cost[selectedMap];
|
||||
cm.gainItem(4032288, -1);
|
||||
}
|
||||
|
||||
if (cm.getMeso() < mesos) {
|
||||
cm.sendNext("You don't have enough mesos. Sorry to say this, but without them, you won't be able to ride the cab.");
|
||||
cm.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
cm.gainMeso(-mesos);
|
||||
cm.warp(maps[selectedMap], 0);
|
||||
cm.dispose();
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ function action(mode, type, selection) {
|
||||
|
||||
if(status == 0) {
|
||||
hasCoin = cm.haveItem(coinId);
|
||||
cm.sendNext("This is the vending machine of the Internet Cafe. Place your erasers or #t" + coinId + "# earned throughout the quests to redeem a prize. You can place #bany amount of erasers#k, however take note that bigger shots improves the reward possibilities!");
|
||||
cm.sendNext("This is the vending machine of the Internet Cafe. Place your erasers or #t" + coinId + "# earned throughout the quests to redeem a prize. You can place #bany amount of erasers#k, however take note that placing #rdifferent erasers#k and #rbigger shots of any of them#k will improve the reward possibilities!");
|
||||
} else if(status == 1) {
|
||||
var sendStr;
|
||||
currentTier = getRewardTier();
|
||||
|
||||
+50
-2
@@ -33,8 +33,39 @@ spawnPnpc = false;
|
||||
spawnPnpcFee = 7000000;
|
||||
jobType = 5;
|
||||
|
||||
var advQuest = 0;
|
||||
function start() {
|
||||
if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()))) {
|
||||
if (cm.isQuestStarted(6330)) {
|
||||
if (cm.getEventInstance() != null) { // missing script for skill test found thanks to Lost(tm)
|
||||
advQuest = 5; // string visibility thanks to iPunchEm & Glvelturall
|
||||
cm.sendNext("Not bad at all. Let's discuss this outside!");
|
||||
cm.setQuestProgress(6330, 0, 1);
|
||||
} else if (cm.getQuestProgress(6330, 0) == 0) {
|
||||
advQuest = 1;
|
||||
cm.sendNext("You're ready, right? Now try to withstand my attacks for 2 minutes. I won't go easy on you. Good luck, because you will need it.");
|
||||
} else {
|
||||
advQuest = 3;
|
||||
cm.teachSkill(5121003, 0, 10, -1);
|
||||
cm.forceCompleteQuest(6330);
|
||||
|
||||
cm.sendNext("Congratulations. You have managed to pass my test. I'll teach you a new skill called \"Super Transformation\".\r\n\r\n #s5221003# #b#q5221003##k");
|
||||
}
|
||||
} else if (cm.isQuestStarted(6370)) {
|
||||
if (cm.getEventInstance() != null) {
|
||||
advQuest = 6;
|
||||
cm.sendNext("Not bad at all. Let's discuss this outside!");
|
||||
cm.setQuestProgress(6370, 0, 1);
|
||||
} else if (cm.getQuestProgress(6370, 0) == 0) {
|
||||
advQuest = 2;
|
||||
cm.sendNext("You're ready, right? Now try to withstand my attacks for 2 minutes. I won't go easy on you. Good luck, because you will need it.");
|
||||
} else {
|
||||
advQuest = 4;
|
||||
cm.teachSkill(5221006, 0, 10, -1);
|
||||
cm.forceCompleteQuest(6370);
|
||||
|
||||
cm.sendNext("Congratulations. You have managed to pass my test. I'll teach you a new skill called \"Battleship\".\r\n\r\n #s5221006# #b#q5221006##k");
|
||||
}
|
||||
} else if (parseInt(cm.getJobId() / 100) == jobType && cm.canSpawnPlayerNpc(Packages.constants.GameConstants.getHallOfFameMapid(cm.getJob()))) {
|
||||
spawnPnpc = true;
|
||||
|
||||
var sendStr = "You have walked a long way to reach the power, wisdom and courage you hold today, haven't you? What do you say about having right now #ra NPC on the Hall of Fame holding the current image of your character#k? Do you like it?";
|
||||
@@ -82,7 +113,24 @@ function action(mode, type, selection) {
|
||||
start();
|
||||
return;
|
||||
} else {
|
||||
if(spawnPnpc) {
|
||||
if (advQuest > 0) {
|
||||
if (advQuest < 3) {
|
||||
var em = cm.getEventManager(advQuest == 1 ? "4jship" : "4jsuper");
|
||||
if(!em.startInstance(cm.getPlayer())) {
|
||||
cm.sendOk("Someone is already challenging the test. Please try again later.");
|
||||
}
|
||||
} else if (advQuest < 5) {
|
||||
if (advQuest == 3) {
|
||||
cm.sendOk("It is similar to that of 'Transformation', but it's much more powerful than that. Keep training, and hope to see you around.");
|
||||
} else {
|
||||
cm.sendOk("Unlike most of the other skills you used as a Pirate, this one definitely is different. You can actually ride the 'Battleship' and attack enemies with it. Your DEF level will increase for the time you're on board, so that'll help you tremendously in combat situations. May you become the best Gunslinger out there...");
|
||||
}
|
||||
} else {
|
||||
cm.warp(120000101);
|
||||
}
|
||||
|
||||
cm.dispose();
|
||||
} else if(spawnPnpc) {
|
||||
if(mode > 0) {
|
||||
if(cm.getMeso() < spawnPnpcFee) {
|
||||
cm.sendOk("Sorry, you don't have enough mesos to purchase your place on the Hall of Fame.");
|
||||
|
||||
+5
-18
@@ -12,12 +12,8 @@
|
||||
var menu = new Array("Victoria Island");
|
||||
var method;
|
||||
|
||||
var hasCoupon = false;
|
||||
|
||||
function start() {
|
||||
status = -1;
|
||||
if(cm.haveItem(4032288)) hasCoupon = true;
|
||||
|
||||
action(1, 0, 0);
|
||||
}
|
||||
|
||||
@@ -36,22 +32,13 @@ function action(mode, type, selection) {
|
||||
}
|
||||
status++;
|
||||
if (status == 0) {
|
||||
if(!hasCoupon) {
|
||||
var display = "";
|
||||
for(var i=0; i < menu.length; i++) {
|
||||
display += "\r\n#L"+i+"##b Victoria Island (1000 mesos)#k";
|
||||
}
|
||||
cm.sendSimple("Eh, Hello...again. Do you want to leave Ereve and go somewhere else? If so, you've come to the right place. I operate a ferry that goes from #bEreve#k to #bVictoria Island#k, I can take you to #bVictoria Island#k if you want... You'll have to pay a fee of #b1000#k Mesos.\r\n"+display);
|
||||
} else {
|
||||
cm.sendYesNo("Hmm, hi there. I see you have been recommended by Neinheart to go to Victoria Island to improve your knightly skills. Well, just this time the ride will be free of charges. Will you embark?");
|
||||
var display = "";
|
||||
for(var i=0; i < menu.length; i++) {
|
||||
display += "\r\n#L"+i+"##b Victoria Island (1000 mesos)#k";
|
||||
}
|
||||
|
||||
cm.sendSimple("Eh, Hello...again. Do you want to leave Ereve and go somewhere else? If so, you've come to the right place. I operate a ferry that goes from #bEreve#k to #bVictoria Island#k, I can take you to #bVictoria Island#k if you want... You'll have to pay a fee of #b1000#k Mesos.\r\n"+display);
|
||||
} else if(status == 1) {
|
||||
if(hasCoupon) {
|
||||
cm.gainItem(4032288, -1);
|
||||
cm.warp(200090031);
|
||||
cm.dispose();
|
||||
} else if(cm.getMeso() < 1000) {
|
||||
if(cm.getMeso() < 1000) {
|
||||
cm.sendNext("Hmm... Are you sure you have #b1000#k Mesos? Check your Inventory and make sure you have enough. You must pay the fee or I can't let you get on...");
|
||||
cm.dispose();
|
||||
} else {
|
||||
|
||||
@@ -10,6 +10,6 @@
|
||||
**/
|
||||
|
||||
function start() {
|
||||
cm.sendOk("Ah, such lovely winds. This should be a perfect voyage as long as no stupid customer falls off for attempting some weird skill. Of course, I'm talking about you. Please refain from using your skills.");
|
||||
cm.sendOk("Ah, such lovely winds. This should be a perfect voyage as long as no stupid customer falls off for attempting some weird skill. Of course, I'm talking about you. Please refrain from using your skills.");
|
||||
cm.dispose();
|
||||
}
|
||||
@@ -1,11 +1,15 @@
|
||||
/*
|
||||
NPC Name: Divine Bird
|
||||
Map(s): Erev
|
||||
Description: Buff
|
||||
Description: 3rd job KoC Buff
|
||||
*/
|
||||
importPackage(Packages.constants);
|
||||
|
||||
function start() {
|
||||
cm.useItem(2022458);
|
||||
if (cm.getPlayer().isCygnus() && GameConstants.getJobBranch(cm.getJob()) > 2) {
|
||||
cm.useItem(2022458);
|
||||
}
|
||||
|
||||
cm.sendOk("Don't stop training. Every ounce of your energy is required to protect the world of Maple....");
|
||||
cm.dispose();
|
||||
cm.dispose();
|
||||
}
|
||||
@@ -49,18 +49,24 @@ function action(mode, type, selection) {
|
||||
status--;
|
||||
|
||||
if(status == 0) {
|
||||
if (!Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
|
||||
cm.sendOk("The Monster Carnival is currently unavailable.");
|
||||
cm.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
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");
|
||||
options.push("Refine crystal ores");
|
||||
}
|
||||
if(refineRocks) {
|
||||
options.push("Refine plates/jewels");
|
||||
options.push("Refine plates/jewels");
|
||||
}
|
||||
|
||||
for (var i = 0; i < options.length; i++){
|
||||
selStr += "\r\n#L" + i + "# " + options[i] + "#l";
|
||||
selStr += "\r\n#L" + i + "# " + options[i] + "#l";
|
||||
}
|
||||
|
||||
cm.sendSimple(selStr);
|
||||
|
||||
@@ -47,10 +47,14 @@ function action(mode, type, selection) {
|
||||
|
||||
var progress = cm.getQuestProgress(3421, 0);
|
||||
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
|
||||
progress |= (1 << meteoriteId);
|
||||
if (cm.canHold(4031117, 1)) {
|
||||
progress |= (1 << meteoriteId);
|
||||
|
||||
cm.gainItem(4031117, 1);
|
||||
cm.setQuestProgress(3421, 0, progress);
|
||||
cm.gainItem(4031117, 1);
|
||||
cm.setQuestProgress(3421, 0, progress);
|
||||
} else {
|
||||
cm.getPlayer().dropMessage(1, "Have a ETC slot available for this item.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,10 +47,14 @@ function action(mode, type, selection) {
|
||||
|
||||
var progress = cm.getQuestProgress(3421, 0);
|
||||
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
|
||||
progress |= (1 << meteoriteId);
|
||||
if (cm.canHold(4031117, 1)) {
|
||||
progress |= (1 << meteoriteId);
|
||||
|
||||
cm.gainItem(4031117, 1);
|
||||
cm.setQuestProgress(3421, 0, progress);
|
||||
cm.gainItem(4031117, 1);
|
||||
cm.setQuestProgress(3421, 0, progress);
|
||||
} else {
|
||||
cm.getPlayer().dropMessage(1, "Have a ETC slot available for this item.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,10 +47,14 @@ function action(mode, type, selection) {
|
||||
|
||||
var progress = cm.getQuestProgress(3421, 0);
|
||||
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
|
||||
progress |= (1 << meteoriteId);
|
||||
if (cm.canHold(4031117, 1)) {
|
||||
progress |= (1 << meteoriteId);
|
||||
|
||||
cm.gainItem(4031117, 1);
|
||||
cm.setQuestProgress(3421, 0, progress);
|
||||
cm.gainItem(4031117, 1);
|
||||
cm.setQuestProgress(3421, 0, progress);
|
||||
} else {
|
||||
cm.getPlayer().dropMessage(1, "Have a ETC slot available for this item.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,10 +47,14 @@ function action(mode, type, selection) {
|
||||
|
||||
var progress = cm.getQuestProgress(3421, 0);
|
||||
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
|
||||
progress |= (1 << meteoriteId);
|
||||
if (cm.canHold(4031117, 1)) {
|
||||
progress |= (1 << meteoriteId);
|
||||
|
||||
cm.gainItem(4031117, 1);
|
||||
cm.setQuestProgress(3421, 0, progress);
|
||||
cm.gainItem(4031117, 1);
|
||||
cm.setQuestProgress(3421, 0, progress);
|
||||
} else {
|
||||
cm.getPlayer().dropMessage(1, "Have a ETC slot available for this item.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,10 +47,14 @@ function action(mode, type, selection) {
|
||||
|
||||
var progress = cm.getQuestProgress(3421, 0);
|
||||
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
|
||||
progress |= (1 << meteoriteId);
|
||||
if (cm.canHold(4031117, 1)) {
|
||||
progress |= (1 << meteoriteId);
|
||||
|
||||
cm.gainItem(4031117, 1);
|
||||
cm.setQuestProgress(3421, 0, progress);
|
||||
cm.gainItem(4031117, 1);
|
||||
cm.setQuestProgress(3421, 0, progress);
|
||||
} else {
|
||||
cm.getPlayer().dropMessage(1, "Have a ETC slot available for this item.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,10 +47,14 @@ function action(mode, type, selection) {
|
||||
|
||||
var progress = cm.getQuestProgress(3421, 0);
|
||||
if((progress >> meteoriteId) % 2 == 0 || (progress == 63 && !cm.haveItem(4031117, 6))) {
|
||||
progress |= (1 << meteoriteId);
|
||||
if (cm.canHold(4031117, 1)) {
|
||||
progress |= (1 << meteoriteId);
|
||||
|
||||
cm.gainItem(4031117, 1);
|
||||
cm.setQuestProgress(3421, 0, progress);
|
||||
cm.gainItem(4031117, 1);
|
||||
cm.setQuestProgress(3421, 0, progress);
|
||||
} else {
|
||||
cm.getPlayer().dropMessage(1, "Have a ETC slot available for this item.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,26 +25,27 @@
|
||||
* @Map(s): Dojo Hall
|
||||
*/
|
||||
importPackage(Packages.server.maps);
|
||||
importPackage(Packages.constants);
|
||||
|
||||
var disabled = false;
|
||||
var belts = Array(1132000, 1132001, 1132002, 1132003, 1132004);
|
||||
var belt_level = Array(25, 35, 45, 60, 75);
|
||||
var belt_on_inventory;
|
||||
|
||||
/* var belt_points = Array(200, 1800, 4000, 9200, 17000); */
|
||||
var belt_points = Array(10, 90, 200, 460, 850); /* Watered down version */
|
||||
var belt_points;
|
||||
|
||||
var status = -1;
|
||||
var selectedMenu = -1;
|
||||
var dojoWarp = 0;
|
||||
|
||||
function start() {
|
||||
if(disabled) {
|
||||
if (disabled) {
|
||||
cm.sendOk("My master has requested that the dojo be #rclosed#k at this time so I can't let you in.");
|
||||
cm.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
belt_points = ServerConstants.USE_FAST_DOJO_UPGRADE ? Array(10, 90, 200, 460, 850) : Array(200, 1800, 4000, 9200, 17000);
|
||||
|
||||
belt_on_inventory = new Array();
|
||||
for (var i = 0; i < belts.length; i++) {
|
||||
belt_on_inventory.push(cm.haveItemWithId(belts[i], true));
|
||||
|
||||
@@ -14,7 +14,7 @@ function action(mode, type, selection) {
|
||||
if (mode == -1) {
|
||||
cm.dispose();
|
||||
} else {
|
||||
if (status == 0 && mode == 0) {
|
||||
if (mode == 0) {
|
||||
cm.sendNext("Aye...are you scared of speed or heights? You can't trust my flying skills? Trust me, I've worked out all the kinks!");
|
||||
cm.dispose();
|
||||
return;
|
||||
@@ -26,7 +26,7 @@ function action(mode, type, selection) {
|
||||
if(status == 0){
|
||||
cm.sendNext("I don't know how you found out about this, but you came to the right place! For those that wandered around Nihal Desert and are getting homesick, I am offering a flight straight to Victorial Island, non-stop! Don't worry about the flying ship--it's only fallen once or twice! Don't you feel claustrophobic being in a long flight on that small ship?");
|
||||
} else if(status == 1){
|
||||
cm.sendAcceptDecline("Please remember two things. One, this line is actually for overseas shipping, so #rI cannot gurantee exactly which town you'll land#k. Two, since I am putting you in this special flight, it'll be a bit expensive. The service charge is #e#b10,000 mesos#n#k. There's a flight thats about to take off. Are you interested in this direct flight?");
|
||||
cm.sendYesNo("Please remember two things. One, this line is actually for overseas shipping, so #rI cannot gurantee exactly which town you'll land#k. Two, since I am putting you in this special flight, it'll be a bit expensive. The service charge is #e#b10,000 mesos#n#k. There's a flight thats about to take off. Are you interested in this direct flight?");
|
||||
} else if(status == 2){
|
||||
cm.sendNext("Okay, ready to takeoff~");
|
||||
} else if(status == 3){
|
||||
|
||||
@@ -51,6 +51,12 @@ function action(mode, type, selection) {
|
||||
}
|
||||
|
||||
if (status == 0) {
|
||||
if (!Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
|
||||
cm.sendOk("Hi, I'm #b#p" + cm.getNpc() + "##k.");
|
||||
cm.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
var selStr = "Hey traveler! Come, come closer... We offer a #bhuge opportunity of business#k to you. If you want to know what it is, keep listening...";
|
||||
cm.sendNext(selStr);
|
||||
}
|
||||
|
||||
+12
-6
@@ -39,6 +39,12 @@ var equip;
|
||||
var maxEqp = 0;
|
||||
|
||||
function start() {
|
||||
if (!Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
|
||||
cm.sendOk("Hi, I'm #b#p" + cm.getNpc() + "##k.");
|
||||
cm.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
cm.getPlayer().setCS(true);
|
||||
var selStr = "Hello, I am the #bAccessory NPC Crafter#k! My works are widely recognized to be too fine, up to the point at which all my items mimic not only the appearance but too the attributes of them! Everything I charge is some 'ingredients' to make them and, of course, a fee for my services. On what kind of equipment are you interessed?#b";
|
||||
var options = ["Pendants","Face accessories","Eye accessories","Belts & medals","Rings"/*,"#t4032496#"*/];
|
||||
@@ -56,7 +62,7 @@ function action(mode, type, selection) {
|
||||
if (status == 0) {
|
||||
if (selection == 0) { //pendants
|
||||
var selStr = "Well, I've got these pendants on my repertoire:#b";
|
||||
items = [1122018,1122007,1122001,1122002,1122003,1122004,1122005,1122006,1122058];
|
||||
items = [1122018,1122007,1122001,1122003,1122004,1122006,1122002,1122005,1122058];
|
||||
for (var i = 0; i < items.length; i++)
|
||||
selStr += "\r\n#L" + i + "##t" + items[i] + "##b";
|
||||
}else if (selection == 1) { //face accessory
|
||||
@@ -103,9 +109,9 @@ function action(mode, type, selection) {
|
||||
if (selectedType != 3) selectedItem = selection;
|
||||
|
||||
if (selectedType == 0) { //pendant refine
|
||||
var matSet = [[4003004, 4030012, 4001356, 4000026], [4000026, 4001356, 4000073, 4001006], [4001344, 4003001, 4003004, 4003005], [4001344, 4003001, 4003004, 4003005], [4001344, 4003001, 4003004, 4003005], [4001344, 4003001, 4003004, 4003005], [4001344, 4003001, 4003004, 4003005], [4001344, 4003001, 4003004, 4003005], [1122007, 4003002, 4000413]];
|
||||
var matQtySet = [[20, 20, 5, 1], [5, 5, 10, 1], [10, 4, 20, 4], [20, 8, 20, 8], [10, 4, 20, 4], [15, 6, 30, 6], [20, 8, 40, 8], [15, 6, 30, 6], [1, 1, 1]];
|
||||
var costSet = [150000, 500000, 200000, 400000, 200000, 300000, 400000, 300000, 2500000];
|
||||
var matSet = [[4003004, 4030012, 4001356, 4000026], [4000026, 4001356, 4000073, 4001006], [4001343, 4011002, 4003004, 4003005], [4001343, 4011006, 4003004, 4003005], [4000091, 4011005, 4003004, 4003005], [4000091, 4011001, 4003004, 4003005], [4000469, 4011000, 4003004, 4003005], [4000469, 4011004, 4003004, 4003005], [1122007, 4003002, 4000413]];
|
||||
var matQtySet = [[20, 20, 5, 1], [5, 5, 10, 1], [10, 2, 20, 4], [10, 1, 20, 4], [15, 3, 30, 6], [15, 3, 30, 6], [20, 5, 20, 8], [20, 4, 40, 8], [1, 1, 1]];
|
||||
var costSet = [150000, 500000, 200000, 200000, 300000, 300000, 400000, 400000, 2500000];
|
||||
}else if (selectedType == 1) { //face accessory refine
|
||||
var matSet = [[4006000, 4003004],[4006000, 4003004,4000026],[4006000, 4003004,4000026,4000082,4003002],[4006000, 4003005],[4006000, 4003005,4000026],[4006000, 4003005,4000026,4000082,4003002],[4001006, 4011008],[4001006, 4011008],[4001006, 4011008],[4001006, 4011008]];
|
||||
var matQtySet = [[5,5],[5,5,5],[5,5,5,5,1],[5,5],[5,5,5],[5,5,5,5,1],[1,1],[1,1],[1,1],[1,1]];
|
||||
@@ -145,9 +151,9 @@ function action(mode, type, selection) {
|
||||
var prompt = "You want me to make ";
|
||||
if(selectedType != 3) {
|
||||
if (qty == 1)
|
||||
prompt += "a #t" + item + "#?";
|
||||
prompt += "a #b#t" + item + "##k?";
|
||||
else
|
||||
prompt += qty + " #t" + item + "#?";
|
||||
prompt += "#b" + qty + " #t" + item + "##k?";
|
||||
}
|
||||
else prompt += "a #bbelt#k or a #bmedal#k?";
|
||||
|
||||
|
||||
+59
-18
@@ -19,31 +19,72 @@
|
||||
*/
|
||||
/* Dalair
|
||||
Medal NPC.
|
||||
|
||||
NPC Equipment Merger:
|
||||
* @author Ronan Lana
|
||||
*/
|
||||
|
||||
importPackage(Packages.client.processor);
|
||||
importPackage(Packages.constants);
|
||||
|
||||
var status;
|
||||
var mergeFee = 50000;
|
||||
var name;
|
||||
|
||||
function start() {
|
||||
status = -1;
|
||||
action(1, 0, 0);
|
||||
status = -1;
|
||||
action(1, 0, 0);
|
||||
}
|
||||
|
||||
function action(mode, type, selection) {
|
||||
if (mode == -1) {
|
||||
cm.dispose();
|
||||
} else {
|
||||
if (mode == 0 && type > 0) {
|
||||
cm.dispose();
|
||||
return;
|
||||
}
|
||||
if (mode == 1)
|
||||
status++;
|
||||
else
|
||||
status--;
|
||||
|
||||
if(status == 0) {
|
||||
cm.sendOk("The medal ranking system is currently unavailable.");
|
||||
cm.dispose();
|
||||
}
|
||||
if (mode == -1) {
|
||||
cm.dispose();
|
||||
} else {
|
||||
if (mode == 0 && type > 0) {
|
||||
cm.dispose();
|
||||
return;
|
||||
}
|
||||
if (mode == 1)
|
||||
status++;
|
||||
else
|
||||
status--;
|
||||
|
||||
if(status == 0) {
|
||||
if (!Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
|
||||
cm.sendOk("The medal ranking system is currently unavailable...");
|
||||
cm.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
var levelLimit = !cm.getPlayer().isCygnus() ? 160 : 110;
|
||||
var selStr = "The medal ranking system is currently unavailable... Therefore, I am providing the #bEquipment Merge#k service! ";
|
||||
|
||||
if (!ServerConstants.USE_STARTER_MERGE && (cm.getPlayer().getLevel() < levelLimit || MakerProcessor.getMakerSkillLevel(cm.getPlayer()) < 3)) {
|
||||
selStr += "However, you must have #rMaker level 3#k and at least #rlevel 110#k (Cygnus Knight), #rlevel 160#k (other classes) and a fund of #r" + cm.numberWithCommas(mergeFee) + " mesos#k to use the service.";
|
||||
cm.sendOk(selStr);
|
||||
cm.dispose();
|
||||
} else if (cm.getMeso() < mergeFee) {
|
||||
selStr += "I'm sorry, but this service tax is of #r" + cm.numberWithCommas(mergeFee) + " mesos#k, which it seems you unfortunately don't have right now... Please, stop by again later.";
|
||||
cm.sendOk(selStr);
|
||||
cm.dispose();
|
||||
} else {
|
||||
selStr += "For the fee of #r" + cm.numberWithCommas(mergeFee) + "#k mesos, merge unnecessary equipments in your inventory into your currently equipped gears to get stat boosts into them, statups based on the attributes of the items used on the merge!";
|
||||
cm.sendNext(selStr);
|
||||
}
|
||||
} else if(status == 1) {
|
||||
selStr = "#rWARNING#b: Make sure you have your items ready to merge at the slots #rAFTER#b the item you have selected to merge.#k Any items #bunder#k the item selected will be merged thoroughly.\r\n\r\nNote that equipments receiving bonuses from merge are going to become #rUntradeable#k thereon, and equipments that already received the merge bonus #rcannot be used for merge#k.\r\n\r\n";
|
||||
cm.sendGetText(selStr);
|
||||
} else if(status == 2) {
|
||||
name = cm.getText();
|
||||
|
||||
if (cm.getPlayer().mergeAllItemsFromName(name)) {
|
||||
cm.gainMeso(-mergeFee);
|
||||
cm.sendOk("Merging complete! Thanks for using the service and enjoy your new equipment stats.");
|
||||
} else {
|
||||
cm.sendOk("There is no #b'" + name + "'#k in your #bEQUIP#k inventory!");
|
||||
}
|
||||
|
||||
cm.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,12 @@ function action(mode, type, selection) {
|
||||
}
|
||||
|
||||
if (status == 0) {
|
||||
if (!Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
|
||||
cm.sendOk("The medal ranking system is currently unavailable...");
|
||||
cm.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
var selStr = "Hello, I am the #bBazaar NPC#k! Sell to me any item on your inventory you don't need. #rWARNING#b: Make sure you have your items ready to sell at the slots #rAFTER#b the item you have selected to sell.#k Any items #bunder#k the item selected will be sold thoroughly.";
|
||||
for (var i = 0; i < options.length; i++)
|
||||
selStr += "\r\n#L" + i + "# " + options[i] + "#l";
|
||||
|
||||
+4
-13
@@ -20,7 +20,6 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
var status = 0;
|
||||
var goToMansion = false;
|
||||
var fee = 15000;
|
||||
|
||||
function start() {
|
||||
@@ -37,19 +36,11 @@ function action(mode, type, selection) {
|
||||
else {
|
||||
status++;
|
||||
if (cm.getPlayer().getMapId() == 682000000) {
|
||||
if (status == 0)
|
||||
cm.sendSimple("Where to, boss? \r\n#b#L0#New Leaf City (" + fee + " mesos)#l\r\n#L1#Haunted Mansion#l#k");
|
||||
else if (status == 1) {
|
||||
if (status == 0) {
|
||||
if (selection == 0)
|
||||
cm.sendYesNo("You want to go to New Leaf City?");
|
||||
else {
|
||||
goToMansion = true;
|
||||
cm.sendYesNo("You're sure you want to enter the Mansion?");
|
||||
}
|
||||
} else if (status == 2) {
|
||||
if(goToMansion) {
|
||||
cm.warp(682000100, 0);
|
||||
} else if(cm.getMeso() >= fee) {
|
||||
cm.sendYesNo("Would you like to return back to #bcivilization#k? The fee is " + fee + " mesos.");
|
||||
} else if (status == 1) {
|
||||
if(cm.getMeso() >= fee) {
|
||||
cm.gainMeso(-fee);
|
||||
cm.warp(600000000);
|
||||
} else {
|
||||
|
||||
@@ -98,6 +98,7 @@ function writeFeatureTab_CashItems() {
|
||||
addFeature("Storage with 'Arrange Items' feature functional.");
|
||||
addFeature("Close-quarters evaluation mode for items.");
|
||||
addFeature("Reviewed Karma scissors & Untradeable items.");
|
||||
addFeature("Reviewed an pet position issue within CASH inventory.");
|
||||
addFeature("Scroll for Spikes on Shoes.");
|
||||
addFeature("Scroll for Cold Protection.");
|
||||
addFeature("Vega's spell.");
|
||||
@@ -187,6 +188,7 @@ function writeFeatureTab_Serverpotentials() {
|
||||
addFeature("Delete Character.");
|
||||
addFeature("Smooth view-all-char, now showing all account chars.");
|
||||
addFeature("Centralized servertime, boosting handler performance.");
|
||||
addFeature("Centralized timestamping, unused rcvd timestamps.");
|
||||
addFeature("Autosaver (periodically saves player's data on DB).");
|
||||
addFeature("Fixed and randomized HP/MP growth rate available.");
|
||||
addFeature("Players' MaxHP/MaxMP method accounting equip gain.");
|
||||
@@ -211,6 +213,7 @@ function writeFeatureTab_CustomNPCs() {
|
||||
addFeature("Asia: scroll & rarities shop NPC.");
|
||||
addFeature("Abdula: lists droppers of needed skill/mastery books.");
|
||||
addFeature("Agent E: accessory crafter.");
|
||||
addFeature("Dalair: automatized equipment-merger.");
|
||||
addFeature("Donation Box: automatized item-buyer.");
|
||||
addFeature("Coco & Ace of Hearts: C. scroll crafters.");
|
||||
}
|
||||
@@ -240,6 +243,7 @@ function writeFeatureTab_Project() {
|
||||
addFeature("Protected many flaws with login management system.");
|
||||
addFeature("Developed a robust anti-exploit login coordinator.");
|
||||
addFeature("Usage of HikariCP to improve DB connection calls.");
|
||||
addFeature("Usage of Java Threadpool to improve runnable calls.");
|
||||
addFeature("Developed many survey tools for content profiling.");
|
||||
addFeature("ThreadTracker: runtime tool for deadlock detection.");
|
||||
addFeature("Channel, World and Server-wide timer management.");
|
||||
|
||||
@@ -33,7 +33,7 @@ function enter(pi) {
|
||||
}
|
||||
|
||||
if(pi.haveItem(4032101 + jobtype, 1)) {
|
||||
pi.message("You have already challenged the Master of Disguise, report your success to Neinheart.");
|
||||
pi.message("You have already challenged the Master of Disguise, report your success to the Chief Knight.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ function enter(pi) {
|
||||
}
|
||||
|
||||
if(pi.haveItem(4032101 + jobtype, 1)) {
|
||||
pi.message("You have already challenged the Master of Disguise, report your success to Neinheart.");
|
||||
pi.message("You have already challenged the Master of Disguise, report your success to the Chief Knight.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ function enter(pi) {
|
||||
}
|
||||
|
||||
if(pi.haveItem(4032101 + jobtype, 1)) {
|
||||
pi.message("You have already challenged the Master of Disguise, report your success to Neinheart.");
|
||||
pi.message("You have already challenged the Master of Disguise, report your success to the Chief Knight.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ function enter(pi) {
|
||||
}
|
||||
|
||||
if(pi.haveItem(4032101 + jobtype, 1)) {
|
||||
pi.message("You have already challenged the Master of Disguise, report your success to Neinheart.");
|
||||
pi.message("You have already challenged the Master of Disguise, report your success to the Chief Knight.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ function enter(pi) {
|
||||
}
|
||||
|
||||
if(pi.haveItem(4032101 + jobtype, 1)) {
|
||||
pi.message("You have already challenged the Master of Disguise, report your success to Neinheart.");
|
||||
pi.message("You have already challenged the Master of Disguise, report your success to the Chief Knight.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
function enter(pi) {
|
||||
var exit = pi.getEventInstance().getIntProperty("canLeave");
|
||||
if (exit == 0) {
|
||||
pi.message("You have to wait one minute before you can leave this place.");
|
||||
return false;
|
||||
} else if (exit == 2) {
|
||||
pi.warp(912010200);
|
||||
return true;
|
||||
} else {
|
||||
pi.warp(120000101);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
function enter(pi) {
|
||||
var exit = pi.getEventInstance().getIntProperty("canLeave");
|
||||
if (exit == 0) {
|
||||
pi.message("You have to wait one minute before you can leave this place.");
|
||||
return false;
|
||||
} else if (exit == 2) {
|
||||
pi.warp(912010200);
|
||||
return true;
|
||||
} else {
|
||||
pi.warp(120000101);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
importPackage(Packages.client);
|
||||
importPackage(Packages.constants);
|
||||
|
||||
status = -1;
|
||||
|
||||
@@ -47,8 +48,10 @@ function start(mode, type, selection) {
|
||||
qm.changeJobById(2100);
|
||||
qm.resetStats();
|
||||
|
||||
//qm.teachSkill(21000000, 0, 10, -1); //learned later...
|
||||
//qm.teachSkill(21001003, 0, 20, -1); //learned later...
|
||||
if (ServerConstants.USE_FULL_ARAN_SKILLSET) {
|
||||
qm.teachSkill(21000000, 0, 10, -1); //combo ability
|
||||
qm.teachSkill(21001003, 0, 20, -1); //polearm booster
|
||||
}
|
||||
|
||||
qm.completeQuest();
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
importPackage(Packages.client);
|
||||
importPackage(Packages.constants);
|
||||
|
||||
var status = -1;
|
||||
|
||||
@@ -66,6 +67,13 @@ function end(mode, type, selection) {
|
||||
qm.gainItem(1142130, true);
|
||||
qm.changeJobById(2110);
|
||||
|
||||
if (ServerConstants.USE_FULL_ARAN_SKILLSET) {
|
||||
qm.teachSkill(21100000, 0, 20, -1); //polearm mastery
|
||||
qm.teachSkill(21100002, 0, 30, -1); //final charge
|
||||
qm.teachSkill(21100004, 0, 20, -1); //combo smash
|
||||
qm.teachSkill(21100005, 0, 20, -1); //combo drain
|
||||
}
|
||||
|
||||
qm.completeQuest();
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
importPackage(Packages.client);
|
||||
importPackage(Packages.constants);
|
||||
|
||||
var status = -1;
|
||||
|
||||
@@ -50,6 +51,10 @@ function end(mode, type, selection) {
|
||||
qm.gainItem(1142131, true);
|
||||
qm.changeJobById(2111);
|
||||
|
||||
if (ServerConstants.USE_FULL_ARAN_SKILLSET) {
|
||||
qm.teachSkill(21110002, 0, 20, -1); //full swing
|
||||
}
|
||||
|
||||
qm.completeQuest();
|
||||
}
|
||||
|
||||
|
||||
+35
-20
@@ -1,30 +1,45 @@
|
||||
importPackage(Packages.tools);
|
||||
var status = -1;
|
||||
|
||||
function end(mode, type, selection) {
|
||||
var rnd;
|
||||
|
||||
if (mode != 1) {
|
||||
if (mode == -1) {
|
||||
qm.dispose();
|
||||
} else {
|
||||
if(qm.haveItem(4031092, 10)) {
|
||||
if(qm.canHold(4031092)) {
|
||||
qm.sendOk("Well done! You brought back all the #t4031092# that were missing. Here, get this scroll as a token of my gratitude...");
|
||||
qm.gainItem(4031092, -10);
|
||||
if(mode == 0 && type > 0) {
|
||||
qm.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
rnd = Math.floor(Math.random() * 4);
|
||||
if(rnd == 0) qm.gainItem(2040704, 1);
|
||||
else if(rnd == 1) qm.gainItem(2040705, 1);
|
||||
else if(rnd == 2) qm.gainItem(2040707, 1);
|
||||
else qm.gainItem(2040708, 1);
|
||||
if (mode == 1)
|
||||
status++;
|
||||
else
|
||||
status--;
|
||||
|
||||
qm.gainExp(2700);
|
||||
qm.forceCompleteQuest();
|
||||
if (status == 0) {
|
||||
if(qm.haveItem(4031092, 10)) {
|
||||
if(qm.getPlayer().getInventory(Packages.client.inventory.MapleInventoryType.USE).getNumFreeSlot() >= 1) {
|
||||
qm.sendOk("Well done! You brought back all the #t4031092# that were missing. Here, take this scroll as a token of my gratitude...");
|
||||
} else {
|
||||
qm.sendOk("Free a space on your USE inventory before receiving your prize.");
|
||||
qm.dispose();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
qm.sendOk("Free a space on your USE inventory before receiving your prize.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qm.sendOk("Please return me 10 #t4031092# that went missing on this room.");
|
||||
qm.dispose();
|
||||
return;
|
||||
}
|
||||
} else if (status == 1) {
|
||||
qm.gainItem(4031092, -10);
|
||||
|
||||
qm.dispose();
|
||||
rnd = Math.floor(Math.random() * 4);
|
||||
if(rnd == 0) qm.gainItem(2040704, 1);
|
||||
else if(rnd == 1) qm.gainItem(2040705, 1);
|
||||
else if(rnd == 2) qm.gainItem(2040707, 1);
|
||||
else qm.gainItem(2040708, 1);
|
||||
|
||||
qm.gainExp(2700);
|
||||
qm.forceCompleteQuest();
|
||||
qm.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-3
@@ -19295,7 +19295,7 @@ USE `heavenms`;
|
||||
(4230116, 2382042, 1, 1, 0, 10000),
|
||||
(4230117, 2382055, 1, 1, 0, 10000),
|
||||
(4230118, 2382067, 1, 1, 0, 10000),
|
||||
(4240000, 2383011, 1, 1, 0, 10000),
|
||||
(4240000, 2383011, 1, 1, 0, 20000),
|
||||
(1210102, 4001354, 1, 1, 28209, 80000),
|
||||
(1110101, 4031773, 1, 1, 2145, 80000),
|
||||
(1130100, 4031773, 1, 1, 2145, 80000),
|
||||
@@ -20292,7 +20292,15 @@ USE `heavenms`;
|
||||
(9400110, 4000092, 1, 1, 0, 400000),
|
||||
(9400111, 4000093, 1, 1, 0, 400000),
|
||||
(3210201, 4031524, 1, 1, 8848, 200000),
|
||||
(3110101, 4031527, 1, 1, 8849, 400000);
|
||||
(3110101, 4031527, 1, 1, 8849, 400000),
|
||||
(5100000, 2022001, 1, 1, 0, 20000),
|
||||
(5100001, 2022001, 1, 1, 0, 20000),
|
||||
(5130105, 2022001, 1, 1, 0, 20000),
|
||||
(5130106, 2022001, 1, 1, 0, 20000),
|
||||
(6130102, 2022001, 1, 1, 0, 20000),
|
||||
(6130103, 2022001, 1, 1, 0, 20000),
|
||||
(6130200, 2022001, 1, 1, 0, 20000),
|
||||
(6130201, 2022001, 1, 1, 0, 20000);
|
||||
|
||||
# (dropperid, itemid, minqty, maxqty, questid, chance)
|
||||
|
||||
@@ -20478,7 +20486,8 @@ USE `heavenms`;
|
||||
(8142100, 2040205, 1, 1, 0, 750),
|
||||
(9400580, 2048010, 1, 1, 0, 750),
|
||||
(5110302, 2048010, 1, 1, 0, 750),
|
||||
(4230118, 4240000, 1, 1, 0, 750),
|
||||
(4230118, 2048011, 1, 1, 0, 750),
|
||||
(4240000, 2048011, 1, 1, 0, 750),
|
||||
(6400100, 2048011, 1, 1, 0, 750),
|
||||
(5130107, 2048012, 1, 1, 0, 750),
|
||||
(6230601, 2048012, 1, 1, 0, 750),
|
||||
|
||||
+305
-107
@@ -72,6 +72,7 @@ import server.MapleStatEffect;
|
||||
import server.MapleStorage;
|
||||
import server.MapleTrade;
|
||||
import server.TimerManager;
|
||||
import server.ThreadManager;
|
||||
import server.events.MapleEvents;
|
||||
import server.events.RescueGaga;
|
||||
import server.events.gm.MapleFitness;
|
||||
@@ -109,6 +110,7 @@ import tools.packets.Wedding;
|
||||
import client.autoban.AutobanManager;
|
||||
import client.creator.CharacterFactoryRecipe;
|
||||
import client.inventory.Equip;
|
||||
import client.inventory.Equip.StatUpgrade;
|
||||
import client.inventory.Item;
|
||||
import client.inventory.ItemFactory;
|
||||
import client.inventory.MapleInventory;
|
||||
@@ -159,12 +161,10 @@ import server.life.MobSkillFactory;
|
||||
import server.maps.MapleMapItem;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import server.movement.AbsoluteLifeMovement;
|
||||
import server.movement.LifeMovementFragment;
|
||||
|
||||
public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
private static final MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
private static final String LEVEL_200 = "[Congrats] %s has reached Level 200! Congratulate %s on such an amazing achievement!";
|
||||
private static final String LEVEL_200 = "[Congrats] %s has reached Level %d! Congratulate %s on such an amazing achievement!";
|
||||
private static final String[] BLOCKED_NAMES = {"admin", "owner", "moderator", "intern", "donor", "administrator", "help", "helper", "alert", "notice", "maplestory", "fuck", "wizet", "fucking", "negro", "fuk", "fuc", "penis", "pussy", "asshole", "gay",
|
||||
"nigger", "homo", "suck", "cum", "shit", "shitty", "condom", "security", "official", "rape", "nigga", "sex", "tit", "boner", "orgy", "clit", "asshole", "fatass", "bitch", "support", "gamemaster", "cock", "gaay", "gm",
|
||||
"operate", "master", "sysop", "party", "GameMaster", "community", "message", "event", "test", "meso", "Scania", "yata", "AsiaSoft", "henesys"};
|
||||
@@ -853,10 +853,15 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
List<Pair<MapleBuffStat, Integer>> ldsstat = Collections.singletonList(new Pair<MapleBuffStat, Integer>(MapleBuffStat.DARKSIGHT, 0));
|
||||
getMap().broadcastGMMessage(this, MaplePacketCreator.giveForeignBuff(id, ldsstat), false);
|
||||
for (MapleMonster mon : this.getControlledMonsters()) {
|
||||
mon.setController(null);
|
||||
mon.setControllerHasAggro(false);
|
||||
mon.setControllerKnowsAboutAggro(false);
|
||||
mon.getMap().updateMonsterController(mon);
|
||||
mon.lockMonster();
|
||||
try {
|
||||
mon.setController(null);
|
||||
mon.setControllerHasAggro(false);
|
||||
mon.setControllerKnowsAboutAggro(false);
|
||||
mon.getMap().updateMonsterController(mon);
|
||||
} finally {
|
||||
mon.unlockMonster();
|
||||
}
|
||||
}
|
||||
}
|
||||
announce(MaplePacketCreator.enableActions());
|
||||
@@ -1178,11 +1183,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
|
||||
public void broadcastStance() {
|
||||
AbsoluteLifeMovement alm = new AbsoluteLifeMovement(0, getPosition(), 0, getStance());
|
||||
alm.setPixelsPerSecond(new Point(0, 0));
|
||||
List<LifeMovementFragment> moveUpdate = Collections.singletonList((LifeMovementFragment) alm);
|
||||
|
||||
map.broadcastMessage(this, MaplePacketCreator.movePlayer(id, moveUpdate), false);
|
||||
map.broadcastMessage(this, MaplePacketCreator.movePlayer(id, this.getIdleMovement()), false);
|
||||
}
|
||||
|
||||
public MapleMap getWarpMap(int map) {
|
||||
@@ -1592,11 +1593,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
map.addPlayer(this);
|
||||
visitMap(map);
|
||||
|
||||
silentPartyUpdateInternal(getParty()); // EIM script calls inside
|
||||
prtLock.lock();
|
||||
try {
|
||||
if (party != null) {
|
||||
mpc.setMapId(to.getId());
|
||||
silentPartyUpdateInternal();
|
||||
client.announce(MaplePacketCreator.updateParty(client.getChannel(), party, PartyOperation.SILENT_UPDATE, null));
|
||||
updatePartyMemberHPInternal();
|
||||
}
|
||||
@@ -1605,8 +1606,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
|
||||
if (getMap().getHPDec() > 0) resetHpDecreaseTask();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
FilePrinter.printError(FilePrinter.MAPLE_MAP, "Character " + this.getName() + " got stuck when moving to map " + map.getId() + ".");
|
||||
}
|
||||
|
||||
@@ -1708,19 +1708,29 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
|
||||
public void checkMonsterAggro(MapleMonster monster) {
|
||||
if (!monster.isControllerHasAggro()) {
|
||||
if (monster.getController() == this) {
|
||||
monster.setControllerHasAggro(true);
|
||||
} else {
|
||||
monster.switchController(this, true);
|
||||
monster.lockMonster();
|
||||
try {
|
||||
if (!monster.isControllerHasAggro()) {
|
||||
if (monster.getController() == this) {
|
||||
monster.setControllerHasAggro(true);
|
||||
} else {
|
||||
monster.switchController(this, true);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
monster.unlockMonster();
|
||||
}
|
||||
}
|
||||
|
||||
public void controlMonster(MapleMonster monster, boolean aggro) {
|
||||
monster.setController(this);
|
||||
controlled.add(monster);
|
||||
client.announce(MaplePacketCreator.controlMonster(monster, false, aggro));
|
||||
monster.lockMonster();
|
||||
try {
|
||||
monster.setController(this);
|
||||
controlled.add(monster);
|
||||
client.announce(MaplePacketCreator.controlMonster(monster, false, aggro));
|
||||
} finally {
|
||||
monster.unlockMonster();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean useItem(final int id) {
|
||||
@@ -1768,7 +1778,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
|
||||
if (ob instanceof MapleMapItem) {
|
||||
MapleMapItem mapitem = (MapleMapItem) ob;
|
||||
if (System.currentTimeMillis() - mapitem.getDropTime() < 900 || !mapitem.canBePickedBy(this)) {
|
||||
if (System.currentTimeMillis() - mapitem.getDropTime() < 400 || !mapitem.canBePickedBy(this)) {
|
||||
client.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
@@ -1778,6 +1788,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
mpcs = getPartyMembersOnSameMap();
|
||||
}
|
||||
|
||||
String itemScriptName = null;
|
||||
mapitem.lockItem();
|
||||
try {
|
||||
if (mapitem.isPickedUp()) {
|
||||
@@ -1852,12 +1863,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
} else if (mItem.getItemId() / 10000 == 243) {
|
||||
MapleItemInformationProvider.scriptedItem info = ii.getScriptedItemInfo(mItem.getItemId());
|
||||
if (info.runOnPickup()) {
|
||||
ItemScriptManager ism = ItemScriptManager.getInstance();
|
||||
String scriptName = info.getScript();
|
||||
if (ism.scriptExists(scriptName)) {
|
||||
ism.getItemScript(client, scriptName);
|
||||
}
|
||||
|
||||
itemScriptName = info.getScript();
|
||||
} else {
|
||||
if (!MapleInventoryManipulator.addFromDrop(client, mItem, true)) {
|
||||
client.announce(MaplePacketCreator.enableActions());
|
||||
@@ -1890,6 +1896,13 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
} finally {
|
||||
mapitem.unlockItem();
|
||||
}
|
||||
|
||||
if (itemScriptName != null) {
|
||||
ItemScriptManager ism = ItemScriptManager.getInstance();
|
||||
if (ism.scriptExists(itemScriptName)) {
|
||||
ism.runItemScript(client, itemScriptName);
|
||||
}
|
||||
}
|
||||
}
|
||||
client.announce(MaplePacketCreator.enableActions());
|
||||
}
|
||||
@@ -2913,16 +2926,21 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized int applyFame(int delta) {
|
||||
int newFame = fame + delta;
|
||||
if (newFame < -30000) {
|
||||
delta = -(30000 + fame);
|
||||
} else if (newFame > 30000) {
|
||||
delta = 30000 - fame;
|
||||
}
|
||||
private Pair<Integer, Integer> applyFame(int delta) {
|
||||
petLock.lock();
|
||||
try {
|
||||
int newFame = fame + delta;
|
||||
if (newFame < -30000) {
|
||||
delta = -(30000 + fame);
|
||||
} else if (newFame > 30000) {
|
||||
delta = 30000 - fame;
|
||||
}
|
||||
|
||||
fame += delta;
|
||||
return delta;
|
||||
fame += delta;
|
||||
return new Pair<>(fame, delta);
|
||||
} finally {
|
||||
petLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void gainFame(int delta) {
|
||||
@@ -2930,9 +2948,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
|
||||
public boolean gainFame(int delta, MapleCharacter fromPlayer, int mode) {
|
||||
delta = applyFame(delta);
|
||||
Pair<Integer, Integer> fameRes = applyFame(delta);
|
||||
delta = fameRes.getRight();
|
||||
if (delta != 0) {
|
||||
int thisFame = fame;
|
||||
int thisFame = fameRes.getLeft();
|
||||
updateSingleStat(MapleStat.FAME, thisFame);
|
||||
|
||||
if (fromPlayer != null) {
|
||||
@@ -3571,10 +3590,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
for (MapleCharacter chr : townChars) {
|
||||
destroyDoor.getTownDoor().sendDestroyData(chr.getClient());
|
||||
}
|
||||
if(destroyDoor.getTownPortal().getId() == 0x80) {
|
||||
if (destroyDoor.getTownPortal().getId() == 0x80) {
|
||||
for (MapleCharacter chr : townChars) {
|
||||
MapleDoor door = chr.getMainTownDoor();
|
||||
if(door != null) {
|
||||
if (door != null) {
|
||||
destroyDoor.getTownDoor().sendSpawnData(chr.getClient());
|
||||
}
|
||||
}
|
||||
@@ -4180,29 +4199,33 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
|
||||
public void applyPartyDoor(MapleDoor door, boolean partyUpdate) {
|
||||
MapleParty chrParty;
|
||||
prtLock.lock();
|
||||
try {
|
||||
if (!partyUpdate) {
|
||||
pdoor = door;
|
||||
}
|
||||
|
||||
if (party != null) {
|
||||
party.addDoor(id, door);
|
||||
silentPartyUpdateInternal();
|
||||
chrParty = getParty();
|
||||
if (chrParty != null) {
|
||||
chrParty.addDoor(id, door);
|
||||
}
|
||||
} finally {
|
||||
prtLock.unlock();
|
||||
}
|
||||
|
||||
silentPartyUpdateInternal(chrParty);
|
||||
}
|
||||
|
||||
private MapleDoor removePartyDoor(boolean partyUpdate) {
|
||||
MapleDoor ret = null;
|
||||
MapleParty chrParty;
|
||||
|
||||
prtLock.lock();
|
||||
try {
|
||||
if (party != null) {
|
||||
party.removeDoor(id);
|
||||
silentPartyUpdateInternal();
|
||||
chrParty = getParty();
|
||||
if (chrParty != null) {
|
||||
chrParty.removeDoor(id);
|
||||
}
|
||||
|
||||
if (!partyUpdate) {
|
||||
@@ -4213,6 +4236,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
prtLock.unlock();
|
||||
}
|
||||
|
||||
silentPartyUpdateInternal(chrParty);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -5796,18 +5820,16 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
if (level == maxClassLevel) {
|
||||
if (!this.isGM()) {
|
||||
if (ServerConstants.PLAYERNPC_AUTODEPLOY) {
|
||||
Thread t = new Thread(new Runnable() {
|
||||
ThreadManager.getInstance().newTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
MaplePlayerNPC.spawnPlayerNPC(GameConstants.getHallOfFameMapid(job), MapleCharacter.this);
|
||||
}
|
||||
});
|
||||
|
||||
t.start();
|
||||
}
|
||||
|
||||
final String names = (getMedalText() + name);
|
||||
getWorldServer().broadcastPacket(MaplePacketCreator.serverNotice(6, String.format(LEVEL_200, names, names)));
|
||||
getWorldServer().broadcastPacket(MaplePacketCreator.serverNotice(6, String.format(LEVEL_200, names, maxClassLevel, names)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5874,22 +5896,27 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
Runnable r = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
MapleParty party;
|
||||
boolean partyLeader;
|
||||
|
||||
prtLock.lock();
|
||||
try {
|
||||
if (party != null) {
|
||||
if(isPartyLeader()) party.assignNewLeader(client);
|
||||
PartyOperationHandler.leaveParty(party, mpc, client);
|
||||
|
||||
showHint("You have reached #blevel 10#k, therefore you must leave your #rstarter party#k.");
|
||||
}
|
||||
party = getParty();
|
||||
partyLeader = party != null && isPartyLeader();
|
||||
} finally {
|
||||
prtLock.unlock();
|
||||
}
|
||||
|
||||
if (party != null) {
|
||||
if(partyLeader) party.assignNewLeader(client);
|
||||
PartyOperationHandler.leaveParty(party, mpc, client);
|
||||
|
||||
showHint("You have reached #blevel 10#k, therefore you must leave your #rstarter party#k.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Thread t = new Thread(r);
|
||||
t.start();
|
||||
ThreadManager.getInstance().newTask(r);
|
||||
}
|
||||
|
||||
levelUpMessages();
|
||||
@@ -7567,8 +7594,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
};
|
||||
|
||||
Thread t = new Thread(r); //spawns a new thread to deal with this
|
||||
t.start();
|
||||
ThreadManager.getInstance().newTask(r); //spawns a new thread to deal with this
|
||||
} else {
|
||||
saveCharToDB(true);
|
||||
}
|
||||
@@ -8439,23 +8465,34 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
|
||||
public int sellAllItemsFromName(byte invTypeId, String name) {
|
||||
//player decides from which inventory items should be sold.
|
||||
|
||||
MapleInventoryType type = MapleInventoryType.getByType(invTypeId);
|
||||
|
||||
Item it = getInventory(type).findByName(name);
|
||||
if(it == null) {
|
||||
return(-1);
|
||||
}
|
||||
MapleInventory inv = getInventory(type);
|
||||
inv.lockInventory();
|
||||
try {
|
||||
Item it = inv.findByName(name);
|
||||
if(it == null) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
return(sellAllItemsFromPosition(ii, type, it.getPosition()));
|
||||
return(sellAllItemsFromPosition(ii, type, it.getPosition()));
|
||||
} finally {
|
||||
inv.unlockInventory();
|
||||
}
|
||||
}
|
||||
|
||||
public int sellAllItemsFromPosition(MapleItemInformationProvider ii, MapleInventoryType type, short pos) {
|
||||
int mesoGain = 0;
|
||||
|
||||
for(short i = pos; i <= getInventory(type).getSlotLimit(); i++) {
|
||||
if(getInventory(type).getItem(i) == null) continue;
|
||||
mesoGain += standaloneSell(getClient(), ii, type, i, getInventory(type).getItem(i).getQuantity());
|
||||
MapleInventory inv = getInventory(type);
|
||||
inv.lockInventory();
|
||||
try {
|
||||
for(short i = pos; i <= inv.getSlotLimit(); i++) {
|
||||
if(inv.getItem(i) == null) continue;
|
||||
mesoGain += standaloneSell(getClient(), ii, type, i, inv.getItem(i).getQuantity());
|
||||
}
|
||||
} finally {
|
||||
inv.unlockInventory();
|
||||
}
|
||||
|
||||
return(mesoGain);
|
||||
@@ -8465,36 +8502,199 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
if (quantity == 0xFFFF || quantity == 0) {
|
||||
quantity = 1;
|
||||
}
|
||||
Item item = getInventory(type).getItem((short) slot);
|
||||
if (item == null){ //Basic check
|
||||
return(0);
|
||||
}
|
||||
|
||||
int itemid = item.getItemId();
|
||||
if (ItemConstants.isRechargeable(itemid)) {
|
||||
quantity = item.getQuantity();
|
||||
} else if (ItemConstants.isWeddingToken(itemid) || ItemConstants.isWeddingRing(itemid)) {
|
||||
return(0);
|
||||
}
|
||||
MapleInventory inv = getInventory(type);
|
||||
inv.lockInventory();
|
||||
try {
|
||||
Item item = inv.getItem((short) slot);
|
||||
if (item == null){ //Basic check
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (quantity < 0) {
|
||||
return(0);
|
||||
}
|
||||
short iQuant = item.getQuantity();
|
||||
if (iQuant == 0xFFFF) {
|
||||
iQuant = 1;
|
||||
}
|
||||
int itemid = item.getItemId();
|
||||
if (ItemConstants.isRechargeable(itemid)) {
|
||||
quantity = item.getQuantity();
|
||||
} else if (ItemConstants.isWeddingToken(itemid) || ItemConstants.isWeddingRing(itemid)) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (quantity <= iQuant && iQuant > 0) {
|
||||
MapleInventoryManipulator.removeFromSlot(c, type, (byte) slot, quantity, false);
|
||||
int recvMesos = ii.getPrice(itemid, quantity);
|
||||
if (recvMesos > 0) {
|
||||
gainMeso(recvMesos, false);
|
||||
return(recvMesos);
|
||||
if (quantity < 0) {
|
||||
return(0);
|
||||
}
|
||||
short iQuant = item.getQuantity();
|
||||
if (iQuant == 0xFFFF) {
|
||||
iQuant = 1;
|
||||
}
|
||||
|
||||
if (quantity <= iQuant && iQuant > 0) {
|
||||
MapleInventoryManipulator.removeFromSlot(c, type, (byte) slot, quantity, false);
|
||||
int recvMesos = ii.getPrice(itemid, quantity);
|
||||
if (recvMesos > 0) {
|
||||
gainMeso(recvMesos, false);
|
||||
return(recvMesos);
|
||||
}
|
||||
}
|
||||
|
||||
return(0);
|
||||
} finally {
|
||||
inv.unlockInventory();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasMergeFlag(Item item) {
|
||||
return (item.getFlag() & ItemConstants.MERGE_UNTRADEABLE) == ItemConstants.MERGE_UNTRADEABLE;
|
||||
}
|
||||
|
||||
private static void setMergeFlag(Item item) {
|
||||
int flag = item.getFlag();
|
||||
flag |= ItemConstants.MERGE_UNTRADEABLE;
|
||||
flag |= ItemConstants.UNTRADEABLE;
|
||||
item.setFlag((byte) flag);
|
||||
}
|
||||
|
||||
private List<Equip> getUpgradeableEquipped() {
|
||||
List<Equip> list = new LinkedList<>();
|
||||
|
||||
for (Item item : getInventory(MapleInventoryType.EQUIPPED)) {
|
||||
if (ii.isUpgradeable(item.getItemId())) {
|
||||
list.add((Equip) item);
|
||||
}
|
||||
}
|
||||
|
||||
return(0);
|
||||
return list;
|
||||
}
|
||||
|
||||
private static List<Equip> getEquipsWithStat(List<Pair<Equip, Map<StatUpgrade, Short>>> equipped, StatUpgrade stat) {
|
||||
List<Equip> equippedWithStat = new LinkedList<>();
|
||||
|
||||
for (Pair<Equip, Map<StatUpgrade, Short>> eq : equipped) {
|
||||
if (eq.getRight().containsKey(stat)) {
|
||||
equippedWithStat.add(eq.getLeft());
|
||||
}
|
||||
}
|
||||
|
||||
return equippedWithStat;
|
||||
}
|
||||
|
||||
public boolean mergeAllItemsFromName(String name) {
|
||||
MapleInventoryType type = MapleInventoryType.EQUIP;
|
||||
|
||||
MapleInventory inv = getInventory(type);
|
||||
inv.lockInventory();
|
||||
try {
|
||||
Item it = inv.findByName(name);
|
||||
if(it == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Map<StatUpgrade, Float> statups = new LinkedHashMap<>();
|
||||
mergeAllItemsFromPosition(statups, it.getPosition());
|
||||
|
||||
List<Pair<Equip, Map<StatUpgrade, Short>>> upgradeableEquipped = new LinkedList<>();
|
||||
Map<Equip, List<Pair<StatUpgrade, Integer>>> equipUpgrades = new LinkedHashMap<>();
|
||||
for (Equip eq : getUpgradeableEquipped()) {
|
||||
upgradeableEquipped.add(new Pair<>(eq, eq.getStats()));
|
||||
equipUpgrades.put(eq, new LinkedList<Pair<StatUpgrade, Integer>>());
|
||||
}
|
||||
|
||||
/*
|
||||
for (Entry<StatUpgrade, Float> e : statups.entrySet()) {
|
||||
System.out.println(e);
|
||||
}
|
||||
*/
|
||||
|
||||
for (Entry<StatUpgrade, Float> e : statups.entrySet()) {
|
||||
Double ev = Math.sqrt(e.getValue());
|
||||
|
||||
Set<Equip> extraEquipped = new LinkedHashSet<>(equipUpgrades.keySet());
|
||||
List<Equip> statEquipped = getEquipsWithStat(upgradeableEquipped, e.getKey());
|
||||
float extraRate = (float)(0.2 * Math.random());
|
||||
|
||||
if (!statEquipped.isEmpty()) {
|
||||
float statRate = 1.0f - extraRate;
|
||||
|
||||
int statup = (int) Math.ceil((ev * statRate) / statEquipped.size());
|
||||
for (Equip statEq : statEquipped) {
|
||||
equipUpgrades.get(statEq).add(new Pair<>(e.getKey(), statup));
|
||||
extraEquipped.remove(statEq);
|
||||
}
|
||||
}
|
||||
|
||||
if (!extraEquipped.isEmpty()) {
|
||||
int statup = (int) Math.round((ev * extraRate) / extraEquipped.size());
|
||||
if (statup > 0) {
|
||||
for (Equip extraEq : extraEquipped) {
|
||||
equipUpgrades.get(extraEq).add(new Pair<>(e.getKey(), statup));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dropMessage(6, "EQUIPMENT MERGE operation results:");
|
||||
for (Entry<Equip, List<Pair<StatUpgrade, Integer>>> eqpUpg : equipUpgrades.entrySet()) {
|
||||
List<Pair<StatUpgrade, Integer>> eqpStatups = eqpUpg.getValue();
|
||||
if (!eqpStatups.isEmpty()) {
|
||||
Equip eqp = eqpUpg.getKey();
|
||||
setMergeFlag(eqp);
|
||||
|
||||
String showStr = " '" + MapleItemInformationProvider.getInstance().getName(eqp.getItemId()) + "': ";
|
||||
String upgdStr = eqp.gainStats(eqpStatups).getLeft();
|
||||
|
||||
this.forceUpdateItem(eqp);
|
||||
|
||||
showStr += upgdStr;
|
||||
dropMessage(6, showStr);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} finally {
|
||||
inv.unlockInventory();
|
||||
}
|
||||
}
|
||||
|
||||
public void mergeAllItemsFromPosition(Map<StatUpgrade, Float> statups, short pos) {
|
||||
MapleInventory inv = getInventory(MapleInventoryType.EQUIP);
|
||||
inv.lockInventory();
|
||||
try {
|
||||
for(short i = pos; i <= inv.getSlotLimit(); i++) {
|
||||
standaloneMerge(statups, getClient(), MapleInventoryType.EQUIP, i, inv.getItem(i));
|
||||
}
|
||||
} finally {
|
||||
inv.unlockInventory();
|
||||
}
|
||||
}
|
||||
|
||||
private void standaloneMerge(Map<StatUpgrade, Float> statups, MapleClient c, MapleInventoryType type, short slot, Item item) {
|
||||
short quantity;
|
||||
if (item == null || (quantity = item.getQuantity()) < 1 || ii.isCash(item.getItemId()) || !ii.isUpgradeable(item.getItemId()) || hasMergeFlag(item)){
|
||||
return;
|
||||
}
|
||||
|
||||
Equip e = (Equip) item;
|
||||
for (Entry<StatUpgrade, Short> s : e.getStats().entrySet()) {
|
||||
Float newVal = statups.get(s.getKey());
|
||||
|
||||
float incVal = s.getValue().floatValue();
|
||||
switch (s.getKey()) {
|
||||
case incPAD:
|
||||
case incMAD:
|
||||
case incPDD:
|
||||
case incMDD:
|
||||
incVal = (float) Math.log(incVal);
|
||||
break;
|
||||
}
|
||||
|
||||
if (newVal != null) {
|
||||
newVal += incVal;
|
||||
} else {
|
||||
newVal = incVal;
|
||||
}
|
||||
|
||||
statups.put(s.getKey(), newVal);
|
||||
}
|
||||
|
||||
MapleInventoryManipulator.removeFromSlot(c, type, (byte) slot, quantity, false);
|
||||
}
|
||||
|
||||
public void setShop(MapleShop shop) {
|
||||
@@ -8599,17 +8799,12 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
|
||||
public void silentPartyUpdate() {
|
||||
prtLock.lock();
|
||||
try {
|
||||
silentPartyUpdateInternal();
|
||||
} finally {
|
||||
prtLock.unlock();
|
||||
}
|
||||
silentPartyUpdateInternal(getParty());
|
||||
}
|
||||
|
||||
private void silentPartyUpdateInternal() {
|
||||
if (party != null) {
|
||||
getWorldServer().updateParty(party.getId(), PartyOperation.SILENT_UPDATE, getMPC());
|
||||
private void silentPartyUpdateInternal(MapleParty chrParty) {
|
||||
if (chrParty != null) {
|
||||
getWorldServer().updateParty(chrParty.getId(), PartyOperation.SILENT_UPDATE, getMPC());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8662,7 +8857,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
}
|
||||
|
||||
public void runTirednessSchedule() {
|
||||
public boolean runTirednessSchedule() {
|
||||
if(maplemount != null) {
|
||||
int tiredness = maplemount.incrementAndGetTiredness();
|
||||
|
||||
@@ -8671,8 +8866,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
maplemount.setTiredness(99);
|
||||
this.dispelSkill(this.getJobType() * 10000000 + 1004);
|
||||
this.dropMessage(6, "Your mount grew tired! Treat it some revitalizer before riding it again!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void startMapEffect(String msg, int itemId) {
|
||||
@@ -8956,7 +9154,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
if (!this.isHidden() || client.getPlayer().gmLevel() > 1) {
|
||||
client.announce(MaplePacketCreator.spawnPlayerMapObject(client, this, false));
|
||||
|
||||
if(hasBuffFromSourceid(getJobMapChair(job))) {
|
||||
if (buffEffects.containsKey(getJobMapChair(job))) { // mustn't effLock, chrLock this function
|
||||
client.announce(MaplePacketCreator.giveForeignChairSkillEffect(id));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,7 @@ import scripting.quest.QuestActionManager;
|
||||
import scripting.quest.QuestScriptManager;
|
||||
import server.life.MapleMonster;
|
||||
import server.MapleTrade;
|
||||
import server.ThreadManager;
|
||||
import server.maps.*;
|
||||
import server.quest.MapleQuest;
|
||||
|
||||
@@ -159,7 +160,7 @@ public class MapleClient {
|
||||
}
|
||||
|
||||
public void sendCharList(int server) {
|
||||
this.announce(MaplePacketCreator.getCharList(this, server));
|
||||
this.announce(MaplePacketCreator.getCharList(this, server, 0));
|
||||
}
|
||||
|
||||
public List<MapleCharacter> loadCharacters(int serverId) {
|
||||
@@ -878,11 +879,33 @@ public class MapleClient {
|
||||
}
|
||||
}
|
||||
|
||||
public final synchronized void disconnect(boolean shutdown, boolean cashshop) {//once per MapleClient instance
|
||||
public final void disconnect(final boolean shutdown, final boolean cashshop) {
|
||||
if (isDisconnecting()) {
|
||||
ThreadManager.getInstance().newTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
disconnectInternal(shutdown, cashshop);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public final void forceDisconnect() {
|
||||
if (isDisconnecting()) {
|
||||
disconnectInternal(true, false);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized boolean isDisconnecting() {
|
||||
if (disconnecting) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
disconnecting = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void disconnectInternal(boolean shutdown, boolean cashshop) {//once per MapleClient instance
|
||||
if (player != null && player.isLoggedin() && player.getClient() != null) {
|
||||
final int messengerid = player.getMessenger() == null ? 0 : player.getMessenger().getId();
|
||||
//final int fid = player.getFamilyId();
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package client.autoban;
|
||||
|
||||
import client.MapleCharacter;
|
||||
import constants.ServerConstants;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import net.server.Server;
|
||||
@@ -109,11 +110,15 @@ public class AutobanManager {
|
||||
if (this.timestamp[type] == time) {
|
||||
this.timestampcounter[type]++;
|
||||
if (this.timestampcounter[type] >= times) {
|
||||
chr.getClient().disconnect(false, false);
|
||||
if (ServerConstants.USE_AUTOBAN) {
|
||||
chr.getClient().disconnect(false, false);
|
||||
}
|
||||
|
||||
FilePrinter.print(FilePrinter.EXPLOITS, "Player " + chr + " was caught spamming TYPE " + type + " and has been disconnected.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.timestamp[type] = time;
|
||||
this.timestampcounter[type] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class TimeCommand extends Command {
|
||||
@Override
|
||||
public void execute(MapleClient client, String[] params) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
client.getPlayer().yellowMessage("HeavenMS Server Time: " + dateFormat.format(new Date()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,9 @@ public class SummonCommand extends Command {
|
||||
}
|
||||
|
||||
MapleCharacter victim = c.getChannelServer().getPlayerStorage().getCharacterByName(params[0]);
|
||||
if (victim == null) {//If victim isn't on current channel, loop all channels on current world.
|
||||
if (victim == null) {
|
||||
//If victim isn't on current channel, loop all channels on current world.
|
||||
|
||||
for (Channel ch : Server.getInstance().getChannelsFromWorld(c.getWorld())) {
|
||||
victim = ch.getPlayerStorage().getCharacterByName(params[0]);
|
||||
if (victim != null) {
|
||||
@@ -61,9 +63,10 @@ public class SummonCommand extends Command {
|
||||
victim.getEventInstance().unregisterPlayer(victim);
|
||||
}
|
||||
}
|
||||
|
||||
//Attempt to join the warpers instance.
|
||||
if (player.getEventInstance() != null && changingEvent) {
|
||||
if (player.getClient().getChannel() == victim.getClient().getChannel()) {//just in case.. you never know...
|
||||
if (player.getClient().getChannel() == victim.getClient().getChannel()) {
|
||||
player.getEventInstance().registerPlayer(victim);
|
||||
victim.changeMap(player.getEventInstance().getMapInstance(player.getMapId()), player.getMap().findClosestPortal(player.getPosition()));
|
||||
} else {
|
||||
|
||||
@@ -71,7 +71,8 @@ public class DebugCommand extends Command {
|
||||
List<MapleMapObject> monsters = player.getMap().getMapObjectsInRange(player.getPosition(), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.MONSTER));
|
||||
for (MapleMapObject monstermo : monsters) {
|
||||
MapleMonster monster = (MapleMonster) monstermo;
|
||||
player.message("Monster ID: " + monster.getId() + " Aggro target: " + ((monster.getController() != null) ? monster.getController().getName() : "<none>"));
|
||||
MapleCharacter controller = monster.getController();
|
||||
player.message("Monster ID: " + monster.getId() + " Aggro target: " + ((controller != null) ? controller.getName() : "<none>"));
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import client.MapleCharacter;
|
||||
import client.command.Command;
|
||||
import client.MapleClient;
|
||||
import net.server.Server;
|
||||
import server.ThreadManager;
|
||||
|
||||
public class ServerAddChannelCommand extends Command {
|
||||
{
|
||||
@@ -44,7 +45,7 @@ public class ServerAddChannelCommand extends Command {
|
||||
|
||||
final int worldid = Integer.parseInt(params[0]);
|
||||
|
||||
new Thread(new Runnable() {
|
||||
ThreadManager.getInstance().newTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int chid = Server.getInstance().addChannel(worldid);
|
||||
@@ -64,6 +65,6 @@ public class ServerAddChannelCommand extends Command {
|
||||
}
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import client.MapleCharacter;
|
||||
import client.command.Command;
|
||||
import client.MapleClient;
|
||||
import net.server.Server;
|
||||
import server.ThreadManager;
|
||||
|
||||
public class ServerAddWorldCommand extends Command {
|
||||
{
|
||||
@@ -37,7 +38,7 @@ public class ServerAddWorldCommand extends Command {
|
||||
public void execute(MapleClient c, String[] params) {
|
||||
final MapleCharacter player = c.getPlayer();
|
||||
|
||||
new Thread(new Runnable() {
|
||||
ThreadManager.getInstance().newTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int wid = Server.getInstance().addWorld();
|
||||
@@ -54,6 +55,6 @@ public class ServerAddWorldCommand extends Command {
|
||||
}
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import client.MapleCharacter;
|
||||
import client.command.Command;
|
||||
import client.MapleClient;
|
||||
import net.server.Server;
|
||||
import server.ThreadManager;
|
||||
|
||||
public class ServerRemoveChannelCommand extends Command {
|
||||
{
|
||||
@@ -43,7 +44,7 @@ public class ServerRemoveChannelCommand extends Command {
|
||||
}
|
||||
|
||||
final int worldId = Integer.parseInt(params[0]);
|
||||
new Thread(new Runnable() {
|
||||
ThreadManager.getInstance().newTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if(Server.getInstance().removeChannel(worldId)) {
|
||||
@@ -56,6 +57,6 @@ public class ServerRemoveChannelCommand extends Command {
|
||||
}
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import client.MapleCharacter;
|
||||
import client.command.Command;
|
||||
import client.MapleClient;
|
||||
import net.server.Server;
|
||||
import server.ThreadManager;
|
||||
|
||||
public class ServerRemoveWorldCommand extends Command {
|
||||
{
|
||||
@@ -43,7 +44,7 @@ public class ServerRemoveWorldCommand extends Command {
|
||||
return;
|
||||
}
|
||||
|
||||
new Thread(new Runnable() {
|
||||
ThreadManager.getInstance().newTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if(Server.getInstance().removeWorld()) {
|
||||
@@ -60,6 +61,6 @@ public class ServerRemoveWorldCommand extends Command {
|
||||
}
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,10 @@ package client.inventory;
|
||||
import client.MapleClient;
|
||||
import constants.ServerConstants;
|
||||
import constants.ExpTable;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import server.MapleItemInformationProvider;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Pair;
|
||||
@@ -47,7 +49,7 @@ public class Equip extends Item {
|
||||
}
|
||||
}
|
||||
|
||||
private static enum StatUpgrade {
|
||||
public static enum StatUpgrade {
|
||||
|
||||
incDEX(0), incSTR(1), incINT(2), incLUK(3),
|
||||
incMHP(4), incMMP(5), incPAD(6), incMAD(7),
|
||||
@@ -332,49 +334,30 @@ public class Equip extends Item {
|
||||
if(jump > 0) getUnitStatUpgrade(stats, StatUpgrade.incJump, jump, false);
|
||||
}
|
||||
|
||||
private void gainLevel(MapleClient c) {
|
||||
List<Pair<StatUpgrade, Integer>> stats = new LinkedList<>();
|
||||
public Map<StatUpgrade, Short> getStats() {
|
||||
Map<StatUpgrade, Short> stats = new HashMap<>(5);
|
||||
|
||||
if(isElemental) {
|
||||
List<Pair<String, Integer>> elementalStats = MapleItemInformationProvider.getInstance().getItemLevelupStats(getItemId(), itemLevel);
|
||||
if(dex > 0) stats.put(StatUpgrade.incDEX, dex);
|
||||
if(str > 0) stats.put(StatUpgrade.incSTR, str);
|
||||
if(_int > 0) stats.put(StatUpgrade.incINT,_int);
|
||||
if(luk > 0) stats.put(StatUpgrade.incLUK, luk);
|
||||
if(hp > 0) stats.put(StatUpgrade.incMHP, hp);
|
||||
if(mp > 0) stats.put(StatUpgrade.incMMP, mp);
|
||||
if(watk > 0) stats.put(StatUpgrade.incPAD, watk);
|
||||
if(matk > 0) stats.put(StatUpgrade.incMAD, matk);
|
||||
if(wdef > 0) stats.put(StatUpgrade.incPDD, wdef);
|
||||
if(mdef > 0) stats.put(StatUpgrade.incMDD, mdef);
|
||||
if(avoid > 0) stats.put(StatUpgrade.incEVA, avoid);
|
||||
if(acc > 0) stats.put(StatUpgrade.incACC, acc);
|
||||
if(speed > 0) stats.put(StatUpgrade.incSpeed, speed);
|
||||
if(jump > 0) stats.put(StatUpgrade.incJump, jump);
|
||||
|
||||
for(Pair<String, Integer> p: elementalStats) {
|
||||
if(p.getRight() > 0) stats.add(new Pair<>(StatUpgrade.valueOf(p.getLeft()), p.getRight()));
|
||||
}
|
||||
}
|
||||
|
||||
if(!stats.isEmpty()) {
|
||||
if(ServerConstants.USE_EQUIPMNT_LVLUP_SLOTS) {
|
||||
if(vicious > 0) getUnitSlotUpgrade(stats, StatUpgrade.incVicious);
|
||||
getUnitSlotUpgrade(stats, StatUpgrade.incSlot);
|
||||
}
|
||||
}
|
||||
else {
|
||||
isUpgradeable = false;
|
||||
|
||||
improveDefaultStats(stats);
|
||||
if(ServerConstants.USE_EQUIPMNT_LVLUP_SLOTS) {
|
||||
if(vicious > 0) getUnitSlotUpgrade(stats, StatUpgrade.incVicious);
|
||||
getUnitSlotUpgrade(stats, StatUpgrade.incSlot);
|
||||
}
|
||||
|
||||
if(isUpgradeable) {
|
||||
while(stats.isEmpty()) {
|
||||
improveDefaultStats(stats);
|
||||
if(ServerConstants.USE_EQUIPMNT_LVLUP_SLOTS) {
|
||||
if(vicious > 0) getUnitSlotUpgrade(stats, StatUpgrade.incVicious);
|
||||
getUnitSlotUpgrade(stats, StatUpgrade.incSlot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
itemLevel++;
|
||||
boolean gotVicious = false, gotSlot = false;
|
||||
|
||||
String lvupStr = "'" + MapleItemInformationProvider.getInstance().getName(this.getItemId()) + "' is now level " + itemLevel + "! ";
|
||||
String showStr = "#e'" + MapleItemInformationProvider.getInstance().getName(this.getItemId()) + "'#b is now #elevel #r" + itemLevel + "#k#b!";
|
||||
return stats;
|
||||
}
|
||||
|
||||
public Pair<String, Pair<Boolean, Boolean>> gainStats(List<Pair<StatUpgrade, Integer>> stats) {
|
||||
boolean gotSlot = false, gotVicious = false;
|
||||
String lvupStr = "";
|
||||
Integer statUp, maxStat = ServerConstants.MAX_EQUIPMNT_STAT;
|
||||
for (Pair<StatUpgrade, Integer> stat : stats) {
|
||||
switch (stat.getLeft()) {
|
||||
@@ -460,6 +443,55 @@ public class Equip extends Item {
|
||||
}
|
||||
}
|
||||
|
||||
return new Pair<>(lvupStr, new Pair<>(gotSlot, gotVicious));
|
||||
}
|
||||
|
||||
private void gainLevel(MapleClient c) {
|
||||
List<Pair<StatUpgrade, Integer>> stats = new LinkedList<>();
|
||||
|
||||
if(isElemental) {
|
||||
List<Pair<String, Integer>> elementalStats = MapleItemInformationProvider.getInstance().getItemLevelupStats(getItemId(), itemLevel);
|
||||
|
||||
for(Pair<String, Integer> p: elementalStats) {
|
||||
if(p.getRight() > 0) stats.add(new Pair<>(StatUpgrade.valueOf(p.getLeft()), p.getRight()));
|
||||
}
|
||||
}
|
||||
|
||||
if(!stats.isEmpty()) {
|
||||
if(ServerConstants.USE_EQUIPMNT_LVLUP_SLOTS) {
|
||||
if(vicious > 0) getUnitSlotUpgrade(stats, StatUpgrade.incVicious);
|
||||
getUnitSlotUpgrade(stats, StatUpgrade.incSlot);
|
||||
}
|
||||
} else {
|
||||
isUpgradeable = false;
|
||||
|
||||
improveDefaultStats(stats);
|
||||
if(ServerConstants.USE_EQUIPMNT_LVLUP_SLOTS) {
|
||||
if(vicious > 0) getUnitSlotUpgrade(stats, StatUpgrade.incVicious);
|
||||
getUnitSlotUpgrade(stats, StatUpgrade.incSlot);
|
||||
}
|
||||
|
||||
if(isUpgradeable) {
|
||||
while(stats.isEmpty()) {
|
||||
improveDefaultStats(stats);
|
||||
if(ServerConstants.USE_EQUIPMNT_LVLUP_SLOTS) {
|
||||
if(vicious > 0) getUnitSlotUpgrade(stats, StatUpgrade.incVicious);
|
||||
getUnitSlotUpgrade(stats, StatUpgrade.incSlot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
itemLevel++;
|
||||
|
||||
String lvupStr = "'" + MapleItemInformationProvider.getInstance().getName(this.getItemId()) + "' is now level " + itemLevel + "! ";
|
||||
String showStr = "#e'" + MapleItemInformationProvider.getInstance().getName(this.getItemId()) + "'#b is now #elevel #r" + itemLevel + "#k#b!";
|
||||
|
||||
Pair<String, Pair<Boolean, Boolean>> res = gainStats(stats);
|
||||
lvupStr += res.getLeft();
|
||||
boolean gotSlot = res.getRight().getLeft();
|
||||
boolean gotVicious = res.getRight().getRight();
|
||||
|
||||
if(gotVicious) {
|
||||
//c.getPlayer().dropMessage(6, "A new Vicious Hammer opportunity has been found on the '" + MapleItemInformationProvider.getInstance().getName(getItemId()) + "'!");
|
||||
lvupStr += "+VICIOUS ";
|
||||
|
||||
@@ -73,6 +73,7 @@ public class Item implements Comparable<Item> {
|
||||
|
||||
public void setPosition(short position) {
|
||||
this.position = position;
|
||||
if (this.pet != null) this.pet.setPosition(position);
|
||||
}
|
||||
|
||||
public void setQuantity(short quantity) {
|
||||
|
||||
@@ -215,7 +215,7 @@ public class MaplePet extends Item {
|
||||
enjoyed = false;
|
||||
}
|
||||
|
||||
owner.getMap().broadcastMessage(MaplePacketCreator.commandResponse(owner.getId(), slot, type, enjoyed));
|
||||
owner.getMap().broadcastMessage(MaplePacketCreator.petFoodResponse(owner.getId(), slot, enjoyed, false));
|
||||
saveToDb();
|
||||
|
||||
Item petz = owner.getInventory(MapleInventoryType.CASH).getItem(getPosition());
|
||||
|
||||
@@ -188,6 +188,7 @@ public class MapleInventoryManipulator {
|
||||
short newQ = (short) Math.min(oldQ + quantity, slotMax);
|
||||
quantity -= (newQ - oldQ);
|
||||
eItem.setQuantity(newQ);
|
||||
item.setPosition(eItem.getPosition());
|
||||
c.announce(MaplePacketCreator.modifyInventory(true, Collections.singletonList(new ModifyInventory(1, eItem))));
|
||||
}
|
||||
} else {
|
||||
@@ -209,6 +210,8 @@ public class MapleInventoryManipulator {
|
||||
item.setQuantity((short) (quantity + newQ));
|
||||
return false;
|
||||
}
|
||||
nItem.setPosition(newSlot);
|
||||
item.setPosition(newSlot);
|
||||
c.announce(MaplePacketCreator.modifyInventory(true, Collections.singletonList(new ModifyInventory(0, nItem))));
|
||||
if(MapleInventoryManipulator.isSandboxItem(nItem)) chr.setHasSandboxItem();
|
||||
}
|
||||
@@ -223,6 +226,8 @@ public class MapleInventoryManipulator {
|
||||
c.announce(MaplePacketCreator.getShowInventoryFull());
|
||||
return false;
|
||||
}
|
||||
nItem.setPosition(newSlot);
|
||||
item.setPosition(newSlot);
|
||||
c.announce(MaplePacketCreator.modifyInventory(true, Collections.singletonList(new ModifyInventory(0, nItem))));
|
||||
if(MapleInventoryManipulator.isSandboxItem(nItem)) chr.setHasSandboxItem();
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
@@ -234,6 +239,7 @@ public class MapleInventoryManipulator {
|
||||
c.announce(MaplePacketCreator.getShowInventoryFull());
|
||||
return false;
|
||||
}
|
||||
item.setPosition(newSlot);
|
||||
c.announce(MaplePacketCreator.modifyInventory(true, Collections.singletonList(new ModifyInventory(0, item))));
|
||||
if(MapleInventoryManipulator.isSandboxItem(item)) chr.setHasSandboxItem();
|
||||
} else {
|
||||
|
||||
@@ -43,6 +43,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import server.ThreadManager;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Randomizer;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
@@ -333,13 +334,12 @@ public class AssignAPProcessor {
|
||||
AutobanFactory.PACKET_EDIT.alert(chr, "Didn't send full packet for Auto Assign.");
|
||||
|
||||
final MapleClient client = c;
|
||||
Thread t = new Thread(new Runnable() {
|
||||
ThreadManager.getInstance().newTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
client.disconnect(false, false);
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import client.SkillFactory;
|
||||
import client.autoban.AutobanFactory;
|
||||
import constants.GameConstants;
|
||||
import constants.skills.Aran;
|
||||
import server.ThreadManager;
|
||||
import tools.FilePrinter;
|
||||
import tools.MaplePacketCreator;
|
||||
|
||||
@@ -55,13 +56,12 @@ public class AssignSPProcessor {
|
||||
FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to use skill " + skillid + " without it being in their job.\r\n");
|
||||
|
||||
final MapleClient client = c;
|
||||
Thread t = new Thread(new Runnable() {
|
||||
ThreadManager.getInstance().newTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
client.disconnect(true, false);
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
package client.processor;
|
||||
|
||||
import client.MapleClient;
|
||||
import client.MapleCharacter;
|
||||
import client.inventory.Equip;
|
||||
import client.inventory.Item;
|
||||
import client.inventory.MapleInventoryType;
|
||||
@@ -199,7 +200,7 @@ public class MakerProcessor {
|
||||
c.announce(MaplePacketCreator.showMakerEffect(makerSucceeded));
|
||||
c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showForeignMakerEffect(c.getPlayer().getId(), makerSucceeded), false);
|
||||
|
||||
if(toCreate == 4260003 && c.getPlayer().getQuestStatus(6033) == 1) {
|
||||
if(toCreate == 4260003 && type == 3 && c.getPlayer().getQuestStatus(6033) == 1) {
|
||||
c.getAbstractPlayerInteraction().setQuestProgress(6033, 1);
|
||||
}
|
||||
} else {
|
||||
@@ -282,6 +283,10 @@ public class MakerProcessor {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int getMakerSkillLevel(MapleCharacter chr) {
|
||||
return chr.getSkillLevel((chr.getJob().getId() / 1000) * 10000000 + 1007);
|
||||
}
|
||||
|
||||
private static short getCreateStatus(MapleClient c, MakerItemFactory.MakerItemCreateEntry recipe) {
|
||||
if(recipe == null) {
|
||||
return -1;
|
||||
@@ -299,7 +304,7 @@ public class MakerProcessor {
|
||||
return 3;
|
||||
}
|
||||
|
||||
if(c.getPlayer().getSkillLevel((c.getPlayer().getJob().getId() / 1000) * 10000000 + 1007) < recipe.getReqSkillLevel()) {
|
||||
if(getMakerSkillLevel(c.getPlayer()) < recipe.getReqSkillLevel()) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ public final class ItemConstants {
|
||||
public final static int SANDBOX = 0x40; // let 0x40 until it's proven something uses this
|
||||
public final static int PET_COME = 0x80;
|
||||
public final static int ACCOUNT_SHARING = 0x100;
|
||||
public final static int MERGE_UNTRADEABLE = 0x200;
|
||||
|
||||
public final static boolean EXPIRING_ITEMS = true;
|
||||
public final static Set<Integer> permanentItemids = new HashSet<>();
|
||||
|
||||
@@ -82,7 +82,7 @@ public class ServerConstants {
|
||||
public static final boolean USE_ENFORCE_HPMP_SWAP = false; //Forces players to reuse stats (via AP Resetting) located on HP/MP pool only inside the HP/MP stats.
|
||||
public static final boolean USE_ENFORCE_MOB_LEVEL_RANGE = true; //Players N levels below the killed mob will gain no experience from defeating it.
|
||||
public static final boolean USE_ENFORCE_JOB_LEVEL_RANGE = false;//Caps the player level on the minimum required to advance their current jobs.
|
||||
public static final boolean USE_ENFORCE_JOB_SP_RANGE = true; //Caps the player SP level on the total obtainable by their current jobs. After changing jobs, missing SP will be retrieved.
|
||||
public static final boolean USE_ENFORCE_JOB_SP_RANGE = false; //Caps the player SP level on the total obtainable by their current jobs. After changing jobs, missing SP will be retrieved.
|
||||
public static final boolean USE_ENFORCE_ITEM_SUGGESTION = false;//Forces the Owl of Minerva and the Cash Shop to always display the defined item array instead of those featured by the players.
|
||||
public static final boolean USE_ENFORCE_UNMERCHABLE_CASH = true;//Forces players to not sell CASH items via merchants.
|
||||
public static final boolean USE_ENFORCE_UNMERCHABLE_PET = true; //Forces players to not sell pets via merchants. (since non-named pets gets dirty name and other possible DB-related issues)
|
||||
@@ -115,6 +115,10 @@ public class ServerConstants {
|
||||
public static final boolean USE_MAKER_PERMISSIVE_ATKUP = true; //Allows players to use attack-based strengthening gems on non-weapon items.
|
||||
public static final boolean USE_MAKER_FEE_HEURISTICS = true; //Apply compiled values for stimulants and reagents into the Maker fee calculations (max error revolves around 50k mesos). Set false to use basic constant values instead (results are never higher than requested by the client-side).
|
||||
|
||||
//Custom Configuration
|
||||
public static final boolean USE_ENABLE_CUSTOM_NPC_SCRIPT = true;//Enables usage of custom HeavenMS NPC scripts (Agent E, Coco, etc). Will not disable Abdula (it's actually useful for the gameplay), quests or NPC shops.
|
||||
public static final boolean USE_STARTER_MERGE = false; //Allows any players to use the Equipment Merge custom mechanic (as opposed to the high-level, Maker lv3 requisites).
|
||||
|
||||
//Commands Configuration
|
||||
public static final boolean BLOCK_GENERATE_CASH_ITEM = false; //Prevents creation of cash items with the item/drop command.
|
||||
public static final boolean USE_WHOLE_SERVER_RANKING = false; //Enables a ranking pool made from every character registered on the server for the "ranks" command, instead of separated by worlds.
|
||||
@@ -133,7 +137,7 @@ public class ServerConstants {
|
||||
public static final int PARTY_EXPERIENCE_MOD = 1; //Change for event stuff.
|
||||
|
||||
//Miscellaneous Configuration
|
||||
public static String TIMEZONE = "-GMT3";
|
||||
public static String TIMEZONE = "GMT-3";
|
||||
public static boolean USE_DISPLAY_NUMBERS_WITH_COMMA = true; //Enforce comma on displayed strings (use this when USE_UNITPRICE_WITH_COMMA is active and you still want to display comma-separated values).
|
||||
public static boolean USE_UNITPRICE_WITH_COMMA = true; //Set this accordingly with the layout of the unitPrices on Item.wz XML's, whether it's using commas or dots to represent fractions.
|
||||
public static final byte MIN_UNDERLEVEL_TO_EXP_GAIN = 20; //Characters are unable to get EXP from a mob if their level are under this threshold, only if "USE_ENFORCE_MOB_LEVEL_RANGE" is enabled. For bosses, this attribute is doubled.
|
||||
@@ -178,6 +182,7 @@ public class ServerConstants {
|
||||
public static final boolean USE_ULTRA_THREE_SNAILS = true; //Massive damage on shell toss.
|
||||
|
||||
//Other Skills Configuration
|
||||
public static final boolean USE_FULL_ARAN_SKILLSET = false; //Enables starter availability to all Aran job skills. Suggestion thanks to Masterrulax.
|
||||
public static final boolean USE_FAST_REUSE_HERO_WILL = true;//Greatly reduce cooldown on Hero's Will.
|
||||
public static final boolean USE_ANTI_IMMUNITY_CRASH = true; //Crash skills additionally removes the mob's invincibility buffs. Suggestion thanks to Celestial.
|
||||
public static final boolean USE_UNDISPEL_HOLY_SHIELD = true;//Holy shield buff also prevents players from suffering dispel from mobs.
|
||||
@@ -245,6 +250,7 @@ public class ServerConstants {
|
||||
public static final long EVENT_LOBBY_DELAY = 10; //Cooldown duration in seconds before reopening an event lobby.
|
||||
|
||||
//Dojo Configuration
|
||||
public static final boolean USE_FAST_DOJO_UPGRADE = true; //Reduced Dojo training points amount required for a belt upgrade.
|
||||
public static final boolean USE_DEADLY_DOJO = false; //Should bosses really use 1HP,1MP attacks in dojo?
|
||||
public static final int DOJO_ENERGY_ATK = 100; //Dojo energy gain when deal attack
|
||||
public static final int DOJO_ENERGY_DMG = 20; //Dojo energy gain when recv attack
|
||||
|
||||
@@ -33,6 +33,7 @@ public class WindArcher {
|
||||
public static final int BOW_BOOSTER = 13101001;
|
||||
public static final int FINAL_ATTACK = 13101002;
|
||||
public static final int SOUL_ARROW = 13101003;
|
||||
public static final int STORM_BREAK = 13101005;
|
||||
public static final int WIND_WALK = 13101006;
|
||||
public static final int HURRICANE = 13111002;
|
||||
public static final int PUPPET = 13111004;
|
||||
|
||||
@@ -136,6 +136,7 @@ public final class PacketProcessor {
|
||||
registerHandler(RecvOpcode.NPC_TALK, new NPCTalkHandler());
|
||||
registerHandler(RecvOpcode.NPC_TALK_MORE, new NPCMoreTalkHandler());
|
||||
registerHandler(RecvOpcode.QUEST_ACTION, new QuestActionHandler());
|
||||
registerHandler(RecvOpcode.GRENADE_EFFECT, new GrenadeEffectHandler());
|
||||
registerHandler(RecvOpcode.NPC_SHOP, new NPCShopHandler());
|
||||
registerHandler(RecvOpcode.ITEM_SORT, new InventoryMergeHandler());
|
||||
registerHandler(RecvOpcode.ITEM_MOVE, new ItemMoveHandler());
|
||||
|
||||
@@ -114,7 +114,8 @@ public enum RecvOpcode {
|
||||
TROCK_ADD_MAP(0x66),
|
||||
REPORT(0x6A),
|
||||
QUEST_ACTION(0x6B),
|
||||
//lolno
|
||||
//USER_CALC_DAMAGE_STAT_SET_REQUEST(0x6C),
|
||||
GRENADE_EFFECT(0x6D),
|
||||
SKILL_MACRO(0x6E),
|
||||
USE_ITEM_REWARD(0x70),
|
||||
MAKER_SKILL(0x71),
|
||||
|
||||
@@ -228,6 +228,7 @@ public enum SendOpcode {
|
||||
GIVE_FOREIGN_BUFF(0xC7),
|
||||
CANCEL_FOREIGN_BUFF(0xC8),
|
||||
UPDATE_PARTYMEMBER_HP(0xC9),
|
||||
THROW_GRENADE(0xCC),
|
||||
CANCEL_CHAIR(0xCD),
|
||||
SHOW_ITEM_GAIN_INCHAT(0xCE),
|
||||
DOJO_WARP_UP(0xCF),
|
||||
|
||||
@@ -102,7 +102,7 @@ public class PlayerStorage {
|
||||
for(MapleCharacter mc : chrList) {
|
||||
MapleClient client = mc.getClient();
|
||||
if(client != null) {
|
||||
client.disconnect(true, false);
|
||||
client.forceDisconnect();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -85,8 +85,10 @@ import client.newyear.NewYearCardRecord;
|
||||
import constants.ItemConstants;
|
||||
import constants.GameConstants;
|
||||
import constants.ServerConstants;
|
||||
import java.util.TimeZone;
|
||||
import server.CashShop.CashItemFactory;
|
||||
import server.MapleSkillbookInformationProvider;
|
||||
import server.ThreadManager;
|
||||
import server.TimerManager;
|
||||
import server.life.MaplePlayerNPCFactory;
|
||||
import server.quest.MapleQuest;
|
||||
@@ -147,6 +149,10 @@ public class Server {
|
||||
private boolean online = false;
|
||||
public static long uptime = System.currentTimeMillis();
|
||||
|
||||
public int getCurrentTimestamp() {
|
||||
return (int) (Server.getInstance().getCurrentTime() - Server.uptime);
|
||||
}
|
||||
|
||||
public long getCurrentTime() { // returns a slightly delayed time value, under frequency of UPDATE_INTERVAL
|
||||
return serverCurrentTime;
|
||||
}
|
||||
@@ -825,6 +831,33 @@ public class Server {
|
||||
return rankSystem;
|
||||
}
|
||||
|
||||
private static void clearUnreferencedPetIds() {
|
||||
PreparedStatement ps = null;
|
||||
Connection con = null;
|
||||
try {
|
||||
con = DatabaseConnection.getConnection();
|
||||
|
||||
ps = con.prepareStatement("UPDATE inventoryitems SET petid = -1, expiration = 0 WHERE petid != -1 AND petid NOT IN (SELECT petid FROM pets)");
|
||||
ps.executeUpdate();
|
||||
|
||||
ps.close();
|
||||
con.close();
|
||||
} catch(SQLException ex) {
|
||||
ex.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if(ps != null && !ps.isClosed()) {
|
||||
ps.close();
|
||||
}
|
||||
if(con != null && !con.isClosed()) {
|
||||
con.close();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void init() {
|
||||
Properties p = loadWorldINI();
|
||||
if(p == null) {
|
||||
@@ -833,10 +866,11 @@ public class Server {
|
||||
|
||||
System.out.println("HeavenMS v" + ServerConstants.VERSION + " starting up.\r\n");
|
||||
|
||||
|
||||
if(ServerConstants.SHUTDOWNHOOK)
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(shutdown(false)));
|
||||
|
||||
TimeZone.setDefault(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
|
||||
Connection c = null;
|
||||
try {
|
||||
c = DatabaseConnection.getConnection();
|
||||
@@ -856,6 +890,7 @@ public class Server {
|
||||
sqle.printStackTrace();
|
||||
}
|
||||
|
||||
clearUnreferencedPetIds();
|
||||
MapleCashidGenerator.loadExistentCashIdsFromDb();
|
||||
|
||||
IoBuffer.setUseDirectBuffer(false);
|
||||
@@ -863,6 +898,7 @@ public class Server {
|
||||
acceptor = new NioSocketAcceptor();
|
||||
acceptor.getFilterChain().addLast("codec", (IoFilter) new ProtocolCodecFilter(new MapleCodecFactory()));
|
||||
|
||||
ThreadManager.getInstance().start();
|
||||
TimerManager tMan = TimerManager.getInstance();
|
||||
tMan.start();
|
||||
tMan.register(tMan.purge(), ServerConstants.PURGING_INTERVAL);//Purging ftw...
|
||||
@@ -1716,6 +1752,7 @@ public class Server {
|
||||
|
||||
resetServerWorlds();
|
||||
|
||||
ThreadManager.getInstance().stop();
|
||||
TimerManager.getInstance().purge();
|
||||
TimerManager.getInstance().stop();
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ public class ThreadTracker {
|
||||
StackTraceElement[] ste = threads.get(l).getStackTrace();
|
||||
if(ste.length > 0) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
String df = dateFormat.format(new Date());
|
||||
|
||||
FilePrinter.print(FilePrinter.DEADLOCK_LOCKS, printThreadLog(tt, df));
|
||||
@@ -195,7 +195,7 @@ public class ThreadTracker {
|
||||
}
|
||||
} else { // print status
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
|
||||
FilePrinter.printError(FilePrinter.DEADLOCK_STATE, printThreadTrackerState(dateFormat.format(new Date())));
|
||||
//FilePrinter.printError(FilePrinter.DEADLOCK_STATE, "[" + dateFormat.format(new Date()) + "] Presenting current lock path for lockid " + lockId.name() + ".\r\n" + printLockStatus(lockId) + "\r\n-------------------------------\r\n");
|
||||
|
||||
@@ -62,7 +62,7 @@ public class TrackerReadLock extends ReentrantReadWriteLock.ReadLock implements
|
||||
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||
if(deadlockedState != null) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
|
||||
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "[CRITICAL] " + dateFormat.format(new Date()) + " Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState) + "\r\n\r\n");
|
||||
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
|
||||
|
||||
@@ -64,7 +64,7 @@ public class TrackerReentrantLock extends ReentrantLock implements MonitoredReen
|
||||
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||
if(deadlockedState != null) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
|
||||
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "[CRITICAL] " + dateFormat.format(new Date()) + " Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState) + "\r\n\r\n");
|
||||
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
|
||||
|
||||
@@ -60,7 +60,7 @@ public class TrackerWriteLock extends ReentrantReadWriteLock.WriteLock implement
|
||||
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||
if(deadlockedState != null) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
|
||||
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "[CRITICAL] " + dateFormat.format(new Date()) + " Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState) + "\r\n\r\n");
|
||||
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
|
||||
|
||||
@@ -41,7 +41,7 @@ public class EmptyReadLock implements MonitoredReadLock {
|
||||
|
||||
private static String printThreadStack(StackTraceElement[] list) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
String df = dateFormat.format(new Date());
|
||||
|
||||
String s = "\r\n" + df + "\r\n";
|
||||
|
||||
@@ -41,7 +41,7 @@ public class EmptyReentrantLock implements MonitoredReentrantLock {
|
||||
|
||||
private static String printThreadStack(StackTraceElement[] list) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
String df = dateFormat.format(new Date());
|
||||
|
||||
String s = "\r\n" + df + "\r\n";
|
||||
|
||||
@@ -41,7 +41,7 @@ public class EmptyWriteLock implements MonitoredWriteLock {
|
||||
|
||||
private static String printThreadStack(StackTraceElement[] list) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
String df = dateFormat.format(new Date());
|
||||
|
||||
String s = "\r\n" + df + "\r\n";
|
||||
|
||||
@@ -259,8 +259,9 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
|
||||
else if(attack.skill == Shadower.BOOMERANG_STEP)
|
||||
distanceToDetect += 60000;
|
||||
|
||||
if(distance > distanceToDetect) {
|
||||
if (distance > distanceToDetect) {
|
||||
AutobanFactory.DISTANCE_HACK.alert(player, "Distance Sq to monster: " + distance + " SID: " + attack.skill + " MID: " + monster.getId());
|
||||
monster.refreshMobPosition();
|
||||
}
|
||||
|
||||
int totDamageToOneMonster = 0;
|
||||
@@ -338,7 +339,7 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
|
||||
}
|
||||
}
|
||||
|
||||
if (job == 2111 || job == 2112) {
|
||||
if (player.isAran()) {
|
||||
if (player.getBuffedValue(MapleBuffStat.WK_CHARGE) != null) {
|
||||
Skill snowCharge = SkillFactory.getSkill(Aran.SNOW_CHARGE);
|
||||
if (totDamageToOneMonster > 0) {
|
||||
|
||||
@@ -26,6 +26,7 @@ import net.AbstractMaplePacketHandler;
|
||||
import server.life.MapleMonster;
|
||||
import server.maps.MapleMap;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
import client.MapleCharacter;
|
||||
|
||||
public final class AutoAggroHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
@@ -38,18 +39,26 @@ public final class AutoAggroHandler extends AbstractMaplePacketHandler {
|
||||
int oid = slea.readInt();
|
||||
|
||||
MapleMonster monster = map.getMonsterByOid(oid);
|
||||
if (monster != null && monster.getController() != null) {
|
||||
if (!monster.isControllerHasAggro()) {
|
||||
if (map.getCharacterById(monster.getController().getId()) == null) {
|
||||
monster.switchController(c.getPlayer(), true);
|
||||
if (monster != null) {
|
||||
MapleCharacter currentController = monster.getController();
|
||||
monster.lockMonster();
|
||||
try {
|
||||
if (currentController != null) {
|
||||
if (!monster.isControllerHasAggro()) {
|
||||
if (map.getCharacterById(currentController.getId()) == null) {
|
||||
monster.switchController(c.getPlayer(), true);
|
||||
} else {
|
||||
monster.switchController(currentController, true);
|
||||
}
|
||||
} else if (map.getCharacterById(currentController.getId()) == null) {
|
||||
monster.switchController(c.getPlayer(), true);
|
||||
}
|
||||
} else {
|
||||
monster.switchController(monster.getController(), true);
|
||||
monster.switchController(c.getPlayer(), true);
|
||||
}
|
||||
} else if (map.getCharacterById(monster.getController().getId()) == null) {
|
||||
monster.switchController(c.getPlayer(), true);
|
||||
} finally {
|
||||
monster.unlockMonster();
|
||||
}
|
||||
} else if (monster != null && monster.getController() == null) {
|
||||
monster.switchController(c.getPlayer(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import net.AbstractMaplePacketHandler;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
import client.MapleClient;
|
||||
import client.autoban.AutobanFactory;
|
||||
import net.server.Server;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -35,7 +36,8 @@ public final class ChangeChannelHandler extends AbstractMaplePacketHandler {
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
int channel = slea.readByte() + 1;
|
||||
c.getPlayer().getAutobanManager().setTimestamp(6, slea.readInt(), 2);
|
||||
slea.readInt();
|
||||
c.getPlayer().getAutobanManager().setTimestamp(6, Server.getInstance().getCurrentTimestamp(), 3);
|
||||
if(c.getChannel() == channel) {
|
||||
AutobanFactory.GENERAL.alert(c.getPlayer(), "CCing to same channel.");
|
||||
c.disconnect(false, false);
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.channel.handlers;
|
||||
|
||||
import client.MapleClient;
|
||||
import client.MapleCharacter;
|
||||
import constants.skills.Gunslinger;
|
||||
import constants.skills.NightWalker;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
import java.awt.Point;
|
||||
import tools.FilePrinter;
|
||||
|
||||
/*
|
||||
* @author GabrielSin
|
||||
*/
|
||||
public class GrenadeEffectHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
@Override
|
||||
public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
Point position = new Point(slea.readInt(), slea.readInt());
|
||||
int keyDown = slea.readInt();
|
||||
int skillId = slea.readInt();
|
||||
|
||||
switch (skillId) {
|
||||
case NightWalker.POISON_BOMB:
|
||||
case Gunslinger.GRENADE:
|
||||
int skillLevel = chr.getSkillLevel(skillId);
|
||||
if (skillLevel > 0) {
|
||||
chr.getMap().broadcastMessage(chr, MaplePacketCreator.throwGrenade(chr.getId(), position, keyDown, skillId, skillLevel), position);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
FilePrinter.printError(FilePrinter.UNHANDLED_EVENT, "The skill id: " + skillId + " is not coded in " + this.getClass().getName() + ".");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -38,12 +38,12 @@ public final class HealOvertimeHandler extends AbstractMaplePacketHandler {
|
||||
if(!chr.isLoggedinWorld()) return;
|
||||
|
||||
AutobanManager abm = chr.getAutobanManager();
|
||||
int timestamp = (int) (Server.getInstance().getCurrentTime() - Server.uptime);
|
||||
int timestamp = Server.getInstance().getCurrentTimestamp();
|
||||
slea.skip(8);
|
||||
|
||||
short healHP = slea.readShort();
|
||||
if (healHP != 0) {
|
||||
abm.setTimestamp(8, timestamp, 3); // thanks Vcoc for pointing out d/c happening here
|
||||
abm.setTimestamp(8, timestamp, 4); // thanks Vcoc for pointing out d/c happening here
|
||||
if ((abm.getLastSpam(0) + 1500) > timestamp) AutobanFactory.FAST_HP_HEALING.addPoint(abm, "Fast hp healing");
|
||||
|
||||
int abHeal = 120 + (int)(20 * MapleMapFactory.getMapRecoveryRate(chr.getMapId())); // Sleepywood sauna and showa spa...
|
||||
@@ -58,7 +58,7 @@ public final class HealOvertimeHandler extends AbstractMaplePacketHandler {
|
||||
}
|
||||
short healMP = slea.readShort();
|
||||
if (healMP != 0 && healMP < 1000) {
|
||||
abm.setTimestamp(9, timestamp, 3);
|
||||
abm.setTimestamp(9, timestamp, 4);
|
||||
if ((abm.getLastSpam(1) + 1500) > timestamp) AutobanFactory.FAST_MP_HEALING.addPoint(abm, "Fast mp healing");
|
||||
chr.addMP(healMP);
|
||||
abm.spam(1, timestamp);
|
||||
|
||||
@@ -31,6 +31,7 @@ import client.MapleClient;
|
||||
import client.inventory.Item;
|
||||
import client.inventory.MapleInventory;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import net.server.Server;
|
||||
import server.MapleItemInformationProvider;
|
||||
|
||||
public final class InventoryMergeHandler extends AbstractMaplePacketHandler {
|
||||
@@ -38,7 +39,8 @@ public final class InventoryMergeHandler extends AbstractMaplePacketHandler {
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
chr.getAutobanManager().setTimestamp(2, slea.readInt(), 3);
|
||||
slea.readInt();
|
||||
chr.getAutobanManager().setTimestamp(2, Server.getInstance().getCurrentTimestamp(), 4);
|
||||
|
||||
if(!ServerConstants.USE_ITEM_SORT) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
|
||||
@@ -24,7 +24,6 @@ package net.server.channel.handlers;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import constants.ServerConstants;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
@@ -35,7 +34,9 @@ import client.inventory.Equip;
|
||||
import client.inventory.MapleInventory;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import client.inventory.ModifyInventory;
|
||||
import constants.ServerConstants;
|
||||
import server.MapleItemInformationProvider;
|
||||
import net.server.Server;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -187,7 +188,8 @@ public final class InventorySortHandler extends AbstractMaplePacketHandler {
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
chr.getAutobanManager().setTimestamp(3, slea.readInt(), 3);
|
||||
slea.readInt();
|
||||
chr.getAutobanManager().setTimestamp(3, Server.getInstance().getCurrentTimestamp(), 4);
|
||||
|
||||
if(!ServerConstants.USE_ITEM_SORT) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
|
||||
@@ -61,7 +61,7 @@ public final class MoveLifeHandler extends AbstractMovementPacketHandler {
|
||||
}
|
||||
|
||||
MapleMonster monster = (MapleMonster) mmo;
|
||||
List<MapleCharacter> banishPlayers = new LinkedList<>();
|
||||
List<MapleCharacter> banishPlayers = null;
|
||||
|
||||
byte pNibbles = slea.readByte();
|
||||
byte rawActivity = slea.readByte();
|
||||
@@ -70,7 +70,7 @@ public final class MoveLifeHandler extends AbstractMovementPacketHandler {
|
||||
short pOption = slea.readShort();
|
||||
slea.skip(8);
|
||||
|
||||
if (rawActivity >= 0) {
|
||||
if (rawActivity >= 0) {
|
||||
rawActivity = (byte) (rawActivity & 0xFF >> 1);
|
||||
}
|
||||
|
||||
@@ -78,7 +78,9 @@ public final class MoveLifeHandler extends AbstractMovementPacketHandler {
|
||||
boolean isSkill = inRangeInclusive(rawActivity, 21, 25);
|
||||
|
||||
byte attackId = (byte) (isAttack ? rawActivity - 12 : -1);
|
||||
boolean nextMovementCouldBeSkill = (pNibbles & 0x0F) != 0;
|
||||
isSkill |= (pNibbles != 0);
|
||||
|
||||
boolean nextMovementCouldBeSkill = true;
|
||||
boolean pUnk = (pNibbles & 0xF0) != 0;
|
||||
|
||||
boolean currentController = (monster.getController() == player);
|
||||
@@ -86,6 +88,7 @@ public final class MoveLifeHandler extends AbstractMovementPacketHandler {
|
||||
MobSkill toUse = null;
|
||||
int useSkillId = 0, useSkillLevel = 0;
|
||||
|
||||
int rnd = 0;
|
||||
if (isSkill) {
|
||||
int noSkills = monster.getNoSkills();
|
||||
if (noSkills > 0) {
|
||||
@@ -95,11 +98,10 @@ public final class MoveLifeHandler extends AbstractMovementPacketHandler {
|
||||
useSkillId = skillToUse.getLeft();
|
||||
useSkillLevel = skillToUse.getRight();
|
||||
toUse = MobSkillFactory.getMobSkill(useSkillId, useSkillLevel);
|
||||
} else {
|
||||
|
||||
rnd = rndSkill;
|
||||
nextMovementCouldBeSkill = false;
|
||||
}
|
||||
} else {
|
||||
nextMovementCouldBeSkill = false;
|
||||
}
|
||||
|
||||
int mobMp;
|
||||
@@ -107,9 +109,10 @@ public final class MoveLifeHandler extends AbstractMovementPacketHandler {
|
||||
mobMp = monster.getMp();
|
||||
|
||||
int animationTime = MapleMonsterInformationProvider.getInstance().getMobSkillAnimationTime(toUse);
|
||||
if(animationTime > 0) {
|
||||
toUse.applyDelayedEffect(player, monster, true, banishPlayers, animationTime);
|
||||
if(animationTime > 0 && toUse.getSkillId() != 129) {
|
||||
toUse.applyDelayedEffect(player, monster, true, animationTime);
|
||||
} else {
|
||||
banishPlayers = new LinkedList<>();
|
||||
toUse.applyEffect(player, monster, true, banishPlayers);
|
||||
}
|
||||
} else {
|
||||
@@ -138,36 +141,45 @@ public final class MoveLifeHandler extends AbstractMovementPacketHandler {
|
||||
short start_y = slea.readShort(); // hmm...
|
||||
Point startPos = new Point(start_x, start_y - 2);
|
||||
List<LifeMovementFragment> res = parseMovement(slea);
|
||||
if (!currentController) {
|
||||
if (monster.isAttackedBy(player)) {
|
||||
monster.switchController(player, true);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (rawActivity == -1 && monster.isControllerKnowsAboutAggro() && !monster.isMobile() && !monster.isFirstAttack()) {
|
||||
monster.setControllerHasAggro(false);
|
||||
monster.setControllerKnowsAboutAggro(false);
|
||||
}
|
||||
|
||||
boolean aggro = monster.isControllerHasAggro();
|
||||
boolean aggro;
|
||||
monster.lockMonster();
|
||||
try {
|
||||
if (!currentController) {
|
||||
if (monster.isAttackedBy(player)) {
|
||||
monster.switchController(player, true);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (rawActivity == -1 && monster.isControllerKnowsAboutAggro() && !monster.isMobile() && !monster.isFirstAttack()) {
|
||||
monster.setControllerHasAggro(false);
|
||||
monster.setControllerKnowsAboutAggro(false);
|
||||
}
|
||||
|
||||
aggro = monster.isControllerHasAggro();
|
||||
if (aggro) {
|
||||
monster.setControllerKnowsAboutAggro(true);
|
||||
}
|
||||
} finally {
|
||||
monster.unlockMonster();
|
||||
}
|
||||
|
||||
if (toUse != null) {
|
||||
c.announce(MaplePacketCreator.moveMonsterResponse(objectid, moveid, mobMp, aggro, toUse.getSkillId(), toUse.getSkillLevel()));
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.moveMonsterResponse(objectid, moveid, mobMp, aggro));
|
||||
}
|
||||
|
||||
if (aggro) {
|
||||
monster.setControllerKnowsAboutAggro(true);
|
||||
}
|
||||
|
||||
if (res != null) {
|
||||
map.broadcastMessage(player, MaplePacketCreator.moveMonster(objectid, nextMovementCouldBeSkill, rawActivity, useSkillId, useSkillLevel, pOption, startPos, res), monster.getPosition());
|
||||
updatePosition(res, monster, -2);
|
||||
map.moveMonster(monster, monster.getPosition());
|
||||
}
|
||||
|
||||
for (MapleCharacter chr : banishPlayers) {
|
||||
chr.changeMapBanish(monster.getBanish().getMap(), monster.getBanish().getPortal(), monster.getBanish().getMsg());
|
||||
if (banishPlayers != null) {
|
||||
for (MapleCharacter chr : banishPlayers) {
|
||||
chr.changeMapBanish(monster.getBanish().getMap(), monster.getBanish().getPortal(), monster.getBanish().getMsg());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,8 +54,9 @@ public final class PetCommandHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
if (Randomizer.nextInt(101) <= petCommand.getProbability()) {
|
||||
pet.gainClosenessFullness(chr, petCommand.getIncrease(), 0, command);
|
||||
chr.getMap().broadcastMessage(MaplePacketCreator.commandResponse(chr.getId(), petIndex, false, command, false));
|
||||
} else {
|
||||
chr.getMap().broadcastMessage(MaplePacketCreator.commandResponse(chr.getId(), petIndex, command, false));
|
||||
chr.getMap().broadcastMessage(MaplePacketCreator.commandResponse(chr.getId(), petIndex, true, command, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
package net.server.channel.handlers;
|
||||
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
import client.inventory.MapleInventory;
|
||||
@@ -28,8 +29,8 @@ import client.inventory.MapleInventoryType;
|
||||
import client.inventory.MaplePet;
|
||||
import client.autoban.AutobanManager;
|
||||
import client.inventory.Item;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import client.inventory.manipulator.MapleInventoryManipulator;
|
||||
import net.server.Server;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
|
||||
@@ -44,7 +45,8 @@ public final class PetFoodHandler extends AbstractMaplePacketHandler {
|
||||
return;
|
||||
}
|
||||
abm.spam(2);
|
||||
abm.setTimestamp(1, slea.readInt(), 3);
|
||||
slea.readInt(); // timestamp issue detected thanks to Masterrulax
|
||||
abm.setTimestamp(1, Server.getInstance().getCurrentTimestamp(), 3);
|
||||
if (chr.getNoPets() == 0) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
|
||||
@@ -179,7 +179,7 @@ public final class RangedAttackHandler extends AbstractDealDamageHandler {
|
||||
}
|
||||
}
|
||||
|
||||
if (projectile != 0 || soulArrow || attack.skill == 11101004 || attack.skill == 15111007 || attack.skill == 14101006 || attack.skill == 4111004) {
|
||||
if (projectile != 0 || soulArrow || attack.skill == 11101004 || attack.skill == 15111007 || attack.skill == 14101006 || attack.skill == 4111004 || attack.skill == 13101005) {
|
||||
int visProjectile = projectile; //visible projectile sent to players
|
||||
if (ItemConstants.isThrowingStar(projectile)) {
|
||||
MapleInventory cash = chr.getInventory(MapleInventoryType.CASH);
|
||||
@@ -192,7 +192,7 @@ public final class RangedAttackHandler extends AbstractDealDamageHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (soulArrow || attack.skill == 3111004 || attack.skill == 3211004 || attack.skill == 11101004 || attack.skill == 15111007 || attack.skill == 14101006) {
|
||||
} else if (soulArrow || attack.skill == 3111004 || attack.skill == 3211004 || attack.skill == 11101004 || attack.skill == 15111007 || attack.skill == 14101006 || attack.skill == 13101005) {
|
||||
visProjectile = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ public final class ScriptedItemHandler extends AbstractMaplePacketHandler {
|
||||
if (item == null || item.getItemId() != itemId || item.getQuantity() < 1 || !ism.scriptExists(info.getScript())) {
|
||||
return;
|
||||
}
|
||||
ism.getItemScript(c, info.getScript());
|
||||
ism.runItemScript(c, info.getScript());
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
//NPCScriptManager.getInstance().start(c, info.getNpc(), null, null);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
import client.MapleStat;
|
||||
import client.Skill;
|
||||
import client.SkillFactory;
|
||||
import constants.ServerConstants;
|
||||
@@ -41,14 +40,15 @@ import constants.skills.Hero;
|
||||
import constants.skills.Paladin;
|
||||
import constants.skills.Priest;
|
||||
import constants.skills.SuperGM;
|
||||
|
||||
import net.server.Server;
|
||||
|
||||
public final class SpecialMoveHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
chr.getAutobanManager().setTimestamp(4, slea.readInt(), 3);
|
||||
slea.readInt();
|
||||
chr.getAutobanManager().setTimestamp(4, Server.getInstance().getCurrentTimestamp(), 5);
|
||||
int skillid = slea.readInt();
|
||||
|
||||
/*
|
||||
@@ -99,9 +99,14 @@ public final class SpecialMoveHandler extends AbstractMaplePacketHandler {
|
||||
chr.getMap().broadcastMessage(chr, MaplePacketCreator.showMagnet(mobId, success), false);
|
||||
MapleMonster monster = chr.getMap().getMonsterByOid(mobId);
|
||||
if (monster != null) {
|
||||
if (!monster.isBoss()) {
|
||||
monster.switchController(chr, monster.isControllerHasAggro());
|
||||
}
|
||||
if (!monster.isBoss()) {
|
||||
monster.lockMonster();
|
||||
try {
|
||||
monster.switchController(chr, monster.isControllerHasAggro());
|
||||
} finally {
|
||||
monster.unlockMonster();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
byte direction = slea.readByte();
|
||||
|
||||
@@ -32,6 +32,8 @@ import tools.data.input.SeekableLittleEndianAccessor;
|
||||
* @author Generic
|
||||
*/
|
||||
public final class TouchReactorHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
int oid = slea.readInt();
|
||||
MapleReactor reactor = c.getPlayer().getMap().getReactorByOid(oid);
|
||||
|
||||
@@ -27,6 +27,7 @@ import client.inventory.MapleInventoryType;
|
||||
import client.autoban.AutobanManager;
|
||||
import constants.ItemConstants;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import net.server.Server;
|
||||
import client.inventory.manipulator.MapleInventoryManipulator;
|
||||
import server.life.MapleMonster;
|
||||
import tools.MaplePacketCreator;
|
||||
@@ -41,7 +42,8 @@ public final class UseCatchItemHandler extends AbstractMaplePacketHandler {
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
AutobanManager abm = chr.getAutobanManager();
|
||||
abm.setTimestamp(5, slea.readInt(), 3);
|
||||
slea.readInt();
|
||||
abm.setTimestamp(5, Server.getInstance().getCurrentTimestamp(), 4);
|
||||
slea.readShort();
|
||||
int itemId = slea.readInt();
|
||||
int monsterid = slea.readInt();
|
||||
|
||||
@@ -35,7 +35,6 @@ import constants.GameConstants;
|
||||
/**
|
||||
* @author Ronan
|
||||
*/
|
||||
|
||||
public final class UseOwlOfMinervaHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1402,7 +1402,9 @@ public class World {
|
||||
|
||||
int dpVal = dp.getValue() + 1;
|
||||
if(dpVal == ServerConstants.MOUNT_EXHAUST_COUNT) {
|
||||
chr.runTirednessSchedule();
|
||||
if (!chr.runTirednessSchedule()) {
|
||||
continue;
|
||||
}
|
||||
dpVal = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -512,21 +512,21 @@ public class AbstractPlayerInteraction {
|
||||
petId = MaplePet.createPet(id);
|
||||
|
||||
if(from != null) {
|
||||
evolved = MaplePet.loadFromDb(id, (short) 0, petId);
|
||||
evolved = MaplePet.loadFromDb(id, (short) 0, petId);
|
||||
|
||||
Point pos = getPlayer().getPosition();
|
||||
pos.y -= 12;
|
||||
evolved.setPos(pos);
|
||||
evolved.setFh(getPlayer().getMap().getFootholds().findBelow(evolved.getPos()).getId());
|
||||
evolved.setStance(0);
|
||||
evolved.setSummoned(true);
|
||||
Point pos = getPlayer().getPosition();
|
||||
pos.y -= 12;
|
||||
evolved.setPos(pos);
|
||||
evolved.setFh(getPlayer().getMap().getFootholds().findBelow(evolved.getPos()).getId());
|
||||
evolved.setStance(0);
|
||||
evolved.setSummoned(true);
|
||||
|
||||
evolved.setName(from.getName().compareTo(MapleItemInformationProvider.getInstance().getName(from.getItemId())) != 0 ? from.getName() : MapleItemInformationProvider.getInstance().getName(id));
|
||||
evolved.setCloseness(from.getCloseness());
|
||||
evolved.setFullness(from.getFullness());
|
||||
evolved.setLevel(from.getLevel());
|
||||
evolved.setExpiration(System.currentTimeMillis() + expires);
|
||||
evolved.saveToDb();
|
||||
evolved.setName(from.getName().compareTo(MapleItemInformationProvider.getInstance().getName(from.getItemId())) != 0 ? from.getName() : MapleItemInformationProvider.getInstance().getName(id));
|
||||
evolved.setCloseness(from.getCloseness());
|
||||
evolved.setFullness(from.getFullness());
|
||||
evolved.setLevel(from.getLevel());
|
||||
evolved.setExpiration(System.currentTimeMillis() + expires);
|
||||
evolved.saveToDb();
|
||||
}
|
||||
|
||||
//MapleInventoryManipulator.addById(c, id, (short) 1, null, petId, expires == -1 ? -1 : System.currentTimeMillis() + expires);
|
||||
|
||||
@@ -69,6 +69,7 @@ import net.server.coordinator.MapleEventRecallCoordinator;
|
||||
import scripting.AbstractPlayerInteraction;
|
||||
import scripting.event.worker.EventScriptScheduler;
|
||||
import server.MapleItemInformationProvider;
|
||||
import server.ThreadManager;
|
||||
import server.life.MapleLifeFactory;
|
||||
import server.life.MapleNPC;
|
||||
import tools.MaplePacketCreator;
|
||||
@@ -228,51 +229,42 @@ public class EventInstanceManager {
|
||||
|
||||
}
|
||||
|
||||
public synchronized void registerPlayer(MapleCharacter chr) {
|
||||
public synchronized void registerPlayer(final MapleCharacter chr) {
|
||||
if (chr == null || !chr.isLoggedinWorld() || disposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
wL.lock();
|
||||
try {
|
||||
wL.lock();
|
||||
try {
|
||||
if(chars.containsKey(chr.getId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
chars.put(chr.getId(), chr);
|
||||
chr.setEventInstance(this);
|
||||
} finally {
|
||||
wL.unlock();
|
||||
if(chars.containsKey(chr.getId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
sL.lock();
|
||||
try {
|
||||
em.getIv().invokeFunction("playerEntry", this, chr);
|
||||
} finally {
|
||||
sL.unlock();
|
||||
}
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
chars.put(chr.getId(), chr);
|
||||
chr.setEventInstance(this);
|
||||
} finally {
|
||||
wL.unlock();
|
||||
}
|
||||
|
||||
try {
|
||||
em.getIv().invokeFunction("playerEntry", EventInstanceManager.this, chr);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void exitPlayer(MapleCharacter chr) {
|
||||
public void exitPlayer(final MapleCharacter chr) {
|
||||
if (chr == null || !chr.isLoggedin()){
|
||||
return;
|
||||
}
|
||||
try {
|
||||
unregisterPlayer(chr);
|
||||
|
||||
sL.lock();
|
||||
try {
|
||||
em.getIv().invokeFunction("playerExit", this, chr);
|
||||
} finally {
|
||||
sL.unlock();
|
||||
}
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
unregisterPlayer(chr);
|
||||
|
||||
try {
|
||||
em.getIv().invokeFunction("playerExit", EventInstanceManager.this, chr);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void dropMessage(int type, String message) {
|
||||
@@ -297,15 +289,10 @@ public class EventInstanceManager {
|
||||
event_schedule = TimerManager.getInstance().schedule(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
dismissEventTimer();
|
||||
dismissEventTimer();
|
||||
|
||||
sL.lock();
|
||||
try {
|
||||
em.getIv().invokeFunction("scheduledTimeout", EventInstanceManager.this);
|
||||
} finally {
|
||||
sL.unlock();
|
||||
}
|
||||
try {
|
||||
em.getIv().invokeFunction("scheduledTimeout", EventInstanceManager.this);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, "Event '" + em.getName() + "' does not implement scheduledTimeout function.", ex);
|
||||
}
|
||||
@@ -314,31 +301,25 @@ public class EventInstanceManager {
|
||||
}
|
||||
|
||||
public void addEventTimer(long time) {
|
||||
if(event_schedule != null) {
|
||||
if(event_schedule.cancel(false)) {
|
||||
if (event_schedule != null) {
|
||||
if (event_schedule.cancel(false)) {
|
||||
long nextTime = getTimeLeft() + time;
|
||||
eventTime += time;
|
||||
|
||||
event_schedule = TimerManager.getInstance().schedule(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
dismissEventTimer();
|
||||
dismissEventTimer();
|
||||
|
||||
sL.lock();
|
||||
try {
|
||||
em.getIv().invokeFunction("scheduledTimeout", EventInstanceManager.this);
|
||||
} finally {
|
||||
sL.unlock();
|
||||
}
|
||||
try {
|
||||
em.getIv().invokeFunction("scheduledTimeout", EventInstanceManager.this);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, "Event '" + em.getName() + "' does not implement scheduledTimeout function.", ex);
|
||||
}
|
||||
}
|
||||
}, nextTime);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
startEventTimer(time);
|
||||
}
|
||||
}
|
||||
@@ -358,6 +339,7 @@ public class EventInstanceManager {
|
||||
event_schedule.cancel(false);
|
||||
event_schedule = null;
|
||||
}
|
||||
|
||||
dismissEventTimer();
|
||||
}
|
||||
|
||||
@@ -370,7 +352,7 @@ public class EventInstanceManager {
|
||||
}
|
||||
|
||||
public void registerParty(MapleCharacter chr) {
|
||||
if(chr.isPartyLeader()) {
|
||||
if (chr.isPartyLeader()) {
|
||||
registerParty(chr.getParty(), chr.getMap());
|
||||
}
|
||||
}
|
||||
@@ -390,20 +372,16 @@ public class EventInstanceManager {
|
||||
private void registerExpeditionTeam(MapleExpedition exped, int recruitMap) {
|
||||
expedition = exped;
|
||||
|
||||
for(MapleCharacter chr: exped.getMembers()) {
|
||||
if(chr.getMapId() == recruitMap)
|
||||
for (MapleCharacter chr: exped.getMembers()) {
|
||||
if (chr.getMapId() == recruitMap) {
|
||||
registerPlayer(chr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterPlayer(MapleCharacter chr) {
|
||||
public void unregisterPlayer(final MapleCharacter chr) {
|
||||
try {
|
||||
sL.lock();
|
||||
try {
|
||||
em.getIv().invokeFunction("playerUnregistered", EventInstanceManager.this, chr);
|
||||
} finally {
|
||||
sL.unlock();
|
||||
}
|
||||
em.getIv().invokeFunction("playerUnregistered", EventInstanceManager.this, chr);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, "Event '" + em.getName() + "' does not implement playerUnregistered function.", ex);
|
||||
}
|
||||
@@ -462,180 +440,140 @@ public class EventInstanceManager {
|
||||
}
|
||||
}
|
||||
|
||||
public void movePlayer(MapleCharacter chr) {
|
||||
try {
|
||||
sL.lock();
|
||||
try {
|
||||
em.getIv().invokeFunction("moveMap", this, chr);
|
||||
} finally {
|
||||
sL.unlock();
|
||||
}
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void changedMap(MapleCharacter chr, int mapId) {
|
||||
try {
|
||||
sL.lock();
|
||||
try {
|
||||
em.getIv().invokeFunction("changedMap", this, chr, mapId);
|
||||
} finally {
|
||||
sL.unlock();
|
||||
}
|
||||
} catch (ScriptException | NoSuchMethodException ex) {} // optional
|
||||
}
|
||||
|
||||
public void afterChangedMap(MapleCharacter chr, int mapId) {
|
||||
try {
|
||||
sL.lock();
|
||||
try {
|
||||
em.getIv().invokeFunction("afterChangedMap", this, chr, mapId);
|
||||
} finally {
|
||||
sL.unlock();
|
||||
}
|
||||
} catch (ScriptException | NoSuchMethodException ex) {} // optional
|
||||
}
|
||||
|
||||
public void changedLeader(MapleCharacter ldr) {
|
||||
public void movePlayer(final MapleCharacter chr) {
|
||||
try {
|
||||
sL.lock();
|
||||
try {
|
||||
em.getIv().invokeFunction("changedLeader", this, ldr);
|
||||
} finally {
|
||||
sL.unlock();
|
||||
}
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
em.getIv().invokeFunction("moveMap", EventInstanceManager.this, chr);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void changedMap(final MapleCharacter chr, final int mapId) {
|
||||
try {
|
||||
em.getIv().invokeFunction("changedMap", EventInstanceManager.this, chr, mapId);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {} // optional
|
||||
}
|
||||
|
||||
public void afterChangedMap(final MapleCharacter chr, final int mapId) {
|
||||
try {
|
||||
em.getIv().invokeFunction("afterChangedMap", EventInstanceManager.this, chr, mapId);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {} // optional
|
||||
}
|
||||
|
||||
public synchronized void changedLeader(final MapleCharacter ldr) {
|
||||
try {
|
||||
em.getIv().invokeFunction("changedLeader", EventInstanceManager.this, ldr);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
leaderId = ldr.getId();
|
||||
}
|
||||
|
||||
public void monsterKilled(MapleMonster mob, boolean hasKiller) {
|
||||
public void monsterKilled(final MapleMonster mob, final boolean hasKiller) {
|
||||
int scriptResult = 0;
|
||||
|
||||
sL.lock();
|
||||
try {
|
||||
mobs.remove(mob);
|
||||
|
||||
if(eventStarted) {
|
||||
try {
|
||||
em.getIv().invokeFunction("monsterKilled", mob, this, hasKiller);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
scriptResult = 1;
|
||||
|
||||
if (mobs.isEmpty()) {
|
||||
try {
|
||||
em.getIv().invokeFunction("allMonstersDead", this, hasKiller);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
scriptResult = 2;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
sL.unlock();
|
||||
}
|
||||
|
||||
if (scriptResult > 0) {
|
||||
try {
|
||||
em.getIv().invokeFunction("monsterKilled", mob, EventInstanceManager.this, hasKiller);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
if (scriptResult > 1) {
|
||||
try {
|
||||
em.getIv().invokeFunction("allMonstersDead", EventInstanceManager.this, hasKiller);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void friendlyKilled(MapleMonster mob, boolean hasKiller) {
|
||||
try {
|
||||
sL.lock();
|
||||
try {
|
||||
em.getIv().invokeFunction("friendlyKilled", mob, this, hasKiller);
|
||||
} finally {
|
||||
sL.unlock();
|
||||
}
|
||||
public void friendlyKilled(final MapleMonster mob, final boolean hasKiller) {
|
||||
try {
|
||||
em.getIv().invokeFunction("friendlyKilled", mob, EventInstanceManager.this, hasKiller);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {} //optional
|
||||
}
|
||||
|
||||
public void playerKilled(MapleCharacter chr) {
|
||||
try {
|
||||
sL.lock();
|
||||
try {
|
||||
em.getIv().invokeFunction("playerDead", this, chr);
|
||||
} finally {
|
||||
sL.unlock();
|
||||
public void playerKilled(final MapleCharacter chr) {
|
||||
ThreadManager.getInstance().newTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
em.getIv().invokeFunction("playerDead", EventInstanceManager.this, chr);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {} // optional
|
||||
}
|
||||
} catch (ScriptException | NoSuchMethodException ex) {} // optional
|
||||
});
|
||||
}
|
||||
|
||||
public void reviveMonster(MapleMonster mob) {
|
||||
try {
|
||||
sL.lock();
|
||||
try {
|
||||
em.getIv().invokeFunction("monsterRevive", this, mob);
|
||||
} finally {
|
||||
sL.unlock();
|
||||
}
|
||||
} catch (ScriptException | NoSuchMethodException ex) {} // optional
|
||||
public void reviveMonster(final MapleMonster mob) {
|
||||
try {
|
||||
em.getIv().invokeFunction("monsterRevive", EventInstanceManager.this, mob);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {} // optional
|
||||
}
|
||||
|
||||
public boolean revivePlayer(MapleCharacter chr) {
|
||||
try {
|
||||
Object b;
|
||||
|
||||
sL.lock();
|
||||
try {
|
||||
b = em.getIv().invokeFunction("playerRevive", this, chr);
|
||||
} finally {
|
||||
sL.unlock();
|
||||
public boolean revivePlayer(final MapleCharacter chr) {
|
||||
try {
|
||||
Object b = em.getIv().invokeFunction("playerRevive", EventInstanceManager.this, chr);
|
||||
if (b instanceof Boolean) {
|
||||
return (Boolean) b;
|
||||
}
|
||||
|
||||
if (b instanceof Boolean) {
|
||||
return (Boolean) b;
|
||||
}
|
||||
} catch (ScriptException | NoSuchMethodException ex) {} // optional
|
||||
} catch (ScriptException | NoSuchMethodException ex) {} // optional
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void playerDisconnected(MapleCharacter chr) {
|
||||
try {
|
||||
sL.lock();
|
||||
try {
|
||||
em.getIv().invokeFunction("playerDisconnected", this, chr);
|
||||
} finally {
|
||||
sL.unlock();
|
||||
}
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
public void playerDisconnected(final MapleCharacter chr) {
|
||||
try {
|
||||
em.getIv().invokeFunction("playerDisconnected", EventInstanceManager.this, chr);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
MapleEventRecallCoordinator.getInstance().storeEventInstance(chr.getId(), this);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param chr
|
||||
* @param mob
|
||||
*/
|
||||
public void monsterKilled(MapleCharacter chr, MapleMonster mob) {
|
||||
try {
|
||||
Integer kc = killCount.get(chr);
|
||||
public void monsterKilled(MapleCharacter chr, final MapleMonster mob) {
|
||||
try {
|
||||
int inc;
|
||||
|
||||
sL.lock();
|
||||
try {
|
||||
if(ServerConstants.JAVA_8)
|
||||
inc = (int)em.getIv().invokeFunction("monsterValue", this, mob.getId());
|
||||
else
|
||||
inc = ((Double) em.getIv().invokeFunction("monsterValue", this, mob.getId())).intValue();
|
||||
} finally {
|
||||
sL.unlock();
|
||||
if (ServerConstants.JAVA_8) {
|
||||
inc = (int)em.getIv().invokeFunction("monsterValue", EventInstanceManager.this, mob.getId());
|
||||
} else {
|
||||
inc = ((Double) em.getIv().invokeFunction("monsterValue", EventInstanceManager.this, mob.getId())).intValue();
|
||||
}
|
||||
|
||||
if (kc == null) {
|
||||
kc = inc;
|
||||
} else {
|
||||
kc += inc;
|
||||
}
|
||||
killCount.put(chr, kc);
|
||||
if (expedition != null){
|
||||
expedition.monsterKilled(chr, mob);
|
||||
}
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
if (inc != 0) {
|
||||
Integer kc = killCount.get(chr);
|
||||
if (kc == null) {
|
||||
kc = inc;
|
||||
} else {
|
||||
kc += inc;
|
||||
}
|
||||
killCount.put(chr, kc);
|
||||
if (expedition != null){
|
||||
expedition.monsterKilled(chr, mob);
|
||||
}
|
||||
}
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public int getKillCount(MapleCharacter chr) {
|
||||
@@ -651,14 +589,7 @@ public class EventInstanceManager {
|
||||
rL.unlock();
|
||||
}
|
||||
|
||||
Thread t = new Thread( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
dispose(false);
|
||||
}
|
||||
});
|
||||
|
||||
t.start();
|
||||
dispose(false);
|
||||
}
|
||||
|
||||
public synchronized void dispose(boolean shutdown) { // should not trigger any event script method after disposed
|
||||
@@ -666,12 +597,7 @@ public class EventInstanceManager {
|
||||
|
||||
disposed = true;
|
||||
try {
|
||||
sL.lock();
|
||||
try {
|
||||
em.getIv().invokeFunction("dispose", this);
|
||||
} finally {
|
||||
sL.unlock();
|
||||
}
|
||||
em.getIv().invokeFunction("dispose", EventInstanceManager.this);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
@@ -738,13 +664,8 @@ public class EventInstanceManager {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
sL.lock();
|
||||
try {
|
||||
if(em == null) return;
|
||||
em.getIv().invokeFunction(methodName, EventInstanceManager.this);
|
||||
} finally {
|
||||
sL.unlock();
|
||||
}
|
||||
if(em == null) return;
|
||||
em.getIv().invokeFunction(methodName, EventInstanceManager.this);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
@@ -848,56 +769,36 @@ public class EventInstanceManager {
|
||||
}
|
||||
}
|
||||
|
||||
public void leftParty(MapleCharacter chr) {
|
||||
try {
|
||||
sL.lock();
|
||||
try {
|
||||
em.getIv().invokeFunction("leftParty", this, chr);
|
||||
} finally {
|
||||
sL.unlock();
|
||||
}
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
public void leftParty(final MapleCharacter chr) {
|
||||
try {
|
||||
em.getIv().invokeFunction("leftParty", EventInstanceManager.this, chr);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void disbandParty() {
|
||||
try {
|
||||
sL.lock();
|
||||
try {
|
||||
em.getIv().invokeFunction("disbandParty", this);
|
||||
} finally {
|
||||
sL.unlock();
|
||||
}
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
em.getIv().invokeFunction("disbandParty", EventInstanceManager.this);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void clearPQ() {
|
||||
try {
|
||||
sL.lock();
|
||||
try {
|
||||
em.getIv().invokeFunction("clearPQ", this);
|
||||
} finally {
|
||||
sL.unlock();
|
||||
}
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
em.getIv().invokeFunction("clearPQ", EventInstanceManager.this);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void removePlayer(MapleCharacter chr) {
|
||||
try {
|
||||
sL.lock();
|
||||
try {
|
||||
em.getIv().invokeFunction("playerExit", this, chr);
|
||||
} finally {
|
||||
sL.unlock();
|
||||
}
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
public void removePlayer(final MapleCharacter chr) {
|
||||
try {
|
||||
em.getIv().invokeFunction("playerExit", EventInstanceManager.this, chr);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isLeader(MapleCharacter chr) {
|
||||
@@ -1158,15 +1059,11 @@ public class EventInstanceManager {
|
||||
}
|
||||
}
|
||||
|
||||
public final void startEvent() {
|
||||
public final synchronized void startEvent() {
|
||||
eventStarted = true;
|
||||
|
||||
try {
|
||||
sL.lock();
|
||||
try {
|
||||
eventStarted = true;
|
||||
em.getIv().invokeFunction("afterSetup", this);
|
||||
} finally {
|
||||
sL.unlock();
|
||||
}
|
||||
em.getIv().invokeFunction("afterSetup", EventInstanceManager.this);
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -60,6 +60,8 @@ import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import server.ThreadManager;
|
||||
//import jdk.nashorn.api.scripting.ScriptUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -647,12 +649,11 @@ public class EventManager {
|
||||
if(p != null) {
|
||||
List<MaplePartyCharacter> lmpc;
|
||||
|
||||
/*
|
||||
if(ServerConstants.JAVA_8)
|
||||
/*if(ServerConstants.JAVA_8) {
|
||||
lmpc = new ArrayList<>(((Map<String, MaplePartyCharacter>)(ScriptUtils.convert(p, Map.class))).values());
|
||||
else
|
||||
} else {
|
||||
lmpc = new ArrayList<>((List<MaplePartyCharacter>) p);
|
||||
*/
|
||||
}*/
|
||||
|
||||
lmpc = new ArrayList<>((List<MaplePartyCharacter>) p);
|
||||
party.setEligibleMembers(lmpc);
|
||||
@@ -809,8 +810,7 @@ public class EventManager {
|
||||
}
|
||||
|
||||
private void fillEimQueue() {
|
||||
Thread t = new Thread(new EventManagerWorker()); //call new thread to fill up readied instances queue
|
||||
t.start();
|
||||
ThreadManager.getInstance().newTask(new EventManagerWorker()); //call new thread to fill up readied instances queue
|
||||
}
|
||||
|
||||
private EventInstanceManager getReadyInstance() {
|
||||
|
||||
@@ -32,6 +32,7 @@ import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import server.ThreadManager;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -105,68 +106,62 @@ public class EventScriptScheduler {
|
||||
|
||||
public void registerEntry(final Runnable scheduledAction, final long duration) {
|
||||
|
||||
Thread t = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
schedulerLock.lock();
|
||||
try {
|
||||
idleProcs = 0;
|
||||
if(schedulerTask == null) {
|
||||
if(disposed) return;
|
||||
ThreadManager.getInstance().newTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
schedulerLock.lock();
|
||||
try {
|
||||
idleProcs = 0;
|
||||
if(schedulerTask == null) {
|
||||
if(disposed) return;
|
||||
|
||||
schedulerTask = TimerManager.getInstance().register(monitorTask, ServerConstants.MOB_STATUS_MONITOR_PROC, ServerConstants.MOB_STATUS_MONITOR_PROC);
|
||||
}
|
||||
schedulerTask = TimerManager.getInstance().register(monitorTask, ServerConstants.MOB_STATUS_MONITOR_PROC, ServerConstants.MOB_STATUS_MONITOR_PROC);
|
||||
}
|
||||
|
||||
registeredEntries.put(scheduledAction, Server.getInstance().getCurrentTime() + duration);
|
||||
} finally {
|
||||
schedulerLock.unlock();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
t.start();
|
||||
registeredEntries.put(scheduledAction, Server.getInstance().getCurrentTime() + duration);
|
||||
} finally {
|
||||
schedulerLock.unlock();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void cancelEntry(final Runnable scheduledAction) {
|
||||
|
||||
Thread t = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
schedulerLock.lock();
|
||||
try {
|
||||
registeredEntries.remove(scheduledAction);
|
||||
} finally {
|
||||
schedulerLock.unlock();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
t.start();
|
||||
ThreadManager.getInstance().newTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
schedulerLock.lock();
|
||||
try {
|
||||
registeredEntries.remove(scheduledAction);
|
||||
} finally {
|
||||
schedulerLock.unlock();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
|
||||
Thread t = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
schedulerLock.lock();
|
||||
try {
|
||||
if(schedulerTask != null) {
|
||||
schedulerTask.cancel(false);
|
||||
schedulerTask = null;
|
||||
}
|
||||
ThreadManager.getInstance().newTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
schedulerLock.lock();
|
||||
try {
|
||||
if(schedulerTask != null) {
|
||||
schedulerTask.cancel(false);
|
||||
schedulerTask = null;
|
||||
}
|
||||
|
||||
registeredEntries.clear();
|
||||
disposed = true;
|
||||
} finally {
|
||||
schedulerLock.unlock();
|
||||
}
|
||||
registeredEntries.clear();
|
||||
disposed = true;
|
||||
} finally {
|
||||
schedulerLock.unlock();
|
||||
}
|
||||
|
||||
disposeLocks();
|
||||
}
|
||||
});
|
||||
|
||||
t.start();
|
||||
disposeLocks();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
|
||||
@@ -59,7 +59,7 @@ public class ItemScriptManager {
|
||||
return scriptFile.exists();
|
||||
}
|
||||
|
||||
public void getItemScript(MapleClient c, String scriptName) {
|
||||
public void runItemScript(MapleClient c, String scriptName) {
|
||||
if (scripts.containsKey(scriptName)) {
|
||||
try {
|
||||
scripts.get(scriptName).invokeFunction("start", new ItemScriptMethods(c));
|
||||
|
||||
@@ -62,7 +62,7 @@ public class MapScriptManager {
|
||||
return scriptFile.exists();
|
||||
}
|
||||
|
||||
public void getMapScript(MapleClient c, String scriptName, boolean firstUser) {
|
||||
public void runMapScript(MapleClient c, String scriptName, boolean firstUser) {
|
||||
if (scripts.containsKey(scriptName)) {
|
||||
try {
|
||||
scripts.get(scriptName).invokeFunction("start", new MapScriptMethods(c));
|
||||
|
||||
@@ -646,7 +646,7 @@ public class MapleItemInformationProvider {
|
||||
}
|
||||
|
||||
public static boolean rollSuccessChance(double prop) {
|
||||
return Math.random() > testYourLuck(prop / 100.0, ServerConstants.SCROLL_CHANCE_RATE);
|
||||
return Math.random() >= testYourLuck(prop / 100.0, ServerConstants.SCROLL_CHANCE_RATE);
|
||||
}
|
||||
|
||||
private static short getMaximumShortMaxIfOverflow(int value1, int value2) {
|
||||
@@ -1238,9 +1238,11 @@ public class MapleItemInformationProvider {
|
||||
boolean bRestricted = false;
|
||||
if(itemId != 0) {
|
||||
MapleData data = getItemData(itemId);
|
||||
bRestricted = MapleDataTool.getIntConvert("info/tradeBlock", data, 0) == 1;
|
||||
if (!bRestricted) {
|
||||
bRestricted = MapleDataTool.getIntConvert("info/accountSharable", data, 0) == 1;
|
||||
if (data != null) {
|
||||
bRestricted = MapleDataTool.getIntConvert("info/tradeBlock", data, 0) == 1;
|
||||
if (!bRestricted) {
|
||||
bRestricted = MapleDataTool.getIntConvert("info/accountSharable", data, 0) == 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
package server;
|
||||
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.RejectedExecutionHandler;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ronan
|
||||
*/
|
||||
public class ThreadManager {
|
||||
private static ThreadManager instance = new ThreadManager();
|
||||
|
||||
public static ThreadManager getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private ThreadPoolExecutor tpe;
|
||||
|
||||
private ThreadManager() {}
|
||||
|
||||
private class RejectedExecutionHandlerImpl implements RejectedExecutionHandler {
|
||||
|
||||
@Override
|
||||
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
|
||||
Thread t = new Thread(r);
|
||||
t.start();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void newTask(Runnable r) {
|
||||
tpe.execute(r);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
RejectedExecutionHandler reh = new RejectedExecutionHandlerImpl();
|
||||
ThreadFactory tf = Executors.defaultThreadFactory();
|
||||
|
||||
tpe = new ThreadPoolExecutor(20, 1000, 77, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(50), tf, reh);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
tpe.shutdown();
|
||||
try {
|
||||
tpe.awaitTermination(5, TimeUnit.MINUTES);
|
||||
} catch (InterruptedException ie) {}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -573,14 +573,27 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
}
|
||||
}
|
||||
|
||||
private void removeController() {
|
||||
this.lockMonster();
|
||||
try {
|
||||
MapleCharacter chrController = getController();
|
||||
if (chrController != null) { // this can/should only happen when a hidden gm attacks the monster
|
||||
chrController.announce(MaplePacketCreator.stopControllingMonster(this.getObjectId()));
|
||||
chrController.stopControllingMonster(this);
|
||||
}
|
||||
|
||||
setController(null);
|
||||
setControllerHasAggro(false);
|
||||
setControllerKnowsAboutAggro(false);
|
||||
} finally {
|
||||
this.unlockMonster();
|
||||
}
|
||||
}
|
||||
|
||||
public MapleCharacter killBy(final MapleCharacter killer) {
|
||||
distributeExperience(killer != null ? killer.getId() : 0);
|
||||
|
||||
MapleCharacter chrController = getController();
|
||||
if (chrController != null) { // this can/should only happen when a hidden gm attacks the monster
|
||||
chrController.announce(MaplePacketCreator.stopControllingMonster(this.getObjectId()));
|
||||
chrController.stopControllingMonster(this);
|
||||
}
|
||||
removeController();
|
||||
|
||||
final List<Integer> toSpawn = this.getRevives(); // this doesn't work (?)
|
||||
if (toSpawn != null) {
|
||||
@@ -647,8 +660,9 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 8810017; i >= 8810010; i--)
|
||||
for(int i = 8810017; i >= 8810010; i--) {
|
||||
reviveMap.killMonster(reviveMap.getMonsterById(i), killer, true);
|
||||
}
|
||||
}
|
||||
|
||||
if(eim != null) {
|
||||
@@ -787,20 +801,24 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
}
|
||||
|
||||
public void switchController(MapleCharacter newController, boolean immediateAggro) {
|
||||
MapleCharacter controllers = getController();
|
||||
if (controllers == newController) {
|
||||
return;
|
||||
this.lockMonster();
|
||||
try {
|
||||
MapleCharacter controllers = getController();
|
||||
if (controllers == newController) {
|
||||
return;
|
||||
}
|
||||
|
||||
removeController();
|
||||
|
||||
newController.controlMonster(this, immediateAggro);
|
||||
setController(newController);
|
||||
if (immediateAggro) {
|
||||
setControllerHasAggro(true);
|
||||
}
|
||||
setControllerKnowsAboutAggro(false);
|
||||
} finally {
|
||||
this.unlockMonster();
|
||||
}
|
||||
if (controllers != null) {
|
||||
controllers.stopControllingMonster(this);
|
||||
controllers.getClient().announce(MaplePacketCreator.stopControllingMonster(getObjectId()));
|
||||
}
|
||||
newController.controlMonster(this, immediateAggro);
|
||||
setController(newController);
|
||||
if (immediateAggro) {
|
||||
setControllerHasAggro(true);
|
||||
}
|
||||
setControllerKnowsAboutAggro(false);
|
||||
}
|
||||
|
||||
public void addListener(MonsterListener listener) {
|
||||
@@ -863,20 +881,21 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendSpawnData(MapleClient c) {
|
||||
if (!isAlive()) {
|
||||
public void sendSpawnData(MapleClient client) {
|
||||
if (hp.get() <= 0) { // mustn't monsterLock this function
|
||||
return;
|
||||
}
|
||||
if (isFake()) {
|
||||
c.announce(MaplePacketCreator.spawnFakeMonster(this, 0));
|
||||
if (fake) {
|
||||
client.announce(MaplePacketCreator.spawnFakeMonster(this, 0));
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.spawnMonster(this, false));
|
||||
client.announce(MaplePacketCreator.spawnMonster(this, false));
|
||||
}
|
||||
|
||||
statiLock.lock();
|
||||
try {
|
||||
if (stati.size() > 0) {
|
||||
for (final MonsterStatusEffect mse : this.stati.values()) {
|
||||
c.announce(MaplePacketCreator.applyMonsterStatus(getObjectId(), mse, null));
|
||||
client.announce(MaplePacketCreator.applyMonsterStatus(getObjectId(), mse, null));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
@@ -884,7 +903,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
}
|
||||
|
||||
if (hasBossHPBar()) {
|
||||
c.announceBossHpBar(this, this.hashCode(), makeBossHPBarPacket());
|
||||
client.announceBossHpBar(this, this.hashCode(), makeBossHPBarPacket());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1156,6 +1175,18 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
map.getChannelServer().registerMobStatus(map.getId(), effect, cancelTask, duration);
|
||||
}
|
||||
|
||||
public void refreshMobPosition() {
|
||||
updateMobPosition(getPosition());
|
||||
}
|
||||
|
||||
public void updateMobPosition(Point newPoint) {
|
||||
removeController();
|
||||
setPosition(newPoint);
|
||||
map.broadcastMessage(MaplePacketCreator.moveMonster(this.getObjectId(), false, -1, 0, 0, 0, this.getPosition(), this.getIdleMovement()));
|
||||
map.moveMonster(this, this.getPosition());
|
||||
map.updateMonsterController(this);
|
||||
}
|
||||
|
||||
private void debuffMobStat(MonsterStatus stat) {
|
||||
statiLock.lock();
|
||||
try {
|
||||
|
||||
@@ -44,12 +44,8 @@ public class MapleNPC extends AbstractLoadedMapleLife {
|
||||
|
||||
@Override
|
||||
public void sendSpawnData(MapleClient client) {
|
||||
if (this.getId() > 9010010 && this.getId() < 9010014) {
|
||||
client.announce(MaplePacketCreator.spawnNPCRequestController(this, false));
|
||||
} else {
|
||||
client.announce(MaplePacketCreator.spawnNPC(this));
|
||||
client.announce(MaplePacketCreator.spawnNPCRequestController(this, true));
|
||||
}
|
||||
client.announce(MaplePacketCreator.spawnNPC(this));
|
||||
client.announce(MaplePacketCreator.spawnNPCRequestController(this, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -103,12 +103,12 @@ public class MobSkill {
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
public void applyDelayedEffect(final MapleCharacter player, final MapleMonster monster, final boolean skill, final List<MapleCharacter> banishPlayers, int animationTime) {
|
||||
public void applyDelayedEffect(final MapleCharacter player, final MapleMonster monster, final boolean skill, int animationTime) {
|
||||
Runnable toRun = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if(monster.isAlive()) {
|
||||
applyEffect(player, monster, skill, banishPlayers);
|
||||
applyEffect(player, monster, skill, null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user