/*
* This file is part of the OdinMS Maple Story Server Copyright (C) 2008 ~ 2010
* Patrick Huy <patrick.huy@frz.cc> Matthias Butz <matze@odinms.de> Jan
* Christian Meyer <vimes@odinms.de>
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by
* the Free Software Foundation. You may not use, modify or distribute this
* program under any other version of the GNU Affero General Public License.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package javastory.game.data;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javastory.game.BanishInfo;
import javastory.game.AttackNature;
import javastory.game.Effectiveness;
import javastory.game.SkillLevelEntry;
import javastory.wz.WzData;
import javastory.wz.WzDataProvider;
import javastory.wz.WzDataProviderFactory;
import javastory.wz.WzDataTool;
import javastory.wz.WzDataType;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
public final class MobInfo {
private static final WzDataProvider stringRoot = WzDataProviderFactory.getDataProvider("String.wz");
private static final WzData mobStrings = stringRoot.getData("Mob.img");
private final int mobId;
private final byte cp;
private byte selfDestruction_action;
private byte tagColor;
private byte tagBgColor;
private final byte rareItemDropLevel;
private final byte hpDisplayType;
private final short level, physicalDefense, magicDefense, evasion;
private final int exp, hp, mp, removeAfter, buffToGive, fixedDamage;
private int selfDestruction_hp;
private final boolean boss, undead, isFreeForAllLoot;
private boolean firstAttack;
private final boolean isExplosiveReward;
private final boolean mobile;
private final boolean fly;
private final boolean onlyNormalAttack;
private final boolean friendly;
private final String name;
private final Map<AttackNature, Effectiveness> effectiveness;
private List<Integer> revives = Lists.newArrayList();
private final List<SkillLevelEntry> skills = Lists.newArrayList();
private BanishInfo banish;
public MobInfo(final int mobId, final WzData data, final WzData linkedData) {
WzData info = data.getChildByPath("info");
this.mobId = mobId;
this.hp = WzDataTool.getIntConvert("maxHP", info);
this.mp = WzDataTool.getIntConvert("maxMP", info, 0);
this.exp = WzDataTool.getIntConvert("exp", info, 0);
this.level = (short) WzDataTool.getIntConvert("level", info);
this.removeAfter = WzDataTool.getIntConvert("removeAfter", info, 0);
this.rareItemDropLevel = (byte) WzDataTool.getIntConvert("rareItemDropLevel", info, 0);
this.fixedDamage = WzDataTool.getIntConvert("fixedDamage", info, -1);
this.onlyNormalAttack = WzDataTool.getIntConvert("onlyNormalAttack", info, 0) > 0;
this.boss = WzDataTool.getIntConvert("boss", info, 0) > 0 || this.mobId == 8810018 || this.mobId == 9410066;
this.isExplosiveReward = WzDataTool.getIntConvert("explosiveReward", info, 0) > 0;
this.isFreeForAllLoot = WzDataTool.getIntConvert("publicReward", info, 0) > 0;
this.undead = WzDataTool.getIntConvert("undead", info, 0) > 0;
this.name = WzDataTool.getString(this.mobId + "/name", mobStrings, "MISSINGNO");
this.buffToGive = WzDataTool.getIntConvert("buff", info, -1);
this.friendly = WzDataTool.getIntConvert("damagedByMob", info, 0) > 0;
this.cp = (byte) WzDataTool.getIntConvert("getCP", info, 0);
this.physicalDefense = (short) WzDataTool.getIntConvert("PDDamage", info, 0);
this.magicDefense = (short) WzDataTool.getIntConvert("MDDamage", info, 0);
this.evasion = (short) WzDataTool.getIntConvert("eva", info, 0);
final WzData selfd = info.getChildByPath("selfDestruction");
if (selfd != null) {
this.selfDestruction_hp = WzDataTool.getIntConvert("hp", selfd, 0);
this.selfDestruction_action = (byte) WzDataTool.getIntConvert("action", selfd, -1);
} else {
this.selfDestruction_action = (byte) -1;
}
final WzData firstAttackData = info.getChildByPath("firstAttack");
if (firstAttackData != null) {
if (firstAttackData.getType() == WzDataType.FLOAT) {
this.firstAttack = Math.round(WzDataTool.getFloat(firstAttackData)) > 0;
} else {
this.firstAttack = WzDataTool.getInt(firstAttackData) > 0;
}
}
if (this.isBoss() || isDamageSponge(this.mobId)) {
if (info.getChildByPath("hpTagColor") == null || info.getChildByPath("hpTagBgcolor") == null) {
this.tagColor = (byte) 0;
this.tagBgColor = (byte) 0;
} else {
this.tagColor = (byte) WzDataTool.getIntConvert("hpTagColor", info);
this.tagBgColor = (byte) WzDataTool.getIntConvert("hpTagBgcolor", info);
}
}
final WzData banishData = info.getChildByPath("ban");
if (banishData != null) {
this.banish = new BanishInfo(WzDataTool.getString("banMsg", banishData), WzDataTool.getInt("banMap/0/field", banishData, -1), WzDataTool.getString(
"banMap/0/portal", banishData, "sp"));
}
final WzData reviveInfo = info.getChildByPath("revive");
if (reviveInfo != null) {
final List<Integer> revives = Lists.newLinkedList();
for (final WzData bdata : reviveInfo) {
revives.add(WzDataTool.getInt(bdata));
}
this.revives = revives;
}
final WzData monsterSkillData = info.getChildByPath("skill");
if (monsterSkillData != null) {
int i = 0;
final List<SkillLevelEntry> skills = Lists.newArrayList();
while (monsterSkillData.getChildByPath(Integer.toString(i)) != null) {
final int skill = WzDataTool.getInt(i + "/skill", monsterSkillData, 0);
final int level = WzDataTool.getInt(i + "/level", monsterSkillData, 0);
skills.add(new SkillLevelEntry(skill, level));
i++;
}
for (final SkillLevelEntry skill : skills) {
this.skills.add(skill);
}
}
final String elementString = WzDataTool.getString("elemAttr", info, "");
this.effectiveness = Effectiveness.fromString(elementString);
// Other data which isn't in the mob, but might in the linked data
if (linkedData != null) {
info = linkedData.getChildByPath("info");
}
this.mobile = info.getChildByPath("move") != null;
this.fly = info.getChildByPath("fly") != null;
// TS TODO: Make fun of the person who wrote this:
// OUTER:
// for (WzData idata : data) {
// switch (idata.getName()) {
// case "fly":
// this.fly = true;
// this.mobile = true;
// break OUTER;
// case "move":
// this.mobile = true;
// break;
// }
// }
byte hpDisplayType = -1;
if (this.getTagColor() > 0) {
hpDisplayType = 0;
} else if (this.isFriendly()) {
hpDisplayType = 1;
} else if (this.mobId >= 9300184 && this.mobId <= 9300215) {
// Mulung TC mobs
hpDisplayType = 2;
} else if (!this.isBoss() || this.mobId == 9410066) {
// Not boss and dong dong chiang
hpDisplayType = 3;
}
this.hpDisplayType = hpDisplayType;
}
private static boolean isDamageSponge(final int lifeId) {
switch (lifeId) {
case 8810018:
case 8820010:
case 8820011:
case 8820012:
case 8820013:
case 8820014:
return true;
}
return false;
}
public int getExp() {
return this.exp;
}
public int getHp() {
return this.hp;
}
public int getMp() {
return this.mp;
}
public short getLevel() {
return this.level;
}
public byte getSelfD() {
return this.selfDestruction_action;
}
public int getSelfDHp() {
return this.selfDestruction_hp;
}
public int getFixedDamage() {
return this.fixedDamage;
}
public short getPhysicalDefense() {
return this.physicalDefense;
}
public final short getMagicDefense() {
return this.magicDefense;
}
public final short getEvasion() {
return this.evasion;
}
public boolean getOnlyNoramlAttack() {
return this.onlyNormalAttack;
}
public BanishInfo getBanishInfo() {
return this.banish;
}
public int getRemoveAfter() {
return this.removeAfter;
}
public byte getRareItemDropLevel() {
return this.rareItemDropLevel;
}
public boolean isBoss() {
return this.boss;
}
public boolean isFreeForAllLoot() {
return this.isFreeForAllLoot;
}
public boolean isExplosiveReward() {
return this.isExplosiveReward;
}
public boolean getMobile() {
return this.mobile;
}
public boolean getFly() {
return this.fly;
}
public List<Integer> getRevives() {
return this.revives;
}
public boolean getUndead() {
return this.undead;
}
public ImmutableMap<AttackNature, Effectiveness> getEffectivenessMap() {
return ImmutableMap.copyOf(this.effectiveness);
}
public String getName() {
return this.name;
}
public byte getTagColor() {
return this.tagColor;
}
public byte getTagBgColor() {
return this.tagBgColor;
}
public List<SkillLevelEntry> getSkills() {
return Collections.unmodifiableList(this.skills);
}
public byte getNoSkills() {
return (byte) this.skills.size();
}
public boolean hasSkill(final int skillId, final int level) {
for (final SkillLevelEntry skill : this.skills) {
if (skill.skill == skillId && skill.level == level) {
return true;
}
}
return false;
}
public boolean isFirstAttack() {
return this.firstAttack;
}
public byte getCP() {
return this.cp;
}
public boolean isFriendly() {
return this.friendly;
}
public int getBuffToGive() {
return this.buffToGive;
}
public byte getHpDisplayType() {
return this.hpDisplayType;
}
public int getMobId() {
return this.mobId;
}
}