diff --git a/mychanges_ptbr.txt b/mychanges_ptbr.txt
index 4ea438c08f..af7c4aae9a 100644
--- a/mychanges_ptbr.txt
+++ b/mychanges_ptbr.txt
@@ -225,4 +225,8 @@ Implementa
17 Maio 2017,
Correção de bug com o item "Pet Name Tag", que não retirava o item após ser usado.
-Correção em bug de uma quest (id 3927) de Ariant que envolve uma "parede".
\ No newline at end of file
+Correção em bug de uma quest (id 3927) de Ariant que envolve uma "parede".
+
+18 - 19 Maio 2017,
+Implementação das mecânicas do Horntail (spawn e kill).
+Correção de bugs em casos onde valores de EXP ganhos excedem o limite máximo de um inteiro de 32bits.
\ No newline at end of file
diff --git a/nbproject/private/private.xml b/nbproject/private/private.xml
index ae5b7fa230..3cdb87e887 100644
--- a/nbproject/private/private.xml
+++ b/nbproject/private/private.xml
@@ -3,18 +3,24 @@
- file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/UseCashItemHandler.java
- file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/SpecialMoveHandler.java
- file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/CashOperationHandler.java
- file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/MapleStatEffect.java
- file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/constants/skills/Priest.java
- file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/PacketProcessor.java
+ file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/inventory/MaplePet.java
+ file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/partyquest/MonsterCarnival.java
+ file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/command/Commands.java
+ file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/npc/world0/2013002.js
+ file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/constants/ServerConstants.java
+ file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/life/MapleMonster.java
+ file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/tools/MaplePacketCreator.java
+ file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/event/OrbisPQ.js
+ file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/MapleServerHandler.java
+ file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/event/LudiPQ.js
+ file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/ScrollHandler.java
+ file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/ItemRewardHandler.java
file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/GeneralChatHandler.java
- file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/scripting/AbstractPlayerInteraction.java
- file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/MapleBuffStat.java
- file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/PetFoodHandler.java
+ file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/MapleInventoryManipulator.java
file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/MapleCharacter.java
- file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/CashShop.java
+ file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/maps/MapleMap.java
+ file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/PetLootHandler.java
+ file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/ItemPickupHandler.java
diff --git a/src/client/MapleCharacter.java b/src/client/MapleCharacter.java
index b7f7db9c04..f2fc599687 100644
--- a/src/client/MapleCharacter.java
+++ b/src/client/MapleCharacter.java
@@ -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));
}
diff --git a/src/client/command/Commands.java b/src/client/command/Commands.java
index 0c80212829..507afee3a9 100644
--- a/src/client/command/Commands.java
+++ b/src/client/command/Commands.java
@@ -101,8 +101,7 @@ import java.util.ArrayList;
import server.maps.FieldLimit;
public class Commands {
-
- private static HashMap gotomaps = new HashMap();
+ private static HashMap gotomaps = new HashMap();
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 ");
+ player.yellowMessage("Syntax: !go ");
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 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 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() : ""));
}
} 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 ");
@@ -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.");
diff --git a/src/server/life/MapleMonster.java b/src/server/life/MapleMonster.java
index 47be9bf154..f9798b2c80 100644
--- a/src/server/life/MapleMonster.java
+++ b/src/server/life/MapleMonster.java
@@ -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);
}
diff --git a/src/server/life/MonsterListener.java b/src/server/life/MonsterListener.java
index eaf5d78464..49e41620a8 100644
--- a/src/server/life/MonsterListener.java
+++ b/src/server/life/MonsterListener.java
@@ -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);
}
diff --git a/src/server/life/SpawnPoint.java b/src/server/life/SpawnPoint.java
index 3288dd69d8..be523cc3e0 100644
--- a/src/server/life/SpawnPoint.java
+++ b/src/server/life/SpawnPoint.java
@@ -91,6 +91,9 @@ public class SpawnPoint {
}
spawnedMonsters.decrementAndGet();
}
+
+ @Override
+ public void monsterDamaged(MapleCharacter from, int trueDmg) {}
});
if (mobTime == 0) {
nextPossibleSpawn = System.currentTimeMillis() + mobInterval;
diff --git a/src/server/maps/MapleMap.java b/src/server/maps/MapleMap.java
index 55a9b1f945..87a6a981ae 100644
--- a/src/server/maps/MapleMap.java
+++ b/src/server/maps/MapleMap.java
@@ -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);
+ }
}