PNPC & Pmob + Events Wheel & P. Leave patch + Proper cash use deplete
Reworked cash item consume. It now depletes from the selected slot rather than from the first slot it appears on inventory. Implemented PNPC and PMOB commands. Solved an issue with some events finishing abruptly when players quit a party. Added missing mandatory script functions to the event scripts. Solved an interaction issue with Wheel of Destiny activation in event instances. Added interaction with NPC Mom & Dad in the Engagement prequest. Solved an issue with event maps being disposed while reactor's spray items activity is still in effect. Fixed modifier scrolls such as Spikes on Shoes depleting a upgrade slot. Added a server flag for avoiding compulsory consuming by pet autopot. Added a cache for fetching mob names. Implemented boss drop rate. Smart protected commands system against command requests in burst by the same user. Revised login handler, bringing disconnection checks before checking login state and preventing new client reattribution to already logged-in character objects. Botched login handler sessions now properly gets closed.
This commit is contained in:
@@ -4362,6 +4362,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
return dropRate / (dropCoupon * getWorldServer().getDropRate());
|
||||
}
|
||||
|
||||
public int getBossDropRate() {
|
||||
World w = getWorldServer();
|
||||
return (dropRate / w.getDropRate()) * w.getBossDropRate();
|
||||
}
|
||||
|
||||
public int getMesoRate() {
|
||||
return mesoRate;
|
||||
}
|
||||
@@ -5545,7 +5550,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
long timeNow = Server.getInstance().getCurrentTime();
|
||||
|
||||
if (timeNow - lastDeathtime > ServerConstants.BUYBACK_RETURN_MINUTES * 60 * 1000) {
|
||||
this.dropMessage(5, "The time available to decide has expired, therefore you are unable to buyback.");
|
||||
this.dropMessage(5, "The period of time to decide has expired, therefore you are unable to buyback.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -989,6 +989,11 @@ public class MapleClient {
|
||||
|
||||
clear();
|
||||
} else {
|
||||
if (session.containsAttribute(MapleClient.CLIENT_KEY)) {
|
||||
MapleSessionCoordinator.getInstance().closeSession(session, false);
|
||||
session.removeAttribute(MapleClient.CLIENT_KEY);
|
||||
}
|
||||
|
||||
engines.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +81,18 @@ public class CommandsExecutor {
|
||||
}
|
||||
|
||||
public void handle(MapleClient client, String message){
|
||||
if (client.tryacquireClient()) {
|
||||
try {
|
||||
handleInternal(client, message);
|
||||
} finally {
|
||||
client.releaseClient();
|
||||
}
|
||||
} else {
|
||||
client.getPlayer().dropMessage(5, "Try again in a while... Latest commands are currently being processed.");
|
||||
}
|
||||
}
|
||||
|
||||
private void handleInternal(MapleClient client, String message){
|
||||
final String[] spitedMessage = message.toLowerCase().substring(1).split("[ ]");
|
||||
final String commandName = spitedMessage[0];
|
||||
final RegisteredCommand command = registeredCommands.get(commandName);
|
||||
@@ -321,8 +333,12 @@ public class CommandsExecutor {
|
||||
addCommand("pap", 4, PapCommand.class);
|
||||
addCommand("pianus", 4, PianusCommand.class);
|
||||
addCommand("cake", 4, CakeCommand.class);
|
||||
addCommand("playernpcremove", 4, PlayerNpcRemoveCommand.class);
|
||||
addCommand("playernpc", 4, PlayerNpcCommand.class);
|
||||
addCommand("playernpcremove", 4, PlayerNpcRemoveCommand.class);
|
||||
addCommand("pnpc", 4, PnpcCommand.class);
|
||||
addCommand("pnpcremove", 4, PnpcRemoveCommand.class);
|
||||
addCommand("pmob", 4, PmobCommand.class);
|
||||
addCommand("pmobremove", 4, PmobRemoveCommand.class);
|
||||
|
||||
commandsNameDesc.add(levelCommandsCursor);
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ public class RatesCommand extends Command {
|
||||
showMsg_ += "EXP Rate: #e#b" + player.getExpRate() + "x#k#n" + "\r\n";
|
||||
showMsg_ += "MESO Rate: #e#b" + player.getMesoRate() + "x#k#n" + "\r\n";
|
||||
showMsg_ += "DROP Rate: #e#b" + player.getDropRate() + "x#k#n" + "\r\n";
|
||||
showMsg_ += "BOSS DROP Rate: #e#b" + player.getBossDropRate() + "x#k#n" + "\r\n";
|
||||
if(ServerConstants.USE_QUEST_RATE) showMsg_ += "QUEST Rate: #e#b" + c.getWorldServer().getQuestRate() + "x#k#n" + "\r\n";
|
||||
|
||||
player.showHint(showMsg_, 300);
|
||||
|
||||
@@ -37,30 +37,36 @@ public class ShowRatesCommand extends Command {
|
||||
public void execute(MapleClient c, String[] params) {
|
||||
MapleCharacter player = c.getPlayer();
|
||||
String showMsg = "#eEXP RATE#n" + "\r\n";
|
||||
showMsg += "Server EXP Rate: #k" + c.getWorldServer().getExpRate() + "x#k" + "\r\n";
|
||||
showMsg += "World EXP Rate: #k" + c.getWorldServer().getExpRate() + "x#k" + "\r\n";
|
||||
showMsg += "Player EXP Rate: #k" + player.getRawExpRate() + "x#k" + "\r\n";
|
||||
if(player.getCouponExpRate() != 1) showMsg += "Coupon EXP Rate: #k" + player.getCouponExpRate() + "x#k" + "\r\n";
|
||||
showMsg += "EXP Rate: #e#b" + player.getExpRate() + "x#k#n" + "\r\n";
|
||||
|
||||
showMsg += "\r\n" + "#eMESO RATE#n" + "\r\n";
|
||||
showMsg += "Server MESO Rate: #k" + c.getWorldServer().getMesoRate() + "x#k" + "\r\n";
|
||||
showMsg += "World MESO Rate: #k" + c.getWorldServer().getMesoRate() + "x#k" + "\r\n";
|
||||
showMsg += "Player MESO Rate: #k" + player.getRawMesoRate() + "x#k" + "\r\n";
|
||||
if(player.getCouponMesoRate() != 1) showMsg += "Coupon MESO Rate: #k" + player.getCouponMesoRate() + "x#k" + "\r\n";
|
||||
showMsg += "MESO Rate: #e#b" + player.getMesoRate() + "x#k#n" + "\r\n";
|
||||
|
||||
showMsg += "\r\n" + "#eDROP RATE#n" + "\r\n";
|
||||
showMsg += "Server DROP Rate: #k" + c.getWorldServer().getDropRate() + "x#k" + "\r\n";
|
||||
showMsg += "World DROP Rate: #k" + c.getWorldServer().getDropRate() + "x#k" + "\r\n";
|
||||
showMsg += "Player DROP Rate: #k" + player.getRawDropRate() + "x#k" + "\r\n";
|
||||
if(player.getCouponDropRate() != 1) showMsg += "Coupon DROP Rate: #k" + player.getCouponDropRate() + "x#k" + "\r\n";
|
||||
showMsg += "DROP Rate: #e#b" + player.getDropRate() + "x#k#n" + "\r\n";
|
||||
|
||||
showMsg += "\r\n" + "#eBOSS DROP RATE#n" + "\r\n";
|
||||
showMsg += "World BOSS DROP Rate: #k" + c.getWorldServer().getBossDropRate() + "x#k" + "\r\n";
|
||||
showMsg += "Player DROP Rate: #k" + player.getRawDropRate() + "x#k" + "\r\n";
|
||||
if(player.getCouponDropRate() != 1) showMsg += "Coupon DROP Rate: #k" + player.getCouponDropRate() + "x#k" + "\r\n";
|
||||
showMsg += "BOSS DROP Rate: #e#b" + player.getBossDropRate() + "x#k#n" + "\r\n";
|
||||
|
||||
if(ServerConstants.USE_QUEST_RATE) {
|
||||
showMsg += "\r\n" + "#eQUEST RATE#n" + "\r\n";
|
||||
showMsg += "Server QUEST Rate: #e#b" + c.getWorldServer().getQuestRate() + "x#k#n" + "\r\n";
|
||||
showMsg += "World QUEST Rate: #e#b" + c.getWorldServer().getQuestRate() + "x#k#n" + "\r\n";
|
||||
}
|
||||
|
||||
showMsg += "\r\n" + "#eTRAVEL RATE#n" + "\r\n";
|
||||
showMsg += "Server TRAVEL Rate: #e#b" + c.getWorldServer().getTravelRate() + "x#k#n" + "\r\n";
|
||||
showMsg += "\r\n";
|
||||
showMsg += "World TRAVEL Rate: #e#b" + c.getWorldServer().getTravelRate() + "x#k#n" + "\r\nServer\r\nPlayer";
|
||||
|
||||
player.showHint(showMsg, 300);
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ public class WhatDropsFromCommand extends Command {
|
||||
if (name == null || name.equals("null") || drop.chance == 0){
|
||||
continue;
|
||||
}
|
||||
float chance = 1000000 / drop.chance / player.getDropRate();
|
||||
float chance = 1000000 / drop.chance / (!MapleMonsterInformationProvider.getInstance().isBoss(mobId) ? player.getDropRate() : player.getBossDropRate());
|
||||
output += "- " + name + " (1/" + (int) chance + ")\r\n";
|
||||
} catch (Exception ex){
|
||||
ex.printStackTrace();
|
||||
|
||||
@@ -29,7 +29,6 @@ import client.MapleClient;
|
||||
import server.MapleItemInformationProvider;
|
||||
import server.life.MapleMonsterInformationProvider;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Pair;
|
||||
|
||||
import java.sql.Connection;
|
||||
@@ -66,7 +65,7 @@ public class WhoDropsCommand extends Command {
|
||||
ps.setInt(1, data.getLeft());
|
||||
ResultSet rs = ps.executeQuery();
|
||||
while(rs.next()) {
|
||||
String resultName = MapleMonsterInformationProvider.getMobNameFromID(rs.getInt("dropperid"));
|
||||
String resultName = MapleMonsterInformationProvider.getInstance().getMobNameFromId(rs.getInt("dropperid"));
|
||||
if (resultName != null) {
|
||||
output += resultName + ", ";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
|
||||
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
|
||||
*/
|
||||
package client.command.commands.gm4;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import net.server.channel.Channel;
|
||||
import server.life.MapleLifeFactory;
|
||||
import server.maps.MapleMap;
|
||||
import client.command.Command;
|
||||
import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
import java.awt.Point;
|
||||
import server.life.MapleMonster;
|
||||
import tools.DatabaseConnection;
|
||||
|
||||
public class PmobCommand extends Command {
|
||||
{
|
||||
setDescription("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(MapleClient c, String[] params) {
|
||||
MapleCharacter player = c.getPlayer();
|
||||
if (params.length < 1) {
|
||||
player.yellowMessage("Syntax: !pmob <mobid> [<mobtime>]");
|
||||
return;
|
||||
}
|
||||
|
||||
// command suggestion thanks to HighKey21, none, bibiko94 (TAYAMO), asafgb
|
||||
int mapId = player.getMapId();
|
||||
int mobId = Integer.parseInt(params[0]);
|
||||
int mobTime = (params.length > 1) ? Integer.parseInt(params[1]) : -1;
|
||||
|
||||
Point checkpos = player.getMap().getGroundBelow(player.getPosition());
|
||||
int xpos = checkpos.x;
|
||||
int ypos = checkpos.y;
|
||||
int fh = player.getMap().getFootholds().findBelow(checkpos).getId();
|
||||
|
||||
MapleMonster mob = MapleLifeFactory.getMonster(mobId);
|
||||
if (mob != null && !mob.getName().equals("MISSINGNO")) {
|
||||
mob.setPosition(checkpos);
|
||||
mob.setCy(ypos);
|
||||
mob.setRx0(xpos + 50);
|
||||
mob.setRx1(xpos - 50);
|
||||
mob.setFh(fh);
|
||||
try {
|
||||
Connection con = DatabaseConnection.getConnection();
|
||||
PreparedStatement ps = con.prepareStatement("INSERT INTO plife ( life, f, fh, cy, rx0, rx1, type, x, y, world, map, mobtime, hide ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )");
|
||||
ps.setInt(1, mobId);
|
||||
ps.setInt(2, 0);
|
||||
ps.setInt(3, fh);
|
||||
ps.setInt(4, ypos);
|
||||
ps.setInt(5, xpos + 50);
|
||||
ps.setInt(6, xpos - 50);
|
||||
ps.setString(7, "m");
|
||||
ps.setInt(8, xpos);
|
||||
ps.setInt(9, ypos);
|
||||
ps.setInt(10, player.getWorld());
|
||||
ps.setInt(11, mapId);
|
||||
ps.setInt(12, mobTime);
|
||||
ps.setInt(13, 0);
|
||||
ps.executeUpdate();
|
||||
ps.close();
|
||||
con.close();
|
||||
|
||||
for (Channel ch: player.getWorldServer().getChannels()) {
|
||||
MapleMap map = ch.getMapFactory().getMap(mapId);
|
||||
map.addMonsterSpawn(mob, mobTime, -1);
|
||||
map.addAllMonsterSpawn(mob, mobTime, -1);
|
||||
}
|
||||
|
||||
player.yellowMessage("Pmob created.");
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
player.dropMessage(5, "Failed to store pmob in the database.");
|
||||
}
|
||||
} else {
|
||||
player.dropMessage(5, "You have entered an invalid mob id.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
|
||||
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
|
||||
*/
|
||||
package client.command.commands.gm4;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import net.server.channel.Channel;
|
||||
import server.maps.MapleMap;
|
||||
import client.command.Command;
|
||||
import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
import java.awt.Point;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.Pair;
|
||||
|
||||
public class PmobRemoveCommand extends Command {
|
||||
{
|
||||
setDescription("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(MapleClient c, String[] params) {
|
||||
MapleCharacter player = c.getPlayer();
|
||||
|
||||
int mapId = player.getMapId();
|
||||
int mobId = params.length > 0 ? Integer.parseInt(params[0]) : -1;
|
||||
|
||||
Point pos = player.getPosition();
|
||||
int xpos = pos.x;
|
||||
int ypos = pos.y;
|
||||
|
||||
List<Pair<Integer, Pair<Integer, Integer>>> toRemove = new LinkedList<>();
|
||||
try {
|
||||
Connection con = DatabaseConnection.getConnection();
|
||||
PreparedStatement ps;
|
||||
|
||||
if (mobId > -1) {
|
||||
String select = "SELECT * FROM plife WHERE world = ? AND map = ? AND type LIKE ? AND life = ?";
|
||||
ps = con.prepareStatement(select, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
|
||||
ps.setInt(1, player.getWorld());
|
||||
ps.setInt(2, mapId);
|
||||
ps.setString(3, "m");
|
||||
ps.setInt(4, mobId);
|
||||
} else {
|
||||
String select = "SELECT * FROM plife WHERE world = ? AND map = ? AND type LIKE ? AND x >= ? AND x <= ? AND y >= ? AND y <= ?";
|
||||
ps = con.prepareStatement(select, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
|
||||
ps.setInt(1, player.getWorld());
|
||||
ps.setInt(2, mapId);
|
||||
ps.setString(3, "m");
|
||||
ps.setInt(4, xpos - 50);
|
||||
ps.setInt(5, xpos + 50);
|
||||
ps.setInt(6, ypos - 50);
|
||||
ps.setInt(7, ypos + 50);
|
||||
}
|
||||
|
||||
ResultSet rs = ps.executeQuery();
|
||||
while (true) {
|
||||
rs.beforeFirst();
|
||||
if (!rs.next()) {
|
||||
break;
|
||||
}
|
||||
|
||||
toRemove.add(new Pair<>(rs.getInt("life"), new Pair<>(rs.getInt("x"), rs.getInt("y"))));
|
||||
rs.deleteRow();
|
||||
}
|
||||
|
||||
rs.close();
|
||||
ps.close();
|
||||
con.close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
player.dropMessage(5, "Failed to remove pmob from the database.");
|
||||
}
|
||||
|
||||
if (!toRemove.isEmpty()) {
|
||||
for (Channel ch: player.getWorldServer().getChannels()) {
|
||||
MapleMap map = ch.getMapFactory().getMap(mapId);
|
||||
|
||||
for (Pair<Integer, Pair<Integer, Integer>> r : toRemove) {
|
||||
map.removeMonsterSpawn(r.getLeft(), r.getRight().getLeft(), r.getRight().getRight());
|
||||
map.removeAllMonsterSpawn(r.getLeft(), r.getRight().getLeft(), r.getRight().getRight());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
player.yellowMessage("Cleared " + toRemove.size() + " pmob placements.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
|
||||
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
|
||||
*/
|
||||
package client.command.commands.gm4;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import net.server.channel.Channel;
|
||||
import server.life.MapleLifeFactory;
|
||||
import server.life.MapleNPC;
|
||||
import client.command.Command;
|
||||
import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
import java.awt.Point;
|
||||
import server.maps.MapleMap;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.MaplePacketCreator;
|
||||
|
||||
public class PnpcCommand extends Command {
|
||||
{
|
||||
setDescription("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(MapleClient c, String[] params) {
|
||||
MapleCharacter player = c.getPlayer();
|
||||
if (params.length < 1) {
|
||||
player.yellowMessage("Syntax: !pnpc <npcid>");
|
||||
return;
|
||||
}
|
||||
|
||||
// command suggestion thanks to HighKey21, none, bibiko94 (TAYAMO), asafgb
|
||||
int mapId = player.getMapId();
|
||||
int npcId = Integer.parseInt(params[0]);
|
||||
if (player.getMap().containsNPC(npcId)) {
|
||||
player.dropMessage(5, "This map already contains the specified NPC.");
|
||||
return;
|
||||
}
|
||||
|
||||
MapleNPC npc = MapleLifeFactory.getNPC(npcId);
|
||||
|
||||
Point checkpos = player.getMap().getGroundBelow(player.getPosition());
|
||||
int xpos = checkpos.x;
|
||||
int ypos = checkpos.y;
|
||||
int fh = player.getMap().getFootholds().findBelow(checkpos).getId();
|
||||
|
||||
if (npc != null && !npc.getName().equals("MISSINGNO")) {
|
||||
try {
|
||||
Connection con = DatabaseConnection.getConnection();
|
||||
PreparedStatement ps = con.prepareStatement("INSERT INTO plife ( life, f, fh, cy, rx0, rx1, type, x, y, world, map, mobtime, hide ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )");
|
||||
ps.setInt(1, npcId);
|
||||
ps.setInt(2, 0);
|
||||
ps.setInt(3, fh);
|
||||
ps.setInt(4, ypos);
|
||||
ps.setInt(5, xpos + 50);
|
||||
ps.setInt(6, xpos - 50);
|
||||
ps.setString(7, "n");
|
||||
ps.setInt(8, xpos);
|
||||
ps.setInt(9, ypos);
|
||||
ps.setInt(10, player.getWorld());
|
||||
ps.setInt(11, mapId);
|
||||
ps.setInt(12, -1);
|
||||
ps.setInt(13, 0);
|
||||
ps.executeUpdate();
|
||||
ps.close();
|
||||
con.close();
|
||||
|
||||
for (Channel ch: player.getWorldServer().getChannels()) {
|
||||
npc = MapleLifeFactory.getNPC(npcId);
|
||||
npc.setPosition(checkpos);
|
||||
npc.setCy(ypos);
|
||||
npc.setRx0(xpos + 50);
|
||||
npc.setRx1(xpos - 50);
|
||||
npc.setFh(fh);
|
||||
|
||||
MapleMap map = ch.getMapFactory().getMap(mapId);
|
||||
map.addMapObject(npc);
|
||||
map.broadcastMessage(MaplePacketCreator.spawnNPC(npc));
|
||||
}
|
||||
|
||||
player.yellowMessage("Pnpc created.");
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
player.dropMessage(5, "Failed to store pNPC in the database.");
|
||||
}
|
||||
} else {
|
||||
player.dropMessage(5, "You have entered an invalid NPC id.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
|
||||
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
|
||||
*/
|
||||
package client.command.commands.gm4;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import net.server.channel.Channel;
|
||||
import client.command.Command;
|
||||
import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
import java.awt.Point;
|
||||
import java.sql.ResultSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import server.maps.MapleMap;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.Pair;
|
||||
|
||||
public class PnpcRemoveCommand extends Command {
|
||||
{
|
||||
setDescription("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(MapleClient c, String[] params) {
|
||||
MapleCharacter player = c.getPlayer();
|
||||
|
||||
int mapId = player.getMapId();
|
||||
int npcId = params.length > 0 ? Integer.parseInt(params[0]) : -1;
|
||||
|
||||
Point pos = player.getPosition();
|
||||
int xpos = pos.x;
|
||||
int ypos = pos.y;
|
||||
|
||||
List<Pair<Integer, Pair<Integer, Integer>>> toRemove = new LinkedList<>();
|
||||
try {
|
||||
Connection con = DatabaseConnection.getConnection();
|
||||
PreparedStatement ps;
|
||||
|
||||
if (npcId > -1) {
|
||||
String select = "SELECT * FROM plife WHERE world = ? AND map = ? AND type LIKE ? AND life = ?";
|
||||
ps = con.prepareStatement(select, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
|
||||
ps.setInt(1, player.getWorld());
|
||||
ps.setInt(2, mapId);
|
||||
ps.setString(3, "n");
|
||||
ps.setInt(4, npcId);
|
||||
} else {
|
||||
String select = "SELECT * FROM plife WHERE world = ? AND map = ? AND type LIKE ? AND x >= ? AND x <= ? AND y >= ? AND y <= ?";
|
||||
ps = con.prepareStatement(select, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
|
||||
ps.setInt(1, player.getWorld());
|
||||
ps.setInt(2, mapId);
|
||||
ps.setString(3, "n");
|
||||
ps.setInt(4, xpos - 50);
|
||||
ps.setInt(5, xpos + 50);
|
||||
ps.setInt(6, ypos - 50);
|
||||
ps.setInt(7, ypos + 50);
|
||||
}
|
||||
|
||||
ResultSet rs = ps.executeQuery();
|
||||
while (true) {
|
||||
rs.beforeFirst();
|
||||
if (!rs.next()) {
|
||||
break;
|
||||
}
|
||||
|
||||
toRemove.add(new Pair<>(rs.getInt("life"), new Pair<>(rs.getInt("x"), rs.getInt("y"))));
|
||||
rs.deleteRow();
|
||||
}
|
||||
|
||||
rs.close();
|
||||
ps.close();
|
||||
con.close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
player.dropMessage(5, "Failed to remove pNPC from the database.");
|
||||
}
|
||||
|
||||
if (!toRemove.isEmpty()) {
|
||||
for (Channel ch: player.getWorldServer().getChannels()) {
|
||||
MapleMap map = ch.getMapFactory().getMap(mapId);
|
||||
|
||||
for (Pair<Integer, Pair<Integer, Integer>> r : toRemove) {
|
||||
map.destroyNPC(r.getLeft());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
player.yellowMessage("Cleared " + toRemove.size() + " pNPC placements.");
|
||||
}
|
||||
}
|
||||
@@ -82,7 +82,7 @@ public class MaplePet extends Item {
|
||||
}
|
||||
}
|
||||
|
||||
public static void deleteFromDb(int petid) {
|
||||
public static void deleteFromDb(MapleCharacter owner, int petid) {
|
||||
try {
|
||||
Connection con = DatabaseConnection.getConnection();
|
||||
|
||||
@@ -98,6 +98,7 @@ public class MaplePet extends Item {
|
||||
|
||||
con.close();
|
||||
|
||||
owner.resetExcluded(petid);
|
||||
MapleCashidGenerator.freeCashId(petid);
|
||||
} catch (SQLException ex) {
|
||||
ex.printStackTrace();
|
||||
|
||||
@@ -391,7 +391,7 @@ public class MapleInventoryManipulator {
|
||||
announceModifyInventory(c, item, fromDrop, allowZero);
|
||||
}
|
||||
|
||||
MaplePet.deleteFromDb(petid);
|
||||
MaplePet.deleteFromDb(chr, petid);
|
||||
} else {
|
||||
inv.removeItem(slot, quantity, allowZero);
|
||||
if(type != MapleInventoryType.CANHOLD) {
|
||||
|
||||
@@ -62,8 +62,7 @@ public class SpawnPetProcessor {
|
||||
long expiration = chr.getInventory(MapleInventoryType.CASH).getItem(slot).getExpiration();
|
||||
MapleInventoryManipulator.removeById(c, MapleInventoryType.CASH, petid, (short) 1, false, false);
|
||||
MapleInventoryManipulator.addById(c, evolveid, (short) 1, null, petId, expiration);
|
||||
MaplePet.deleteFromDb(petId);
|
||||
|
||||
MaplePet.deleteFromDb(chr, petId);
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -143,6 +143,10 @@ public final class ItemConstants {
|
||||
return scrollId > 2048999 && scrollId < 2049004;
|
||||
}
|
||||
|
||||
public static boolean isModifierScroll(int scrollId) {
|
||||
return scrollId == 2040727 || scrollId == 2041058;
|
||||
}
|
||||
|
||||
public static boolean isFlagModifier(int scrollId, byte flag) {
|
||||
if(scrollId == 2041058 && ((flag & ItemConstants.COLD) == ItemConstants.COLD)) return true;
|
||||
if(scrollId == 2040727 && ((flag & ItemConstants.SPIKES) == ItemConstants.SPIKES)) return true;
|
||||
|
||||
@@ -129,9 +129,10 @@ public class ServerConstants {
|
||||
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.
|
||||
|
||||
//Server Rates And Experience
|
||||
public static final int EXP_RATE = 10;
|
||||
public static final int EXP_RATE = 10; //NOTE: World-specific rates within "world.ini" OVERRIDES the default rates from here.
|
||||
public static final int MESO_RATE = 10;
|
||||
public static final int DROP_RATE = 10;
|
||||
public static final int BOSS_DROP_RATE = 10; //NOTE: Boss drop rate OVERRIDES common drop rate, for bosses-only.
|
||||
public static final int QUEST_RATE = 5; //Multiplier for Exp & Meso gains when completing a quest. Only available when USE_QUEST_RATE is true. Stacks with server Exp & Meso rates.
|
||||
public static final int TRAVEL_RATE = 10; //Means of transportation rides/departs using 1/N of the default time.
|
||||
|
||||
@@ -196,7 +197,7 @@ public class ServerConstants {
|
||||
//Character Configuration
|
||||
public static final boolean USE_ADD_SLOTS_BY_LEVEL = true; //Slots are added each 20 levels.
|
||||
public static final boolean USE_ADD_RATES_BY_LEVEL = true; //Rates are added each 20 levels.
|
||||
public static final boolean USE_STACK_COUPON_RATES = true; //Multiple coupons effects builds up together.
|
||||
public static final boolean USE_STACK_COUPON_RATES = false; //Multiple coupons effects builds up together.
|
||||
public static final boolean USE_PERFECT_PITCH = true; //For lvl 30 or above, each lvlup grants player 1 perfect pitch.
|
||||
|
||||
//Quest Configuration
|
||||
@@ -239,6 +240,7 @@ public class ServerConstants {
|
||||
public static final boolean PLAYERNPC_AUTODEPLOY = true; //Makes PlayerNPC automatically deployed on the Hall of Fame at the instant one reaches max level. If false, eligible players must talk to 1st job instructor to deploy a NPC.
|
||||
|
||||
//Pet Auto-Pot Configuration
|
||||
public static final boolean USE_COMPULSORY_AUTOPOT = true; //Pets will consume as many potions as needed to fulfill the AUTOHP/MP ratio threshold.
|
||||
public static final boolean USE_EQUIPS_ON_AUTOPOT = true; //Player MaxHP and MaxMP check values on autopot handler will be updated by the HP/MP bonuses on equipped items.
|
||||
public static final double PET_AUTOHP_RATIO = 0.99; //Will automatically consume potions until given ratio of the MaxHP/MaxMP is reached.
|
||||
public static final double PET_AUTOMP_RATIO = 0.99;
|
||||
|
||||
@@ -394,13 +394,14 @@ public class Server {
|
||||
int exprate = getWorldProperty(p, "exprate", i, ServerConstants.EXP_RATE);
|
||||
int mesorate = getWorldProperty(p, "mesorate", i, ServerConstants.MESO_RATE);
|
||||
int droprate = getWorldProperty(p, "droprate", i, ServerConstants.DROP_RATE);
|
||||
int bossdroprate = getWorldProperty(p, "bossdroprate", i, ServerConstants.BOSS_DROP_RATE);
|
||||
int questrate = getWorldProperty(p, "questrate", i, ServerConstants.QUEST_RATE);
|
||||
int travelrate = getWorldProperty(p, "travelrate", i, ServerConstants.TRAVEL_RATE);
|
||||
|
||||
World world = new World(i,
|
||||
Integer.parseInt(p.getProperty("flag" + i)),
|
||||
p.getProperty("eventmessage" + i),
|
||||
exprate, droprate, mesorate, questrate, travelrate);
|
||||
exprate, droprate, bossdroprate, mesorate, questrate, travelrate);
|
||||
|
||||
worldRecommendedList.add(new Pair<>(i, p.getProperty("whyamirecommended" + i)));
|
||||
worlds.add(world);
|
||||
|
||||
@@ -80,23 +80,24 @@ public final class ChangeMapHandler extends AbstractMaplePacketHandler {
|
||||
slea.readByte();
|
||||
boolean wheel = slea.readShort() > 0;
|
||||
if (targetid != -1 && !chr.isAlive()) {
|
||||
boolean executeStandardPath = true;
|
||||
if (chr.getEventInstance() != null) {
|
||||
executeStandardPath = chr.getEventInstance().revivePlayer(chr);
|
||||
}
|
||||
if (executeStandardPath) {
|
||||
MapleMap map = chr.getMap();
|
||||
MapleMap map = chr.getMap();
|
||||
if (wheel && chr.haveItemWithId(5510000, false)) {
|
||||
// thanks lucasziron for showing revivePlayer() also being triggered by Wheel
|
||||
|
||||
if (wheel && chr.haveItemWithId(5510000, false)) {
|
||||
MapleInventoryManipulator.removeById(c, MapleInventoryType.CASH, 5510000, 1, true, false);
|
||||
chr.announce(MaplePacketCreator.showWheelsLeft(chr.getItemQuantity(5510000, false)));
|
||||
|
||||
chr.updateHp(50);
|
||||
chr.changeMap(map, map.getRandomPlayerSpawnpoint());
|
||||
} else {
|
||||
chr.respawn(map.getReturnMapId());
|
||||
}
|
||||
}
|
||||
MapleInventoryManipulator.removeById(c, MapleInventoryType.CASH, 5510000, 1, true, false);
|
||||
chr.announce(MaplePacketCreator.showWheelsLeft(chr.getItemQuantity(5510000, false)));
|
||||
|
||||
chr.updateHp(50);
|
||||
chr.changeMap(map, map.findClosestPlayerSpawnpoint(chr.getPosition()));
|
||||
} else {
|
||||
boolean executeStandardPath = true;
|
||||
if (chr.getEventInstance() != null) {
|
||||
executeStandardPath = chr.getEventInstance().revivePlayer(chr);
|
||||
}
|
||||
if (executeStandardPath) {
|
||||
chr.respawn(map.getReturnMapId());
|
||||
}
|
||||
}
|
||||
} else if (targetid != -1) {
|
||||
if(chr.isGM()) {
|
||||
MapleMap to = chr.getWarpMap(targetid);
|
||||
|
||||
@@ -104,12 +104,16 @@ public final class PetAutoPotHandler extends AbstractMaplePacketHandler {
|
||||
incMp = stat.getMp();
|
||||
if(incMp <= 0 && hasMpGain) incMp = Math.ceil(maxMp * stat.getMpRate());
|
||||
|
||||
if (hasHpGain) {
|
||||
qtyCount = (int) Math.ceil(((ServerConstants.PET_AUTOHP_RATIO * maxHp) - curHp) / incHp);
|
||||
}
|
||||
|
||||
if (hasMpGain) {
|
||||
qtyCount = Math.max(qtyCount, (int) Math.ceil(((ServerConstants.PET_AUTOMP_RATIO * maxMp) - curMp) / incMp));
|
||||
if (ServerConstants.USE_COMPULSORY_AUTOPOT) {
|
||||
if (hasHpGain) {
|
||||
qtyCount = (int) Math.ceil(((ServerConstants.PET_AUTOHP_RATIO * maxHp) - curHp) / incHp);
|
||||
}
|
||||
|
||||
if (hasMpGain) {
|
||||
qtyCount = Math.max(qtyCount, (int) Math.ceil(((ServerConstants.PET_AUTOMP_RATIO * maxMp) - curMp) / incMp));
|
||||
}
|
||||
} else {
|
||||
qtyCount = 1; // non-compulsory autopot concept thanks to marcuswoon
|
||||
}
|
||||
|
||||
while (true) {
|
||||
|
||||
@@ -81,7 +81,25 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
final int cid = slea.readInt();
|
||||
final Server server = Server.getInstance();
|
||||
MapleCharacter player = c.getWorldServer().getPlayerStorage().getCharacterById(cid);
|
||||
|
||||
World wserv = server.getWorld(c.getWorld());
|
||||
if(wserv == null) {
|
||||
c.disconnect(true, false);
|
||||
return;
|
||||
}
|
||||
|
||||
Channel cserv = wserv.getChannel(c.getChannel());
|
||||
if(cserv == null) {
|
||||
c.setChannel(1);
|
||||
cserv = wserv.getChannel(c.getChannel());
|
||||
|
||||
if(cserv == null) {
|
||||
c.disconnect(true, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MapleCharacter player = wserv.getPlayerStorage().getCharacterById(cid);
|
||||
boolean newcomer = false;
|
||||
|
||||
IoSession session = c.getSession();
|
||||
@@ -106,40 +124,17 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
|
||||
}
|
||||
} else {
|
||||
remoteHwid = player.getClient().getHWID();
|
||||
c.setCharacterSlots((byte) player.getClient().getCharacterSlots());
|
||||
player.newClient(c);
|
||||
}
|
||||
|
||||
if (player == null) { //If you are still getting null here then please just uninstall the game >.>, we dont need you fucking with the logs
|
||||
c.disconnect(true, false);
|
||||
return;
|
||||
}
|
||||
|
||||
int hwidLen = remoteHwid.length();
|
||||
session.setAttribute(MapleClient.CLIENT_HWID, remoteHwid);
|
||||
session.setAttribute(MapleClient.CLIENT_NIBBLEHWID, remoteHwid.substring(hwidLen - 8, hwidLen));
|
||||
c.setHWID(remoteHwid);
|
||||
|
||||
c.setPlayer(player);
|
||||
c.setAccID(player.getAccountID());
|
||||
|
||||
boolean allowLogin = true;
|
||||
|
||||
World world = server.getWorld(c.getWorld());
|
||||
if(world == null) {
|
||||
c.disconnect(true, false);
|
||||
return;
|
||||
}
|
||||
|
||||
Channel cserv = world.getChannel(c.getChannel());
|
||||
if(cserv == null) {
|
||||
c.setChannel(1);
|
||||
cserv = world.getChannel(c.getChannel());
|
||||
|
||||
if(cserv == null) {
|
||||
c.disconnect(true, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* is this check really necessary?
|
||||
if (state == MapleClient.LOGIN_SERVER_TRANSITION || state == MapleClient.LOGIN_NOTLOGGEDIN) {
|
||||
@@ -149,7 +144,7 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
|
||||
}
|
||||
|
||||
for (String charName : charNames) {
|
||||
if(c.getWorldServer().getPlayerStorage().getCharacterByName(charName) != null) {
|
||||
if(wserv.getPlayerStorage().getCharacterByName(charName) != null) {
|
||||
allowLogin = false;
|
||||
break;
|
||||
}
|
||||
@@ -160,12 +155,16 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
|
||||
c.lockClient(); // Sync this to prevent wrong login state for double channel changes
|
||||
try {
|
||||
int state = c.getLoginState();
|
||||
if (state == MapleClient.LOGIN_LOGGEDIN) {
|
||||
return;
|
||||
}
|
||||
if (state != MapleClient.LOGIN_SERVER_TRANSITION || !allowLogin) {
|
||||
c.setPlayer(null);
|
||||
c.announce(MaplePacketCreator.getAfterLoginError(7));
|
||||
c.setAccID(0);
|
||||
|
||||
if (state == MapleClient.LOGIN_LOGGEDIN) {
|
||||
c.disconnect(true, false);
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.getAfterLoginError(7));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
c.updateLoginState(MapleClient.LOGIN_LOGGEDIN);
|
||||
@@ -173,8 +172,18 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
|
||||
c.unlockClient();
|
||||
}
|
||||
|
||||
if (!newcomer) {
|
||||
c.setCharacterSlots((byte) player.getClient().getCharacterSlots());
|
||||
player.newClient(c);
|
||||
}
|
||||
|
||||
int hwidLen = remoteHwid.length();
|
||||
session.setAttribute(MapleClient.CLIENT_HWID, remoteHwid);
|
||||
session.setAttribute(MapleClient.CLIENT_NIBBLEHWID, remoteHwid.substring(hwidLen - 8, hwidLen));
|
||||
c.setHWID(remoteHwid);
|
||||
|
||||
cserv.addPlayer(player);
|
||||
world.addPlayer(player);
|
||||
wserv.addPlayer(player);
|
||||
player.setEnteredChannelWorld();
|
||||
|
||||
List<PlayerBuffValueHolder> buffs = server.getPlayerBuffStorage().getBuffsFromStorage(cid);
|
||||
@@ -209,8 +218,8 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
BuddyList bl = player.getBuddylist();
|
||||
int buddyIds[] = bl.getBuddyIds();
|
||||
world.loggedOn(player.getName(), player.getId(), c.getChannel(), buddyIds);
|
||||
for (CharacterIdChannelPair onlineBuddy : world.multiBuddyFind(player.getId(), buddyIds)) {
|
||||
wserv.loggedOn(player.getName(), player.getId(), c.getChannel(), buddyIds);
|
||||
for (CharacterIdChannelPair onlineBuddy : wserv.multiBuddyFind(player.getId(), buddyIds)) {
|
||||
BuddylistEntry ble = bl.get(onlineBuddy.getCharacterId());
|
||||
ble.setChannel(onlineBuddy.getChannel());
|
||||
bl.put(ble);
|
||||
@@ -219,10 +228,10 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
c.announce(MaplePacketCreator.loadFamily(player));
|
||||
if (player.getFamilyId() > 0) {
|
||||
MapleFamily f = world.getFamily(player.getFamilyId());
|
||||
MapleFamily f = wserv.getFamily(player.getFamilyId());
|
||||
if (f == null) {
|
||||
f = new MapleFamily(player.getId());
|
||||
world.addFamily(player.getFamilyId(), f);
|
||||
wserv.addFamily(player.getFamilyId(), f);
|
||||
}
|
||||
player.setFamily(f);
|
||||
c.announce(MaplePacketCreator.getFamilyInfo(f.getMember(player.getId())));
|
||||
@@ -271,7 +280,7 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
|
||||
pchar.setChannel(c.getChannel());
|
||||
pchar.setMapId(player.getMapId());
|
||||
pchar.setOnline(true);
|
||||
world.updateParty(player.getParty().getId(), PartyOperation.LOG_ONOFF, pchar);
|
||||
wserv.updateParty(player.getParty().getId(), PartyOperation.LOG_ONOFF, pchar);
|
||||
player.updatePartyMemberHP();
|
||||
}
|
||||
|
||||
@@ -292,22 +301,20 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
|
||||
c.announce(MaplePacketCreator.requestBuddylistAdd(pendingBuddyRequest.getId(), c.getPlayer().getId(), pendingBuddyRequest.getName()));
|
||||
}
|
||||
|
||||
if (newcomer) {
|
||||
for(MaplePet pet : player.getPets()) {
|
||||
if(pet != null)
|
||||
world.registerPetHunger(player, player.getPetIndex(pet));
|
||||
}
|
||||
|
||||
player.reloadQuestExpirations();
|
||||
}
|
||||
|
||||
c.announce(MaplePacketCreator.updateGender(player));
|
||||
player.checkMessenger();
|
||||
c.announce(MaplePacketCreator.enableReport());
|
||||
player.changeSkillLevel(SkillFactory.getSkill(10000000 * player.getJobType() + 12), (byte) (player.getLinkedLevel() / 10), 20, -1);
|
||||
player.checkBerserk(player.isHidden());
|
||||
|
||||
if (newcomer){
|
||||
if (newcomer) {
|
||||
for(MaplePet pet : player.getPets()) {
|
||||
if(pet != null)
|
||||
wserv.registerPetHunger(player, player.getPetIndex(pet));
|
||||
}
|
||||
|
||||
player.reloadQuestExpirations();
|
||||
|
||||
/*
|
||||
if (!c.hasVotedAlready()){
|
||||
player.announce(MaplePacketCreator.earnTitleMessage("You can vote now! Vote and earn a vote point!"));
|
||||
@@ -354,7 +361,7 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
if(player.getPartnerId() > 0) {
|
||||
int partnerId = player.getPartnerId();
|
||||
final MapleCharacter partner = c.getWorldServer().getPlayerStorage().getCharacterById(partnerId);
|
||||
final MapleCharacter partner = wserv.getPlayerStorage().getCharacterById(partnerId);
|
||||
|
||||
if(partner != null && !partner.isAwayFromWorld()) {
|
||||
player.announce(Wedding.OnNotifyWeddingPartnerTransfer(partnerId, partner.getMapId()));
|
||||
|
||||
@@ -79,7 +79,7 @@ public final class ScrollHandler extends AbstractMaplePacketHandler {
|
||||
c.announce(MaplePacketCreator.getInventoryFull());
|
||||
return;
|
||||
}
|
||||
} else if (((Equip) toScroll).getUpgradeSlots() < 1) {
|
||||
} else if (!ItemConstants.isModifierScroll(scroll.getItemId()) && ((Equip) toScroll).getUpgradeSlots() < 1) {
|
||||
c.announce(MaplePacketCreator.getInventoryFull());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import client.creator.veteran.*;
|
||||
import client.inventory.Equip;
|
||||
import client.inventory.Equip.ScrollResult;
|
||||
import client.inventory.Item;
|
||||
import client.inventory.MapleInventory;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import client.inventory.MaplePet;
|
||||
import client.inventory.ModifyInventory;
|
||||
@@ -75,24 +76,38 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
||||
player.setLastUsedCashItem(timeNow);
|
||||
|
||||
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
slea.readShort();
|
||||
short position = slea.readShort();
|
||||
int itemId = slea.readInt();
|
||||
int itemType = itemId / 10000;
|
||||
Item toUse = player.getInventory(MapleInventoryType.CASH).getItem(player.getInventory(MapleInventoryType.CASH).findById(itemId).getPosition());
|
||||
|
||||
MapleInventory cashInv = player.getInventory(MapleInventoryType.CASH);
|
||||
Item toUse = cashInv.getItem(position);
|
||||
if (toUse == null || toUse.getItemId() != itemId) {
|
||||
toUse = cashInv.findById(itemId);
|
||||
|
||||
if (toUse == null) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
position = toUse.getPosition();
|
||||
}
|
||||
|
||||
if (toUse.getQuantity() < 1) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
String medal = "";
|
||||
Item medalItem = player.getInventory(MapleInventoryType.EQUIPPED).getItem((short) -49);
|
||||
if (medalItem != null) {
|
||||
medal = "<" + ii.getName(medalItem.getItemId()) + "> ";
|
||||
}
|
||||
if (toUse == null || toUse.getItemId() != itemId || toUse.getQuantity() < 1) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
if (itemType == 504) { // vip teleport rock
|
||||
String error1 = "Either the player could not be found or you were trying to teleport to an illegal location.";
|
||||
boolean vip = slea.readByte() == 1;
|
||||
remove(c, itemId);
|
||||
remove(c, position, itemId);
|
||||
if (!vip) {
|
||||
int mapId = slea.readInt();
|
||||
if (c.getChannelServer().getMapFactory().getMap(mapId).getForcedReturnId() == 999999999) {
|
||||
@@ -155,7 +170,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
||||
return;
|
||||
}
|
||||
}
|
||||
remove(c, itemId);
|
||||
remove(c, position, itemId);
|
||||
} else if (itemType == 506) {
|
||||
Item eq = null;
|
||||
if (itemId == 5060000) { // Item tag.
|
||||
@@ -193,7 +208,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
||||
eq.setExpiration(currentServerTime() + (period * 60 * 60 * 24 * 1000));
|
||||
}
|
||||
|
||||
remove(c, itemId);
|
||||
remove(c, position, itemId);
|
||||
} else if (itemId == 5060002) { // Incubator
|
||||
byte inventory2 = (byte) slea.readInt();
|
||||
short slot2 = (short) slea.readInt();
|
||||
@@ -204,14 +219,14 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
||||
}
|
||||
if (getIncubatedItem(c, itemId)) {
|
||||
MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.getByType(inventory2), slot2, (short) 1, false);
|
||||
remove(c, itemId);
|
||||
remove(c, position, itemId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
slea.readInt(); // time stamp
|
||||
if (eq != null) {
|
||||
player.forceUpdateItem(eq);
|
||||
remove(c, itemId);
|
||||
remove(c, position, itemId);
|
||||
}
|
||||
} else if (itemType == 507) {
|
||||
boolean whisper;
|
||||
@@ -298,13 +313,13 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
||||
Server.getInstance().broadcastMessage(c.getWorld(), MaplePacketCreator.getMultiMegaphone(msg2, c.getChannel(), whisper));
|
||||
break;
|
||||
}
|
||||
remove(c, itemId);
|
||||
remove(c, position, itemId);
|
||||
} else if (itemType == 508) { // graduation banner, thanks to tmskdl12. Also, thanks ratency for first pointing lack of Kite handling
|
||||
MapleKite kite = new MapleKite(player, slea.readMapleAsciiString(), itemId);
|
||||
|
||||
if (!GameConstants.isFreeMarketRoom(player.getMapId())) {
|
||||
player.getMap().spawnKite(kite);
|
||||
remove(c, itemId);
|
||||
remove(c, position, itemId);
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.sendCannotSpawnKite());
|
||||
}
|
||||
@@ -316,10 +331,10 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
remove(c, itemId);
|
||||
remove(c, position, itemId);
|
||||
} else if (itemType == 510) {
|
||||
player.getMap().broadcastMessage(MaplePacketCreator.musicChange("Jukebox/Congratulation"));
|
||||
remove(c, itemId);
|
||||
remove(c, position, itemId);
|
||||
} else if (itemType == 512) {
|
||||
if (ii.getStateChangeItem(itemId) != 0) {
|
||||
for (MapleCharacter mChar : player.getMap().getCharacters()) {
|
||||
@@ -327,7 +342,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
||||
}
|
||||
}
|
||||
player.getMap().startMapEffect(ii.getMsg(itemId).replaceFirst("%s", player.getName()).replaceFirst("%s", slea.readMapleAsciiString()), itemId);
|
||||
remove(c, itemId);
|
||||
remove(c, position, itemId);
|
||||
} else if (itemType == 517) {
|
||||
MaplePet pet = player.getPet(0);
|
||||
if (pet == null) {
|
||||
@@ -344,10 +359,10 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
player.getMap().broadcastMessage(player, MaplePacketCreator.changePetName(player, newName, 1), true);
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
remove(c, itemId);
|
||||
remove(c, position, itemId);
|
||||
} else if (itemType == 520) {
|
||||
player.gainMeso(ii.getMeso(itemId), true, false, true);
|
||||
remove(c, itemId);
|
||||
remove(c, position, itemId);
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
} else if (itemType == 523) {
|
||||
int itemid = slea.readInt();
|
||||
@@ -355,7 +370,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
||||
if(!ServerConstants.USE_ENFORCE_ITEM_SUGGESTION) c.getWorldServer().addOwlItemSearch(itemid);
|
||||
player.setOwlSearch(itemid);
|
||||
List<Pair<MaplePlayerShopItem, AbstractMapleMapObject>> hmsAvailable = c.getWorldServer().getAvailableItemBundles(itemid);
|
||||
if(!hmsAvailable.isEmpty()) remove(c, itemId);
|
||||
if(!hmsAvailable.isEmpty()) remove(c, position, itemId);
|
||||
|
||||
c.announce(MaplePacketCreator.owlOfMinerva(c, itemid, hmsAvailable));
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
@@ -368,7 +383,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
if (p.getRight()) {
|
||||
pet.gainClosenessFullness(player, p.getLeft(), 100, 1);
|
||||
remove(c, itemId);
|
||||
remove(c, position, itemId);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@@ -378,7 +393,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
} else if (itemType == 530) {
|
||||
ii.getItemEffect(itemId).applyTo(player);
|
||||
remove(c, itemId);
|
||||
remove(c, position, itemId);
|
||||
} else if (itemType == 533) {
|
||||
NPCScriptManager.getInstance().start(c, 9010009, null);
|
||||
} else if (itemType == 537) {
|
||||
@@ -399,7 +414,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
||||
Server.getInstance().broadcastMessage(world, MaplePacketCreator.byeAvatarMega());
|
||||
}
|
||||
}, 1000 * 10);
|
||||
remove(c, itemId);
|
||||
remove(c, position, itemId);
|
||||
} else if (itemType == 543) {
|
||||
if(itemId == 5432000 && !c.gainCharacterSlot()) {
|
||||
player.dropMessage(1, "You have already used up all 12 extra character slots.");
|
||||
@@ -442,7 +457,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
||||
c.announce(MaplePacketCreator.sendMapleLifeError(0)); // success!
|
||||
|
||||
player.showHint("#bSuccess#k on creation of the new character through the Maple Life card.");
|
||||
remove(c, itemId);
|
||||
remove(c, position, itemId);
|
||||
} else {
|
||||
if(createStatus == -1) { // check name
|
||||
c.announce(MaplePacketCreator.sendMapleLifeNameError());
|
||||
@@ -455,7 +470,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
||||
MapleShop shop = MapleShopFactory.getInstance().getShop(1338);
|
||||
if (shop != null) {
|
||||
shop.sendShop(c);
|
||||
remove(c, itemId);
|
||||
remove(c, position, itemId);
|
||||
}
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
@@ -470,10 +485,10 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
MapleKarmaManipulator.setKarmaFlag(item);
|
||||
player.forceUpdateItem(item);
|
||||
remove(c, itemId);
|
||||
remove(c, position, itemId);
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
} else if (itemType == 552) { //DS EGG THING
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
@@ -487,7 +502,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
||||
}
|
||||
equip.setVicious(equip.getVicious() + 1);
|
||||
equip.setUpgradeSlots(equip.getUpgradeSlots() + 1);
|
||||
remove(c, itemId);
|
||||
remove(c, position, itemId);
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
c.announce(MaplePacketCreator.sendHammerData(equip.getVicious()));
|
||||
player.forceUpdateItem(equip);
|
||||
@@ -528,7 +543,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
||||
//opcodes 0x42, 0x44: "this item cannot be used"; 0x39, 0x45: crashes
|
||||
|
||||
MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.USE, uSlot, (short) 1, false);
|
||||
remove(c, itemId);
|
||||
remove(c, position, itemId);
|
||||
|
||||
final MapleClient client = c;
|
||||
TimerManager.getInstance().schedule(new Runnable() {
|
||||
@@ -558,8 +573,22 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private static void remove(MapleClient c, int itemId) {
|
||||
MapleInventoryManipulator.removeById(c, MapleInventoryType.CASH, itemId, 1, true, false);
|
||||
private static void remove(MapleClient c, short position, int itemid) {
|
||||
MapleInventory cashInv = c.getPlayer().getInventory(MapleInventoryType.CASH);
|
||||
cashInv.lockInventory();
|
||||
try {
|
||||
Item it = cashInv.getItem(position);
|
||||
if (it == null || it.getItemId() != itemid) {
|
||||
it = cashInv.findById(itemid);
|
||||
if (it != null) {
|
||||
position = it.getPosition();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
cashInv.unlockInventory();
|
||||
}
|
||||
|
||||
MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.CASH, position, (short) 1, true, false);
|
||||
}
|
||||
|
||||
private static boolean getIncubatedItem(MapleClient c, int id) {
|
||||
|
||||
@@ -128,17 +128,18 @@ public final class WhisperHandler extends AbstractMaplePacketHandler {
|
||||
c.announce(MaplePacketCreator.getWhisperReply(recipient, (byte) 0));
|
||||
}
|
||||
} else if (mode == 0x44) {
|
||||
//Buddy find
|
||||
//Buddy find, thanks to Atoot
|
||||
|
||||
String recipient = slea.readMapleAsciiString();
|
||||
MapleCharacter player = c.getWorldServer().getPlayerStorage().getCharacterByName(recipient);
|
||||
if (player != null && c.getPlayer().gmLevel() >= player.gmLevel()) {
|
||||
if (player.getCashShop().isOpened()) { // in CashShop
|
||||
c.getSession().write(MaplePacketCreator.getFindReplyWithCS(recipient));
|
||||
c.getSession().write(MaplePacketCreator.getFindReplyWithCS(recipient));
|
||||
} else if (player.isAwayFromWorld()) { // in MTS
|
||||
c.getSession().write(MaplePacketCreator.getFindReplyWithMTS(recipient));
|
||||
c.getSession().write(MaplePacketCreator.getFindReplyWithMTS(recipient));
|
||||
} else {
|
||||
c.getSession().write(MaplePacketCreator.getFindReplyWithMap(player.getName(), player.getMap().getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
*/
|
||||
public class World {
|
||||
|
||||
private int id, flag, exprate, droprate, mesorate, questrate, travelrate;
|
||||
private int id, flag, exprate, droprate, bossdroprate, mesorate, questrate, travelrate;
|
||||
private String eventmsg;
|
||||
private List<Channel> channels = new ArrayList<>();
|
||||
private Map<Integer, Byte> pnpcStep = new HashMap<>();
|
||||
@@ -158,12 +158,13 @@ public class World {
|
||||
private ScheduledFuture<?> charactersSchedule;
|
||||
private ScheduledFuture<?> marriagesSchedule;
|
||||
|
||||
public World(int world, int flag, String eventmsg, int exprate, int droprate, int mesorate, int questrate, int travelrate) {
|
||||
public World(int world, int flag, String eventmsg, int exprate, int droprate, int bossdroprate, int mesorate, int questrate, int travelrate) {
|
||||
this.id = world;
|
||||
this.flag = flag;
|
||||
this.eventmsg = eventmsg;
|
||||
this.exprate = exprate;
|
||||
this.droprate = droprate;
|
||||
this.bossdroprate = bossdroprate;
|
||||
this.mesorate = mesorate;
|
||||
this.questrate = questrate;
|
||||
this.travelrate = travelrate;
|
||||
@@ -322,6 +323,14 @@ public class World {
|
||||
chr.setWorldRates();
|
||||
}
|
||||
}
|
||||
|
||||
public int getBossDropRate() { // boss rate concept thanks to Lapeiro
|
||||
return bossdroprate;
|
||||
}
|
||||
|
||||
public void setBossDropRate(int bossdrop) {
|
||||
bossdroprate = bossdrop;
|
||||
}
|
||||
|
||||
public int getMesoRate() {
|
||||
return mesorate;
|
||||
|
||||
@@ -602,7 +602,6 @@ public class EventInstanceManager {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
mapFactory.dispose();
|
||||
ess.dispose();
|
||||
|
||||
wL.lock();
|
||||
@@ -610,7 +609,6 @@ public class EventInstanceManager {
|
||||
for(MapleCharacter chr: chars.values()) chr.setEventInstance(null);
|
||||
chars.clear();
|
||||
mobs.clear();
|
||||
mapFactory = null;
|
||||
ess = null;
|
||||
} finally {
|
||||
wL.unlock();
|
||||
@@ -635,7 +633,20 @@ public class EventInstanceManager {
|
||||
sL.unlock();
|
||||
}
|
||||
|
||||
disposeLocks();
|
||||
TimerManager.getInstance().schedule(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mapFactory.dispose(); // reactors issue on dispose event maps found thanks to MedicOP
|
||||
wL.lock();
|
||||
try {
|
||||
mapFactory = null;
|
||||
} finally {
|
||||
wL.unlock();
|
||||
}
|
||||
|
||||
disposeLocks();
|
||||
}
|
||||
}, 60 * 1000);
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
|
||||
@@ -993,13 +993,13 @@ public class MapleItemInformationProvider {
|
||||
break;
|
||||
}
|
||||
if (!ItemConstants.isCleanSlate(scrollId)) {
|
||||
if (!assertGM) {
|
||||
if (!assertGM && !ItemConstants.isModifierScroll(scrollId)) { // issue with modifier scrolls taking slots found thanks to Masterrulax, justin, BakaKnyx
|
||||
nEquip.setUpgradeSlots((byte) (nEquip.getUpgradeSlots() - 1));
|
||||
}
|
||||
nEquip.setLevel((byte) (nEquip.getLevel() + 1));
|
||||
}
|
||||
} else {
|
||||
if (!ServerConstants.USE_PERFECT_SCROLLING && !usingWhiteScroll && !ItemConstants.isCleanSlate(scrollId) && !assertGM) {
|
||||
if (!ServerConstants.USE_PERFECT_SCROLLING && !usingWhiteScroll && !ItemConstants.isCleanSlate(scrollId) && !assertGM && !ItemConstants.isModifierScroll(scrollId)) {
|
||||
nEquip.setUpgradeSlots((byte) (nEquip.getUpgradeSlots() - 1));
|
||||
}
|
||||
if (Randomizer.nextInt(100) < stats.get("cursed")) {
|
||||
@@ -2055,7 +2055,7 @@ public class MapleItemInformationProvider {
|
||||
ps.setInt(1, itemId);
|
||||
ResultSet rs = ps.executeQuery();
|
||||
while(rs.next()) {
|
||||
String resultName = MapleMonsterInformationProvider.getMobNameFromId(rs.getInt("dropperid"));
|
||||
String resultName = MapleMonsterInformationProvider.getInstance().getMobNameFromId(rs.getInt("dropperid"));
|
||||
if (resultName != null) {
|
||||
list.add(resultName);
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public enum MapleExpeditionType {
|
||||
CHAOS_ZAKUM(6, 30, 120, 255, 5),
|
||||
CHAOS_HORNTAIL(6, 30, 120, 255, 5),
|
||||
PINKBEAN(6, 30, 120, 255, 5),
|
||||
CWKPQ(6, 30, 100, 255, 5);
|
||||
CWKPQ(6, 30, 90, 255, 5); // CWKPQ min-level 90, found thanks to Cato
|
||||
|
||||
private int minSize;
|
||||
private int maxSize;
|
||||
|
||||
@@ -63,6 +63,9 @@ public class MapleMonsterInformationProvider {
|
||||
private final Map<MobSkill, Integer> mobSkillAnimationTime = new HashMap<>();
|
||||
|
||||
private final Map<Integer, Pair<Integer, Integer>> mobAttackInfo = new HashMap<>();
|
||||
|
||||
private final Map<Integer, Boolean> mobBossCache = new HashMap<>();
|
||||
private final Map<Integer, String> mobNameCache = new HashMap<>();
|
||||
|
||||
protected MapleMonsterInformationProvider() {
|
||||
retrieveGlobal();
|
||||
@@ -275,38 +278,48 @@ public class MapleMonsterInformationProvider {
|
||||
return retMobs;
|
||||
}
|
||||
|
||||
public static String getMobNameFromId(int id) {
|
||||
try
|
||||
{
|
||||
return MapleLifeFactory.getMonster(id).getName();
|
||||
}
|
||||
catch (NullPointerException npe)
|
||||
{
|
||||
return null; //nonexistant mob
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
System.err.println("Nonexistant mob id " + id);
|
||||
return null; //nonexistant mob
|
||||
}
|
||||
public boolean isBoss(int id) {
|
||||
Boolean boss = mobBossCache.get(id);
|
||||
if (boss == null) {
|
||||
try {
|
||||
boss = MapleLifeFactory.getMonster(id).isBoss();
|
||||
} catch (NullPointerException npe) {
|
||||
boss = false;
|
||||
} catch (Exception e) { //nonexistant mob
|
||||
boss = false;
|
||||
|
||||
e.printStackTrace();
|
||||
System.err.println("Nonexistant mob id " + id);
|
||||
}
|
||||
|
||||
mobBossCache.put(id, boss);
|
||||
}
|
||||
|
||||
return boss;
|
||||
}
|
||||
|
||||
public static String getMobNameFromID(int id) {
|
||||
try
|
||||
{
|
||||
return MapleLifeFactory.getMonster(id).getName();
|
||||
}
|
||||
catch (NullPointerException npe)
|
||||
{
|
||||
return null; //nonexistant mob
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
System.err.println("Nonexistant mob id " + id);
|
||||
return null; //nonexistant mob
|
||||
}
|
||||
public String getMobNameFromId(int id) {
|
||||
String mobName = mobNameCache.get(id);
|
||||
if (mobName == null) {
|
||||
try
|
||||
{
|
||||
mobName = MapleLifeFactory.getMonster(id).getName();
|
||||
}
|
||||
catch (NullPointerException npe)
|
||||
{
|
||||
mobName = ""; //nonexistant mob
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
System.err.println("Nonexistant mob id " + id);
|
||||
mobName = ""; //nonexistant mob
|
||||
}
|
||||
|
||||
mobNameCache.put(id, mobName);
|
||||
}
|
||||
|
||||
return mobName;
|
||||
}
|
||||
|
||||
public final void clearDrops() {
|
||||
|
||||
@@ -697,7 +697,7 @@ public class MapleMap {
|
||||
|
||||
final byte droptype = (byte) (mob.getStats().isExplosiveReward() ? 3 : mob.getStats().isFfaLoot() ? 2 : chr.getParty() != null ? 1 : 0);
|
||||
final int mobpos = mob.getPosition().x;
|
||||
int chRate = chr.getDropRate();
|
||||
int chRate = !mob.isBoss() ? chr.getDropRate() : chr.getBossDropRate();
|
||||
byte d = 1;
|
||||
Point pos = new Point(0, mob.getPosition().y);
|
||||
|
||||
@@ -1681,7 +1681,7 @@ public class MapleMap {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void destroyNPC(int npcid) {
|
||||
public void destroyNPC(int npcid) { // assumption: there's at most one of the same NPC in a map.
|
||||
List<MapleMapObject> npcs = getMapObjectsInRange(new Point(0, 0), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.NPC));
|
||||
|
||||
chrRLock.lock();
|
||||
@@ -1893,12 +1893,24 @@ public class MapleMap {
|
||||
}
|
||||
}
|
||||
|
||||
private List<SpawnPoint> getMonsterSpawn() {
|
||||
synchronized (monsterSpawn) {
|
||||
return new ArrayList<>(monsterSpawn);
|
||||
}
|
||||
}
|
||||
|
||||
private List<SpawnPoint> getAllMonsterSpawn() {
|
||||
synchronized (allMonsterSpawn) {
|
||||
return new ArrayList<>(allMonsterSpawn);
|
||||
}
|
||||
}
|
||||
|
||||
public void spawnAllMonsterIdFromMapSpawnList(int id) {
|
||||
spawnAllMonsterIdFromMapSpawnList(id, 1, false);
|
||||
}
|
||||
|
||||
public void spawnAllMonsterIdFromMapSpawnList(int id, int difficulty, boolean isPq) {
|
||||
for(SpawnPoint sp: allMonsterSpawn) {
|
||||
for(SpawnPoint sp: getAllMonsterSpawn()) {
|
||||
if(sp.getMonsterId() == id) {
|
||||
spawnMonster(sp.getMonster(), difficulty, isPq);
|
||||
}
|
||||
@@ -1910,7 +1922,7 @@ public class MapleMap {
|
||||
}
|
||||
|
||||
public void spawnAllMonstersFromMapSpawnList(int difficulty, boolean isPq) {
|
||||
for(SpawnPoint sp: allMonsterSpawn) {
|
||||
for(SpawnPoint sp: getAllMonsterSpawn()) {
|
||||
spawnMonster(sp.getMonster(), difficulty, isPq);
|
||||
}
|
||||
}
|
||||
@@ -2481,10 +2493,6 @@ public class MapleMap {
|
||||
}
|
||||
}
|
||||
}, travelTime);
|
||||
} else if (mapid == 103040400) {
|
||||
if (chr.getEventInstance() != null) {
|
||||
chr.getEventInstance().movePlayer(chr);
|
||||
}
|
||||
} else if (MapleMiniDungeonInfo.isDungeonMap(mapid)) {
|
||||
MapleMiniDungeon mmd = chr.getClient().getChannelServer().getMiniDungeon(mapid);
|
||||
if(mmd != null) mmd.registerPlayer(chr);
|
||||
@@ -3053,9 +3061,55 @@ public class MapleMap {
|
||||
allMonsterSpawn.add(sp);
|
||||
}
|
||||
|
||||
public void removeMonsterSpawn(int mobId, int x, int y) {
|
||||
// assumption: spawn points are identified by tuple (lifeid, x, y)
|
||||
|
||||
Point checkpos = calcPointBelow(new Point(x, y));
|
||||
checkpos.y -= 1;
|
||||
|
||||
List<SpawnPoint> toRemove = new LinkedList<>();
|
||||
for(SpawnPoint sp: getMonsterSpawn()) {
|
||||
Point pos = sp.getPosition();
|
||||
if (sp.getMonsterId() == mobId && checkpos.equals(pos)) {
|
||||
toRemove.add(sp);
|
||||
}
|
||||
}
|
||||
|
||||
if (!toRemove.isEmpty()) {
|
||||
synchronized (monsterSpawn) {
|
||||
for (SpawnPoint sp : toRemove) {
|
||||
monsterSpawn.remove(sp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAllMonsterSpawn(int mobId, int x, int y) {
|
||||
// assumption: spawn points are identified by tuple (lifeid, x, y)
|
||||
|
||||
Point checkpos = calcPointBelow(new Point(x, y));
|
||||
checkpos.y -= 1;
|
||||
|
||||
List<SpawnPoint> toRemove = new LinkedList<>();
|
||||
for(SpawnPoint sp: getAllMonsterSpawn()) {
|
||||
Point pos = sp.getPosition();
|
||||
if (sp.getMonsterId() == mobId && checkpos.equals(pos)) {
|
||||
toRemove.add(sp);
|
||||
}
|
||||
}
|
||||
|
||||
if (!toRemove.isEmpty()) {
|
||||
synchronized (allMonsterSpawn) {
|
||||
for (SpawnPoint sp : toRemove) {
|
||||
allMonsterSpawn.remove(sp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void reportMonsterSpawnPoints(MapleCharacter chr) {
|
||||
chr.dropMessage(6, "Mob spawnpoints on map " + getId() + ", with available Mob SPs " + monsterSpawn.size() + ", used " + spawnedMonstersOnMap.get() + ":");
|
||||
for(SpawnPoint sp: allMonsterSpawn) {
|
||||
for(SpawnPoint sp: getAllMonsterSpawn()) {
|
||||
chr.dropMessage(6, " id: " + sp.getMonsterId() + " canSpawn: " + !sp.getDenySpawn() + " numSpawned: " + sp.getSpawned() + " x: " + sp.getPosition().getX() + " y: " + sp.getPosition().getY() + " time: " + sp.getMobTime() + " team: " + sp.getTeam());
|
||||
}
|
||||
}
|
||||
@@ -3399,7 +3453,7 @@ public class MapleMap {
|
||||
}
|
||||
|
||||
public void instanceMapFirstSpawn(int difficulty, boolean isPq) {
|
||||
for(SpawnPoint spawnPoint: allMonsterSpawn) {
|
||||
for(SpawnPoint spawnPoint: getAllMonsterSpawn()) {
|
||||
if(spawnPoint.getMobTime() == -1) { //just those allowed to be spawned only once
|
||||
spawnMonster(spawnPoint.getMonster());
|
||||
}
|
||||
@@ -3411,7 +3465,7 @@ public class MapleMap {
|
||||
|
||||
final int numShouldSpawn = (short) ((monsterSpawn.size() - spawnedMonstersOnMap.get()));//Fking lol'd
|
||||
if (numShouldSpawn > 0) {
|
||||
List<SpawnPoint> randomSpawn = new ArrayList<>(monsterSpawn);
|
||||
List<SpawnPoint> randomSpawn = getMonsterSpawn();
|
||||
Collections.shuffle(randomSpawn);
|
||||
int spawned = 0;
|
||||
for (SpawnPoint spawnPoint : randomSpawn) {
|
||||
@@ -3431,7 +3485,7 @@ public class MapleMap {
|
||||
|
||||
final int numShouldSpawn = (short) ((monsterSpawn.size() - spawnedMonstersOnMap.get()));//Fking lol'd
|
||||
if (numShouldSpawn > 0) {
|
||||
List<SpawnPoint> randomSpawn = new ArrayList<>(monsterSpawn);
|
||||
List<SpawnPoint> randomSpawn = getMonsterSpawn();
|
||||
Collections.shuffle(randomSpawn);
|
||||
int spawned = 0;
|
||||
for (SpawnPoint spawnPoint : randomSpawn) {
|
||||
@@ -3447,19 +3501,19 @@ public class MapleMap {
|
||||
}
|
||||
|
||||
public void closeMapSpawnPoints() {
|
||||
for (SpawnPoint spawnPoint : monsterSpawn) {
|
||||
for (SpawnPoint spawnPoint : getMonsterSpawn()) {
|
||||
spawnPoint.setDenySpawn(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void restoreMapSpawnPoints() {
|
||||
for (SpawnPoint spawnPoint : monsterSpawn) {
|
||||
for (SpawnPoint spawnPoint : getMonsterSpawn()) {
|
||||
spawnPoint.setDenySpawn(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void setAllowSpawnPointInBox(boolean allow, Rectangle box) {
|
||||
for(SpawnPoint sp: monsterSpawn) {
|
||||
for(SpawnPoint sp: getMonsterSpawn()) {
|
||||
if(box.contains(sp.getPosition())) {
|
||||
sp.setDenySpawn(!allow);
|
||||
}
|
||||
@@ -3467,7 +3521,7 @@ public class MapleMap {
|
||||
}
|
||||
|
||||
public void setAllowSpawnPointInRange(boolean allow, Point from, double rangeSq) {
|
||||
for(SpawnPoint sp: monsterSpawn) {
|
||||
for(SpawnPoint sp: getMonsterSpawn()) {
|
||||
if(from.distanceSq(sp.getPosition()) <= rangeSq) {
|
||||
sp.setDenySpawn(!allow);
|
||||
}
|
||||
@@ -3477,7 +3531,7 @@ public class MapleMap {
|
||||
public SpawnPoint findClosestSpawnpoint(Point from) {
|
||||
SpawnPoint closest = null;
|
||||
double shortestDistance = Double.POSITIVE_INFINITY;
|
||||
for (SpawnPoint sp : monsterSpawn) {
|
||||
for (SpawnPoint sp : getMonsterSpawn()) {
|
||||
double distance = sp.getPosition().distanceSq(from);
|
||||
if (distance < shortestDistance) {
|
||||
closest = sp;
|
||||
@@ -3494,7 +3548,7 @@ public class MapleMap {
|
||||
private int getNumShouldSpawn(int numPlayers) {
|
||||
/*
|
||||
System.out.println("----------------------------------");
|
||||
for (SpawnPoint spawnPoint : monsterSpawn) {
|
||||
for (SpawnPoint spawnPoint : getMonsterSpawn()) {
|
||||
System.out.println("sp " + spawnPoint.getPosition().getX() + ", " + spawnPoint.getPosition().getY() + ": " + spawnPoint.getDenySpawn());
|
||||
}
|
||||
System.out.println("try " + monsterSpawn.size() + " - " + spawnedMonstersOnMap.get());
|
||||
@@ -3526,7 +3580,7 @@ public class MapleMap {
|
||||
|
||||
int numShouldSpawn = getNumShouldSpawn(numPlayers);
|
||||
if(numShouldSpawn > 0) {
|
||||
List<SpawnPoint> randomSpawn = new ArrayList<>(monsterSpawn);
|
||||
List<SpawnPoint> randomSpawn = new ArrayList<>(getMonsterSpawn());
|
||||
Collections.shuffle(randomSpawn);
|
||||
short spawned = 0;
|
||||
for(SpawnPoint spawnPoint : randomSpawn) {
|
||||
|
||||
@@ -85,6 +85,77 @@ public class MapleMapFactory {
|
||||
return getMap(mapid);
|
||||
}
|
||||
|
||||
private void loadLifeFromWz(MapleMap map, MapleData mapData) {
|
||||
for (MapleData life : mapData.getChildByPath("life")) {
|
||||
String id = MapleDataTool.getString(life.getChildByPath("id"));
|
||||
String type = MapleDataTool.getString(life.getChildByPath("type"));
|
||||
int cy = MapleDataTool.getInt(life.getChildByPath("cy"));
|
||||
MapleData dF = life.getChildByPath("f");
|
||||
int f = (dF != null) ? MapleDataTool.getInt(dF) : 0;
|
||||
int fh = MapleDataTool.getInt(life.getChildByPath("fh"));
|
||||
int rx0 = MapleDataTool.getInt(life.getChildByPath("rx0"));
|
||||
int rx1 = MapleDataTool.getInt(life.getChildByPath("rx1"));
|
||||
int x = MapleDataTool.getInt(life.getChildByPath("x"));
|
||||
int y = MapleDataTool.getInt(life.getChildByPath("y"));
|
||||
int hide = MapleDataTool.getInt("hide", life, 0);
|
||||
int mobTime = MapleDataTool.getInt("mobTime", life, 0);
|
||||
int team = MapleDataTool.getInt("team", life, -1);
|
||||
|
||||
loadLifeRaw(map, Integer.parseInt(id), type, cy, f, fh, rx0, rx1, x, y, hide, mobTime, team);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadLifeFromDb(MapleMap map) {
|
||||
try {
|
||||
Connection con = DatabaseConnection.getConnection();
|
||||
PreparedStatement ps = con.prepareStatement("SELECT * FROM plife WHERE map = ? and world = ?");
|
||||
ps.setInt(1, map.getId());
|
||||
ps.setInt(2, map.getWorld());
|
||||
|
||||
ResultSet rs = ps.executeQuery();
|
||||
while(rs.next()) {
|
||||
int id = rs.getInt("life");
|
||||
String type = rs.getString("type");
|
||||
int cy = rs.getInt("cy");
|
||||
int f = rs.getInt("f");
|
||||
int fh = rs.getInt("fh");
|
||||
int rx0 = rs.getInt("rx0");
|
||||
int rx1 = rs.getInt("rx1");
|
||||
int x = rs.getInt("x");
|
||||
int y = rs.getInt("y");
|
||||
int hide = rs.getInt("hide");
|
||||
int mobTime = rs.getInt("mobtime");
|
||||
int team = rs.getInt("team");
|
||||
|
||||
loadLifeRaw(map, id, type, cy, f, fh, rx0, rx1, x, y, hide, mobTime, team);
|
||||
}
|
||||
|
||||
rs.close();
|
||||
ps.close();
|
||||
con.close();
|
||||
} catch (SQLException sqle) {
|
||||
sqle.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadLifeRaw(MapleMap map, int id, String type, int cy, int f, int fh, int rx0, int rx1, int x, int y, int hide, int mobTime, int team) {
|
||||
AbstractLoadedMapleLife myLife = loadLife(id, type, cy, f, fh, rx0, rx1, x, y, hide);
|
||||
if (myLife instanceof MapleMonster) {
|
||||
MapleMonster monster = (MapleMonster) myLife;
|
||||
|
||||
if (mobTime == -1) { //does not respawn, force spawn once
|
||||
map.spawnMonster(monster);
|
||||
} else {
|
||||
map.addMonsterSpawn(monster, mobTime, team);
|
||||
}
|
||||
|
||||
//should the map be reseted, use allMonsterSpawn list of monsters to spawn them again
|
||||
map.addAllMonsterSpawn(monster, mobTime, team);
|
||||
} else {
|
||||
map.addMapObject(myLife);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized MapleMap loadMapFromWz(int mapid, Integer omapid) {
|
||||
MapleMap map;
|
||||
|
||||
@@ -225,27 +296,10 @@ public class MapleMapFactory {
|
||||
}
|
||||
}
|
||||
}
|
||||
for (MapleData life : mapData.getChildByPath("life")) {
|
||||
String id = MapleDataTool.getString(life.getChildByPath("id"));
|
||||
String type = MapleDataTool.getString(life.getChildByPath("type"));
|
||||
AbstractLoadedMapleLife myLife = loadLife(life, id, type);
|
||||
if (myLife instanceof MapleMonster) {
|
||||
MapleMonster monster = (MapleMonster) myLife;
|
||||
int mobTime = MapleDataTool.getInt("mobTime", life, 0);
|
||||
int team = MapleDataTool.getInt("team", life, -1);
|
||||
if (mobTime == -1) { //does not respawn, force spawn once
|
||||
map.spawnMonster(monster);
|
||||
} else {
|
||||
map.addMonsterSpawn(monster, mobTime, team);
|
||||
}
|
||||
|
||||
//should the map be reseted, use allMonsterSpawn list of monsters to spawn them again
|
||||
map.addAllMonsterSpawn(monster, mobTime, team);
|
||||
} else {
|
||||
map.addMapObject(myLife);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
loadLifeFromWz(map, mapData);
|
||||
loadLifeFromDb(map);
|
||||
|
||||
if (mapData.getChildByPath("reactor") != null) {
|
||||
for (MapleData reactor : mapData.getChildByPath("reactor")) {
|
||||
String id = MapleDataTool.getString(reactor.getChildByPath("id"));
|
||||
@@ -333,21 +387,15 @@ public class MapleMapFactory {
|
||||
mapsRLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private AbstractLoadedMapleLife loadLife(MapleData life, String id, String type) {
|
||||
AbstractLoadedMapleLife myLife = MapleLifeFactory.getLife(Integer.parseInt(id), type);
|
||||
myLife.setCy(MapleDataTool.getInt(life.getChildByPath("cy")));
|
||||
MapleData dF = life.getChildByPath("f");
|
||||
if (dF != null) {
|
||||
myLife.setF(MapleDataTool.getInt(dF));
|
||||
}
|
||||
myLife.setFh(MapleDataTool.getInt(life.getChildByPath("fh")));
|
||||
myLife.setRx0(MapleDataTool.getInt(life.getChildByPath("rx0")));
|
||||
myLife.setRx1(MapleDataTool.getInt(life.getChildByPath("rx1")));
|
||||
int x = MapleDataTool.getInt(life.getChildByPath("x"));
|
||||
int y = MapleDataTool.getInt(life.getChildByPath("y"));
|
||||
|
||||
private AbstractLoadedMapleLife loadLife(int id, String type, int cy, int f, int fh, int rx0, int rx1, int x, int y, int hide) {
|
||||
AbstractLoadedMapleLife myLife = MapleLifeFactory.getLife(id, type);
|
||||
myLife.setCy(cy);
|
||||
myLife.setF(f);
|
||||
myLife.setFh(fh);
|
||||
myLife.setRx0(rx0);
|
||||
myLife.setRx1(rx1);
|
||||
myLife.setPosition(new Point(x, y));
|
||||
int hide = MapleDataTool.getInt("hide", life, 0);
|
||||
if (hide == 1) {
|
||||
myLife.setHide(true);
|
||||
}
|
||||
|
||||
@@ -1065,7 +1065,7 @@ public class MaplePacketCreator {
|
||||
mplew.writeShort(chr.getHp());
|
||||
mplew.writeBool(false);
|
||||
mplew.writeLong(getTime(Server.getInstance().getCurrentTime()));
|
||||
mplew.skip(8);
|
||||
mplew.skip(10);
|
||||
return mplew.getPacket();
|
||||
}
|
||||
|
||||
@@ -1082,7 +1082,7 @@ public class MaplePacketCreator {
|
||||
mplew.writeInt(spawnPosition.x); // spawn position placement thanks to Arnah (Vertisy)
|
||||
mplew.writeInt(spawnPosition.y);
|
||||
mplew.writeLong(getTime(Server.getInstance().getCurrentTime()));
|
||||
mplew.skip(8);
|
||||
mplew.skip(10);
|
||||
return mplew.getPacket();
|
||||
}
|
||||
|
||||
@@ -6066,7 +6066,7 @@ public class MaplePacketCreator {
|
||||
}
|
||||
return mplew.getPacket();
|
||||
}
|
||||
|
||||
|
||||
public static byte[] getFindReplyWithMap(String target, int mapid) {
|
||||
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
||||
mplew.writeShort(SendOpcode.WHISPER.getValue());
|
||||
@@ -6074,7 +6074,7 @@ public class MaplePacketCreator {
|
||||
mplew.writeMapleAsciiString(target);
|
||||
mplew.write(1);
|
||||
mplew.writeInt(mapid);
|
||||
mplew.write(new byte[8]);
|
||||
mplew.skip(8);
|
||||
return mplew.getPacket();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user