Fixed Horntail command + minor EXP gain issue fix

Now Horntail can be spawned properly by a command. Fixed a rase case
where an extremely high value of EXP gain would cause integer overflow,
potentially crashing one's client.
This commit is contained in:
ronancpl
2017-05-19 19:11:03 -03:00
parent de22d2b3eb
commit 36c3b7dea8
8 changed files with 118 additions and 54 deletions

View File

@@ -1730,17 +1730,18 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
gain *= 0.5;
party *= 0.5;
}
int equip = (gain / 10) * pendantExp;
int total = gain + equip + party;
if(gain < 0) gain = Integer.MAX_VALUE; // integer overflow, heh.
int equip = (int)Math.min((long)((gain / 10) * pendantExp), Integer.MAX_VALUE);
long total = gain + equip + party;
if (level < getMaxLevel()) {
if ((long) this.exp.get() + (long) total > (long) Integer.MAX_VALUE) {
if ((long) this.exp.get() + total > (long) Integer.MAX_VALUE) {
int gainFirst = ExpTable.getExpNeededForLevel(level) - this.exp.get();
total -= gainFirst + 1;
this.gainExp(gainFirst + 1, party, false, inChat, white);
}
updateSingleStat(MapleStat.EXP, this.exp.addAndGet(total));
updateSingleStat(MapleStat.EXP, this.exp.addAndGet((int)Math.min(total, Integer.MAX_VALUE)));
if (show && gain != 0) {
client.announce(MaplePacketCreator.getShowExpGain(gain, equip, party, inChat, white));
}

View File

@@ -101,8 +101,7 @@ import java.util.ArrayList;
import server.maps.FieldLimit;
public class Commands {
private static HashMap<String, Integer> gotomaps = new HashMap<String, Integer>();
private static HashMap<String, Integer> gotomaps = new HashMap<String, Integer>();
private static String[] tips = {
"Please only use @gm in emergencies or to report somebody.",
@@ -612,7 +611,7 @@ public class Commands {
bar += i < percent ? "|" : ".";
}
bar += "]";
player.yellowMessage(monster.getName() + " has " + percent + "% HP left.");
player.yellowMessage(monster.getName() + " (" + monster.getId() + ") has " + percent + "% HP left.");
player.yellowMessage("HP: " + bar);
}
}
@@ -755,7 +754,7 @@ public class Commands {
player.getMap().clearDrops(player);
} else if (sub[0].equals("go")) {
if (sub.length < 2){
player.yellowMessage("Syntax: !spawn <mobid>");
player.yellowMessage("Syntax: !go <mapid>");
return false;
}
@@ -1132,7 +1131,7 @@ public class Commands {
e.printStackTrace();
}
}
} else if (sub[0].equals("killall")) {
} else if (sub[0].equals("killall")) { // will need to be used again in case of horntail or multiple state baddies
List<MapleMapObject> monsters = player.getMap().getMapObjectsInRange(player.getPosition(), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.MONSTER));
MapleMap map = player.getMap();
for (MapleMapObject monstermo : monsters) {
@@ -1147,7 +1146,7 @@ public class Commands {
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());
player.message("Monster ID: " + monster.getId() + " Aggro target: " + ((monster.getController() != null) ? monster.getController().getName() : "<none>"));
}
} else if (sub[0].equals("unbug")) {
c.getPlayer().getMap().broadcastMessage(MaplePacketCreator.enableActions());
@@ -1428,6 +1427,24 @@ public class Commands {
public static void executeAdminCommand(MapleClient c, String[] sub, char heading) {
MapleCharacter player = c.getPlayer();
switch (sub[0]) {
case "zakum":
player.getMap().spawnFakeMonsterOnGroundBelow(MapleLifeFactory.getMonster(8800000), player.getPosition());
for (int x = 8800003; x < 8800011; x++) {
player.getMap().spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(x), player.getPosition());
}
break;
case "horntail":
final Point targetPoint = player.getPosition();
final MapleMap targetMap = player.getMap();
targetMap.spawnHorntailOnGroundBelow(targetPoint);
break;
case "pinkbean":
player.getMap().spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(8820001), player.getPosition());
break;
case "sp": //Changed to support giving sp /a
if (sub.length < 2){
player.yellowMessage("Syntax: !sp <newsp>");
@@ -1443,9 +1460,7 @@ public class Commands {
victim.updateSingleStat(MapleStat.AVAILABLESP, player.getRemainingSp());
}
break;
case "horntail":
player.getMap().spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(8810026), player.getPosition());
break;
case "packet":
player.getMap().broadcastMessage(MaplePacketCreator.customPacket(joinStringFrom(sub, 1)));
break;
@@ -1613,12 +1628,6 @@ public class Commands {
player.getMap().removeMapObject(item);
}
break;
case "zakum":
player.getMap().spawnFakeMonsterOnGroundBelow(MapleLifeFactory.getMonster(8800000), player.getPosition());
for (int x = 8800003; x < 8800011; x++) {
player.getMap().spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(x), player.getPosition());
}
break;
case "clearquestcache":
MapleQuest.clearCache();
player.dropMessage(5, "Quest Cache Cleared.");

View File

@@ -210,6 +210,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
int trueDamage = Math.min(hp, damage); // since magic happens otherwise B^)
if(ServerConstants.USE_DEBUG == true && from != null) from.dropMessage(5, "Hitted MOB " + this.getId());
dispatchMonsterDamaged(from, trueDamage);
hp -= damage;
if (takenDamage.containsKey(from.getId())) {
@@ -368,16 +369,14 @@ public class MapleMonster extends AbstractLoadedMapleLife {
personalExp *= (stati.get(MonsterStatus.SHOWDOWN).getStati().get(MonsterStatus.SHOWDOWN).doubleValue() / 100.0 + 1.0);
}
}
if (exp < 0) {//O.O ><
personalExp = Integer.MAX_VALUE;
}
attacker.gainExp(personalExp, partyExp, true, false, isKiller);
attacker.mobKilled(getId());
attacker.increaseEquipExp(personalExp);//better place
}
}
public MapleCharacter killBy(MapleCharacter killer) {
public MapleCharacter killBy(final MapleCharacter killer) {
distributeExperience(killer != null ? killer.getId() : 0);
if (getController() != null) { // this can/should only happen when a hidden gm attacks the monster
@@ -424,11 +423,16 @@ public class MapleMonster extends AbstractLoadedMapleLife {
mob.disableDrops();
}
reviveMap.spawnMonster(mob);
if(mob.getId() >= 8810010 && mob.getId() <= 8810017 && reviveMap.isHorntailDefeated()) {
for(int i = 8810018; i >= 8810010; i--)
reviveMap.killMonster(reviveMap.getMonsterById(i), killer, true);
}
}
}
}, getAnimationTime("die1"));
}
else {
else { // is this even necessary?
System.out.println("[CRITICAL LOSS] toSpawn is null for " + this.getName());
}
@@ -447,6 +451,12 @@ public class MapleMonster extends AbstractLoadedMapleLife {
listener.monsterKilled(getAnimationTime("die1"));
}
}
public void dispatchMonsterDamaged(MapleCharacter from, int trueDmg) {
for (MonsterListener listener : listeners.toArray(new MonsterListener[listeners.size()])) {
listener.monsterDamaged(from, trueDmg);
}
}
// should only really be used to determine drop owner
private int getHighestDamagerId() {
@@ -992,7 +1002,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
return(1.0f);
}
private final void changeLevelByDifficulty(final int difficulty, boolean pqMob) {
private void changeLevelByDifficulty(final int difficulty, boolean pqMob) {
changeLevel((int)(this.getLevel() * getDifficultyRate(difficulty)), pqMob);
}

View File

@@ -1,6 +1,8 @@
package server.life;
import client.MapleCharacter;
public interface MonsterListener {
public void monsterKilled(int aniTime);
public void monsterDamaged(MapleCharacter from, int trueDmg);
}

View File

@@ -91,6 +91,9 @@ public class SpawnPoint {
}
spawnedMonsters.decrementAndGet();
}
@Override
public void monsterDamaged(MapleCharacter from, int trueDmg) {}
});
if (mobTime == 0) {
nextPossibleSpawn = System.currentTimeMillis() + mobInterval;

View File

@@ -77,6 +77,7 @@ import server.partyquest.MonsterCarnival;
import server.partyquest.MonsterCarnivalParty;
import server.partyquest.Pyramid;
import scripting.event.EventInstanceManager;
import server.life.MonsterListener;
import tools.FilePrinter;
import tools.MaplePacketCreator;
import tools.Pair;
@@ -611,7 +612,7 @@ public class MapleMap {
}
if (monster.getStats().selfDestruction() != null && monster.getStats().selfDestruction().getHp() > -1) {// should work ;p
if (monster.getHp() <= monster.getStats().selfDestruction().getHp()) {
killMonster(monster, chr, true, false, monster.getStats().selfDestruction().getAction());
killMonster(monster, chr, true, monster.getStats().selfDestruction().getAction());
return true;
}
}
@@ -632,20 +633,12 @@ public class MapleMap {
}
public void killMonster(final MapleMonster monster, final MapleCharacter chr, final boolean withDrops) {
killMonster(monster, chr, withDrops, false, 1);
killMonster(monster, chr, withDrops, 1);
}
public void killMonster(final MapleMonster monster, final MapleCharacter chr, final boolean withDrops, final boolean secondTime, int animation) {
if (monster.getId() == 8810018 && !secondTime) {
TimerManager.getInstance().schedule(new Runnable() {
@Override
public void run() {
killMonster(monster, chr, withDrops, true, 1);
killAllMonsters();
}
}, 3000);
return;
}
public void killMonster(final MapleMonster monster, final MapleCharacter chr, final boolean withDrops, int animation) {
if(monster == null) return;
if (chr == null) {
spawnedMonstersOnMap.decrementAndGet();
monster.setHp(0);
@@ -780,7 +773,7 @@ public class MapleMap {
continue;
}
killMonster(monster, null, false, false, 1);
killMonster(monster, null, false, 1);
}
}
@@ -792,7 +785,7 @@ public class MapleMap {
for (MapleMapObject monstermo : getMapObjectsInRange(new Point(0, 0), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.MONSTER))) {
MapleMonster monster = (MapleMonster) monstermo;
killMonster(monster, null, false, false, 1);
killMonster(monster, null, false, 1);
}
}
@@ -1174,7 +1167,7 @@ public class MapleMap {
TimerManager.getInstance().schedule(new Runnable() {
@Override
public void run() {
killMonster(monster, null, false, false, selfDestruction.getAction());
killMonster(monster, null, false, selfDestruction.getAction());
}
}, selfDestruction.removeAfter() * 1000);
}
@@ -2666,4 +2659,40 @@ public class MapleMap {
public boolean isDojoMap() {
return mapid >= 925020000 && mapid < 925040000;
}
public boolean isHorntailDefeated() { // all parts of dead horntail can be found here?
for(int i = 8810010; i <= 8810017; i++) {
if(getMonsterById(i) == null) return false;
}
return true;
}
public void spawnHorntailOnGroundBelow(final Point targetPoint) { // ayy lmao
spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(8810026), targetPoint);
TimerManager.getInstance().schedule(new Runnable() {
@Override
public void run() {
for (int x = 8810002; x <= 8810009; x++) {
spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(x), targetPoint);
}
spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(8810018), targetPoint);
final MapleMonster ht = getMonsterById(8810018);
for(int mobId = 8810002; mobId <= 8810009; mobId++) {
getMonsterById(mobId).addListener(new MonsterListener() {
@Override
public void monsterKilled(int aniTime) {}
@Override
public void monsterDamaged(MapleCharacter from, int trueDmg) {
ht.damage(from, trueDmg);
}
});
}
}
}, 5 * 1000);
}
}