package client;
import constants.GameConstants;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import provider.MapleData;
import provider.MapleDataTool;
import server.MapleStatEffect;
import server.Randomizer;
import server.life.Element;
import tools.Pair;
public class Skill implements Comparator<Skill> {
private String name = "", psdDamR = "", targetPlus = "";
private final List<MapleStatEffect> effects = new ArrayList<>();
private List<MapleStatEffect> pvpEffects = null;
private List<Integer> animation = null;
private final List<Pair<String, Integer>> requiredSkill = new ArrayList<>();
private Element element = Element.NEUTRAL;
private int id, animationTime = 0, masterLevel = 0, maxLevel = 0, delay = 0, trueMax = 0, eventTamingMob = 0, skillTamingMob = 0, skillType = 0, psd = 0, psdSkill = 0; //4 is alert
private boolean invisible = false, chargeskill = false, timeLimited = false, combatOrders = false, pvpDisabled = false, magic = false, casterMove = false, pushTarget = false, pullTarget = false;
private int hyper = 0;
public Skill(final int id) {
super();
this.id = id;
}
public void setName(final String name) {
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public static Skill loadFromData(final int id, final MapleData data, final MapleData delayData) {
Skill ret = new Skill(id);
boolean isBuff;
final int skillType = MapleDataTool.getInt("skillType", data, -1);
final String elem = MapleDataTool.getString("elemAttr", data, null);
if (elem != null) {
ret.element = Element.getFromChar(elem.charAt(0));
}
ret.skillType = skillType;
ret.invisible = MapleDataTool.getInt("invisible", data, 0) > 0;
ret.timeLimited = MapleDataTool.getInt("timeLimited", data, 0) > 0;
ret.combatOrders = MapleDataTool.getInt("combatOrders", data, 0) > 0;
ret.hyper = MapleDataTool.getInt("hyper", data, 0);
ret.masterLevel = MapleDataTool.getInt("masterLevel", data, 0);
ret.psd = MapleDataTool.getInt("psd", data, 0);
if(ret.psd == 1){
final MapleData psdskill = data.getChildByPath("psdSkill");
if (psdskill != null)
{
ret.psdSkill = Integer.parseInt(data.getChildByPath("psdSkill").getChildren().get(0).getName());
}
}
if ((id == 22111001 || id == 22140000 || id == 22141002)) {
ret.masterLevel = 5; //hack
}
ret.eventTamingMob = MapleDataTool.getInt("eventTamingMob", data, 0);
ret.skillTamingMob = MapleDataTool.getInt("skillTamingMob", data, 0);
final MapleData inf = data.getChildByPath("info");
if (inf != null) {
ret.pvpDisabled = MapleDataTool.getInt("pvp", inf, 1) <= 0;
ret.magic = MapleDataTool.getInt("magicDamage", inf, 0) > 0;
ret.casterMove = MapleDataTool.getInt("casterMove", inf, 0) > 0;
ret.pushTarget = MapleDataTool.getInt("pushTarget", inf, 0) > 0;
ret.pullTarget = MapleDataTool.getInt("pullTarget", inf, 0) > 0;
}
final MapleData effect = data.getChildByPath("effect");
if (skillType == 2) {
isBuff = true;
} else if (skillType == 3) { //final attack
ret.animation = new ArrayList<>();
ret.animation.add(0);
isBuff = effect != null;
} else {
MapleData action_ = data.getChildByPath("action");
final MapleData hit = data.getChildByPath("hit");
final MapleData ball = data.getChildByPath("ball");
boolean action = false;
if (action_ == null) {
if (data.getChildByPath("prepare/action") != null) {
action_ = data.getChildByPath("prepare/action");
action = true;
}
}
isBuff = effect != null && hit == null && ball == null;
if (action_ != null) {
String d;
if (action) { //prepare
d = MapleDataTool.getString(action_, null);
} else {
d = MapleDataTool.getString("0", action_, null);
}
if (d != null) {
isBuff |= d.equals("alert2");
final MapleData dd = delayData.getChildByPath(d);
if (dd != null) {
for (MapleData del : dd) {
ret.delay += Math.abs(MapleDataTool.getInt("delay", del, 0));
}
if (ret.delay > 30) {
ret.delay = (int) Math.round(ret.delay * 11.0 / 16.0);
ret.delay -= (ret.delay % 30);
}
}
if (SkillFactory.getDelay(d) != null) { //this should return true always
ret.animation = new ArrayList<>();
ret.animation.add(SkillFactory.getDelay(d));
if (!action) {
for (MapleData ddc : action_) {
if (!MapleDataTool.getString(ddc, d).equals(d)) {
String c = MapleDataTool.getString(ddc);
if (SkillFactory.getDelay(c) != null) {
ret.animation.add(SkillFactory.getDelay(c));
}
}
}
}
}
}
}
switch (id) {
case 1076:
case 11076:
case 2111002:
case 2111003:
case 2121001:
case 2221001:
case 2301002:
case 2321001:
case 4211001:
case 12111005:
case 22161003:
isBuff = false;
break;
case 93:
case 1004:
case 4121054:
case 1026:
case 1111002:
case 65111100:
case 1111007:
case 1211009:
case 4341054:
case 1220013:
case 5321054:
case 1311007:
case 1320009:
case 2120010:
case 2121009:
case 4341052:
case 31201002:
case 31001001:
case 2220010:
case 2221009:
case 2311006:
case 2320011:
case 2321010:
case 3120006:
case 3121002:
case 3220005:
case 3221002:
case 4111001:
case 4111009:
case 4211003:
case 4221013:
case 4321000:
case 4331003:
case 4341002:
case 5110001:
case 5111005:
case 5111007:
case 5120011:
case 5120012:
case 5121003:
case 5121009:
case 5121015:
case 5211001:
case 5211002:
case 5211006:
case 5211007:
case 5211009:
case 5220002:
case 5220011:
case 5220012:
case 5311004:
case 5311005:
case 5320007:
case 5321003:
case 5321004:
case 5701005:
case 5711001:
case 5711011:
case 5720005:
case 5721002:
case 9001004:
case 9101004:
case 10000093:
case 10001004:
case 10001026:
case 13111005:
case 14111007:
case 15100004:
case 15101006:
case 15111002:
case 15111005:
case 15111006:
case 15111011:
case 20000093:
case 20001004:
case 20001026:
case 20010093:
case 20011004:
case 20011026:
case 20020093:
case 20021026:
case 20031209:
case 20031210:
case 21000000:
case 21101003:
case 22121001:
case 22131001:
case 22131002:
case 22141002:
case 22151002:
case 22151003:
case 22161002:
case 22161004:
case 22171000:
case 22171004:
case 22181000:
case 22181003:
case 22181004:
case 24101005:
case 24111002:
case 24121008:
case 24121009:
case 27101202:
case 27110007:
case 30000093:
case 30001026:
case 30010093:
case 30011026:
case 31121005:
case 32001003:
case 32101003:
case 32110000:
case 32110007:
case 32110008:
case 32110009:
case 32111005:
case 32111006:
case 32111012:
case 32120000:
case 32120001:
case 32121003:
case 33101006:
case 33111003:
case 35001001:
case 35001002:
case 35101005:
case 35101007:
case 35101009:
case 35111001:
case 35111002:
case 35111004:
case 35111005:
case 35111009:
case 35111010:
case 35111011:
case 35111013:
case 35120000:
case 35120014:
case 35121003:
case 35121005:
case 35121006:
case 35121009:
case 35121010:
case 35121013:
case 36111006:
case 41001001:
case 41121003:
case 42100010:
case 42101002:
case 42101004:
case 42111006:
case 42121008:
case 50001214:
case 51101003:
case 51111003:
case 51111004:
case 51121004:
case 51121005:
case 60001216:
case 61100005:
case 60001217:
case 61101002:
case 61111008://Kaiser mode
case 61120007:
case 61120008://Kaiser mode
case 61121053://Kaiser Hyper Mode
case 61121054://Kaiser's Majesty
case 61120011:
case 80001000:
case 80001089:
case 31211003:
case 31221004:
case 32121054:
case 2121054:
case 11101021:
case 13111024:
case 2321054:
case 11101022: //polling moon
case 11111022:
case 36121054:
case 31011001:
case 31211004:
case 32121006:
case 3101004:
case 3201004:
case 5001005:
case 5220014://dice2 cosair
case 15001003:
case 5111010:
case 80001079:
case 80001080:
case 80001081:
// case 33001001:
case 1101013:
case 36121003:
case 33111006:
case 35111016:
case 33111007:
case 61111004:
case 24121054:
case 80001155:
case 31221054:
case 5721054:
case 5721052:
// case 27121005:
case 27001004: // 익스텐드 마나
case 27100003: // 블레스 오브 다크니스
// case 27101202: // 보이드 프레셔
case 27111004: // 안티 매직쉘
case 27111005: // 라이트쉐도우 가드
case 27111006: // 포틱 메디테이션
// case 27110007: // 라이프 타이달
case 27121006: // 다크니스 소서리
case 27111202: // 녹스피어
case 27121202: // 아포칼립스
case 27101100: // 실피드 랜서
case 27111100: // 스펙트럴 라이트
case 27121100: // 라이트 리플렉션
case 27111303: // 데스 사이드
case 27121303: // 앱솔루트 킬
case 27121054: // 메모라이즈
case 42101020:
case 42101021:
case 42101022:
case 42101023:
case 36121013:
case 36121014:
case 36121002:
// case 15001022:
// case 1301013:
case 1321015:
case 20041239:
isBuff = true;
}
if (GameConstants.isAngel(id)/* || GameConstants.isSummon(id)*/) {
isBuff = false;
}
}
ret.chargeskill = data.getChildByPath("keydown") != null;
final MapleData level = data.getChildByPath("common");
if (level != null) {
ret.maxLevel = MapleDataTool.getInt("maxLevel", level, 1); //10 just a failsafe, shouldn't actually happens
ret.psdDamR = MapleDataTool.getString("damR", level, ""); //for the psdSkill tag
ret.targetPlus = MapleDataTool.getString("targetPlus", level, "");
ret.trueMax = ret.maxLevel + (ret.combatOrders ? 2 : 0);
for (int i = 1; i <= ret.trueMax; i++) {
ret.effects.add(MapleStatEffect.loadSkillEffectFromData(level, id, isBuff, i, "x"));
}
} else {
for (final MapleData leve : data.getChildByPath("level")) {
ret.effects.add(MapleStatEffect.loadSkillEffectFromData(leve, id, isBuff, Byte.parseByte(leve.getName()), null));
}
ret.maxLevel = ret.effects.size();
ret.trueMax = ret.effects.size();
}
final MapleData level2 = data.getChildByPath("PVPcommon");
if (level2 != null) {
ret.pvpEffects = new ArrayList<>();
for (int i = 1; i <= ret.trueMax; i++) {
ret.pvpEffects.add(MapleStatEffect.loadSkillEffectFromData(level2, id, isBuff, i, "x"));
}
}
final MapleData reqDataRoot = data.getChildByPath("req");
if (reqDataRoot != null) {
for (final MapleData reqData : reqDataRoot.getChildren()) {
ret.requiredSkill.add(new Pair<>(reqData.getName(), MapleDataTool.getInt(reqData, 1)));
}
}
ret.animationTime = 0;
if (effect != null) {
for (final MapleData effectEntry : effect) {
ret.animationTime += MapleDataTool.getIntConvert("delay", effectEntry, 0);
}
}
return ret;
}
public MapleStatEffect getEffect(final int level) {
if (effects.size() < level) {
if (effects.size() > 0) { //incAllskill
return effects.get(effects.size() - 1);
}
return null;
} else if (level <= 0) {
return effects.get(0);
}
return effects.get(level - 1);
}
public MapleStatEffect getPVPEffect(final int level) {
if (pvpEffects == null) {
return getEffect(level);
}
if (pvpEffects.size() < level) {
if (pvpEffects.size() > 0) { //incAllskill
return pvpEffects.get(pvpEffects.size() - 1);
}
return null;
} else if (level <= 0) {
return pvpEffects.get(0);
}
return pvpEffects.get(level - 1);
}
public int getSkillType() {
return skillType;
}
public List<Integer> getAllAnimation() {
return animation;
}
public int getAnimation() {
if (animation == null) {
return -1;
}
return (animation.get(Randomizer.nextInt(animation.size()))).intValue();
}
public boolean isPVPDisabled() {
return pvpDisabled;
}
public boolean isChargeSkill() {
return chargeskill;
}
public boolean isInvisible() {
return invisible;
}
public boolean hasRequiredSkill() {
return requiredSkill.size() > 0;
}
public int getPsdSkill(){
return psdSkill;
}
public int getPsd(){
return psd;
}
public String getPsdDamR(){
return psdDamR;
}
public String getPsdtarget() {
return targetPlus;
}
public List<Pair<String, Integer>> getRequiredSkills() {
return requiredSkill;
}
public int getMaxLevel() {
return maxLevel;
}
public int getTrueMax() {
return trueMax;
}
public boolean combatOrders() {
return combatOrders;
}
public boolean canBeLearnedBy(int job) { //test
// if (GameConstants.getBeginnerJob((short) (id / 10000)) == GameConstants.getBeginnerJob((short) job))
// return true;
int jid = job;
int skillForJob = id / 10000;
if (skillForJob == 2001) {
return GameConstants.isEvan(job); //special exception for beginner -.-
} else if (skillForJob == 0) {
return GameConstants.isAdventurer(job); //special exception for beginner
} else if (skillForJob == 1000) {
return GameConstants.isKOC(job); //special exception for beginner
} else if (skillForJob == 2000) {
return GameConstants.isAran(job); //special exception for beginner
} else if (skillForJob == 3000) {
return GameConstants.isResistance(job); //special exception for beginner
} else if (skillForJob == 1) {
return GameConstants.isCannon(job); //special exception for beginner
} else if (skillForJob == 3001) {
return GameConstants.isDemonSlayer(job) || GameConstants.isDemonAvenger(job); //special exception for beginner
} else if (skillForJob == 2002) {
return GameConstants.isMercedes(job); //special exception for beginner
} else if (skillForJob == 508) {
return GameConstants.isJett(job); //special exception for beginner
} else if (skillForJob == 2003) {
return GameConstants.isPhantom(job); //special exception for beginner
} else if (skillForJob == 5000) {
return GameConstants.isMihile(job); //special exception for beginner
} else if (skillForJob == 2004) {
return GameConstants.isLuminous(job); //special exception for beginner
} else if (skillForJob == 6000) {
return GameConstants.isKaiser(job); //special exception for beginner
} else if (skillForJob == 6001) {
return GameConstants.isAngelicBuster(job); //special exception for beginner
} else if (skillForJob == 3002) {
return GameConstants.isXenon(job); //special exception for beginner
}else if (skillForJob == 10000) {
return GameConstants.isZero(job); //special exception for beginner
} else if (jid / 100 != skillForJob / 100) { // wrong job
return false;
} else if (jid / 1000 != skillForJob / 1000) { // wrong job
return false;
} else if (GameConstants.isDemonAvenger(skillForJob) && !GameConstants.isDemonAvenger(job)) {
return false;
} else if (GameConstants.isXenon(skillForJob) && !GameConstants.isXenon(job)) {
return false;
} else if (GameConstants.isZero(skillForJob) && !GameConstants.isZero(job)) {
return false;
//} else if (GameConstants.isBeastTamer(skillForJob) && !GameConstants.isBeastTamer(job)) {
// return false;
} else if (GameConstants.isAngelicBuster(skillForJob) && !GameConstants.isAngelicBuster(job)) {
return false;
} else if (GameConstants.isKaiser(skillForJob) && !GameConstants.isKaiser(job)) {
return false;
} else if (GameConstants.isMihile(skillForJob) && !GameConstants.isMihile(job)) {
return false;
} else if (GameConstants.isLuminous(skillForJob) && !GameConstants.isLuminous(job)) {
return false;
} else if (GameConstants.isPhantom(skillForJob) && !GameConstants.isPhantom(job)) {
return false;
} else if (GameConstants.isJett(skillForJob) && !GameConstants.isJett(job)) {
return false;
} else if (GameConstants.isCannon(skillForJob) && !GameConstants.isCannon(job)) {
return false;
} else if (GameConstants.isDemonSlayer(skillForJob) && !GameConstants.isDemonSlayer(job)) {
return false;
} else if (GameConstants.isAdventurer(skillForJob) && !GameConstants.isAdventurer(job)) {
return false;
} else if (GameConstants.isKOC(skillForJob) && !GameConstants.isKOC(job)) {
return false;
} else if (GameConstants.isAran(skillForJob) && !GameConstants.isAran(job)) {
return false;
} else if (GameConstants.isEvan(skillForJob) && !GameConstants.isEvan(job)) {
return false;
} else if (GameConstants.isMercedes(skillForJob) && !GameConstants.isMercedes(job)) {
return false;
} else if (GameConstants.isResistance(skillForJob) && !GameConstants.isResistance(job)) {
return false;
} else if ((job / 10) % 10 == 0 && (skillForJob / 10) % 10 > (job / 10) % 10) { // wrong 2nd job
return false;
} else if ((skillForJob / 10) % 10 != 0 && (skillForJob / 10) % 10 != (job / 10) % 10) { //wrong 2nd job
return false;
} else if (skillForJob % 10 > job % 10) { // wrong 3rd/4th job
return false;
}
return true;
}
public boolean isTimeLimited() {
return timeLimited;
}
public boolean isFourthJobSkill(int skillid) {
switch (skillid / 10000) {
case 112:
case 122:
case 132:
case 212:
case 222:
case 232:
case 312:
case 322:
case 412:
case 422:
case 512:
case 522:
return true;
}
return false;
}
public boolean isThirdJobSkill(int skillid) {
switch (skillid / 10000) {
case 111:
case 121:
case 131:
case 211:
case 221:
case 231:
case 311:
case 321:
case 411:
case 421:
case 511:
case 521:
return true;
}
return false;
}
public boolean isSecondJobSkill(int skillid) {
switch (skillid / 10000) {
case 110:
case 120:
case 130:
case 210:
case 220:
case 230:
case 310:
case 320:
case 410:
case 420:
case 510:
case 520:
return true;
}
return false;
}
public boolean isFourthJob() {
switch (id) { // I guess imma make an sql table to store these, so that we could max them all out.
case 3120011:
case 3220010:
case 4320005:
case 4340010:
case 5120012:
case 5211009:
case 5220014:
case 5320007:
case 5321006:
case 5720008:
case 21120011:
case 22181004:
case 23120011:
case 23121008:
case 33120010:
case 33121005:
case 1001008:
return false;
}
if (isHyper()) {
return true;
}
if ((this.id / 10000 == 2312) || (this.id / 10000 == 2712) || (this.id / 10000 == 6112) || (this.id / 10000 == 6512)) {
return true;
}
if ((this.id == 24121009) || (this.id == 24121010)) {
return true;
}
if ((this.id / 10000 == 3612) && (getMasterLevel() >= 10)) {
return true;
}
if ((getMaxLevel() <= 15 && !invisible && getMasterLevel() <= 0)) {
return false;
}
if (id / 10000 >= 2210 && id / 10000 < 3000) { //evan skill
return ((id / 10000) % 10) >= 7 || getMasterLevel() > 0;
}
if (id / 10000 >= 430 && id / 10000 <= 434) { //db skill
return ((id / 10000) % 10) == 4 || getMasterLevel() > 0;
}
if (id / 10000 >= 400 && id / 10000 <= 412) { //nl skill
return ((id / 10000) % 10) == 4 || getMasterLevel() > 0;
}
return ((id / 10000) % 10) == 2 && id < 90000000 && !isBeginnerSkill();
}
public Element getElement() {
return element;
}
public int getAnimationTime() {
return animationTime;
}
public int getMasterLevel() {
return masterLevel;
}
public int getDelay() {
return delay;
}
public int getTamingMob() {
return eventTamingMob;
}
public int getSkillTamingMob() {
return eventTamingMob;
}
public boolean isBeginnerSkill() {
int jobId = id / 10000;
return GameConstants.isBeginnerJob(jobId);
}
public boolean isMagic() {
return magic;
}
public boolean isHyper() {
return hyper > 0;
}
public int getHyper() {
return hyper;
}
public boolean isMovement() {
return casterMove;
}
public boolean isPush() {
return pushTarget;
}
public boolean isPull() {
return pullTarget;
}
public boolean isSpecialSkill() {
int jobId = id / 10000;
return jobId == 900 || jobId == 800 || jobId == 9000 || jobId == 9200 || jobId == 9201 || jobId == 9202 || jobId == 9203 || jobId == 9204;
}
@Override
public int compare(Skill o1, Skill o2) {
return (Integer.valueOf(o1.getId()).compareTo(Integer.valueOf(o2.getId())));
}
}