HikariCP config + MaxHP/MP & EXP overhaul + Venom fix
Overhauled the HikariCP connection, now it properly tries the best to hand out a DB connection. Fixed "commands" NPC crashing out players when entering the command multiple times in a short time. Rebalanced HP/MP gain on leveling up/AP resetting. Rebalanced HP/MP loss when AP resetting to use the same amount they would be earning on levelup. Fixed EXP distribution now computing overall monster maxHP plus heal instead of flat monter maxHP, that rendered on distributions of over 100% of the raw EXP. Added concurrency protection on MapleMonster. Fixed an issue on venom skills that would let an "1 dmg" appear to the client alongside the DOT.
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
#Sun, 22 Oct 2017 15:23:02 -0200
|
#Fri, 27 Oct 2017 11:16:00 -0200
|
||||||
|
|
||||||
|
|
||||||
C\:\\Nexon\\MapleSolaxia\\MapleSolaxiaV2=
|
C\:\\Nexon\\MapleSolaxia\\MapleSolaxiaV2=
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
dist/MapleSolaxia.jar
vendored
BIN
dist/MapleSolaxia.jar
vendored
Binary file not shown.
@@ -76,6 +76,7 @@ Server potentials:
|
|||||||
* Owl of Minerva.
|
* Owl of Minerva.
|
||||||
* Pet item ignore.
|
* Pet item ignore.
|
||||||
* Autosaver (periodically saves on DB current state of every player in-game).
|
* Autosaver (periodically saves on DB current state of every player in-game).
|
||||||
|
* Fixed and randomized versions of HP/MP growth rate, regarding player job. Placeholder for HP/MP washing feature.
|
||||||
|
|
||||||
Admin/GM commands:
|
Admin/GM commands:
|
||||||
* Server commands layered by GM levels.
|
* Server commands layered by GM levels.
|
||||||
|
|||||||
@@ -603,3 +603,15 @@ Corrigido itens com ownership diferente sendo agrupados num mesmo slot, perdendo
|
|||||||
Implementado feature "Arrange Items" do MapleStorage. Ele faz os devidos agrupamentos de itens e organiza os itens do storage.
|
Implementado feature "Arrange Items" do MapleStorage. Ele faz os devidos agrupamentos de itens e organiza os itens do storage.
|
||||||
Corrigido storage mesclando itens que deveriam ser únicos (que não poderiam haver mais de um num mesmo slot, ou no inventário do jogador).
|
Corrigido storage mesclando itens que deveriam ser únicos (que não poderiam haver mais de um num mesmo slot, ou no inventário do jogador).
|
||||||
Corrigido bug onde colocar um pet equipado no Cash Inventory e voltar ao jogo causaria crash no jogador.
|
Corrigido bug onde colocar um pet equipado no Cash Inventory e voltar ao jogo causaria crash no jogador.
|
||||||
|
|
||||||
|
23 - 24 Outubro 2017,
|
||||||
|
Adicionado proteção contra acesso concorrente em módulos de MapleMonster.
|
||||||
|
Corrigido bug com Venom fazendo aparecer "dano 1" no DOT.
|
||||||
|
Corrigido sistema de EXP agora contabilizando devidamente HP curado pelo mob na distribuição do EXP.
|
||||||
|
|
||||||
|
25 Outubro 2017,
|
||||||
|
Corrigido alguns problemas com as configs de inicialização do HikariCP.
|
||||||
|
Corrigido bug com inicialização de NPC scripts podendo desconectar o jogador se instaciado múltiplas vezes.
|
||||||
|
|
||||||
|
26 Outubro 2017,
|
||||||
|
Adicionado feature de randomização dos stats ganhos de HP e MP. Stat ganho de MP leva na contabilização INT do jogador.
|
||||||
@@ -7,4 +7,4 @@ file.reference.slf4j-api-1.6.6.jar=C:\\Nexon\\MapleSolaxia\\MapleSolaxiaV2\\core
|
|||||||
file.reference.slf4j-jdk14-1.7.5.jar=C:\\Nexon\\MapleSolaxia\\MapleSolaxiaV2\\cores\\slf4j-jdk14-1.7.5.jar
|
file.reference.slf4j-jdk14-1.7.5.jar=C:\\Nexon\\MapleSolaxia\\MapleSolaxiaV2\\cores\\slf4j-jdk14-1.7.5.jar
|
||||||
javac.debug=true
|
javac.debug=true
|
||||||
javadoc.preview=true
|
javadoc.preview=true
|
||||||
user.properties.file=C:\\Users\\RonanLana\\AppData\\Roaming\\NetBeans\\8.0.2\\build.properties
|
user.properties.file=C:\\Users\\USER\\AppData\\Roaming\\NetBeans\\8.0.2\\build.properties
|
||||||
|
|||||||
@@ -2,15 +2,6 @@
|
|||||||
<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
|
<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
|
||||||
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="2"/>
|
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="2"/>
|
||||||
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
|
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
|
||||||
<group>
|
<group/>
|
||||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/PlayerLoggedinHandler.java</file>
|
|
||||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/command/Commands.java</file>
|
|
||||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/CashOperationHandler.java</file>
|
|
||||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/quest/requirements/QuestRequirement.java</file>
|
|
||||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/InventoryMergeHandler.java</file>
|
|
||||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/MapleStorage.java</file>
|
|
||||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/MapleCharacter.java</file>
|
|
||||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/MapleStorageInventory.java</file>
|
|
||||||
</group>
|
|
||||||
</open-files>
|
</open-files>
|
||||||
</project-private>
|
</project-private>
|
||||||
|
|||||||
@@ -35,6 +35,11 @@ function action(mode, type, selection) {
|
|||||||
if (mode < 0)
|
if (mode < 0)
|
||||||
cm.dispose();
|
cm.dispose();
|
||||||
else {
|
else {
|
||||||
|
if (mode == 0 && type > 0) {
|
||||||
|
cm.dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (mode == 1)
|
if (mode == 1)
|
||||||
status++;
|
status++;
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ public class ServerConstants {
|
|||||||
public static final boolean USE_MTS = false;
|
public static final boolean USE_MTS = false;
|
||||||
public static final boolean USE_FAMILY_SYSTEM = false;
|
public static final boolean USE_FAMILY_SYSTEM = false;
|
||||||
public static final boolean USE_DUEY = true;
|
public static final boolean USE_DUEY = true;
|
||||||
|
public static final boolean USE_RANDOMIZE_HPMP_GAIN = true; //Enables randomizing on MaxHP/MaxMP gains and INT accounting for the MaxMP gain.
|
||||||
public static final boolean USE_STORAGE_ITEM_SORT = true; //Enables storage "Arrange Items" feature.
|
public static final boolean USE_STORAGE_ITEM_SORT = true; //Enables storage "Arrange Items" feature.
|
||||||
public static final boolean USE_ITEM_SORT = true; //Enables inventory "Item Sort/Merge" feature.
|
public static final boolean USE_ITEM_SORT = true; //Enables inventory "Item Sort/Merge" feature.
|
||||||
public static final boolean USE_ITEM_SORT_BY_NAME = false; //Item sorting based on name rather than id.
|
public static final boolean USE_ITEM_SORT_BY_NAME = false; //Item sorting based on name rather than id.
|
||||||
@@ -49,7 +50,7 @@ public class ServerConstants {
|
|||||||
public static final boolean USE_AUTOSAVE = true; //Enables server autosaving feature (saves characters to DB each 1 hour).
|
public static final boolean USE_AUTOSAVE = true; //Enables server autosaving feature (saves characters to DB each 1 hour).
|
||||||
public static final boolean USE_SERVER_AUTOASSIGNER = true; //Server-builtin autoassigner, uses algorithm based on distributing AP accordingly with required secondary stat on equipments.
|
public static final boolean USE_SERVER_AUTOASSIGNER = true; //Server-builtin autoassigner, uses algorithm based on distributing AP accordingly with required secondary stat on equipments.
|
||||||
public static final boolean USE_REFRESH_RANK_MOVE = true;
|
public static final boolean USE_REFRESH_RANK_MOVE = true;
|
||||||
public static final boolean USE_ENFORCE_OWL_SUGGESTIONS = false;//Forces the Owl of Minerva to always display the defined item array on GameConstants.OWL_DATA instead of the featured by the players.
|
public static final boolean USE_ENFORCE_OWL_SUGGESTIONS = false;//Forces the Owl of Minerva to always display the defined item array on GameConstants.OWL_DATA instead of those featured by the players.
|
||||||
public static final boolean USE_ENFORCE_UNMERCHABLE_PET = true; //Forces players to not sell pets via merchants. (since non-named pets gets dirty name and other possible DB-related issues)
|
public static final boolean USE_ENFORCE_UNMERCHABLE_PET = true; //Forces players to not sell pets via merchants. (since non-named pets gets dirty name and other possible DB-related issues)
|
||||||
public static final boolean USE_ENFORCE_MDOOR_POSITION = true; //Forces mystic door to be spawned near spawnpoints. (since things bugs out other way, and this helps players to locate the door faster)
|
public static final boolean USE_ENFORCE_MDOOR_POSITION = true; //Forces mystic door to be spawned near spawnpoints. (since things bugs out other way, and this helps players to locate the door faster)
|
||||||
public static final boolean USE_ERASE_PERMIT_ON_OPENSHOP = true;//Forces "shop permit" item to be consumed when player deploy his/her player shop.
|
public static final boolean USE_ERASE_PERMIT_ON_OPENSHOP = true;//Forces "shop permit" item to be consumed when player deploy his/her player shop.
|
||||||
@@ -70,6 +71,8 @@ public class ServerConstants {
|
|||||||
|
|
||||||
public static final int PARTY_EXPERIENCE_MOD = 1; //Change for event stuff.
|
public static final int PARTY_EXPERIENCE_MOD = 1; //Change for event stuff.
|
||||||
|
|
||||||
|
//Miscellaneous COnfiguration
|
||||||
|
public static final byte MIN_UNDERLEVEL_FOR_EXP_GAIN = 5; //Characters are unable to get EXP from a mob if their level are under this threshold, only if "USE_UNDERLEVELED_EXP_BLOCK" is enabled.
|
||||||
public static final byte MAX_MONITORED_BUFFSTATS = 5; //Limits accounting for "dormant" buff effects, that should take place when stronger stat buffs expires.
|
public static final byte MAX_MONITORED_BUFFSTATS = 5; //Limits accounting for "dormant" buff effects, that should take place when stronger stat buffs expires.
|
||||||
public static final int MAX_AP = 32767; //Max AP allotted on the auto-assigner.
|
public static final int MAX_AP = 32767; //Max AP allotted on the auto-assigner.
|
||||||
public static final int MAX_EVENT_LEVELS = 8; //Event has different levels of rewarding system.
|
public static final int MAX_EVENT_LEVELS = 8; //Event has different levels of rewarding system.
|
||||||
|
|||||||
@@ -582,10 +582,11 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
|
|||||||
ret.speed = lea.readByte();
|
ret.speed = lea.readByte();
|
||||||
lea.skip(4);
|
lea.skip(4);
|
||||||
}
|
}
|
||||||
int calcDmgMax = 0;
|
|
||||||
|
|
||||||
// Find the base damage to base futher calculations on.
|
// Find the base damage to base futher calculations on.
|
||||||
// Several skills have their own formula in this section.
|
// Several skills have their own formula in this section.
|
||||||
|
int calcDmgMax = 0;
|
||||||
|
|
||||||
if(magic && ret.skill != 0) {
|
if(magic && ret.skill != 0) {
|
||||||
calcDmgMax = (chr.getTotalMagic() * chr.getTotalMagic() / 1000 + chr.getTotalMagic()) / 30 + chr.getTotalInt() / 200;
|
calcDmgMax = (chr.getTotalMagic() * chr.getTotalMagic() / 1000 + chr.getTotalMagic()) / 30 + chr.getTotalInt() / 200;
|
||||||
} else if(ret.skill == 4001344 || ret.skill == NightWalker.LUCKY_SEVEN || ret.skill == NightLord.TRIPLE_THROW) {
|
} else if(ret.skill == 4001344 || ret.skill == NightWalker.LUCKY_SEVEN || ret.skill == NightLord.TRIPLE_THROW) {
|
||||||
@@ -743,7 +744,7 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
|
|||||||
if(skill.getElement() != Element.NEUTRAL && chr.getBuffedValue(MapleBuffStat.ELEMENTAL_RESET) == null) {
|
if(skill.getElement() != Element.NEUTRAL && chr.getBuffedValue(MapleBuffStat.ELEMENTAL_RESET) == null) {
|
||||||
// The skill has an element effect, so we need to factor that in.
|
// The skill has an element effect, so we need to factor that in.
|
||||||
if(monster != null) {
|
if(monster != null) {
|
||||||
ElementalEffectiveness eff = monster.getEffectiveness(skill.getElement());
|
ElementalEffectiveness eff = monster.getElementalEffectiveness(skill.getElement());
|
||||||
if(eff == ElementalEffectiveness.WEAK) {
|
if(eff == ElementalEffectiveness.WEAK) {
|
||||||
calcDmgMax *= 1.5;
|
calcDmgMax *= 1.5;
|
||||||
} else if(eff == ElementalEffectiveness.STRONG) {
|
} else if(eff == ElementalEffectiveness.STRONG) {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import client.MapleJob;
|
|||||||
import client.MapleStat;
|
import client.MapleStat;
|
||||||
import client.Skill;
|
import client.Skill;
|
||||||
import client.SkillFactory;
|
import client.SkillFactory;
|
||||||
|
import constants.ServerConstants;
|
||||||
import constants.skills.BlazeWizard;
|
import constants.skills.BlazeWizard;
|
||||||
import constants.skills.Brawler;
|
import constants.skills.Brawler;
|
||||||
import constants.skills.DawnWarrior;
|
import constants.skills.DawnWarrior;
|
||||||
@@ -34,16 +35,18 @@ import constants.skills.Magician;
|
|||||||
import constants.skills.Warrior;
|
import constants.skills.Warrior;
|
||||||
import net.AbstractMaplePacketHandler;
|
import net.AbstractMaplePacketHandler;
|
||||||
import tools.MaplePacketCreator;
|
import tools.MaplePacketCreator;
|
||||||
|
import tools.Randomizer;
|
||||||
import tools.data.input.SeekableLittleEndianAccessor;
|
import tools.data.input.SeekableLittleEndianAccessor;
|
||||||
|
|
||||||
public final class DistributeAPHandler extends AbstractMaplePacketHandler {
|
public final class DistributeAPHandler extends AbstractMaplePacketHandler {
|
||||||
private static final int max = 32767;
|
private static final int max = 32767;
|
||||||
|
|
||||||
|
@Override
|
||||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||||
slea.readInt();
|
slea.readInt();
|
||||||
int num = slea.readInt();
|
int num = slea.readInt();
|
||||||
if (c.getPlayer().getRemainingAp() > 0) {
|
if (c.getPlayer().getRemainingAp() > 0) {
|
||||||
if (addStat(c, num)) {
|
if (addStat(c, num, false)) {
|
||||||
c.getPlayer().setRemainingAp(c.getPlayer().getRemainingAp() - 1);
|
c.getPlayer().setRemainingAp(c.getPlayer().getRemainingAp() - 1);
|
||||||
c.getPlayer().updateSingleStat(MapleStat.AVAILABLEAP, c.getPlayer().getRemainingAp());
|
c.getPlayer().updateSingleStat(MapleStat.AVAILABLEAP, c.getPlayer().getRemainingAp());
|
||||||
}
|
}
|
||||||
@@ -51,7 +54,7 @@ public final class DistributeAPHandler extends AbstractMaplePacketHandler {
|
|||||||
c.announce(MaplePacketCreator.enableActions());
|
c.announce(MaplePacketCreator.enableActions());
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean addStat(MapleClient c, int apTo) {
|
public static boolean addStat(MapleClient c, int apTo, boolean usedAPReset) {
|
||||||
switch (apTo) {
|
switch (apTo) {
|
||||||
case 64: // Str
|
case 64: // Str
|
||||||
if (c.getPlayer().getStr() >= max) {
|
if (c.getPlayer().getStr() >= max) {
|
||||||
@@ -90,25 +93,76 @@ public final class DistributeAPHandler extends AbstractMaplePacketHandler {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int addHP(MapleClient c) {
|
private static int addHP(MapleClient c) {
|
||||||
MapleCharacter player = c.getPlayer();
|
MapleCharacter player = c.getPlayer();
|
||||||
MapleJob job = player.getJob();
|
MapleJob job = player.getJob();
|
||||||
int MaxHP = player.getMaxHp();
|
int MaxHP = player.getMaxHp();
|
||||||
if (player.getHpMpApUsed() > 9999 || MaxHP >= 30000) {
|
if (player.getHpMpApUsed() > 9999 || MaxHP >= 30000) {
|
||||||
return MaxHP;
|
return MaxHP;
|
||||||
}
|
}
|
||||||
if (job.isA(MapleJob.WARRIOR) || job.isA(MapleJob.DAWNWARRIOR1) || job.isA(MapleJob.ARAN1)) {
|
|
||||||
|
return MaxHP + calcHpChange(player, job, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int calcHpChange(MapleCharacter player, MapleJob job, boolean usedAPReset) {
|
||||||
|
int MaxHP = 0;
|
||||||
|
|
||||||
|
if (job.isA(MapleJob.WARRIOR) || job.isA(MapleJob.DAWNWARRIOR1)) {
|
||||||
Skill increaseHP = SkillFactory.getSkill(job.isA(MapleJob.DAWNWARRIOR1) ? DawnWarrior.MAX_HP_INCREASE : Warrior.IMPROVED_MAXHP);
|
Skill increaseHP = SkillFactory.getSkill(job.isA(MapleJob.DAWNWARRIOR1) ? DawnWarrior.MAX_HP_INCREASE : Warrior.IMPROVED_MAXHP);
|
||||||
int sLvl = player.getSkillLevel(increaseHP);
|
int sLvl = player.getSkillLevel(increaseHP);
|
||||||
|
|
||||||
if(sLvl > 0)
|
if(sLvl > 0)
|
||||||
MaxHP += increaseHP.getEffect(sLvl).getY();
|
MaxHP += increaseHP.getEffect(sLvl).getY();
|
||||||
|
|
||||||
|
if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
|
||||||
|
if (usedAPReset) {
|
||||||
|
MaxHP += 18;
|
||||||
|
} else {
|
||||||
|
MaxHP += Randomizer.rand(18, 22);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
MaxHP += 20;
|
MaxHP += 20;
|
||||||
|
}
|
||||||
|
} else if(job.isA(MapleJob.ARAN1)) {
|
||||||
|
if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
|
||||||
|
if (usedAPReset) {
|
||||||
|
MaxHP += 26;
|
||||||
|
} else {
|
||||||
|
MaxHP += Randomizer.rand(26, 30);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MaxHP += 28;
|
||||||
|
}
|
||||||
} else if (job.isA(MapleJob.MAGICIAN) || job.isA(MapleJob.BLAZEWIZARD1)) {
|
} else if (job.isA(MapleJob.MAGICIAN) || job.isA(MapleJob.BLAZEWIZARD1)) {
|
||||||
|
if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
|
||||||
|
if (usedAPReset) {
|
||||||
|
MaxHP += 5;
|
||||||
|
} else {
|
||||||
|
MaxHP += Randomizer.rand(5, 9);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
MaxHP += 6;
|
MaxHP += 6;
|
||||||
} else if (job.isA(MapleJob.BOWMAN) || job.isA(MapleJob.WINDARCHER1) || job.isA(MapleJob.THIEF) || job.isA(MapleJob.NIGHTWALKER1)) {
|
}
|
||||||
|
} else if (job.isA(MapleJob.THIEF) || job.isA(MapleJob.NIGHTWALKER1)) {
|
||||||
|
if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
|
||||||
|
if (usedAPReset) {
|
||||||
|
MaxHP += 14;
|
||||||
|
} else {
|
||||||
|
MaxHP += Randomizer.rand(14, 18);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
MaxHP += 16;
|
MaxHP += 16;
|
||||||
|
}
|
||||||
|
} else if(job.isA(MapleJob.BOWMAN) || job.isA(MapleJob.WINDARCHER1)) {
|
||||||
|
if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
|
||||||
|
if (usedAPReset) {
|
||||||
|
MaxHP += 14;
|
||||||
|
} else {
|
||||||
|
MaxHP += Randomizer.rand(14, 18);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MaxHP += 16;
|
||||||
|
}
|
||||||
} else if (job.isA(MapleJob.PIRATE) || job.isA(MapleJob.THUNDERBREAKER1)) {
|
} else if (job.isA(MapleJob.PIRATE) || job.isA(MapleJob.THUNDERBREAKER1)) {
|
||||||
Skill increaseHP = SkillFactory.getSkill(Brawler.IMPROVE_MAX_HP);
|
Skill increaseHP = SkillFactory.getSkill(Brawler.IMPROVE_MAX_HP);
|
||||||
int sLvl = player.getSkillLevel(increaseHP);
|
int sLvl = player.getSkillLevel(increaseHP);
|
||||||
@@ -116,22 +170,52 @@ public final class DistributeAPHandler extends AbstractMaplePacketHandler {
|
|||||||
if(sLvl > 0)
|
if(sLvl > 0)
|
||||||
MaxHP += increaseHP.getEffect(sLvl).getY();
|
MaxHP += increaseHP.getEffect(sLvl).getY();
|
||||||
|
|
||||||
MaxHP += 18;
|
if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
|
||||||
|
if (usedAPReset) {
|
||||||
|
MaxHP += 16;
|
||||||
} else {
|
} else {
|
||||||
|
MaxHP += Randomizer.rand(16, 20);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MaxHP += 18;
|
||||||
|
}
|
||||||
|
} else if (usedAPReset) {
|
||||||
MaxHP += 8;
|
MaxHP += 8;
|
||||||
|
} else {
|
||||||
|
if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
|
||||||
|
MaxHP += Randomizer.rand(8, 12);
|
||||||
|
} else {
|
||||||
|
MaxHP += 10;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return MaxHP;
|
return MaxHP;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int addMP(MapleClient c) {
|
private static int addMP(MapleClient c) {
|
||||||
MapleCharacter player = c.getPlayer();
|
MapleCharacter player = c.getPlayer();
|
||||||
int MaxMP = player.getMaxMp();
|
int MaxMP = player.getMaxMp();
|
||||||
MapleJob job = player.getJob();
|
MapleJob job = player.getJob();
|
||||||
if (player.getHpMpApUsed() > 9999 || player.getMaxMp() >= 30000) {
|
if (player.getHpMpApUsed() > 9999 || player.getMaxMp() >= 30000) {
|
||||||
return MaxMP;
|
return MaxMP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return MaxMP + calcMpChange(player, job, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int calcMpChange(MapleCharacter player, MapleJob job, boolean usedAPReset) {
|
||||||
|
int MaxMP = 0;
|
||||||
|
|
||||||
if (job.isA(MapleJob.WARRIOR) || job.isA(MapleJob.DAWNWARRIOR1) || job.isA(MapleJob.ARAN1)) {
|
if (job.isA(MapleJob.WARRIOR) || job.isA(MapleJob.DAWNWARRIOR1) || job.isA(MapleJob.ARAN1)) {
|
||||||
MaxMP += 2;
|
if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
|
||||||
|
if(!usedAPReset) {
|
||||||
|
MaxMP += (Randomizer.rand(2, 4) + (player.getInt() / 10));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
MaxMP += (2 + (player.getInt() / 10));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MaxMP += 3;
|
||||||
|
}
|
||||||
} else if (job.isA(MapleJob.MAGICIAN) || job.isA(MapleJob.BLAZEWIZARD1)) {
|
} else if (job.isA(MapleJob.MAGICIAN) || job.isA(MapleJob.BLAZEWIZARD1)) {
|
||||||
Skill increaseMP = SkillFactory.getSkill(job.isA(MapleJob.BLAZEWIZARD1) ? BlazeWizard.INCREASING_MAX_MP : Magician.IMPROVED_MAX_MP_INCREASE);
|
Skill increaseMP = SkillFactory.getSkill(job.isA(MapleJob.BLAZEWIZARD1) ? BlazeWizard.INCREASING_MAX_MP : Magician.IMPROVED_MAX_MP_INCREASE);
|
||||||
int sLvl = player.getSkillLevel(increaseMP);
|
int sLvl = player.getSkillLevel(increaseMP);
|
||||||
@@ -139,25 +223,72 @@ public final class DistributeAPHandler extends AbstractMaplePacketHandler {
|
|||||||
if(sLvl > 0)
|
if(sLvl > 0)
|
||||||
MaxMP += increaseMP.getEffect(sLvl).getY();
|
MaxMP += increaseMP.getEffect(sLvl).getY();
|
||||||
|
|
||||||
|
if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
|
||||||
|
if(!usedAPReset) {
|
||||||
|
MaxMP += (Randomizer.rand(12, 16) + (player.getInt() / 20));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
MaxMP += (12 + (player.getInt() / 20));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
MaxMP += 18;
|
MaxMP += 18;
|
||||||
} else if (job.isA(MapleJob.BOWMAN) || job.isA(MapleJob.WINDARCHER1) || job.isA(MapleJob.THIEF) || job.isA(MapleJob.NIGHTWALKER1)) {
|
}
|
||||||
|
} else if (job.isA(MapleJob.BOWMAN) || job.isA(MapleJob.WINDARCHER1)) {
|
||||||
|
if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
|
||||||
|
if(!usedAPReset) {
|
||||||
|
MaxMP += (Randomizer.rand(6, 8) + (player.getInt() / 10));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
MaxMP += (6 + (player.getInt() / 10));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
MaxMP += 10;
|
MaxMP += 10;
|
||||||
|
}
|
||||||
|
} else if(job.isA(MapleJob.THIEF) || job.isA(MapleJob.NIGHTWALKER1)) {
|
||||||
|
if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
|
||||||
|
if(!usedAPReset) {
|
||||||
|
MaxMP += (Randomizer.rand(6, 8) + (player.getInt() / 10));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
MaxMP += (6 + (player.getInt() / 10));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MaxMP += 10;
|
||||||
|
}
|
||||||
} else if (job.isA(MapleJob.PIRATE) || job.isA(MapleJob.THUNDERBREAKER1)) {
|
} else if (job.isA(MapleJob.PIRATE) || job.isA(MapleJob.THUNDERBREAKER1)) {
|
||||||
|
if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
|
||||||
|
if(!usedAPReset) {
|
||||||
|
MaxMP += (Randomizer.rand(7, 9) + (player.getInt() / 10));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
MaxMP += (7 + (player.getInt() / 10));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
MaxMP += 14;
|
MaxMP += 14;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(ServerConstants.USE_RANDOMIZE_HPMP_GAIN) {
|
||||||
|
if(!usedAPReset) {
|
||||||
|
MaxMP += (Randomizer.rand(4, 6) + (player.getInt() / 10));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
MaxMP += (4 + (player.getInt() / 10));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
MaxMP += 6;
|
MaxMP += 6;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return MaxMP;
|
return MaxMP;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addHP(MapleCharacter player, int MaxHP) {
|
private static void addHP(MapleCharacter player, int MaxHP) {
|
||||||
MaxHP = Math.min(30000, MaxHP);
|
MaxHP = Math.min(30000, MaxHP);
|
||||||
player.setHpMpApUsed(player.getHpMpApUsed() + 1);
|
player.setHpMpApUsed(player.getHpMpApUsed() + 1);
|
||||||
player.setMaxHp(MaxHP);
|
player.setMaxHp(MaxHP);
|
||||||
player.updateSingleStat(MapleStat.MAXHP, MaxHP);
|
player.updateSingleStat(MapleStat.MAXHP, MaxHP);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addMP(MapleCharacter player, int MaxMP) {
|
private static void addMP(MapleCharacter player, int MaxMP) {
|
||||||
MaxMP = Math.min(30000, MaxMP);
|
MaxMP = Math.min(30000, MaxMP);
|
||||||
player.setHpMpApUsed(player.getHpMpApUsed() + 1);
|
player.setHpMpApUsed(player.getHpMpApUsed() + 1);
|
||||||
player.setMaxMp(MaxMP);
|
player.setMaxMp(MaxMP);
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ public final class DistributeSPHandler extends AbstractMaplePacketHandler {
|
|||||||
c.getSession().write(MaplePacketCreator.enableActions());
|
c.getSession().write(MaplePacketCreator.enableActions());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MapleCharacter player = c.getPlayer();
|
MapleCharacter player = c.getPlayer();
|
||||||
int remainingSp = player.getRemainingSpBySkill(GameConstants.getSkillBook(skillid/10000));
|
int remainingSp = player.getRemainingSpBySkill(GameConstants.getSkillBook(skillid/10000));
|
||||||
boolean isBeginnerSkill = false;
|
boolean isBeginnerSkill = false;
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
|||||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||||
final MapleCharacter player = c.getPlayer();
|
final MapleCharacter player = c.getPlayer();
|
||||||
if (System.currentTimeMillis() - player.getLastUsedCashItem() < 3000) {
|
if (System.currentTimeMillis() - player.getLastUsedCashItem() < 3000) {
|
||||||
player.dropMessage(1, "You have used a cash item recently. Wait a moment and try again.");
|
player.dropMessage(1, "You have used a cash item recently. Wait a moment, then try again.");
|
||||||
c.announce(MaplePacketCreator.enableActions());
|
c.announce(MaplePacketCreator.enableActions());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -83,6 +83,11 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (itemType == 505) { // AP/SP reset
|
if (itemType == 505) { // AP/SP reset
|
||||||
|
if(!player.isAlive()) {
|
||||||
|
c.announce(MaplePacketCreator.enableActions());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (itemId > 5050000) {
|
if (itemId > 5050000) {
|
||||||
int SPTo = slea.readInt();
|
int SPTo = slea.readInt();
|
||||||
int SPFrom = slea.readInt();
|
int SPFrom = slea.readInt();
|
||||||
@@ -101,80 +106,76 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
|||||||
switch (APFrom) {
|
switch (APFrom) {
|
||||||
case 64: // str
|
case 64: // str
|
||||||
if (player.getStr() < 5) {
|
if (player.getStr() < 5) {
|
||||||
|
c.getPlayer().message("You don't have the minimum STR required to swap.");
|
||||||
|
c.announce(MaplePacketCreator.enableActions());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
player.addStat(1, -1);
|
player.addStat(1, -1);
|
||||||
break;
|
break;
|
||||||
case 128: // dex
|
case 128: // dex
|
||||||
if (player.getDex() < 5) {
|
if (player.getDex() < 5) {
|
||||||
|
c.getPlayer().message("You don't have the minimum DEX required to swap.");
|
||||||
|
c.announce(MaplePacketCreator.enableActions());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
player.addStat(2, -1);
|
player.addStat(2, -1);
|
||||||
break;
|
break;
|
||||||
case 256: // int
|
case 256: // int
|
||||||
if (player.getInt() < 5) {
|
if (player.getInt() < 5) {
|
||||||
|
c.getPlayer().message("You don't have the minimum INT required to swap.");
|
||||||
|
c.announce(MaplePacketCreator.enableActions());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
player.addStat(3, -1);
|
player.addStat(3, -1);
|
||||||
break;
|
break;
|
||||||
case 512: // luk
|
case 512: // luk
|
||||||
if (player.getLuk() < 5) {
|
if (player.getLuk() < 5) {
|
||||||
|
c.getPlayer().message("You don't have the minimum LUK required to swap.");
|
||||||
|
c.announce(MaplePacketCreator.enableActions());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
player.addStat(4, -1);
|
player.addStat(4, -1);
|
||||||
break;
|
break;
|
||||||
case 2048: // HP
|
case 2048: // HP
|
||||||
if (APTo != 8192) {
|
if (APTo != 8192) {
|
||||||
|
c.getPlayer().message("You can only swap HP ability points to MP.");
|
||||||
c.announce(MaplePacketCreator.enableActions());
|
c.announce(MaplePacketCreator.enableActions());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int hplose = 0;
|
|
||||||
final int jobid = player.getJob().getId();
|
int hp = player.getHp();
|
||||||
if (jobid == 0 || jobid == 1000 || jobid == 2000 || jobid >= 1200 && jobid <= 1211) { // Beginner
|
int level_ = player.getLevel();
|
||||||
hplose -= 12;
|
|
||||||
} else if (jobid >= 100 && jobid <= 132) { // Warrior
|
boolean canWash_ = true;
|
||||||
Skill improvinghplose = SkillFactory.getSkill(1000001);
|
if (hp < level_ * 14 + 148) {
|
||||||
int improvinghploseLevel = c.getPlayer().getSkillLevel(improvinghplose);
|
canWash_ = false;
|
||||||
hplose -= 24;
|
|
||||||
if (improvinghploseLevel >= 1) {
|
|
||||||
hplose -= improvinghplose.getEffect(improvinghploseLevel).getY();
|
|
||||||
}
|
}
|
||||||
} else if (jobid >= 200 && jobid <= 232) { // Magician
|
|
||||||
hplose -= 10;
|
if (!canWash_) {
|
||||||
} else if (jobid >= 500 && jobid <= 522) { // Pirate
|
c.getPlayer().message("You don't have the minimum HP pool required to swap.");
|
||||||
Skill improvinghplose = SkillFactory.getSkill(5100000);
|
c.announce(MaplePacketCreator.enableActions());
|
||||||
int improvinghploseLevel = c.getPlayer().getSkillLevel(improvinghplose);
|
return;
|
||||||
hplose -= 22;
|
|
||||||
if (improvinghploseLevel > 0) {
|
|
||||||
hplose -= improvinghplose.getEffect(improvinghploseLevel).getY();
|
|
||||||
}
|
}
|
||||||
} else if (jobid >= 1100 && jobid <= 1111) { // Soul Master
|
|
||||||
Skill improvinghplose = SkillFactory.getSkill(11000000);
|
int hplose = -DistributeAPHandler.calcHpChange(player, player.getJob(), true);
|
||||||
int improvinghploseLevel = c.getPlayer().getSkillLevel(improvinghplose);
|
int nextHp = Math.max(1, player.getHp() + hplose), nextMaxHp = Math.max(50, player.getMaxHp() + hplose);
|
||||||
hplose -= 27;
|
|
||||||
if (improvinghploseLevel >= 1) {
|
player.setHp(nextHp);
|
||||||
hplose -= improvinghplose.getEffect(improvinghploseLevel).getY();
|
player.setMaxHp(nextMaxHp);
|
||||||
}
|
statupdate.add(new Pair<>(MapleStat.HP, nextHp));
|
||||||
} else if ((jobid >= 1300 && jobid <= 1311) || (jobid >= 1400 && jobid <= 1411)) { // Wind Breaker and Night Walker
|
statupdate.add(new Pair<>(MapleStat.MAXHP, nextMaxHp));
|
||||||
hplose -= 17;
|
|
||||||
} else if (jobid >= 300 && jobid <= 322 || jobid >= 400 && jobid <= 422 || jobid >= 2000 && jobid <= 2112) { // Aran
|
|
||||||
hplose -= 20;
|
|
||||||
} else { // GameMaster
|
|
||||||
hplose -= 20;
|
|
||||||
}
|
|
||||||
player.setHp(player.getHp() + hplose);
|
|
||||||
player.setMaxHp(player.getMaxHp() + hplose);
|
|
||||||
statupdate.add(new Pair<>(MapleStat.HP, player.getHp()));
|
|
||||||
statupdate.add(new Pair<>(MapleStat.MAXHP, player.getMaxHp()));
|
|
||||||
break;
|
break;
|
||||||
case 8192: // MP
|
case 8192: // MP
|
||||||
if (APTo != 2048) {
|
if (APTo != 2048) {
|
||||||
|
c.getPlayer().message("You can only swap MP ability points to HP.");
|
||||||
c.announce(MaplePacketCreator.enableActions());
|
c.announce(MaplePacketCreator.enableActions());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int mp = player.getMp();
|
int mp = player.getMp();
|
||||||
int level = player.getLevel();
|
int level = player.getLevel();
|
||||||
MapleJob job = player.getJob();
|
MapleJob job = player.getJob();
|
||||||
|
|
||||||
boolean canWash = true;
|
boolean canWash = true;
|
||||||
if (job.isA(MapleJob.SPEARMAN) && mp < 4 * level + 156) {
|
if (job.isA(MapleJob.SPEARMAN) && mp < 4 * level + 156) {
|
||||||
canWash = false;
|
canWash = false;
|
||||||
@@ -185,30 +186,26 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
|||||||
} else if (mp < level * 14 + 148) {
|
} else if (mp < level * 14 + 148) {
|
||||||
canWash = false;
|
canWash = false;
|
||||||
}
|
}
|
||||||
if (canWash) {
|
|
||||||
int minmp = 0;
|
if (!canWash) {
|
||||||
if (job.isA(MapleJob.WARRIOR) || job.isA(MapleJob.DAWNWARRIOR1) || job.isA(MapleJob.ARAN1)) {
|
c.getPlayer().message("You don't have the minimum MP pool required to swap.");
|
||||||
minmp += 4;
|
c.announce(MaplePacketCreator.enableActions());
|
||||||
} else if (job.isA(MapleJob.MAGICIAN) || job.isA(MapleJob.BLAZEWIZARD1)) {
|
return;
|
||||||
minmp += 36;
|
|
||||||
} else if (job.isA(MapleJob.BOWMAN) || job.isA(MapleJob.WINDARCHER1) || job.isA(MapleJob.THIEF) || job.isA(MapleJob.NIGHTWALKER1)) {
|
|
||||||
minmp += 12;
|
|
||||||
} else if (job.isA(MapleJob.PIRATE) || job.isA(MapleJob.THUNDERBREAKER1)) {
|
|
||||||
minmp += 16;
|
|
||||||
} else {
|
|
||||||
minmp += 8;
|
|
||||||
}
|
}
|
||||||
player.setMp(player.getMp() - minmp);
|
|
||||||
player.setMaxMp(player.getMaxMp() - minmp);
|
int mplose = -DistributeAPHandler.calcMpChange(player, job, true);
|
||||||
statupdate.add(new Pair<>(MapleStat.MP, player.getMp()));
|
int nextMp = Math.max(0, player.getMp() + mplose), nextMaxMp = Math.max(5, player.getMaxMp() + mplose);
|
||||||
statupdate.add(new Pair<>(MapleStat.MAXMP, player.getMaxMp()));
|
|
||||||
|
player.setHp(nextMp);
|
||||||
|
player.setMaxHp(nextMaxMp);
|
||||||
|
statupdate.add(new Pair<>(MapleStat.HP, nextMp));
|
||||||
|
statupdate.add(new Pair<>(MapleStat.MAXHP, nextMaxMp));
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
c.announce(MaplePacketCreator.updatePlayerStats(MaplePacketCreator.EMPTY_STATUPDATE, true, c.getPlayer()));
|
c.announce(MaplePacketCreator.updatePlayerStats(MaplePacketCreator.EMPTY_STATUPDATE, true, c.getPlayer()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DistributeAPHandler.addStat(c, APTo);
|
DistributeAPHandler.addStat(c, APTo, true);
|
||||||
c.announce(MaplePacketCreator.updatePlayerStats(statupdate, true, c.getPlayer()));
|
c.announce(MaplePacketCreator.updatePlayerStats(statupdate, true, c.getPlayer()));
|
||||||
}
|
}
|
||||||
remove(c, itemId);
|
remove(c, itemId);
|
||||||
|
|||||||
@@ -249,6 +249,8 @@ public class AbstractPlayerInteraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void openNpc(int npcid, String script) {
|
public void openNpc(int npcid, String script) {
|
||||||
|
if(c.getCM() != null) return;
|
||||||
|
|
||||||
c.removeClickedNPC();
|
c.removeClickedNPC();
|
||||||
NPCScriptManager.getInstance().dispose(c);
|
NPCScriptManager.getInstance().dispose(c);
|
||||||
NPCScriptManager.getInstance().start(c, npcid, script, null);
|
NPCScriptManager.getInstance().start(c, npcid, script, null);
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import client.status.MonsterStatus;
|
|||||||
import client.status.MonsterStatusEffect;
|
import client.status.MonsterStatusEffect;
|
||||||
import constants.ServerConstants;
|
import constants.ServerConstants;
|
||||||
import constants.skills.FPMage;
|
import constants.skills.FPMage;
|
||||||
import constants.skills.Hermit;
|
|
||||||
import constants.skills.ILMage;
|
import constants.skills.ILMage;
|
||||||
import constants.skills.NightLord;
|
import constants.skills.NightLord;
|
||||||
import constants.skills.NightWalker;
|
import constants.skills.NightWalker;
|
||||||
@@ -51,6 +50,7 @@ import java.util.Map.Entry;
|
|||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import net.server.world.MapleParty;
|
import net.server.world.MapleParty;
|
||||||
import net.server.world.MaplePartyCharacter;
|
import net.server.world.MaplePartyCharacter;
|
||||||
@@ -66,12 +66,14 @@ import tools.Randomizer;
|
|||||||
public class MapleMonster extends AbstractLoadedMapleLife {
|
public class MapleMonster extends AbstractLoadedMapleLife {
|
||||||
private ChangeableStats ostats = null; //unused, v83 WZs offers no support for changeable stats.
|
private ChangeableStats ostats = null; //unused, v83 WZs offers no support for changeable stats.
|
||||||
private MapleMonsterStats stats;
|
private MapleMonsterStats stats;
|
||||||
private int hp, mp;
|
private AtomicInteger hp = new AtomicInteger(1);
|
||||||
|
private AtomicLong maxHpPlusHeal = new AtomicLong(1);
|
||||||
|
private int mp;
|
||||||
private WeakReference<MapleCharacter> controller = new WeakReference<>(null);
|
private WeakReference<MapleCharacter> controller = new WeakReference<>(null);
|
||||||
private boolean controllerHasAggro, controllerKnowsAboutAggro;
|
private boolean controllerHasAggro, controllerKnowsAboutAggro;
|
||||||
private Collection<MonsterListener> listeners = new LinkedList<>();
|
private Collection<MonsterListener> listeners = new LinkedList<>();
|
||||||
private EnumMap<MonsterStatus, MonsterStatusEffect> stati = new EnumMap<>(MonsterStatus.class);
|
private EnumMap<MonsterStatus, MonsterStatusEffect> stati = new EnumMap<>(MonsterStatus.class);
|
||||||
private ArrayList<MonsterStatus> alreadyBuffed = new ArrayList<MonsterStatus>();
|
private ArrayList<MonsterStatus> alreadyBuffed = new ArrayList<>();
|
||||||
private MapleMap map;
|
private MapleMap map;
|
||||||
private int VenomMultiplier = 0;
|
private int VenomMultiplier = 0;
|
||||||
private boolean fake = false;
|
private boolean fake = false;
|
||||||
@@ -82,7 +84,9 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
private int team;
|
private int team;
|
||||||
private final HashMap<Integer, AtomicInteger> takenDamage = new HashMap<>();
|
private final HashMap<Integer, AtomicInteger> takenDamage = new HashMap<>();
|
||||||
|
|
||||||
|
private ReentrantLock externalLock = new ReentrantLock();
|
||||||
private ReentrantLock monsterLock = new ReentrantLock();
|
private ReentrantLock monsterLock = new ReentrantLock();
|
||||||
|
private ReentrantLock statiLock = new ReentrantLock();
|
||||||
|
|
||||||
public MapleMonster(int id, MapleMonsterStats stats) {
|
public MapleMonster(int id, MapleMonsterStats stats) {
|
||||||
super(id);
|
super(id);
|
||||||
@@ -95,18 +99,20 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void lockMonster() {
|
public void lockMonster() {
|
||||||
monsterLock.lock();
|
externalLock.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unlockMonster() {
|
public void unlockMonster() {
|
||||||
monsterLock.unlock();
|
externalLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initWithStats(MapleMonsterStats stats) {
|
private void initWithStats(MapleMonsterStats stats) {
|
||||||
setStance(5);
|
setStance(5);
|
||||||
this.stats = stats;
|
this.stats = stats;
|
||||||
hp = stats.getHp();
|
hp.set(stats.getHp());
|
||||||
mp = stats.getMp();
|
mp = stats.getMp();
|
||||||
|
|
||||||
|
maxHpPlusHeal.set(hp.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disableDrops() {
|
public void disableDrops() {
|
||||||
@@ -122,11 +128,11 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getHp() {
|
public int getHp() {
|
||||||
return hp;
|
return hp.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHp(int hp) {
|
public void setHp(int hp) {
|
||||||
this.hp = hp;
|
this.hp.set(hp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMaxHp() {
|
public int getMaxHp() {
|
||||||
@@ -209,12 +215,13 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
if (!isAlive()) {
|
if (!isAlive()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int trueDamage = Math.min(hp, damage); // since magic happens otherwise B^)
|
int curHp = hp.get();
|
||||||
|
int trueDamage = Math.min(curHp, damage); // since magic happens otherwise B^)
|
||||||
|
|
||||||
if(ServerConstants.USE_DEBUG == true) from.dropMessage(5, "Hitted MOB " + this.getId() + ", OID " + this.getObjectId());
|
if(ServerConstants.USE_DEBUG == true) from.dropMessage(5, "Hitted MOB " + this.getId() + ", OID " + this.getObjectId());
|
||||||
dispatchMonsterDamaged(from, trueDamage);
|
dispatchMonsterDamaged(from, trueDamage);
|
||||||
|
|
||||||
hp -= trueDamage;
|
hp.set(curHp - trueDamage);
|
||||||
if (!takenDamage.containsKey(from.getId())) {
|
if (!takenDamage.containsKey(from.getId())) {
|
||||||
takenDamage.put(from.getId(), new AtomicInteger(trueDamage));
|
takenDamage.put(from.getId(), new AtomicInteger(trueDamage));
|
||||||
} else {
|
} else {
|
||||||
@@ -225,7 +232,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
from.setPlayerAggro(this.hashCode());
|
from.setPlayerAggro(this.hashCode());
|
||||||
from.getMap().broadcastBossHpMessage(this, this.hashCode(), makeBossHPBarPacket(), getPosition());
|
from.getMap().broadcastBossHpMessage(this, this.hashCode(), makeBossHPBarPacket(), getPosition());
|
||||||
} else if (!isBoss()) {
|
} else if (!isBoss()) {
|
||||||
int remainingHP = (int) Math.max(1, hp * 100f / getMaxHp());
|
int remainingHP = (int) Math.max(1, hp.get() * 100f / getMaxHp());
|
||||||
byte[] packet = MaplePacketCreator.showMonsterHP(getObjectId(), remainingHP);
|
byte[] packet = MaplePacketCreator.showMonsterHP(getObjectId(), remainingHP);
|
||||||
if (from.getParty() != null) {
|
if (from.getParty() != null) {
|
||||||
for (MaplePartyCharacter mpc : from.getParty().getMembers()) {
|
for (MaplePartyCharacter mpc : from.getParty().getMembers()) {
|
||||||
@@ -241,17 +248,24 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void heal(int hp, int mp) {
|
public void heal(int hp, int mp) {
|
||||||
|
int hpHealed = hp;
|
||||||
int hp2Heal = getHp() + hp;
|
int hp2Heal = getHp() + hp;
|
||||||
int mp2Heal = getMp() + mp;
|
int mp2Heal = getMp() + mp;
|
||||||
if (hp2Heal >= getMaxHp()) {
|
|
||||||
hp2Heal = getMaxHp();
|
int maxHp = getMaxHp();
|
||||||
|
int maxMp = getMaxMp();
|
||||||
|
if (hp2Heal >= maxHp) {
|
||||||
|
hpHealed = hp2Heal - maxHp;
|
||||||
|
hp2Heal = maxHp;
|
||||||
}
|
}
|
||||||
if (mp2Heal >= getMaxMp()) {
|
if (mp2Heal >= maxMp) {
|
||||||
mp2Heal = getMaxMp();
|
mp2Heal = maxMp;
|
||||||
}
|
}
|
||||||
setHp(hp2Heal);
|
setHp(hp2Heal);
|
||||||
setMp(mp2Heal);
|
setMp(mp2Heal);
|
||||||
getMap().broadcastMessage(MaplePacketCreator.healMonster(getObjectId(), hp));
|
getMap().broadcastMessage(MaplePacketCreator.healMonster(getObjectId(), hp));
|
||||||
|
|
||||||
|
maxHpPlusHeal.addAndGet(hpHealed);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAttackedBy(MapleCharacter chr) {
|
public boolean isAttackedBy(MapleCharacter chr) {
|
||||||
@@ -273,7 +287,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int partyLevel = 0;
|
int partyLevel = 0;
|
||||||
int leechMinLevel = (ServerConstants.USE_UNDERLEVELED_EXP_BLOCK) ? getLevel() - 20 : 0; //NO EXP WILL BE GIVEN for those who are underleveled!
|
int leechMinLevel = (ServerConstants.USE_UNDERLEVELED_EXP_BLOCK) ? getLevel() - ServerConstants.MIN_UNDERLEVEL_FOR_EXP_GAIN : 0; //NO EXP WILL BE GIVEN for those who are underleveled!
|
||||||
|
|
||||||
int leechCount = 0;
|
int leechCount = 0;
|
||||||
for (MapleCharacter mc : members) {
|
for (MapleCharacter mc : members) {
|
||||||
@@ -307,15 +321,15 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int exp = getExp();
|
int exp = getExp();
|
||||||
int totalHealth = getMaxHp();
|
long totalHealth = maxHpPlusHeal.get();
|
||||||
Map<Integer, Integer> expDist = new HashMap<>();
|
Map<Integer, Integer> expDist = new HashMap<>();
|
||||||
Map<Integer, Integer> partyExp = new HashMap<>();
|
Map<Integer, Integer> partyExp = new HashMap<>();
|
||||||
|
|
||||||
float exp8 = (0.8f * exp); // 80% of pool is split amongst all the damagers
|
float exp8perHp = (0.8f * exp) / totalHealth; // 80% of pool is split amongst all the damagers
|
||||||
float exp2 = (0.2f * exp); // 20% of pool goes to the killer or his/her party
|
float exp2 = (0.2f * exp); // 20% of pool goes to the killer or his/her party
|
||||||
|
|
||||||
for (Entry<Integer, AtomicInteger> damage : takenDamage.entrySet()) {
|
for (Entry<Integer, AtomicInteger> damage : takenDamage.entrySet()) {
|
||||||
expDist.put(damage.getKey(), (int) (Math.min((exp8 * damage.getValue().get()) / totalHealth, Integer.MAX_VALUE)));
|
expDist.put(damage.getKey(), (int) (Math.min((exp8perHp * damage.getValue().get()), Integer.MAX_VALUE)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection<MapleCharacter> chrs = map.getCharacters();
|
Collection<MapleCharacter> chrs = map.getCharacters();
|
||||||
@@ -333,7 +347,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
long pXP = (long)xp + (partyExp.containsKey(pID) ? partyExp.get(pID) : 0);
|
long pXP = (long)xp + (partyExp.containsKey(pID) ? partyExp.get(pID) : 0);
|
||||||
partyExp.put(pID, (int)Math.min(pXP, Integer.MAX_VALUE));
|
partyExp.put(pID, (int)Math.min(pXP, Integer.MAX_VALUE));
|
||||||
} else {
|
} else {
|
||||||
if(!ServerConstants.USE_UNDERLEVELED_EXP_BLOCK || mc.getLevel() >= getLevel() - 20) {
|
if(!ServerConstants.USE_UNDERLEVELED_EXP_BLOCK || mc.getLevel() >= getLevel() - ServerConstants.MIN_UNDERLEVEL_FOR_EXP_GAIN) {
|
||||||
//NO EXP WILL BE GIVEN for those who are underleveled!
|
//NO EXP WILL BE GIVEN for those who are underleveled!
|
||||||
giveExpToCharacter(mc, xp, isKiller, 1);
|
giveExpToCharacter(mc, xp, isKiller, 1);
|
||||||
} else {
|
} else {
|
||||||
@@ -379,9 +393,15 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
personalExp *= 1.0 + (holySymbol.doubleValue() / 100.0);
|
personalExp *= 1.0 + (holySymbol.doubleValue() / 100.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
statiLock.lock();
|
||||||
|
try {
|
||||||
if (stati.containsKey(MonsterStatus.SHOWDOWN)) {
|
if (stati.containsKey(MonsterStatus.SHOWDOWN)) {
|
||||||
personalExp *= (stati.get(MonsterStatus.SHOWDOWN).getStati().get(MonsterStatus.SHOWDOWN).doubleValue() / 100.0 + 1.0);
|
personalExp *= (stati.get(MonsterStatus.SHOWDOWN).getStati().get(MonsterStatus.SHOWDOWN).doubleValue() / 100.0 + 1.0);
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
statiLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
attacker.gainExp(personalExp, partyExp, true, false, isKiller);
|
attacker.gainExp(personalExp, partyExp, true, false, isKiller);
|
||||||
@@ -393,9 +413,10 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
public MapleCharacter killBy(final MapleCharacter killer) {
|
public MapleCharacter killBy(final MapleCharacter killer) {
|
||||||
distributeExperience(killer != null ? killer.getId() : 0);
|
distributeExperience(killer != null ? killer.getId() : 0);
|
||||||
|
|
||||||
if (getController() != null) { // this can/should only happen when a hidden gm attacks the monster
|
MapleCharacter controller = getController();
|
||||||
getController().getClient().announce(MaplePacketCreator.stopControllingMonster(this.getObjectId()));
|
if (controller != null) { // this can/should only happen when a hidden gm attacks the monster
|
||||||
getController().stopControllingMonster(this);
|
controller.getClient().announce(MaplePacketCreator.stopControllingMonster(this.getObjectId()));
|
||||||
|
controller.stopControllingMonster(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<Integer> toSpawn = this.getRevives(); // this doesn't work (?)
|
final List<Integer> toSpawn = this.getRevives(); // this doesn't work (?)
|
||||||
@@ -427,6 +448,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(toSpawn.size() > 0) {
|
||||||
TimerManager.getInstance().schedule(new Runnable() {
|
TimerManager.getInstance().schedule(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -446,6 +468,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
}
|
}
|
||||||
}, getAnimationTime("die1"));
|
}, getAnimationTime("die1"));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else { // is this even necessary?
|
else { // is this even necessary?
|
||||||
System.out.println("[CRITICAL LOSS] toSpawn is null for " + this.getName());
|
System.out.println("[CRITICAL LOSS] toSpawn is null for " + this.getName());
|
||||||
}
|
}
|
||||||
@@ -468,7 +491,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dispatchMonsterDamaged(MapleCharacter from, int trueDmg) {
|
private void dispatchMonsterDamaged(MapleCharacter from, int trueDmg) {
|
||||||
for (MonsterListener listener : listeners.toArray(new MonsterListener[listeners.size()])) {
|
for (MonsterListener listener : listeners.toArray(new MonsterListener[listeners.size()])) {
|
||||||
listener.monsterDamaged(from, trueDmg);
|
listener.monsterDamaged(from, trueDmg);
|
||||||
}
|
}
|
||||||
@@ -488,15 +511,25 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAlive() {
|
public boolean isAlive() {
|
||||||
return this.hp > 0;
|
return this.hp.get() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapleCharacter getController() {
|
public MapleCharacter getController() {
|
||||||
|
monsterLock.lock();
|
||||||
|
try {
|
||||||
return controller.get();
|
return controller.get();
|
||||||
|
} finally {
|
||||||
|
monsterLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setController(MapleCharacter controller) {
|
public void setController(MapleCharacter controller) {
|
||||||
|
monsterLock.lock();
|
||||||
|
try {
|
||||||
this.controller = new WeakReference<>(controller);
|
this.controller = new WeakReference<>(controller);
|
||||||
|
} finally {
|
||||||
|
monsterLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void switchController(MapleCharacter newController, boolean immediateAggro) {
|
public void switchController(MapleCharacter newController, boolean immediateAggro) {
|
||||||
@@ -521,25 +554,45 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isControllerHasAggro() {
|
public boolean isControllerHasAggro() {
|
||||||
|
monsterLock.lock();
|
||||||
|
try {
|
||||||
return fake ? false : controllerHasAggro;
|
return fake ? false : controllerHasAggro;
|
||||||
|
} finally {
|
||||||
|
monsterLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setControllerHasAggro(boolean controllerHasAggro) {
|
public void setControllerHasAggro(boolean controllerHasAggro) {
|
||||||
|
monsterLock.lock();
|
||||||
|
try {
|
||||||
if (fake) {
|
if (fake) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.controllerHasAggro = controllerHasAggro;
|
this.controllerHasAggro = controllerHasAggro;
|
||||||
|
} finally {
|
||||||
|
monsterLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isControllerKnowsAboutAggro() {
|
public boolean isControllerKnowsAboutAggro() {
|
||||||
|
monsterLock.lock();
|
||||||
|
try {
|
||||||
return fake ? false : controllerKnowsAboutAggro;
|
return fake ? false : controllerKnowsAboutAggro;
|
||||||
|
} finally {
|
||||||
|
monsterLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setControllerKnowsAboutAggro(boolean controllerKnowsAboutAggro) {
|
public void setControllerKnowsAboutAggro(boolean controllerKnowsAboutAggro) {
|
||||||
|
monsterLock.lock();
|
||||||
|
try {
|
||||||
if (fake) {
|
if (fake) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.controllerKnowsAboutAggro = controllerKnowsAboutAggro;
|
this.controllerKnowsAboutAggro = controllerKnowsAboutAggro;
|
||||||
|
} finally {
|
||||||
|
monsterLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] makeBossHPBarPacket() {
|
public byte[] makeBossHPBarPacket() {
|
||||||
@@ -560,11 +613,17 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
} else {
|
} else {
|
||||||
c.announce(MaplePacketCreator.spawnMonster(this, false));
|
c.announce(MaplePacketCreator.spawnMonster(this, false));
|
||||||
}
|
}
|
||||||
|
statiLock.lock();
|
||||||
|
try {
|
||||||
if (stati.size() > 0) {
|
if (stati.size() > 0) {
|
||||||
for (final MonsterStatusEffect mse : this.stati.values()) {
|
for (final MonsterStatusEffect mse : this.stati.values()) {
|
||||||
c.announce(MaplePacketCreator.applyMonsterStatus(getObjectId(), mse, null));
|
c.announce(MaplePacketCreator.applyMonsterStatus(getObjectId(), mse, null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
statiLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
if (hasBossHPBar()) {
|
if (hasBossHPBar()) {
|
||||||
if (this.getMap().countMonster(8810026) > 0 && this.getMap().getId() == 240060200) {
|
if (this.getMap().countMonster(8810026) > 0 && this.getMap().getId() == 240060200) {
|
||||||
this.getMap().killAllMonsters();
|
this.getMap().killAllMonsters();
|
||||||
@@ -588,11 +647,44 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
return stats.isMobile();
|
return stats.isMobile();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ElementalEffectiveness getEffectiveness(Element e) {
|
public ElementalEffectiveness getElementalEffectiveness(Element e) {
|
||||||
if (stati.size() > 0 && stati.get(MonsterStatus.DOOM) != null) {
|
statiLock.lock();
|
||||||
|
try {
|
||||||
|
if (stati.get(MonsterStatus.DOOM) != null) {
|
||||||
return ElementalEffectiveness.NORMAL; // like blue snails
|
return ElementalEffectiveness.NORMAL; // like blue snails
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
statiLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
monsterLock.lock();
|
||||||
|
try {
|
||||||
return stats.getEffectiveness(e);
|
return stats.getEffectiveness(e);
|
||||||
|
} finally {
|
||||||
|
monsterLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ElementalEffectiveness getMonsterEffectiveness(Element e) {
|
||||||
|
monsterLock.lock();
|
||||||
|
try {
|
||||||
|
return stats.getEffectiveness(e);
|
||||||
|
} finally {
|
||||||
|
monsterLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int broadcastStatusEffect(final MonsterStatusEffect status) {
|
||||||
|
int animationTime = status.getSkill().getAnimationTime();
|
||||||
|
byte[] packet = MaplePacketCreator.applyMonsterStatus(getObjectId(), status, null);
|
||||||
|
map.broadcastMessage(packet, getPosition());
|
||||||
|
|
||||||
|
MapleCharacter controller = getController();
|
||||||
|
if (controller != null && !controller.isMapObjectVisible(this)) {
|
||||||
|
controller.getClient().announce(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
return animationTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean applyStatus(MapleCharacter from, final MonsterStatusEffect status, boolean poison, long duration) {
|
public boolean applyStatus(MapleCharacter from, final MonsterStatusEffect status, boolean poison, long duration) {
|
||||||
@@ -600,7 +692,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean applyStatus(MapleCharacter from, final MonsterStatusEffect status, boolean poison, long duration, boolean venom) {
|
public boolean applyStatus(MapleCharacter from, final MonsterStatusEffect status, boolean poison, long duration, boolean venom) {
|
||||||
switch (stats.getEffectiveness(status.getSkill().getElement())) {
|
switch (getMonsterEffectiveness(status.getSkill().getElement())) {
|
||||||
case IMMUNE:
|
case IMMUNE:
|
||||||
case STRONG:
|
case STRONG:
|
||||||
case NEUTRAL:
|
case NEUTRAL:
|
||||||
@@ -609,27 +701,27 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
case WEAK:
|
case WEAK:
|
||||||
break;
|
break;
|
||||||
default: {
|
default: {
|
||||||
System.out.println("Unknown elemental effectiveness: " + stats.getEffectiveness(status.getSkill().getElement()));
|
System.out.println("Unknown elemental effectiveness: " + getMonsterEffectiveness(status.getSkill().getElement()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status.getSkill().getId() == FPMage.ELEMENT_COMPOSITION) { // fp compo
|
if (status.getSkill().getId() == FPMage.ELEMENT_COMPOSITION) { // fp compo
|
||||||
ElementalEffectiveness effectiveness = stats.getEffectiveness(Element.POISON);
|
ElementalEffectiveness effectiveness = getMonsterEffectiveness(Element.POISON);
|
||||||
if (effectiveness == ElementalEffectiveness.IMMUNE || effectiveness == ElementalEffectiveness.STRONG) {
|
if (effectiveness == ElementalEffectiveness.IMMUNE || effectiveness == ElementalEffectiveness.STRONG) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (status.getSkill().getId() == ILMage.ELEMENT_COMPOSITION) { // il compo
|
} else if (status.getSkill().getId() == ILMage.ELEMENT_COMPOSITION) { // il compo
|
||||||
ElementalEffectiveness effectiveness = stats.getEffectiveness(Element.ICE);
|
ElementalEffectiveness effectiveness = getMonsterEffectiveness(Element.ICE);
|
||||||
if (effectiveness == ElementalEffectiveness.IMMUNE || effectiveness == ElementalEffectiveness.STRONG) {
|
if (effectiveness == ElementalEffectiveness.IMMUNE || effectiveness == ElementalEffectiveness.STRONG) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (status.getSkill().getId() == NightLord.VENOMOUS_STAR || status.getSkill().getId() == Shadower.VENOMOUS_STAB || status.getSkill().getId() == NightWalker.VENOM) {// venom
|
} else if (status.getSkill().getId() == NightLord.VENOMOUS_STAR || status.getSkill().getId() == Shadower.VENOMOUS_STAB || status.getSkill().getId() == NightWalker.VENOM) {// venom
|
||||||
if (stats.getEffectiveness(Element.POISON) == ElementalEffectiveness.WEAK) {
|
if (getMonsterEffectiveness(Element.POISON) == ElementalEffectiveness.WEAK) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (poison && getHp() <= 1) {
|
if (poison && hp.get() <= 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -642,6 +734,9 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(statis.size() > 0) {
|
||||||
|
statiLock.lock();
|
||||||
|
try {
|
||||||
for (MonsterStatus stat : statis.keySet()) {
|
for (MonsterStatus stat : statis.keySet()) {
|
||||||
final MonsterStatusEffect oldEffect = stati.get(stat);
|
final MonsterStatusEffect oldEffect = stati.get(stat);
|
||||||
if (oldEffect != null) {
|
if (oldEffect != null) {
|
||||||
@@ -652,6 +747,10 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
statiLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TimerManager timerManager = TimerManager.getInstance();
|
TimerManager timerManager = TimerManager.getInstance();
|
||||||
final Runnable cancelTask = new Runnable() {
|
final Runnable cancelTask = new Runnable() {
|
||||||
@@ -661,26 +760,38 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
if (isAlive()) {
|
if (isAlive()) {
|
||||||
byte[] packet = MaplePacketCreator.cancelMonsterStatus(getObjectId(), status.getStati());
|
byte[] packet = MaplePacketCreator.cancelMonsterStatus(getObjectId(), status.getStati());
|
||||||
map.broadcastMessage(packet, getPosition());
|
map.broadcastMessage(packet, getPosition());
|
||||||
if (getController() != null && !getController().isMapObjectVisible(MapleMonster.this)) {
|
|
||||||
getController().getClient().announce(packet);
|
MapleCharacter controller = getController();
|
||||||
|
if (controller != null && !controller.isMapObjectVisible(MapleMonster.this)) {
|
||||||
|
controller.getClient().announce(packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
statiLock.lock();
|
||||||
|
try {
|
||||||
for (MonsterStatus stat : status.getStati().keySet()) {
|
for (MonsterStatus stat : status.getStati().keySet()) {
|
||||||
stati.remove(stat);
|
stati.remove(stat);
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
statiLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
setVenomMulti(0);
|
setVenomMulti(0);
|
||||||
status.cancelDamageSchedule();
|
status.cancelDamageSchedule();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int animationTime;
|
||||||
if (poison) {
|
if (poison) {
|
||||||
int poisonLevel = from.getSkillLevel(status.getSkill());
|
int poisonLevel = from.getSkillLevel(status.getSkill());
|
||||||
int poisonDamage = Math.min(Short.MAX_VALUE, (int) (getMaxHp() / (70.0 - poisonLevel) + 0.999));
|
int poisonDamage = Math.min(Short.MAX_VALUE, (int) (getMaxHp() / (70.0 - poisonLevel) + 0.999));
|
||||||
status.setValue(MonsterStatus.POISON, Integer.valueOf(poisonDamage));
|
status.setValue(MonsterStatus.POISON, Integer.valueOf(poisonDamage));
|
||||||
|
animationTime = broadcastStatusEffect(status);
|
||||||
status.setDamageSchedule(timerManager.register(new DamageTask(poisonDamage, from, status, cancelTask, 0), 1000, 1000));
|
status.setDamageSchedule(timerManager.register(new DamageTask(poisonDamage, from, status, cancelTask, 0), 1000, 1000));
|
||||||
} else if (venom) {
|
} else if (venom) {
|
||||||
if (from.getJob() == MapleJob.NIGHTLORD || from.getJob() == MapleJob.SHADOWER || from.getJob().isA(MapleJob.NIGHTWALKER3)) {
|
if (from.getJob() == MapleJob.NIGHTLORD || from.getJob() == MapleJob.SHADOWER || from.getJob().isA(MapleJob.NIGHTWALKER3)) {
|
||||||
int poisonLevel, matk, id = from.getJob().getId();
|
int poisonLevel, matk, jobid = from.getJob().getId();
|
||||||
int skill = (id == 412 ? NightLord.VENOMOUS_STAR : (id == 422 ? Shadower.VENOMOUS_STAB : NightWalker.VENOM));
|
int skill = (jobid == 412 ? NightLord.VENOMOUS_STAR : (jobid == 422 ? Shadower.VENOMOUS_STAB : NightWalker.VENOM));
|
||||||
poisonLevel = from.getSkillLevel(SkillFactory.getSkill(skill));
|
poisonLevel = from.getSkillLevel(SkillFactory.getSkill(skill));
|
||||||
if (poisonLevel <= 0) {
|
if (poisonLevel <= 0) {
|
||||||
return false;
|
return false;
|
||||||
@@ -699,13 +810,19 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
}
|
}
|
||||||
poisonDamage = Math.min(Short.MAX_VALUE, poisonDamage);
|
poisonDamage = Math.min(Short.MAX_VALUE, poisonDamage);
|
||||||
status.setValue(MonsterStatus.VENOMOUS_WEAPON, Integer.valueOf(poisonDamage));
|
status.setValue(MonsterStatus.VENOMOUS_WEAPON, Integer.valueOf(poisonDamage));
|
||||||
|
status.setValue(MonsterStatus.POISON, Integer.valueOf(poisonDamage));
|
||||||
|
animationTime = broadcastStatusEffect(status);
|
||||||
status.setDamageSchedule(timerManager.register(new DamageTask(poisonDamage, from, status, cancelTask, 0), 1000, 1000));
|
status.setDamageSchedule(timerManager.register(new DamageTask(poisonDamage, from, status, cancelTask, 0), 1000, 1000));
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
} else if (status.getSkill().getId() == Hermit.SHADOW_WEB || status.getSkill().getId() == NightWalker.SHADOW_WEB) { //Shadow Web
|
} else if (status.getSkill().getId() == Hermit.SHADOW_WEB || status.getSkill().getId() == NightWalker.SHADOW_WEB) { //Shadow Web
|
||||||
status.setDamageSchedule(timerManager.schedule(new DamageTask((int) (getMaxHp() / 50.0 + 0.999), from, status, cancelTask, 1), 3500));
|
int webDamage = (int) (getMaxHp() / 50.0 + 0.999);
|
||||||
|
status.setValue(MonsterStatus.SHADOW_WEB, Integer.valueOf(webDamage));
|
||||||
|
animationTime = broadcastStatusEffect(status);
|
||||||
|
status.setDamageSchedule(timerManager.schedule(new DamageTask(webDamage, from, status, cancelTask, 1), 3500));
|
||||||
|
*/
|
||||||
} else if (status.getSkill().getId() == 4121004 || status.getSkill().getId() == 4221004) { // Ninja Ambush
|
} else if (status.getSkill().getId() == 4121004 || status.getSkill().getId() == 4221004) { // Ninja Ambush
|
||||||
final Skill skill = SkillFactory.getSkill(status.getSkill().getId());
|
final Skill skill = SkillFactory.getSkill(status.getSkill().getId());
|
||||||
final byte level = from.getSkillLevel(skill);
|
final byte level = from.getSkillLevel(skill);
|
||||||
@@ -715,19 +832,23 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
status.setValue(MonsterStatus.NINJA_AMBUSH, Integer.valueOf(damage));
|
status.setValue(MonsterStatus.NINJA_AMBUSH, Integer.valueOf(damage));
|
||||||
|
animationTime = broadcastStatusEffect(status);
|
||||||
status.setDamageSchedule(timerManager.register(new DamageTask(damage, from, status, cancelTask, 2), 1000, 1000));
|
status.setDamageSchedule(timerManager.register(new DamageTask(damage, from, status, cancelTask, 2), 1000, 1000));
|
||||||
|
} else {
|
||||||
|
animationTime = broadcastStatusEffect(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
statiLock.lock();
|
||||||
|
try {
|
||||||
for (MonsterStatus stat : status.getStati().keySet()) {
|
for (MonsterStatus stat : status.getStati().keySet()) {
|
||||||
stati.put(stat, status);
|
stati.put(stat, status);
|
||||||
alreadyBuffed.add(stat);
|
alreadyBuffed.add(stat);
|
||||||
}
|
}
|
||||||
int animationTime = status.getSkill().getAnimationTime();
|
} finally {
|
||||||
byte[] packet = MaplePacketCreator.applyMonsterStatus(getObjectId(), status, null);
|
statiLock.unlock();
|
||||||
map.broadcastMessage(packet, getPosition());
|
|
||||||
if (getController() != null && !getController().isMapObjectVisible(this)) {
|
|
||||||
getController().getClient().announce(packet);
|
|
||||||
}
|
}
|
||||||
status.setCancelTask(timerManager.schedule(cancelTask, duration + animationTime));
|
|
||||||
|
status.setCancelTask(timerManager.schedule(cancelTask, duration + animationTime - 100));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -740,24 +861,40 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
if (isAlive()) {
|
if (isAlive()) {
|
||||||
byte[] packet = MaplePacketCreator.cancelMonsterStatus(getObjectId(), stats);
|
byte[] packet = MaplePacketCreator.cancelMonsterStatus(getObjectId(), stats);
|
||||||
map.broadcastMessage(packet, getPosition());
|
map.broadcastMessage(packet, getPosition());
|
||||||
if (getController() != null && !getController().isMapObjectVisible(MapleMonster.this)) {
|
|
||||||
getController().getClient().announce(packet);
|
MapleCharacter controller = getController();
|
||||||
|
if (controller != null && !controller.isMapObjectVisible(MapleMonster.this)) {
|
||||||
|
controller.getClient().announce(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
statiLock.lock();
|
||||||
|
try {
|
||||||
for (final MonsterStatus stat : stats.keySet()) {
|
for (final MonsterStatus stat : stats.keySet()) {
|
||||||
stati.remove(stat);
|
stati.remove(stat);
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
statiLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
final MonsterStatusEffect effect = new MonsterStatusEffect(stats, null, skill, true);
|
final MonsterStatusEffect effect = new MonsterStatusEffect(stats, null, skill, true);
|
||||||
byte[] packet = MaplePacketCreator.applyMonsterStatus(getObjectId(), effect, reflection);
|
byte[] packet = MaplePacketCreator.applyMonsterStatus(getObjectId(), effect, reflection);
|
||||||
map.broadcastMessage(packet, getPosition());
|
map.broadcastMessage(packet, getPosition());
|
||||||
|
|
||||||
|
statiLock.lock();
|
||||||
|
try {
|
||||||
for (MonsterStatus stat : stats.keySet()) {
|
for (MonsterStatus stat : stats.keySet()) {
|
||||||
stati.put(stat, effect);
|
stati.put(stat, effect);
|
||||||
alreadyBuffed.add(stat);
|
alreadyBuffed.add(stat);
|
||||||
}
|
}
|
||||||
if (getController() != null && !getController().isMapObjectVisible(this)) {
|
} finally {
|
||||||
getController().getClient().announce(packet);
|
statiLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
MapleCharacter controller = getController();
|
||||||
|
if (controller != null && !controller.isMapObjectVisible(this)) {
|
||||||
|
controller.getClient().announce(packet);
|
||||||
}
|
}
|
||||||
effect.setCancelTask(timerManager.schedule(cancelTask, duration));
|
effect.setCancelTask(timerManager.schedule(cancelTask, duration));
|
||||||
}
|
}
|
||||||
@@ -765,29 +902,51 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
public void debuffMob(int skillid) {
|
public void debuffMob(int skillid) {
|
||||||
//skillid is not going to be used for now until I get warrior debuff working
|
//skillid is not going to be used for now until I get warrior debuff working
|
||||||
MonsterStatus[] stats = {MonsterStatus.WEAPON_ATTACK_UP, MonsterStatus.WEAPON_DEFENSE_UP, MonsterStatus.MAGIC_ATTACK_UP, MonsterStatus.MAGIC_DEFENSE_UP};
|
MonsterStatus[] stats = {MonsterStatus.WEAPON_ATTACK_UP, MonsterStatus.WEAPON_DEFENSE_UP, MonsterStatus.MAGIC_ATTACK_UP, MonsterStatus.MAGIC_DEFENSE_UP};
|
||||||
|
statiLock.lock();
|
||||||
|
try {
|
||||||
for (int i = 0; i < stats.length; i++) {
|
for (int i = 0; i < stats.length; i++) {
|
||||||
if (isBuffed(stats[i])) {
|
if (isBuffed(stats[i])) {
|
||||||
final MonsterStatusEffect oldEffect = stati.get(stats[i]);
|
final MonsterStatusEffect oldEffect = stati.get(stats[i]);
|
||||||
byte[] packet = MaplePacketCreator.cancelMonsterStatus(getObjectId(), oldEffect.getStati());
|
byte[] packet = MaplePacketCreator.cancelMonsterStatus(getObjectId(), oldEffect.getStati());
|
||||||
map.broadcastMessage(packet, getPosition());
|
map.broadcastMessage(packet, getPosition());
|
||||||
if (getController() != null && !getController().isMapObjectVisible(MapleMonster.this)) {
|
|
||||||
getController().getClient().announce(packet);
|
MapleCharacter controller = getController();
|
||||||
|
if (controller != null && !controller.isMapObjectVisible(MapleMonster.this)) {
|
||||||
|
controller.getClient().announce(packet);
|
||||||
}
|
}
|
||||||
stati.remove(stats);
|
stati.remove(stats[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
statiLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isBuffed(MonsterStatus status) {
|
public boolean isBuffed(MonsterStatus status) {
|
||||||
|
statiLock.lock();
|
||||||
|
try {
|
||||||
return stati.containsKey(status);
|
return stati.containsKey(status);
|
||||||
|
} finally {
|
||||||
|
statiLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFake(boolean fake) {
|
public void setFake(boolean fake) {
|
||||||
|
monsterLock.lock();
|
||||||
|
try {
|
||||||
this.fake = fake;
|
this.fake = fake;
|
||||||
|
} finally {
|
||||||
|
monsterLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFake() {
|
public boolean isFake() {
|
||||||
|
monsterLock.lock();
|
||||||
|
try {
|
||||||
return fake;
|
return fake;
|
||||||
|
} finally {
|
||||||
|
monsterLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapleMap getMap() {
|
public MapleMap getMap() {
|
||||||
@@ -806,18 +965,30 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
if (toUse == null) {
|
if (toUse == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
monsterLock.lock();
|
||||||
|
try {
|
||||||
for (Pair<Integer, Integer> skill : usedSkills) {
|
for (Pair<Integer, Integer> skill : usedSkills) {
|
||||||
if (skill.getLeft() == toUse.getSkillId() && skill.getRight() == toUse.getSkillLevel()) {
|
if (skill.getLeft() == toUse.getSkillId() && skill.getRight() == toUse.getSkillLevel()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
monsterLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
if (toUse.getLimit() > 0) {
|
if (toUse.getLimit() > 0) {
|
||||||
|
monsterLock.lock();
|
||||||
|
try {
|
||||||
if (this.skillsUsed.containsKey(new Pair<>(toUse.getSkillId(), toUse.getSkillLevel()))) {
|
if (this.skillsUsed.containsKey(new Pair<>(toUse.getSkillId(), toUse.getSkillLevel()))) {
|
||||||
int times = this.skillsUsed.get(new Pair<>(toUse.getSkillId(), toUse.getSkillLevel()));
|
int times = this.skillsUsed.get(new Pair<>(toUse.getSkillId(), toUse.getSkillLevel()));
|
||||||
if (times >= toUse.getLimit()) {
|
if (times >= toUse.getLimit()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
monsterLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (toUse.getSkillId() == 200) {
|
if (toUse.getSkillId() == 200) {
|
||||||
Collection<MapleMapObject> mmo = getMap().getMapObjects();
|
Collection<MapleMapObject> mmo = getMap().getMapObjects();
|
||||||
@@ -835,6 +1006,8 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void usedSkill(final int skillId, final int level, long cooltime) {
|
public void usedSkill(final int skillId, final int level, long cooltime) {
|
||||||
|
monsterLock.lock();
|
||||||
|
try {
|
||||||
this.usedSkills.add(new Pair<>(skillId, level));
|
this.usedSkills.add(new Pair<>(skillId, level));
|
||||||
if (this.skillsUsed.containsKey(new Pair<>(skillId, level))) {
|
if (this.skillsUsed.containsKey(new Pair<>(skillId, level))) {
|
||||||
int times = this.skillsUsed.get(new Pair<>(skillId, level)) + 1;
|
int times = this.skillsUsed.get(new Pair<>(skillId, level)) + 1;
|
||||||
@@ -843,6 +1016,10 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
} else {
|
} else {
|
||||||
this.skillsUsed.put(new Pair<>(skillId, level), 1);
|
this.skillsUsed.put(new Pair<>(skillId, level), 1);
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
monsterLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
final MapleMonster mons = this;
|
final MapleMonster mons = this;
|
||||||
TimerManager tMan = TimerManager.getInstance();
|
TimerManager tMan = TimerManager.getInstance();
|
||||||
tMan.schedule(
|
tMan.schedule(
|
||||||
@@ -856,6 +1033,8 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void clearSkill(int skillId, int level) {
|
public void clearSkill(int skillId, int level) {
|
||||||
|
monsterLock.lock();
|
||||||
|
try {
|
||||||
int index = -1;
|
int index = -1;
|
||||||
for (Pair<Integer, Integer> skill : usedSkills) {
|
for (Pair<Integer, Integer> skill : usedSkills) {
|
||||||
if (skill.getLeft() == skillId && skill.getRight() == level) {
|
if (skill.getLeft() == skillId && skill.getRight() == level) {
|
||||||
@@ -866,6 +1045,9 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
usedSkills.remove(index);
|
usedSkills.remove(index);
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
monsterLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNoSkills() {
|
public int getNoSkills() {
|
||||||
@@ -900,16 +1082,19 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
int curHp = hp.get();
|
||||||
|
if(curHp <= 0) return;
|
||||||
|
|
||||||
int damage = dealDamage;
|
int damage = dealDamage;
|
||||||
if (damage >= hp) {
|
if (damage >= curHp) {
|
||||||
damage = hp - 1;
|
damage = curHp - 1;
|
||||||
if (type == 1 || type == 2) {
|
if (type == 1 || type == 2) {
|
||||||
map.broadcastMessage(MaplePacketCreator.damageMonster(getObjectId(), damage), getPosition());
|
map.broadcastMessage(MaplePacketCreator.damageMonster(getObjectId(), damage), getPosition());
|
||||||
cancelTask.run();
|
cancelTask.run();
|
||||||
status.getCancelTask().cancel(false);
|
status.getCancelTask().cancel(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hp > 1 && damage > 0) {
|
if (curHp > 1 && damage > 0) {
|
||||||
damage(chr, damage);
|
damage(chr, damage);
|
||||||
if (type == 1) {
|
if (type == 1) {
|
||||||
map.broadcastMessage(MaplePacketCreator.damageMonster(getObjectId(), damage), getPosition());
|
map.broadcastMessage(MaplePacketCreator.damageMonster(getObjectId(), damage), getPosition());
|
||||||
@@ -931,23 +1116,38 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setTempEffectiveness(Element e, ElementalEffectiveness ee, long milli) {
|
public void setTempEffectiveness(Element e, ElementalEffectiveness ee, long milli) {
|
||||||
|
monsterLock.lock();
|
||||||
|
try {
|
||||||
final Element fE = e;
|
final Element fE = e;
|
||||||
final ElementalEffectiveness fEE = stats.getEffectiveness(e);
|
final ElementalEffectiveness fEE = stats.getEffectiveness(e);
|
||||||
if (!stats.getEffectiveness(e).equals(ElementalEffectiveness.WEAK)) {
|
if (!fEE.equals(ElementalEffectiveness.WEAK)) {
|
||||||
stats.setEffectiveness(e, ee);
|
stats.setEffectiveness(e, ee);
|
||||||
TimerManager.getInstance().schedule(new Runnable() {
|
TimerManager.getInstance().schedule(new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
monsterLock.lock();
|
||||||
|
try {
|
||||||
stats.removeEffectiveness(fE);
|
stats.removeEffectiveness(fE);
|
||||||
stats.setEffectiveness(fE, fEE);
|
stats.setEffectiveness(fE, fEE);
|
||||||
|
} finally {
|
||||||
|
monsterLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, milli);
|
}, milli);
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
monsterLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<MonsterStatus> alreadyBuffedStats() {
|
public Collection<MonsterStatus> alreadyBuffedStats() {
|
||||||
|
statiLock.lock();
|
||||||
|
try {
|
||||||
return Collections.unmodifiableCollection(alreadyBuffed);
|
return Collections.unmodifiableCollection(alreadyBuffed);
|
||||||
|
} finally {
|
||||||
|
statiLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public BanishInfo getBanish() {
|
public BanishInfo getBanish() {
|
||||||
@@ -967,7 +1167,21 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Map<MonsterStatus, MonsterStatusEffect> getStati() {
|
public Map<MonsterStatus, MonsterStatusEffect> getStati() {
|
||||||
return stati;
|
statiLock.lock();
|
||||||
|
try {
|
||||||
|
return Collections.unmodifiableMap(stati);
|
||||||
|
} finally {
|
||||||
|
statiLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MonsterStatusEffect getStati(MonsterStatus ms) {
|
||||||
|
statiLock.lock();
|
||||||
|
try {
|
||||||
|
return stati.get(ms);
|
||||||
|
} finally {
|
||||||
|
statiLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- one can always have fun trying these pieces of codes below in-game rofl ----
|
// ---- one can always have fun trying these pieces of codes below in-game rofl ----
|
||||||
@@ -985,7 +1199,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
|
|
||||||
public final void setOverrideStats(final OverrideMonsterStats ostats) {
|
public final void setOverrideStats(final OverrideMonsterStats ostats) {
|
||||||
this.ostats = new ChangeableStats(stats, ostats);
|
this.ostats = new ChangeableStats(stats, ostats);
|
||||||
this.hp = ostats.getHp();
|
this.hp.set(ostats.getHp());
|
||||||
this.mp = ostats.getMp();
|
this.mp = ostats.getMp();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -998,7 +1212,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.ostats = new ChangeableStats(stats, newLevel, pqMob);
|
this.ostats = new ChangeableStats(stats, newLevel, pqMob);
|
||||||
this.hp = ostats.getHp();
|
this.hp.set(ostats.getHp());
|
||||||
this.mp = ostats.getMp();
|
this.mp = ostats.getMp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -515,9 +515,9 @@ public class MapleMap {
|
|||||||
byte d = 1;
|
byte d = 1;
|
||||||
Point pos = new Point(0, mob.getPosition().y);
|
Point pos = new Point(0, mob.getPosition().y);
|
||||||
|
|
||||||
Map<MonsterStatus, MonsterStatusEffect> stati = mob.getStati();
|
MonsterStatusEffect stati = mob.getStati(MonsterStatus.SHOWDOWN);
|
||||||
if (stati.containsKey(MonsterStatus.SHOWDOWN)) {
|
if (stati != null) {
|
||||||
chRate *= (stati.get(MonsterStatus.SHOWDOWN).getStati().get(MonsterStatus.SHOWDOWN).doubleValue() / 100.0 + 1.0);
|
chRate *= (stati.getStati().get(MonsterStatus.SHOWDOWN).doubleValue() / 100.0 + 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
final MapleMonsterInformationProvider mi = MapleMonsterInformationProvider.getInstance();
|
final MapleMonsterInformationProvider mi = MapleMonsterInformationProvider.getInstance();
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package tools;
|
package tools;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
import java.sql.DriverManager;
|
import java.sql.DriverManager;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import com.zaxxer.hikari.HikariConfig;
|
import com.zaxxer.hikari.HikariConfig;
|
||||||
@@ -18,13 +20,51 @@ public class DatabaseConnection {
|
|||||||
|
|
||||||
public static Connection getConnection() throws SQLException {
|
public static Connection getConnection() throws SQLException {
|
||||||
if(ds != null) {
|
if(ds != null) {
|
||||||
|
try {
|
||||||
return ds.getConnection();
|
return ds.getConnection();
|
||||||
} else {
|
} catch (SQLException sqle) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
int denies = 0;
|
||||||
|
while(true) { // There is no way it can pass with a null out of here
|
||||||
|
try {
|
||||||
return DriverManager.getConnection(ServerConstants.DB_URL, ServerConstants.DB_USER, ServerConstants.DB_PASS);
|
return DriverManager.getConnection(ServerConstants.DB_URL, ServerConstants.DB_USER, ServerConstants.DB_PASS);
|
||||||
|
} catch (SQLException sqle) {
|
||||||
|
denies++;
|
||||||
|
|
||||||
|
if(denies == 3) {
|
||||||
|
// Give up, return null :3
|
||||||
|
FilePrinter.printError(FilePrinter.SQL_EXCEPTION, "SQL Driver refused to give a connection after " + denies + " tries.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getNumberOfAccounts() {
|
||||||
|
try {
|
||||||
|
Connection con = DriverManager.getConnection(ServerConstants.DB_URL, ServerConstants.DB_USER, ServerConstants.DB_PASS);
|
||||||
|
try (PreparedStatement ps = con.prepareStatement("SELECT count(*) FROM accounts")) {
|
||||||
|
try (ResultSet rs = ps.executeQuery()) {
|
||||||
|
rs.next();
|
||||||
|
return rs.getInt(1);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
con.close();
|
||||||
|
}
|
||||||
|
} catch(SQLException sqle) {
|
||||||
|
return 20;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DatabaseConnection() {
|
public DatabaseConnection() {
|
||||||
|
try {
|
||||||
|
Class.forName("com.mysql.jdbc.Driver"); // touch the mysql driver
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
System.out.println("[SEVERE] SQL Driver Not Found. Consider death by clams.");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
ds = null;
|
ds = null;
|
||||||
|
|
||||||
if(ServerConstants.DB_EXPERIMENTAL_POOL) {
|
if(ServerConstants.DB_EXPERIMENTAL_POOL) {
|
||||||
@@ -36,22 +76,18 @@ public class DatabaseConnection {
|
|||||||
config.setUsername(ServerConstants.DB_USER);
|
config.setUsername(ServerConstants.DB_USER);
|
||||||
config.setPassword(ServerConstants.DB_PASS);
|
config.setPassword(ServerConstants.DB_PASS);
|
||||||
|
|
||||||
config.addDataSourceProperty("connectionTimeout", "30000");
|
int poolSize = getNumberOfAccounts() * 10; // make sure pool size is comfortable for the worst case scenario
|
||||||
config.addDataSourceProperty("maximumPoolSize", "100");
|
if(poolSize < 100) poolSize = 100;
|
||||||
|
else if(poolSize > 10000) poolSize = 10000;
|
||||||
|
|
||||||
config.addDataSourceProperty("cachePrepStmts", "true");
|
config.setConnectionTimeout(30 * 1000);
|
||||||
config.addDataSourceProperty("prepStmtCacheSize", "250");
|
config.setMaximumPoolSize(poolSize);
|
||||||
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
|
|
||||||
|
config.addDataSourceProperty("cachePrepStmts", true);
|
||||||
|
config.addDataSourceProperty("prepStmtCacheSize", 250);
|
||||||
|
config.addDataSourceProperty("prepStmtCacheSqlLimit", 2048);
|
||||||
|
|
||||||
ds = new HikariDataSource(config);
|
ds = new HikariDataSource(config);
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
Class.forName("com.mysql.jdbc.Driver"); // touch the mysql driver
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
System.out.println("[SEVERE] SQL Driver Not Found. Consider death by clams.");
|
|
||||||
e.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ public class FilePrinter {
|
|||||||
ERROR38 = "error38.txt",
|
ERROR38 = "error38.txt",
|
||||||
PACKET_LOG = "log.txt",
|
PACKET_LOG = "log.txt",
|
||||||
EXCEPTION = "exceptions.txt",
|
EXCEPTION = "exceptions.txt",
|
||||||
|
SQL_EXCEPTION = "sqlexceptions.txt",
|
||||||
PACKET_HANDLER = "PacketHandler/",
|
PACKET_HANDLER = "PacketHandler/",
|
||||||
PORTAL = "portals/",
|
PORTAL = "portals/",
|
||||||
NPC = "npcs/",
|
NPC = "npcs/",
|
||||||
|
|||||||
Reference in New Issue
Block a user