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:
ronancpl
2019-01-16 14:46:28 -02:00
parent 132a4ee989
commit 0203d45901
107 changed files with 2740 additions and 473 deletions
+3 -3
View File
@@ -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() {
+73 -19
View File
@@ -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) {
+83 -35
View File
@@ -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);
}