diff --git a/src/main/java/kinoko/database/cassandra/CassandraCharacterAccessor.java b/src/main/java/kinoko/database/cassandra/CassandraCharacterAccessor.java index cb27c8be..f37b05a2 100644 --- a/src/main/java/kinoko/database/cassandra/CassandraCharacterAccessor.java +++ b/src/main/java/kinoko/database/cassandra/CassandraCharacterAccessor.java @@ -56,7 +56,8 @@ private CharacterData loadCharacterData(Row row) { final SkillManager sm = new SkillManager(); final Map skillCooltimes = row.getMap(CharacterTable.SKILL_COOLTIMES, Integer.class, Instant.class); if (skillCooltimes != null) { - sm.getSkillCooltimes().putAll(skillCooltimes); + // Figure out stream + //TODO sm.getSkillCooltimes().putAll(skillCooltimes); } final List skillRecords = row.getList(CharacterTable.SKILL_RECORDS, SkillRecord.class); if (skillRecords != null) { diff --git a/src/main/java/kinoko/database/cassandra/codec/SkillRecordCodec.java b/src/main/java/kinoko/database/cassandra/codec/SkillRecordCodec.java index ef76a505..08760099 100644 --- a/src/main/java/kinoko/database/cassandra/codec/SkillRecordCodec.java +++ b/src/main/java/kinoko/database/cassandra/codec/SkillRecordCodec.java @@ -6,6 +6,7 @@ import com.datastax.oss.driver.api.core.type.codec.TypeCodec; import com.datastax.oss.driver.api.core.type.reflect.GenericType; import kinoko.database.cassandra.type.SkillRecordUDT; +import kinoko.meta.SkillId; import kinoko.world.skill.SkillRecord; public final class SkillRecordCodec extends MappingCodec { @@ -23,7 +24,7 @@ protected SkillRecord innerToOuter(UdtValue value) { if (value == null) { return null; } - final int skillId = value.getInt(SkillRecordUDT.SKILL_ID); + final SkillId skillId = SkillId.fromValue(value.getInt(SkillRecordUDT.SKILL_ID)); final SkillRecord sr = new SkillRecord(skillId); sr.setSkillLevel(value.getInt(SkillRecordUDT.SKILL_LEVEL)); sr.setMasterLevel(value.getInt(SkillRecordUDT.MASTER_LEVEL)); @@ -36,7 +37,7 @@ protected UdtValue outerToInner(SkillRecord sr) { return null; } return getCqlType().newValue() - .setInt(SkillRecordUDT.SKILL_ID, sr.getSkillId()) + .setInt(SkillRecordUDT.SKILL_ID, sr.getSkillId().getId()) .setInt(SkillRecordUDT.SKILL_LEVEL, sr.getSkillLevel()) .setInt(SkillRecordUDT.MASTER_LEVEL, sr.getMasterLevel()); } diff --git a/src/main/java/kinoko/handler/field/MobHandler.java b/src/main/java/kinoko/handler/field/MobHandler.java index f9cb35bb..d6640158 100644 --- a/src/main/java/kinoko/handler/field/MobHandler.java +++ b/src/main/java/kinoko/handler/field/MobHandler.java @@ -1,6 +1,7 @@ package kinoko.handler.field; import kinoko.handler.Handler; +import kinoko.meta.SkillId; import kinoko.packet.field.MobPacket; import kinoko.packet.user.UserLocal; import kinoko.packet.world.BroadcastPacket; @@ -238,9 +239,9 @@ public static void handleMobTimeBombEnd(User user, InPacket inPacket) { if (mob.getRelativeRect(SkillConstants.MONSTER_BOMB_RANGE).isInsideRect(x, y)) { final int damage = (int) Math.min(CalcDamage.calcDamageMax(user), user.getHp() - 100); user.addHp(-damage); - user.write(UserLocal.timeBombAttack(Thief.MONSTER_BOMB, mob.getX(), mob.getY(), 120, damage)); + user.write(UserLocal.timeBombAttack(SkillId.DB5_MONSTER_BOMB, mob.getX(), mob.getY(), 120, damage)); } else { - user.write(UserLocal.timeBombAttack(Thief.MONSTER_BOMB, mob.getX(), mob.getY(), 0, 0)); + user.write(UserLocal.timeBombAttack(SkillId.DB5_MONSTER_BOMB, mob.getX(), mob.getY(), 0, 0)); } } diff --git a/src/main/java/kinoko/handler/user/AttackHandler.java b/src/main/java/kinoko/handler/user/AttackHandler.java index fed6dbea..3f7e8127 100644 --- a/src/main/java/kinoko/handler/user/AttackHandler.java +++ b/src/main/java/kinoko/handler/user/AttackHandler.java @@ -1,6 +1,7 @@ package kinoko.handler.user; import kinoko.handler.Handler; +import kinoko.meta.SkillId; import kinoko.packet.field.MobPacket; import kinoko.packet.user.UserLocal; import kinoko.packet.user.UserRemote; @@ -77,7 +78,7 @@ public static void handlerUserMeleeAttack(User user, InPacket inPacket) { attack.mask = inPacket.decodeByte(); // nDamagePerMob | (16 * nMobCount) inPacket.decodeInt(); // ~pDrInfo.dr2 inPacket.decodeInt(); // ~pDrInfo.dr3 - attack.skillId = inPacket.decodeInt(); // nSkillID + attack.skillId = inPacket.decodeSkillId(); // nSkillID attack.combatOrders = inPacket.decodeByte(); // nCombatOrders inPacket.decodeInt(); // dwKey inPacket.decodeInt(); // Crc32 @@ -101,11 +102,11 @@ public static void handlerUserMeleeAttack(User user, InPacket inPacket) { attack.userX = inPacket.decodeShort(); // GetPos()->x attack.userY = inPacket.decodeShort(); // GetPos()->y - if (attack.skillId == NightWalker.POISON_BOMB) { + if (attack.skillId == SkillId.NW3_POISON_BOMB) { attack.grenadeX = inPacket.decodeShort(); // pGrenade->GetPos()->x attack.grenadeY = inPacket.decodeShort(); // pGrenade->GetPos()->y } - if (attack.skillId == Thief.MESO_EXPLOSION) { + if (attack.skillId == SkillId.CHIEFBANDIT_MESO_EXPLOSION) { // CUserLocal::DoActiveSkill_MesoExplosion final int size = inPacket.decodeByte(); attack.drops = new int[size]; @@ -133,7 +134,7 @@ public static void handlerUserShootAttack(User user, InPacket inPacket) { attack.mask = inPacket.decodeByte(); // nDamagePerMob | (16 * nMobCount) inPacket.decodeInt(); // ~pDrInfo.dr2 inPacket.decodeInt(); // ~pDrInfo.dr3 - attack.skillId = inPacket.decodeInt(); // nSkillID + attack.skillId = inPacket.decodeSkillId(); // nSkillID attack.combatOrders = inPacket.decodeByte(); // nCombatOrders inPacket.decodeInt(); // dwKey inPacket.decodeInt(); // Crc32 @@ -170,7 +171,7 @@ public static void handlerUserShootAttack(User user, InPacket inPacket) { } attack.ballStartX = inPacket.decodeShort(); // pt0.x attack.ballStartY = inPacket.decodeShort(); // pt0.y - if (attack.skillId == ThunderBreaker.SPARK) { + if (attack.skillId == SkillId.TB3_SPARK) { inPacket.decodeInt(); // tReserveSpark } @@ -191,7 +192,7 @@ public static void handlerUserMagicAttack(User user, InPacket inPacket) { attack.mask = inPacket.decodeByte(); // nDamagePerMob | (16 * nMobCount) inPacket.decodeInt(); // ~pDrInfo.dr2 inPacket.decodeInt(); // ~pDrInfo.dr3 - attack.skillId = inPacket.decodeInt(); // nSkillID + attack.skillId = inPacket.decodeSkillId(); // nSkillID attack.combatOrders = inPacket.decodeByte(); // nCombatOrders inPacket.decodeInt(); // dwKey inPacket.decodeInt(); // Crc32 @@ -241,7 +242,7 @@ public static void handlerUserBodyAttack(User user, InPacket inPacket) { attack.mask = inPacket.decodeByte(); // nDamagePerMob | (16 * nMobCount) inPacket.decodeInt(); // ~pDrInfo.dr2 inPacket.decodeInt(); // ~pDrInfo.dr3 - attack.skillId = inPacket.decodeInt(); // nSkillID + attack.skillId = inPacket.decodeSkillId(); // nSkillID attack.combatOrders = inPacket.decodeByte(); // nCombatOrders inPacket.decodeInt(); // dwKey inPacket.decodeInt(); // Crc32 @@ -278,7 +279,7 @@ private static void decodeMobAttackInfo(InPacket inPacket, Attack attack) { ai.hitY = inPacket.decodeShort(); // ptHit.y inPacket.decodeShort(); inPacket.decodeShort(); - if (attack.skillId == Thief.MESO_EXPLOSION) { + if (attack.skillId == SkillId.CHIEFBANDIT_MESO_EXPLOSION) { ai.attackCount = inPacket.decodeByte(); for (int j = 0; j < ai.attackCount; j++) { ai.damage[j] = inPacket.decodeInt(); @@ -306,27 +307,28 @@ private static void handleAttack(User user, Attack attack) { } // Set skill level - if (attack.skillId != 0) { + if (attack.skillId != SkillId.NONE) { attack.slv = user.getSkillLevel(attack.skillId); switch (attack.skillId) { - case Aran.FULL_SWING_DOUBLE_SWING, Aran.FULL_SWING_TRIPLE_SWING -> { - attack.slv = user.getSkillLevel(Aran.FULL_SWING); + case SkillId.ARAN3_HIDDEN_FULL_SWING_DOUBLE_SWING, SkillId.ARAN3_HIDDEN_FULL_SWING_TRIPLE_SWING -> { + attack.slv = user.getSkillLevel(SkillId.ARAN3_FULL_SWING); } - case Aran.OVER_SWING_DOUBLE_SWING, Aran.OVER_SWING_TRIPLE_SWING -> { - attack.slv = user.getSkillLevel(Aran.OVER_SWING); + case SkillId.ARAN4_HIDDEN_OVER_SWING_DOUBLE_SWING, SkillId.ARAN4_HIDDEN_OVER_SWING_TRIPLE_SWING -> { + attack.slv = user.getSkillLevel(SkillId.ARAN4_OVER_SWING); } - case Mechanic.ENHANCED_FLAME_LAUNCHER -> { - attack.slv = user.getSkillLevel(Mechanic.FLAME_LAUNCHER); + case SkillId.MECH2_ENHANCED_FLAME_LAUNCHER -> { + attack.slv = user.getSkillLevel(SkillId.MECH1_FLAME_LAUNCHER); } - case Mechanic.ENHANCED_GATLING_GUN -> { - attack.slv = user.getSkillLevel(Mechanic.GATLING_GUN); + case SkillId.MECH2_ENHANCED_GATLING_GUN -> { + attack.slv = user.getSkillLevel(SkillId.MECH1_GATLING_GUN); } - case 35111008, 35111009, 35111010 -> { - attack.slv = user.getSkillLevel(Mechanic.SATELLITE); - } - case 32001007, 32001008, 32001009, 32001010, 32001011 -> { - attack.slv = user.getSkillLevel(BattleMage.THE_FINISHER); + case SkillId.MECH3_SATELLITE_1, SkillId.MECH3_SATELLITE_2 -> { //TODO one satellite missing + attack.slv = user.getSkillLevel(SkillId.MECH3_SATELLITE); } + //TODO + /*case 32001007, 32001008, 32001009, 32001010, 32001011 -> { + attack.slv = user.getSkillLevel(SkillId.THE_FINISHER); + }*/ } if (attack.slv == 0) { log.error("Tried to attack with skill {} not learned by user", attack.skillId); @@ -385,7 +387,7 @@ private static void handleAttack(User user, Attack attack) { } attack.bulletItemId = bulletItem.getItemId(); // Consume bullet for basic attack - if (attack.skillId == 0) { + if (attack.skillId.isNone()) { final int bulletCount = attack.isShadowPartner() ? 2 : 1; if (bulletItem.getQuantity() < bulletCount) { log.error("Tried to attack without enough bullets in position {}", attack.bulletPosition); @@ -397,7 +399,7 @@ private static void handleAttack(User user, Attack attack) { } // Resolve swallow template ID - if (attack.skillId == WildHunter.JAGUAR_OSHI_ATTACK) { + if (attack.skillId == SkillId.WH2_JAGUAROSHI_2) { if (!user.getSecondaryStat().hasOption(CharacterTemporaryStat.Swallow_Template)) { log.error("Tried to attack with Jaguar-oshi without Swallow_Template CTS set"); return; @@ -407,7 +409,7 @@ private static void handleAttack(User user, Attack attack) { } // Process skill - if (attack.skillId != 0 && !SkillConstants.isNoConsumeAttack(attack.skillId)) { + if (!attack.skillId.isNone() && !SkillConstants.isNoConsumeAttack(attack.skillId)) { // Check skill cooltime and cost final SkillInfo si = SkillProvider.getSkillInfoById(attack.skillId).orElseThrow(); if (user.getSkillManager().hasSkillCooltime(attack.skillId)) { @@ -444,7 +446,7 @@ private static void handleAttack(User user, Attack attack) { } final int bulletCon = si.getBulletCon(attack.slv); if (bulletCon > 0) { - final int exJablinProp = user.getSkillStatValue(Thief.EXPERT_THROWING_STAR_HANDLING, SkillStat.prop); + final int exJablinProp = user.getSkillStatValue(SkillId.NIGHTLORD_EXPERT_THROWING_STAR_HANDLING, SkillStat.prop); final boolean exJablin = exJablinProp != 0 && Util.succeedProp(exJablinProp); if (exJablin) { user.write(UserLocal.requestExJablin()); @@ -497,7 +499,7 @@ private static void handleAttack(User user, Attack attack) { CalcDamage.calcPDamage(user, mob, attack, ai); } // Skill specific handling - if (attack.skillId != 0) { + if (!attack.skillId.isNone()) { SkillProcessor.processAttack(user, mob, attack, ai.delay); } // Process damage @@ -506,25 +508,25 @@ private static void handleAttack(User user, Attack attack) { // Handle skills handlePickpocket(user, attack, mob); handleOwlSpirit(user, attack, mob.getMaxHp() == totalDamage); - if (attack.skillId == Aran.COMBO_TEMPEST) { + if (attack.skillId == SkillId.ARAN4_COMBO_TEMPEST) { // client sends normal damage for bosses, normal mobs are set to 1 hp if (!mob.isBoss()) { totalDamage = mob.getHp() - 1; } - } else if (attack.skillId == Warrior.HEAVENS_HAMMER) { + } else if (attack.skillId == SkillId.PALADIN_HEAVENS_HAMMER) { // client sends 1 damage, calculate damage = Math.min(damage, mob.getHp() - 1) totalDamage = calculateHeavensHammer(user, mob); - } else if (attack.skillId == Thief.DRAIN || attack.skillId == NightWalker.VAMPIRE) { + } else if (attack.skillId == SkillId.ASSASSIN_DRAIN || attack.skillId == SkillId.NW2_VAMPIRE) { // cannot absorb more than half of your max hp or more than the enemy's max hp final int absorbAmount = totalDamage * user.getSkillStatValue(attack.skillId, SkillStat.x) / 100; hpGain += Math.min(Math.min(absorbAmount, user.getMaxHp() / 2), mob.getMaxHp()); - } else if (attack.skillId == WildHunter.SWIPE) { + } else if (attack.skillId == SkillId.WH3_SWIPE) { // cannot absorb more than 15% of your max hp or more than the enemy's max hp final int absorbAmount = totalDamage * user.getSkillStatValue(attack.skillId, SkillStat.x) / 100; hpGain += Math.min(Math.min(absorbAmount, user.getMaxHp() * 15 / 100), mob.getMaxHp()); - } else if (attack.skillId == Pirate.ENERGY_DRAIN || attack.skillId == ThunderBreaker.ENERGY_DRAIN) { + } else if (attack.skillId == SkillId.TB3_ENERGY_DRAIN || attack.skillId == SkillId.MARAUDER_ENERGY_DRAIN) { hpGain += totalDamage * user.getSkillStatValue(attack.skillId, SkillStat.x) / 100; - } else if (attack.skillId != 0) { + } else if (!attack.skillId.isNone()) { mpDamage = calculateMpEater(user, mob); } if (user.getSecondaryStat().hasOption(CharacterTemporaryStat.ComboDrain)) { @@ -532,7 +534,7 @@ private static void handleAttack(User user, Attack attack) { hpGain += Math.min(absorbAmount, user.getMaxHp() / 10); } // Process damage - mob.damage(user, totalDamage, attack.skillId == Thief.MESO_EXPLOSION ? attack.dropExplodeDelay : ai.delay); + mob.damage(user, totalDamage, attack.skillId == SkillId.CHIEFBANDIT_MESO_EXPLOSION ? attack.dropExplodeDelay : ai.delay); mob.setMp(mob.getMp() - mpDamage); mpGain += mpDamage; // Process on-hit effects @@ -560,7 +562,7 @@ private static void handleAttack(User user, Attack attack) { if (mpGain > 0) { user.addMp(mpGain); // Show MP eater effect - final int skillId = SkillConstants.getMpEaterSkill(user.getJob()); + final SkillId skillId = SkillConstants.getMpEaterSkill(user.getJob()); final int slv = user.getSkillLevel(skillId); user.write(UserLocal.effect(Effect.skillUse(skillId, slv, user.getLevel()))); user.getField().broadcastPacket(UserRemote.effect(user, Effect.skillUse(skillId, slv, user.getLevel())), user); @@ -587,11 +589,11 @@ private static void handleAttack(User user, Attack attack) { // ----------------------------------------------------------------------------------------------------------------- private static void handlePickpocket(User user, Attack attack, Mob mob) { - if (attack.skillId == Thief.MESO_EXPLOSION || !user.getSecondaryStat().hasOption(CharacterTemporaryStat.PickPocket)) { + if (attack.skillId == SkillId.CHIEFBANDIT_MESO_EXPLOSION || !user.getSecondaryStat().hasOption(CharacterTemporaryStat.PickPocket)) { return; } final TemporaryStatOption option = user.getSecondaryStat().getOption(CharacterTemporaryStat.PickPocket); - final Optional skillInfoResult = SkillProvider.getSkillInfoById(option.rOption); + final Optional skillInfoResult = SkillProvider.getSkillInfoById(SkillId.fromValue(option.rOption)); if (skillInfoResult.isEmpty()) { log.error("Could not resolve skill info for pick pocket skill ID : {}", option.rOption); return; @@ -599,7 +601,7 @@ private static void handlePickpocket(User user, Attack attack, Mob mob) { final SkillInfo si = skillInfoResult.get(); final int money = option.nOption; final int prop = si.getValue(SkillStat.prop, option.nOption) + - user.getSkillStatValue(Thief.MESO_MASTERY, SkillStat.u); + user.getSkillStatValue(SkillId.SHADOWER_MESO_MASTERY, SkillStat.u); // Trigger per hit, spread and delay drops final List drops = new ArrayList<>(); for (int i = 0; i < attack.getDamagePerMob(); i++) { @@ -624,7 +626,7 @@ private static void handleOwlSpirit(User user, Attack attack, boolean instantKil } } // Give buff on instant kill with owl spirit - if (!instantKill || attack.skillId != Thief.OWL_SPIRIT) { + if (!instantKill || attack.skillId != SkillId.DB4_OWL_SPIRIT) { return; } final Optional skillInfoResult = SkillProvider.getSkillInfoById(attack.skillId); @@ -641,7 +643,7 @@ private static void handleOwlSpirit(User user, Attack attack, boolean instantKil private static int calculateHeavensHammer(User user, Mob mob) { // Resolve skill info - final int skillId = Warrior.HEAVENS_HAMMER; + final SkillId skillId = SkillId.PALADIN_HEAVENS_HAMMER; final Optional skillInfoResult = SkillProvider.getSkillInfoById(skillId); if (skillInfoResult.isEmpty()) { log.error("Could not resolve skill info for mp eater skill ID : {}", skillId); @@ -670,7 +672,7 @@ private static int calculateHeavensHammer(User user, Mob mob) { } private static int calculateMpEater(User user, Mob mob) { - final int skillId = SkillConstants.getMpEaterSkill(user.getJob()); + final SkillId skillId = SkillConstants.getMpEaterSkill(user.getJob()); final int slv = user.getSkillLevel(skillId); if (slv == 0) { return 0; @@ -693,7 +695,7 @@ private static void handleHamString(User user, Mob mob, int delay) { return; } final TemporaryStatOption option = user.getSecondaryStat().getOption(CharacterTemporaryStat.HamString); - final int skillId = option.rOption; + final SkillId skillId = option.getSkillId(); final int slv = option.nOption; final Optional skillInfoResult = SkillProvider.getSkillInfoById(skillId); if (skillInfoResult.isEmpty()) { @@ -711,7 +713,7 @@ private static void handleBlind(User user, Mob mob, int delay) { return; } final TemporaryStatOption option = user.getSecondaryStat().getOption(CharacterTemporaryStat.Blind); - final int skillId = option.rOption; + final SkillId skillId = option.getSkillId(); final int slv = option.nOption; final Optional skillInfoResult = SkillProvider.getSkillInfoById(skillId); if (skillInfoResult.isEmpty()) { @@ -725,7 +727,7 @@ private static void handleBlind(User user, Mob mob, int delay) { } private static void handleVenom(User user, Mob mob, int delay) { - final int skillId = SkillConstants.getVenomSkill(user.getJob()); + final SkillId skillId = SkillConstants.getVenomSkill(user.getJob()); final int slv = user.getSkillLevel(skillId); if (slv == 0) { return; @@ -746,13 +748,13 @@ private static void handleWeaponCharge(User user, Mob mob, int delay) { return; } final TemporaryStatOption option = user.getSecondaryStat().getOption(CharacterTemporaryStat.WeaponCharge); - final int skillId = option.rOption; - if (skillId == Warrior.ICE_CHARGE) { + final SkillId skillId = option.getSkillId(); + if (skillId == SkillId.WK_ICE_CHARGE) { final int duration = user.getSkillStatValue(skillId, SkillStat.y); if (duration > 0) { mob.setTemporaryStat(MobTemporaryStat.Freeze, MobStatOption.of(1, skillId, duration * 1000), delay); } - } else if (skillId == Aran.SNOW_CHARGE) { + } else if (skillId == SkillId.ARAN3_SNOW_CHARGE) { final int duration = user.getSkillStatValue(skillId, SkillStat.y); if (duration > 0) { mob.setTemporaryStat(MobTemporaryStat.Speed, MobStatOption.of(user.getSkillStatValue(skillId, SkillStat.x), skillId, duration * 1000), delay); @@ -765,7 +767,7 @@ private static void handleEvanSlow(User user, Mob mob, int delay) { return; } final TemporaryStatOption option = user.getSecondaryStat().getOption(CharacterTemporaryStat.EvanSlow); - final int skillId = option.rOption; + final SkillId skillId = option.getSkillId(); final int slv = option.nOption; final Optional skillInfoResult = SkillProvider.getSkillInfoById(skillId); if (skillInfoResult.isEmpty()) { @@ -782,7 +784,7 @@ private static void handleMortalBlow(User user, Mob mob, int delay) { if (mob.isBoss()) { return; } - final int skillId = SkillConstants.getMortalBlowSkill(user.getJob()); + final SkillId skillId = SkillConstants.getMortalBlowSkill(user.getJob()); final int slv = user.getSkillLevel(skillId); if (slv == 0) { return; @@ -798,7 +800,7 @@ private static void handleMortalBlow(User user, Mob mob, int delay) { } final double percentage = (double) mob.getHp() / mob.getMaxHp(); if (percentage * 100 < si.getValue(SkillStat.x, slv)) { - user.getField().broadcastPacket(MobPacket.mobSpecialEffectBySkill(mob, skillId, user.getCharacterId(), delay)); + user.getField().broadcastPacket(MobPacket.mobSpecialEffectBySkill(mob, skillId.getId(), user.getCharacterId(), delay)); mob.damage(user, mob.getHp(), delay); } } @@ -808,7 +810,7 @@ private static void handleRevive(User user, Mob mob) { return; } final TemporaryStatOption option = user.getSecondaryStat().getOption(CharacterTemporaryStat.Revive); - final int skillId = option.rOption; // 32111006 - Summon Reaper Buff + final SkillId skillId = option.getSkillId(); // 32111006 - Summon Reaper Buff final int slv = option.nOption; final Optional skillInfoResult = SkillProvider.getSkillInfoById(skillId); if (skillInfoResult.isEmpty()) { @@ -828,7 +830,7 @@ private static void handleRevive(User user, Mob mob) { private static void handleAffectedArea(User user, Attack attack) { switch (attack.skillId) { - case Magician.POISON_MIST, BlazeWizard.FLAME_GEAR, NightWalker.POISON_BOMB -> { + case SkillId.FP2_POISON_MIST, SkillId.BW3_FLAME_GEAR, SkillId.NW3_POISON_BOMB -> { final SkillInfo si = SkillProvider.getSkillInfoById(attack.skillId).orElseThrow(); final AffectedArea affectedArea = AffectedArea.userSkill(user, si, attack.slv, 0, attack.userX, attack.userY); user.getField().getAffectedAreaPool().addAffectedArea(affectedArea); @@ -837,7 +839,7 @@ private static void handleAffectedArea(User user, Attack attack) { } private static void handleMesoExplosion(User user, Attack attack) { - if (attack.skillId != Thief.MESO_EXPLOSION) { + if (attack.skillId != SkillId.CHIEFBANDIT_MESO_EXPLOSION) { return; } int index = 0; @@ -854,7 +856,7 @@ private static void handleMesoExplosion(User user, Attack attack) { } private static void handleFinalCut(User user, Attack attack) { - if (attack.skillId != Thief.FINAL_CUT) { + if (attack.skillId != SkillId.DB5_FINAL_CUT) { return; } final SkillInfo si = SkillProvider.getSkillInfoById(attack.skillId).orElseThrow(); @@ -863,7 +865,7 @@ private static void handleFinalCut(User user, Attack attack) { } private static void handleComboAbility(User user, Attack attack) { - final int skillId = SkillConstants.getComboAbilitySkill(user.getJob()); + final SkillId skillId = SkillConstants.getComboAbilitySkill(user.getJob()); final int slv = user.getSkillLevel(skillId); if (slv == 0) { return; @@ -880,13 +882,13 @@ private static void handleComboAttack(User user, Attack attack) { return; } switch (attack.skillId) { - case Warrior.PANIC, Warrior.COMA, DawnWarrior.PANIC, DawnWarrior.COMA -> { + case SkillId.DW3_COMA, SkillId.CRUSADER_COMA, SkillId.CRUSADER_PANIC, SkillId.DW3_PANIC -> { Warrior.resetComboCounter(user); return; } } - final int comboAttackId = SkillConstants.getComboAttackSkill(user.getJob()); - final int advancedComboId = SkillConstants.getAdvancedComboSkill(user.getJob()); + final SkillId comboAttackId = SkillConstants.getComboAttackSkill(user.getJob()); + final SkillId advancedComboId = SkillConstants.getAdvancedComboSkill(user.getJob()); final int maxCombo = 1 + Math.max( user.getSkillStatValue(comboAttackId, SkillStat.x), user.getSkillStatValue(advancedComboId, SkillStat.x) @@ -902,13 +904,13 @@ private static void handleDarkSight(User user) { if (!user.getSecondaryStat().hasOption(CharacterTemporaryStat.DarkSight)) { return; } - if (!Util.succeedProp(user.getSkillStatValue(Thief.ADVANCED_DARK_SIGHT, SkillStat.prop))) { + if (!Util.succeedProp(user.getSkillStatValue(SkillId.DB4_ADVANCED_DARK_SIGHT, SkillStat.prop))) { user.resetTemporaryStat(user.getSecondaryStat().getOption(CharacterTemporaryStat.DarkSight).rOption); } } private static void handleEnergyCharge(User user) { - final int skillId = SkillConstants.getEnergyChargeSkill(user.getJob()); + final SkillId skillId = SkillConstants.getEnergyChargeSkill(user.getJob()); final int slv = user.getSkillLevel(skillId); if (slv == 0) { return; @@ -925,7 +927,7 @@ private static void handleEnergyCharge(User user) { final TwoStateTemporaryStat option = TemporaryStatOption.ofTwoState( CharacterTemporaryStat.EnergyCharged, Math.min(energyCharge + si.getValue(SkillStat.x, slv), SkillConstants.ENERGY_CHARGE_MAX), - skillId, + skillId.getId(), si.getDuration(slv) ); user.setTemporaryStat(CharacterTemporaryStat.EnergyCharged, option); diff --git a/src/main/java/kinoko/handler/user/HitHandler.java b/src/main/java/kinoko/handler/user/HitHandler.java index 7621c0ae..27c6e18a 100644 --- a/src/main/java/kinoko/handler/user/HitHandler.java +++ b/src/main/java/kinoko/handler/user/HitHandler.java @@ -1,6 +1,7 @@ package kinoko.handler.user; import kinoko.handler.Handler; +import kinoko.meta.SkillId; import kinoko.packet.user.SummonedPacket; import kinoko.packet.user.UserLocal; import kinoko.packet.user.UserRemote; @@ -215,7 +216,7 @@ private static int handleReflect(User user, HitInfo hitInfo) { } else if (user.getSecondaryStat().hasOption(CharacterTemporaryStat.ManaReflection)) { // Mana Reflection - reflect si.getValue(SkillStat.x, nManaReflection) % final TemporaryStatOption option = user.getSecondaryStat().getOption(CharacterTemporaryStat.ManaReflection); - final Optional skillInfoResult = SkillProvider.getSkillInfoById(option.rOption); + final Optional skillInfoResult = SkillProvider.getSkillInfoById(option.getSkillId()); if (skillInfoResult.isPresent()) { final int percentage = skillInfoResult.get().getValue(SkillStat.x, option.nOption); final Mob mob = mobResult.get(); @@ -238,8 +239,8 @@ private static int handleMesoGuard(User user, HitInfo hitInfo) { return 0; } // Calculate reduction rate - final int mesoGuardRate = Math.clamp(50 + user.getSkillStatValue(Thief.MESO_MASTERY, SkillStat.v), 50, 100); // hard coded 50 - final int mesoRequiredRate = Math.max(0, user.getSkillStatValue(Thief.MESO_GUARD, SkillStat.x) - user.getSkillStatValue(Thief.MESO_MASTERY, SkillStat.w)); + final int mesoGuardRate = Math.clamp(50 + user.getSkillStatValue(SkillId.SHADOWER_MESO_MASTERY, SkillStat.v), 50, 100); // hard coded 50 + final int mesoRequiredRate = Math.max(0, user.getSkillStatValue(SkillId.CHIEFBANDIT_MESO_GUARD, SkillStat.x) - user.getSkillStatValue(SkillId.SHADOWER_MESO_MASTERY, SkillStat.w)); // Calculate damage reduction final int realDamage = Math.clamp(hitInfo.damage, 1, GameConstants.DAMAGE_MAX); final int mesoGuardReduce = realDamage * mesoGuardRate / 100; @@ -264,14 +265,14 @@ private static int handleMesoGuard(User user, HitInfo hitInfo) { private static int getAchillesReduce(User user, int damage) { // CUserLocal::GetAchillesReduce - final int skillId = switch (user.getJob()) { - case 112 -> Warrior.ACHILLES_HERO; - case 122 -> Warrior.ACHILLES_PALADIN; - case 132 -> Warrior.ACHILLES_DRK; - case 2112 -> Aran.HIGH_DEFENSE; - default -> 0; + final SkillId skillId = switch (user.getJob()) { + case 112 -> SkillId.HERO_ACHILLES; + case 122 -> SkillId.PALADIN_ACHILLES; + case 132 -> SkillId.DRK_ACHILLES; + case 2112 -> SkillId.ARAN4_HIGH_DEFENSE; + default -> SkillId.NONE; }; - if (skillId == 0) { + if (skillId.isNone()) { return 0; } final int x = user.getSkillStatValue(skillId, SkillStat.x); @@ -314,7 +315,7 @@ private static int getBlueAuraReduce(User user, int damage) { return 0; } final TemporaryStatOption option = user.getSecondaryStat().getOption(CharacterTemporaryStat.BlueAura); - final int skillId = option.rOption; + final SkillId skillId = option.getSkillId(); final int slv = option.nOption; final Optional skillInfoResult = SkillProvider.getSkillInfoById(skillId); if (skillInfoResult.isEmpty()) { @@ -330,12 +331,12 @@ private static void handleGuardian(User user, HitInfo hitInfo) { if (hitInfo.knockback <= 1) { return; } - final int stunDuration = user.getSkillStatValue(Warrior.GUARDIAN, SkillStat.time); + final int stunDuration = user.getSkillStatValue(SkillId.PALADIN_GUARDIAN, SkillStat.time); if (stunDuration == 0) { return; } final Optional knockbackMobResult = user.getField().getMobPool().getById(hitInfo.reflectMobId); - knockbackMobResult.ifPresent(mob -> mob.setTemporaryStat(MobTemporaryStat.Stun, MobStatOption.of(1, Warrior.GUARDIAN, stunDuration * 1000), 0)); + knockbackMobResult.ifPresent(mob -> mob.setTemporaryStat(MobTemporaryStat.Stun, MobStatOption.of(1, SkillId.PALADIN_GUARDIAN.getId(), stunDuration * 1000), 0)); } private static void handleDivineShield(User user, HitInfo hitInfo) { @@ -343,7 +344,7 @@ private static void handleDivineShield(User user, HitInfo hitInfo) { return; } // Resolve skill - final int skillId = Warrior.DIVINE_SHIELD; + final SkillId skillId = SkillId.PALADIN_DIVINE_SHIELD; final Optional skillInfoResult = SkillProvider.getSkillInfoById(skillId); if (skillInfoResult.isEmpty()) { log.error("Could not resolve skill info for divine shield skill ID : {}", skillId); @@ -363,7 +364,7 @@ private static void handleDivineShield(User user, HitInfo hitInfo) { CharacterTemporaryStat.BlessingArmorIncPAD, ss.getOption(CharacterTemporaryStat.BlessingArmorIncPAD) // required for TemporaryStatSet )); } else { - user.resetTemporaryStat(skillId); + user.resetTemporaryStat(skillId.getId()); user.setSkillCooltime(skillId, si.getValue(SkillStat.cooltime, slv)); } } else { @@ -383,13 +384,13 @@ private static void handleBeholderCounter(User user, HitInfo hitInfo) { return; } // Resolve summoned - final Optional summonedResult = user.getSummonedBySkillId(Warrior.BEHOLDER); + final Optional summonedResult = user.getSummonedBySkillId(SkillId.DRK_BEHOLDER); if (summonedResult.isEmpty()) { return; } final Summoned summoned = summonedResult.get(); // Resolve skill info - final int skillId = Warrior.HEX_OF_THE_BEHOLDER_COUNTER; + final SkillId skillId = SkillId.DRK_HEX_OF_THE_BEHOLDER; final int slv = user.getSkillLevel(skillId); if (slv == 0) { return; @@ -441,7 +442,7 @@ private static void handleEvasionBoost(User user, HitInfo hitInfo) { if (hitInfo.damage > 0) { return; } - if (user.getSkillLevel(Bowman.EVASION_BOOST_BM) > 0 || user.getSkillLevel(Bowman.EVASION_BOOST_MM) > 0) { + if (user.getSkillLevel(SkillId.SNIPER_EVASION_BOOST) > 0 || user.getSkillLevel(SkillId.RANGER_EVASION_BOOST) > 0) { user.getCalcDamage().setNextAttackCritical(true); } } @@ -450,7 +451,7 @@ private static void handleVengeance(User user, HitInfo hitInfo) { if (hitInfo.attackIndex <= AttackIndex.Counter.getValue()) { return; } - final int prop = user.getSkillStatValue(Bowman.VENGEANCE, SkillStat.prop); + final int prop = user.getSkillStatValue(SkillId.BOWMASTER_VENGEANCE, SkillStat.prop); if (prop != 0 && Util.succeedProp(prop)) { user.write(UserLocal.requestVengeance()); } @@ -468,7 +469,7 @@ private static void handleDarkFlare(User user, HitInfo hitInfo) { return; } // Resolve skill info - final Optional skillInfoResult = SkillProvider.getSkillInfoById(summoned.getSkillId()); + final Optional skillInfoResult = SkillProvider.getSkillInfoById(SkillId.fromValue(summoned.getSkillId())); if (skillInfoResult.isEmpty()) { log.error("Could not resolve skill info for dark flare skill ID : {}", summoned.getSkillId()); return; @@ -502,7 +503,7 @@ private static void handlePiratesRevenge(User user, HitInfo hitInfo) { if (hitInfo.attackIndex <= AttackIndex.Counter.getValue()) { return; } - final int skillId = SkillConstants.getPiratesRevengeSkill(user.getJob()); + final SkillId skillId = SkillConstants.getPiratesRevengeSkill(user.getJob()); if (user.getSkillManager().hasSkillCooltime(skillId)) { return; } @@ -534,9 +535,9 @@ private static void handleBattleship(User user, HitInfo hitInfo) { if (newDurability > 0) { Pirate.setBattleshipDurability(user, newDurability); } else { - user.getSkillManager().getSkillCooltimes().remove(SkillConstants.BATTLESHIP_DURABILITY); + user.getSkillManager().getSkillCooltimes().remove(SkillId.CORSAIR_BATTLESHIP_DURABILITY); user.resetTemporaryStat(option.rOption); - user.setSkillCooltime(option.rOption, user.getSkillStatValue(option.rOption, SkillStat.cooltime)); + user.setSkillCooltime(option.getSkillId(), user.getSkillStatValue(option.getSkillId(), SkillStat.cooltime)); } } } diff --git a/src/main/java/kinoko/handler/user/PetHandler.java b/src/main/java/kinoko/handler/user/PetHandler.java index 59617d5d..b865cddf 100644 --- a/src/main/java/kinoko/handler/user/PetHandler.java +++ b/src/main/java/kinoko/handler/user/PetHandler.java @@ -1,6 +1,7 @@ package kinoko.handler.user; import kinoko.handler.Handler; +import kinoko.meta.SkillId; import kinoko.packet.user.PetPacket; import kinoko.packet.user.UserLocal; import kinoko.packet.user.UserRemote; @@ -69,7 +70,7 @@ public static void handleUserActivatePetRequest(User user, InPacket inPacket) { final long petSn = item.getItemSn(); final Optional petIndexResult = user.getPetIndex(petSn); if (petIndexResult.isEmpty()) { - final boolean hasFollowTheLead = user.getSkillLevel(SkillConstants.getNoviceSkillAsRace(Beginner.FOLLOW_THE_LEAD, user.getJob())) > 0; + final boolean hasFollowTheLead = user.getSkillLevel(SkillConstants.getNoviceSkillAsRace(SkillId.BEGINNER_FOLLOW_THE_LEAD, user.getJob())) > 0; if (hasFollowTheLead && !bossPet) { // Check if max number of pets active if (user.getPets().size() >= GameConstants.PET_COUNT_MAX) { diff --git a/src/main/java/kinoko/handler/user/SkillHandler.java b/src/main/java/kinoko/handler/user/SkillHandler.java index 6d0ca31d..37696b6d 100644 --- a/src/main/java/kinoko/handler/user/SkillHandler.java +++ b/src/main/java/kinoko/handler/user/SkillHandler.java @@ -1,6 +1,7 @@ package kinoko.handler.user; import kinoko.handler.Handler; +import kinoko.meta.SkillId; import kinoko.packet.user.UserLocal; import kinoko.packet.user.UserRemote; import kinoko.packet.world.MessagePacket; @@ -51,10 +52,10 @@ public static void handleUserSkillUseRequest(User user, InPacket inPacket) { inPacket.decodeInt(); // update_time final Skill skill = new Skill(); - skill.skillId = inPacket.decodeInt(); // nSkillID + skill.skillId = inPacket.decodeSkillId(); // nSkillID skill.slv = inPacket.decodeByte(); // nSLV - if (skill.skillId == Mechanic.ROCK_N_SHOCK) { + if (skill.skillId == SkillId.MECH3_ROCK_N_SHOCK) { // CUserLocal::DoActiveSkill_Summon skill.rockAndShockCount = inPacket.decodeByte(); if (skill.rockAndShockCount == 2) { @@ -62,11 +63,11 @@ public static void handleUserSkillUseRequest(User user, InPacket inPacket) { skill.rockAndShock2 = inPacket.decodeInt(); } } - if (skill.skillId == Citizen.CAPTURE) { + if (skill.skillId == SkillId.CITIZEN_CAPTURE) { // CUserLocal::DoActiveSkill_MobCapture skill.captureTargetMobId = inPacket.decodeInt(); } - if (skill.skillId == Citizen.CALL_OF_THE_HUNTER) { + if (skill.skillId == SkillId.CITIZEN_CALL_OF_THE_HUNTER) { // CUserLocal::DoActiveSkill_SummonMonster skill.randomCapturedMobId = inPacket.decodeInt(); } @@ -78,14 +79,14 @@ public static void handleUserSkillUseRequest(User user, InPacket inPacket) { skill.summonLeft = inPacket.decodeBoolean(); } } - if (skill.skillId == Thief.SHADOW_STARS) { + if (skill.skillId == SkillId.NIGHTLORD_SHADOW_STARS) { // CUserLocal::SendSkillUseRequest skill.spiritJavelinItemId = inPacket.decodeInt(); // nSpiritJavelinItemID } if (SkillConstants.isPartySkill(skill.skillId) && inPacket.getRemaining() > 2) { // CUserLocal::SendSkillUseRequest skill.affectedMemberBitMap = inPacket.decodeByte(); - if (skill.skillId == Magician.DISPEL) { + if (skill.skillId == SkillId.PRIEST_DISPEL) { inPacket.decodeShort(); // tDelay } } @@ -95,27 +96,27 @@ public static void handleUserSkillUseRequest(User user, InPacket inPacket) { skill.targetIds = new int[targetCount]; for (int i = 0; i < targetCount; i++) { skill.targetIds[i] = inPacket.decodeInt(); - if (skill.skillId == Thief.CHAINS_OF_HELL) { + if (skill.skillId == SkillId.DB5_CHAINS_OF_HELL) { // CUserLocal::TryDoingMonsterMagnet inPacket.decodeByte(); // anMobMove[k] == 3 || anMobMove[k] == 4 } } } - if (skill.skillId == Thief.CHAINS_OF_HELL || skill.skillId == Citizen.CALL_OF_THE_HUNTER || SkillConstants.isSummonSkill(skill.skillId)) { + if (skill.skillId == SkillId.DB5_CHAINS_OF_HELL || skill.skillId == SkillId.CITIZEN_CALL_OF_THE_HUNTER || SkillConstants.isSummonSkill(skill.skillId)) { // CUserLocal::TryDoingMonsterMagnet || CUserLocal::DoActiveSkill_SummonMonster || CUserLocal::DoActiveSkill_Summon skill.left = inPacket.decodeBoolean(); // nMoveAction & 1 } // ignore tDelay // Check skill root - final int skillRoot = SkillConstants.getSkillRoot(skill.skillId); + final int skillRoot = skill.skillId.getRoot(); if (!JobConstants.isBeginnerJob(skillRoot) && !JobConstants.isCorrectJobForSkillRoot(user.getJob(), skillRoot)) { log.error("Tried to use skill {} as incorrect job : {}", skill.skillId, user.getJob()); user.dispose(); return; } // Check seal - if (user.getSecondaryStat().hasOption(CharacterTemporaryStat.Seal) && skill.skillId != Magician.DISPEL) { + if (user.getSecondaryStat().hasOption(CharacterTemporaryStat.Seal) && skill.skillId != SkillId.PRIEST_DISPEL) { log.error("Tried to use skill {} while sealed", skill.skillId); user.dispose(); return; @@ -137,7 +138,7 @@ public static void handleUserSkillUseRequest(User user, InPacket inPacket) { } } // Mystic Door cooltime to avoid crashes - if (skill.skillId == Magician.MYSTIC_DOOR) { + if (skill.skillId == SkillId.PRIEST_MYSTIC_DOOR) { if (user.getTownPortal() != null && user.getTownPortal().getWaitTime().isAfter(Instant.now())) { user.write(MessagePacket.system("Please wait 5 seconds before casting Mystic Door again.")); user.dispose(); @@ -149,14 +150,14 @@ public static void handleUserSkillUseRequest(User user, InPacket inPacket) { @Handler(InHeader.UserSkillCancelRequest) public static void handleUserSkillCancelRequest(User user, InPacket inPacket) { - final int skillId = inPacket.decodeInt(); // nSkillID + final SkillId skillId = inPacket.decodeSkillId(); // nSkillID if (SkillConstants.isKeydownSkill(skillId)) { - user.getField().broadcastPacket(UserRemote.skillCancel(user, skillId)); + user.getField().broadcastPacket(UserRemote.skillCancel(user, skillId.getId())); return; } // Remove stat matching skill ID final SecondaryStat ss = user.getSecondaryStat(); - final Set resetStats = ss.resetTemporaryStat((cts, option) -> option.rOption == skillId); + final Set resetStats = ss.resetTemporaryStat((cts, option) -> option.getSkillId() == skillId); final BitFlag flag = BitFlag.from(resetStats, CharacterTemporaryStat.FLAG_SIZE); if (!flag.isEmpty()) { user.write(WvsContext.temporaryStatReset(flag)); @@ -164,7 +165,7 @@ public static void handleUserSkillCancelRequest(User user, InPacket inPacket) { } // Additional handling for CTS if (resetStats.contains(CharacterTemporaryStat.Beholder)) { - user.removeSummoned((summoned) -> summoned.getSkillId() == Warrior.BEHOLDER); + user.removeSummoned((summoned) -> summoned.getSkillId() == SkillId.DRK_BEHOLDER.getId()); } if (resetStats.contains(CharacterTemporaryStat.Aura)) { user.resetTemporaryStat(CharacterTemporaryStat.AURA_STAT); @@ -206,7 +207,7 @@ public static void handleUserSkillPrepareRequest(User user, InPacket inPacket) { @Handler(InHeader.UserMovingShootAttackPrepare) public static void handleMovingShootAttackPrepare(User user, InPacket inPacket) { - final int skillId = inPacket.decodeInt(); // nSkillID + final SkillId skillId = inPacket.decodeSkillId(); // nSkillID final short actionAndDir = inPacket.decodeShort(); // (nMoveAction & 1) << 15 | random_shoot_attack_action & 0x7FFF final byte attackSpeed = inPacket.decodeByte(); // nActionSpeed final int slv = user.getSkillLevel(skillId); @@ -214,12 +215,12 @@ public static void handleMovingShootAttackPrepare(User user, InPacket inPacket) log.error("Received UserMovingShootAttackPrepare for skill {}, but skill level is 0", skillId); return; } - user.getField().broadcastPacket(UserRemote.movingShootAttackPrepare(user, skillId, slv, actionAndDir, attackSpeed), user); + user.getField().broadcastPacket(UserRemote.movingShootAttackPrepare(user, skillId.getId(), slv, actionAndDir, attackSpeed), user); } @Handler(InHeader.UserEffectLocal) public static void handleUserEffectLocal(User user, InPacket inPacket) { - final int skillId = inPacket.decodeInt(); + final SkillId skillId = inPacket.decodeSkillId(); final int slv = inPacket.decodeByte(); final boolean sendLocal = inPacket.decodeBoolean(); @@ -227,10 +228,11 @@ public static void handleUserEffectLocal(User user, InPacket inPacket) { if (sendLocal) { user.write(UserLocal.effect(effect)); + //TODO // Not a real skill ID, but client sends this when trying to cancel Mech: Siege Mode (35111004), Mech: Missile Tank (35121005), and Mech: Siege Mode 2 (35121013) - if (skillId == 35110004 || skillId == 35120005 || skillId == 35120013) { + if (skillId.getId() == 35110004 || skillId.getId() == 35120005 || skillId.getId() == 35120013) { if (user.getSecondaryStat().hasOption(CharacterTemporaryStat.Mechanic)) { - Mechanic.handleMech(user, skillId == 35120013 ? Mechanic.MECH_MISSILE_TANK : Mechanic.MECH_PROTOTYPE); + Mechanic.handleMech(user, skillId.getId() == 35120013 ? SkillId.MECH4_MECH_MISSILE_TANK : SkillId.MECH1_MECH_PROTOTYPE); } } } @@ -254,10 +256,10 @@ public static void handleUserThrowGrenade(User user, InPacket inPacket) { skill.positionY = inPacket.decodeInt(); inPacket.decodeInt(); skill.keyDown = inPacket.decodeInt(); - skill.skillId = inPacket.decodeInt(); + skill.skillId = inPacket.decodeSkillId(); skill.slv = inPacket.decodeInt(); - if (skill.skillId != Thief.FLASHBANG && skill.skillId != Thief.MONSTER_BOMB) { + if (skill.skillId != SkillId.DB3_FLASHBANG && skill.skillId != SkillId.DB5_MONSTER_BOMB) { handleSkill(user, skill); } user.getField().broadcastPacket(UserRemote.throwGrenade(user, skill), user); @@ -277,7 +279,7 @@ public static void handleUserClientTimerEndRequest(User user, InPacket inPacket) } private static void handleSkill(User user, Skill skill) { - if (skill.skillId == WildHunter.JAGUAR_OSHI_DIGESTED && user.getHp() <= 0) { + if (skill.skillId == SkillId.WH2_JAGUAROSHI_1 && user.getHp() <= 0) { log.error("Tried to use skill {} while dead", skill.skillId); user.dispose(); return; diff --git a/src/main/java/kinoko/handler/user/SummonedHandler.java b/src/main/java/kinoko/handler/user/SummonedHandler.java index fd22d5df..1eec5c0f 100644 --- a/src/main/java/kinoko/handler/user/SummonedHandler.java +++ b/src/main/java/kinoko/handler/user/SummonedHandler.java @@ -1,6 +1,7 @@ package kinoko.handler.user; import kinoko.handler.Handler; +import kinoko.meta.SkillId; import kinoko.packet.user.SummonedPacket; import kinoko.provider.SkillProvider; import kinoko.provider.skill.SkillInfo; @@ -61,7 +62,7 @@ public static void handleSummonedAttack(User user, InPacket inPacket) { } final Summoned summoned = summonedResult.get(); final Attack attack = new Attack(OutHeader.SummonedAttack); - attack.skillId = summoned.getSkillId(); + attack.skillId = SkillId.fromValue(summoned.getSkillId()); inPacket.decodeInt(); // ~drInfo.dr0 inPacket.decodeInt(); // ~drInfo.dr1 @@ -116,7 +117,7 @@ public static void handleSummonedAttack(User user, InPacket inPacket) { attack.crc = inPacket.decodeInt(); // Crc // Check CRC - final Optional skillInfoResult = SkillProvider.getSkillInfoById(summoned.getSkillId()); + final Optional skillInfoResult = SkillProvider.getSkillInfoById(SkillId.fromValue(summoned.getSkillId())); if (skillInfoResult.isEmpty()) { log.error("Could not to resolve skill info for summoned attack for {}", summoned); return; @@ -189,14 +190,14 @@ public static void handleSummonedSkill(User user, InPacket inPacket) { final Summoned summoned = summonedResult.get(); final Skill skill = new Skill(); - skill.skillId = inPacket.decodeInt(); // nSkillID + skill.skillId = inPacket.decodeSkillId(); // nSkillID final byte actionAndDir = inPacket.decodeByte(); // (nMoveAction << 7) | (nAttackAction & 0x7F) - if (skill.skillId == Warrior.HEX_OF_THE_BEHOLDER) { + if (skill.skillId == SkillId.DRK_HEX_OF_THE_BEHOLDER) { skill.summonBuffType = inPacket.decodeByte(); } // Resolve skill level - if (skill.skillId == summoned.getSkillId()) { + if (skill.skillId.getId() == summoned.getSkillId()) { skill.slv = summoned.getSkillLevel(); } else { skill.slv = user.getSkillLevel(skill.skillId); @@ -231,7 +232,7 @@ public static void handleSummonedRemove(User user, InPacket inPacket) { summoned.getSkillId() == Mechanic.SATELLITE_3) { if (user.getSecondaryStat().hasOption(CharacterTemporaryStat.SafetyDamage)) { user.resetTemporaryStat(Set.of(CharacterTemporaryStat.SafetyDamage, CharacterTemporaryStat.SafetyAbsorb)); - user.setSkillCooltime(Mechanic.SATELLITE_SAFETY, user.getSkillStatValue(Mechanic.SATELLITE_SAFETY, SkillStat.cooltime)); + user.setSkillCooltime(SkillId.MECH4_SATELLITE_SAFETY, user.getSkillStatValue(SkillId.MECH4_SATELLITE_SAFETY, SkillStat.cooltime)); } } } diff --git a/src/main/java/kinoko/handler/user/UserHandler.java b/src/main/java/kinoko/handler/user/UserHandler.java index 0fc011c2..456ff24e 100644 --- a/src/main/java/kinoko/handler/user/UserHandler.java +++ b/src/main/java/kinoko/handler/user/UserHandler.java @@ -3,6 +3,7 @@ import kinoko.database.CharacterInfo; import kinoko.database.DatabaseManager; import kinoko.handler.Handler; +import kinoko.meta.SkillId; import kinoko.packet.field.*; import kinoko.packet.stage.CashShopPacket; import kinoko.packet.user.*; @@ -615,7 +616,7 @@ public static void handleUserChangeStatRequest(User user, InPacket inPacket) { @Handler(InHeader.UserSkillUpRequest) public static void handleUserSkillUpRequest(User user, InPacket inPacket) { inPacket.decodeInt(); // update_time - final int skillId = inPacket.decodeInt(); // nSkillID + final SkillId skillId = inPacket.decodeSkillId(); // nSkillID // Resolve skill info final Optional skillInfoResult = SkillProvider.getSkillInfoById(skillId); @@ -651,7 +652,7 @@ public static void handleUserSkillUpRequest(User user, InPacket inPacket) { } } - final int skillRoot = SkillConstants.getSkillRoot(skillId); + final int skillRoot = skillId.getRoot(); if (JobConstants.isBeginnerJob(skillRoot)) { // Check if valid beginner skill if (!SkillConstants.isBeginnerSpAddableSkill(skillId)) { diff --git a/src/main/java/kinoko/handler/user/item/ItemHandler.java b/src/main/java/kinoko/handler/user/item/ItemHandler.java index 059bbb3d..87645f6f 100644 --- a/src/main/java/kinoko/handler/user/item/ItemHandler.java +++ b/src/main/java/kinoko/handler/user/item/ItemHandler.java @@ -1,6 +1,7 @@ package kinoko.handler.user.item; import kinoko.handler.Handler; +import kinoko.meta.SkillId; import kinoko.packet.user.PetPacket; import kinoko.packet.user.UserLocal; import kinoko.packet.user.UserRemote; @@ -354,7 +355,8 @@ public static void handleUserSkillLearnItemUseRequest(User user, InPacket inPack // Check requirements final SkillManager sm = user.getSkillManager(); - final Optional skillIdResult = skill.stream() + final Optional skillIdResult = skill.stream() + .map(SkillId::fromValue) .filter((skillId) -> { if (reqSkillLevel > 0) { final Optional skillRecordResult = sm.getSkill(skillId); @@ -364,7 +366,7 @@ public static void handleUserSkillLearnItemUseRequest(User user, InPacket inPack final SkillRecord skillRecord = skillRecordResult.get(); return skillRecord.getSkillLevel() >= reqSkillLevel && skillRecord.getMasterLevel() < masterLevel; } else { - final int skillRoot = SkillConstants.getSkillRoot(skillId); + final int skillRoot = skillId.getRoot(); return JobConstants.isCorrectJobForSkillRoot(user.getJob(), skillRoot) && sm.getSkill(skillId).isEmpty(); } }) @@ -373,7 +375,7 @@ public static void handleUserSkillLearnItemUseRequest(User user, InPacket inPack user.write(WvsContext.skillLearnItemResult(user.getCharacterId(), isMasteryBook, false, false, true)); return; } - final int skillId = skillIdResult.get(); + final SkillId skillId = skillIdResult.get(); // Resolve skill final Optional skillInfoResult = SkillProvider.getSkillInfoById(skillId); diff --git a/src/main/java/kinoko/meta/SkillCategory.java b/src/main/java/kinoko/meta/SkillCategory.java new file mode 100644 index 00000000..9efc52d6 --- /dev/null +++ b/src/main/java/kinoko/meta/SkillCategory.java @@ -0,0 +1,31 @@ +package kinoko.meta; + +public enum SkillCategory { + BoundJump, + CombatStep, + DamageMeter, + Flying, + Heal, + HookAndHit, + MagicAttack, + MeleeAttack, + MesoExplosion, + MobCapture, + NotPrepareBomb, + OpenGate, + Prepare, + RecoveryAura, + RepeatSkill, + RocketBooster, + ShootAttack, + SmokeShell, + StatChange, + StatChangeAdmin, + Summon, + SummonMonster, + Teleport, + TownPortal, + VehicleShootAttack, + WeaponBooster, + None; +} diff --git a/src/main/java/kinoko/meta/SkillId.java b/src/main/java/kinoko/meta/SkillId.java new file mode 100644 index 00000000..2a503fd4 --- /dev/null +++ b/src/main/java/kinoko/meta/SkillId.java @@ -0,0 +1,1334 @@ +package kinoko.meta; + + +public enum SkillId { + NONE(0), + BEGINNER_FOLLOW_THE_LEAD(8), + BEGINNER_BLESSING_OF_THE_FAIRY(12), + BEGINNER_THREE_SNAILS(1000), + BEGINNER_RECOVERY(1001), + BEGINNER_NIMBLE_FEET(1002), + BEGINNER_LEGENDARY_SPIRIT(1003), + BEGINNER_MONSTER_RIDER(1004), + BEGINNER_ECHO_OF_HERO(1005), + BEGINNER_TEST(1006), + BEGINNER_MAKER(1007), + BEGINNER_BAMBOO_RAIN(1009), + BEGINNER_INVINCIBILITY(1010), + BEGINNER_POWER_EXPLOSION(1011), + BEGINNER_SPACESHIP(1013), + BEGINNER_SPACE_DASH(1014), + BEGINNER_SPACE_BEAM(1015), + BEGINNER_YETI_RIDER(1017), + BEGINNER_YETI_MOUNT(1018), + BEGINNER_WITCHS_BROOMSTICK(1019), + BEGINNER_RAGE_OF_PHARAOH(1020), + BEGINNER_CHARGE_WOODEN_PONY(1025), + BEGINNER_SOARING(1026), + BEGINNER_CROCO(1027), + BEGINNER_BLACK_SCOOTER(1028), + BEGINNER_PINK_SCOOTER(1029), + BEGINNER_NIMBUS_CLOUD(1030), + BEGINNER_BALROG(1031), + BEGINNER_(1033), + BEGINNER_ZD_TIGER(1034), + BEGINNER_MIST_BALROG(1035), + BEGINNER_LION(1036), + BEGINNER_UNICORN(1037), + BEGINNER_LOW_RIDER(1038), + BEGINNER_RED_TRUCK(1039), + BEGINNER_GARGOYLE(1040), + BEGINNER_SHINJO(1042), + BEGINNER_ORANGE_MUSHROOM(1044), + BEGINNER_HELICOPTER(1045), + BEGINNER_SPACESHIP_1(1046), + BEGINNER_SPACE_DASH_1(1047), + BEGINNER_SPACE_BEAM_1(1048), + BEGINNER_NIGHTMARE(1049), + BEGINNER_YETI(1050), + BEGINNER_OSTRICH(1051), + BEGINNER_PINK_BEAR_HOTAIR_BALLOON(1052), + BEGINNER_TRANSFORMATION_ROBOT(1053), + BEGINNER_CHICKEN(1054), + BEGINNER_MOTORCYCLE(1063), + BEGINNER_POWER_SUIT(1064), + BEGINNER_OS4_SHUTTLE(1065), + BEGINNER_VISITOR_MELEE_ATTACK(1066), + BEGINNER_VISITOR_RANGE_ATTACK(1067), + BEGINNER_OWL(1069), + BEGINNER_MOTHERSHIP(1070), + BEGINNER_OS3A_MACHINE(1071), + BEGINNER_DECENT_HASTE(8000), + BEGINNER_DECENT_MYSTIC_DOOR(8001), + BEGINNER_DECENT_SHARP_EYES(8002), + BEGINNER_DECENT_HYPER_BODY(8003), + BEGINNER_PIGS_WEAKNESS(9000), + BEGINNER_STUMPS_WEAKNESS(9001), + BEGINNER_SLIMES_WEAKNESS(9002), + WARRIOR_HP_BOOST(1000006), + WARRIOR_IRON_BODY(1001003), + WARRIOR_POWER_STRIKE(1001004), + WARRIOR_SLASH_BLAST(1001005), + FIGHTER_WEAPON_MASTERY(1100000), + FIGHTER_FINAL_ATTACK(1100002), + FIGHTER_ENHANCED_BASICS(1100009), + FIGHTER_WEAPON_BOOSTER(1101004), + FIGHTER_RAGE(1101006), + FIGHTER_POWER_GUARD(1101007), + FIGHTER_GROUND_SMASH(1101008), + CRUSADER_IMPROVING_MP_RECOVERY(1110000), + CRUSADER_CHANCE_ATTACK(1110009), + CRUSADER_COMBO_ATTACK(1111002), + CRUSADER_PANIC(1111003), + CRUSADER_COMA(1111005), + CRUSADER_MAGIC_CRASH(1111007), + CRUSADER_SHOUT(1111008), + CRUSADER_BRANDISH(1111010), + HERO_ADVANCED_COMBO_ATTACK(1120003), + HERO_ACHILLES(1120004), + HERO_COMBAT_MASTERY(1120012), + HERO_MAPLE_WARRIOR(1121000), + HERO_MONSTER_MAGNET(1121001), + HERO_POWER_STANCE(1121002), + HERO_RUSH(1121006), + HERO_INTREPID_SLASH(1121008), + HERO_ENRAGE(1121010), + HERO_HEROS_WILL(1121011), + PAGE_WEAPON_MASTERY(1200000), + PAGE_FINAL_ATTACK(1200002), + PAGE_ENHANCED_BASICS(1200009), + PAGE_WEAPON_BOOSTER(1201004), + PAGE_THREATEN(1201006), + PAGE_POWER_GUARD(1201007), + PAGE_GROUND_SMASH(1201008), + WK_SHIELD_MASTERY(1210001), + WK_CHARGED_BLOW(1211002), + WK_FIRE_CHARGE(1211004), + WK_ICE_CHARGE(1211006), + WK_LIGHTNING_CHARGE(1211008), + WK_MAGIC_CRASH(1211009), + WK_HP_RECOVERY(1211010), + WK_COMBAT_ORDERS(1211011), + PALADIN_ACHILLES(1220005), + PALADIN_GUARDIAN(1220006), + PALADIN_ADVANCED_CHARGE(1220010), + PALADIN_DIVINE_SHIELD(1220013), + PALADIN_MAPLE_WARRIOR(1221000), + PALADIN_POWER_STANCE(1221002), + PALADIN_DIVINE_CHARGE(1221004), + PALADIN_RUSH(1221007), + PALADIN_BLAST(1221009), + PALADIN_HEAVENS_HAMMER(1221011), + PALADIN_HEROS_WILL(1221012), + SPEARNMAN_WEAPON_MASTERY(1300000), + SPEARNMAN_FINAL_ATTACK(1300002), + SPEARNMAN_ENHANCED_BASICS(1300009), + SPEARNMAN_WEAPON_BOOSTER(1301004), + SPEARNMAN_IRON_WILL(1301006), + SPEARNMAN_HYPER_BODY(1301007), + SPEARNMAN_GROUND_SMASH(1301008), + DK_ELEMENTAL_RESISTANCE(1310000), + DK_DRAGON_WISDOM(1310009), + DK_DRAGON_BUSTER(1311001), + DK_DRAGON_FURY(1311003), + DK_SACRIFICE(1311005), + DK_DRAGON_ROAR(1311006), + DK_MAGIC_CRASH(1311007), + DK_DRAGON_BLOOD(1311008), + DRK_ACHILLES(1320005), + DRK_BERSERK(1320006), + DRK_AURA_OF_THE_BEHOLDER(1320008), + DRK_HEX_OF_THE_BEHOLDER(1320009), + DRK_HEX_OF_THE_BEHOLDER_1(1320011), + DRK_MAPLE_WARRIOR(1321000), + DRK_MONSTER_MAGNET(1321001), + DRK_POWER_STANCE(1321002), + DRK_RUSH(1321003), + DRK_BEHOLDER(1321007), + DRK_HEROS_WILL(1321010), + MAGE_MP_BOOST(2000006), + MAGE_MAGIC_GUARD(2001002), + MAGE_MAGIC_ARMOR(2001003), + MAGE_ENERGY_BOLT(2001004), + MAGE_MAGIC_CLAW(2001005), + FP1_MP_EATER(2100000), + FP1_SPELL_MASTERY(2100006), + FP1_MEDITATION(2101001), + FP1_TELEPORT(2101002), + FP1_SLOW(2101003), + FP1_FIRE_ARROW(2101004), + FP1_POISON_BREATH(2101005), + FP2_PARTIAL_RESISTANCE(2110000), + FP2_ELEMENT_AMPLIFICATION(2110001), + FP2_EXPLOSION(2111002), + FP2_POISON_MIST(2111003), + FP2_SEAL(2111004), + FP2_SPELL_BOOSTER(2111005), + FP2_ELEMENT_COMPOSITION(2111006), + FP2_TELEPORT_MASTERY(2111007), + FP2_ELEMENTAL_DECREASE(2111008), + FP3_BUFF_MASTERY(2120009), + FP3_MAPLE_WARRIOR(2121000), + FP3_BIG_BANG(2121001), + FP3_MANA_REFLECTION(2121002), + FP3_FIRE_DEMON(2121003), + FP3_INFINITY(2121004), + FP3_IFRIT(2121005), + FP3_PARALYZE(2121006), + FP3_METEOR_SHOWER(2121007), + FP3_HEROS_WILL(2121008), + IL1_MP_EATER(2200000), + IL1_SPELL_MASTERY(2200006), + IL1_MEDITATION(2201001), + IL1_TELEPORT(2201002), + IL1_SLOW(2201003), + IL1_COLD_BEAM(2201004), + IL1_THUNDER_BOLT(2201005), + IL2_PARTIAL_RESISTANCE(2210000), + IL2_ELEMENT_AMPLIFICATION(2210001), + IL2_ICE_STRIKE(2211002), + IL2_THUNDER_SPEAR(2211003), + IL2_SEAL(2211004), + IL2_SPELL_BOOSTER(2211005), + IL2_ELEMENT_COMPOSITION(2211006), + IL2_TELEPORT_MASTERY(2211007), + IL2_ELEMENTAL_DECREASE(2211008), + IL3_BUFF_MASTERY(2220009), + IL3_MAPLE_WARRIOR(2221000), + IL3_BIG_BANG(2221001), + IL3_MANA_REFLECTION(2221002), + IL3_ICE_DEMON(2221003), + IL3_INFINITY(2221004), + IL3_ELQUINES(2221005), + IL3_CHAIN_LIGHTNING(2221006), + IL3_BLIZZARD(2221007), + IL3_HEROS_WILL(2221008), + CLERIC_MP_EATER(2300000), + CLERIC_SPELL_MASTERY(2300006), + CLERIC_TELEPORT(2301001), + CLERIC_HEAL(2301002), + CLERIC_INVINCIBLE(2301003), + CLERIC_BLESS(2301004), + CLERIC_HOLY_ARROW(2301005), + PRIEST_ELEMENTAL_RESISTANCE(2310000), + PRIEST_HOLY_FOCUS(2310008), + PRIEST_DISPEL(2311001), + PRIEST_MYSTIC_DOOR(2311002), + PRIEST_HOLY_SYMBOL(2311003), + PRIEST_SHINING_RAY(2311004), + PRIEST_DOOM(2311005), + PRIEST_SUMMON_DRAGON(2311006), + PRIEST_TELEPORT_MASTERY(2311007), + BISHOP_BUFF_MASTERY(2320010), + BISHOP_MAPLE_WARRIOR(2321000), + BISHOP_BIG_BANG(2321001), + BISHOP_MANA_REFLECTION(2321002), + BISHOP_BAHAMUT(2321003), + BISHOP_INFINITY(2321004), + BISHOP_HOLY_SHIELD(2321005), + BISHOP_RESURRECTION(2321006), + BISHOP_ANGEL_RAY(2321007), + BISHOP_GENESIS(2321008), + BISHOP_HEROS_WILL(2321009), + BOWMAN_CRITICAL_SHOT(3000001), + BOWMAN_THE_EYE_OF_AMAZON(3000002), + BOWMAN_FOCUS(3001003), + BOWMAN_ARROW_BLOW(3001004), + BOWMAN_DOUBLE_SHOT(3001005), + HUNTER_BOW_MASTERY(3100000), + HUNTER_FINAL_ATTACK_BOW(3100001), + HUNTER_ENHANCED_BASICS(3100006), + HUNTER_BOW_BOOSTER(3101002), + HUNTER_POWER_KNOCKBACK(3101003), + HUNTER_SOUL_ARROW_BOW(3101004), + HUNTER_ARROW_BOMB_BOW(3101005), + RANGER_THRUST(3110000), + RANGER_MORTAL_BLOW(3110001), + RANGER_EVASION_BOOST(3110007), + RANGER_PUPPET(3111002), + RANGER_INFERNO(3111003), + RANGER_ARROW_RAIN(3111004), + RANGER_SILVER_HAWK(3111005), + RANGER_STRAFE(3111006), + BOWMASTER_BOW_EXPERT(3120005), + BOWMASTER_VENGEANCE(3120010), + BOWMASTER_MARKSMANSHIP(3120011), + BOWMASTER_MAPLE_WARRIOR(3121000), + BOWMASTER_SHARP_EYES(3121002), + BOWMASTER_DRAGONS_BREATH(3121003), + BOWMASTER_HURRICANE(3121004), + BOWMASTER_PHOENIX(3121006), + BOWMASTER_HAMSTRING(3121007), + BOWMASTER_CONCENTRATE(3121008), + BOWMASTER_HEROS_WILL(3121009), + CROSSBOWMAN_CROSSBOW_MASTERY(3200000), + CROSSBOWMAN_FINAL_ATTACK_CROSSBOW(3200001), + CROSSBOWMAN_ENHANCED_BASICS(3200006), + CROSSBOWMAN_CROSSBOW_BOOSTER(3201002), + CROSSBOWMAN_POWER_KNOCKBACK(3201003), + CROSSBOWMAN_SOUL_ARROW_CROSSBOW(3201004), + CROSSBOWMAN_IRON_ARROW_CROSSBOW(3201005), + SNIPER_THRUST(3210000), + SNIPER_MORTAL_BLOW(3210001), + SNIPER_EVASION_BOOST(3210007), + SNIPER_PUPPET(3211002), + SNIPER_BLIZZARD(3211003), + SNIPER_ARROW_ERUPTION(3211004), + SNIPER_GOLDEN_EAGLE(3211005), + SNIPER_STRAFE(3211006), + MARKSMAN_MARKSMAN_BOOST(3220004), + MARKSMAN_MARKSMANSHIP(3220009), + MARKSMAN_ULTIMATE_STRAFE(3220010), + MARKSMAN_MAPLE_WARRIOR(3221000), + MARKSMAN_PIERCING_ARROW(3221001), + MARKSMAN_SHARP_EYES(3221002), + MARKSMAN_DRAGONS_BREATH(3221003), + MARKSMAN_FROSTPREY(3221005), + MARKSMAN_BLIND(3221006), + MARKSMAN_SNIPE(3221007), + MARKSMAN_HEROS_WILL(3221008), + THIEF_NIMBLE_BODY(4000000), + THIEF_KEEN_EYES(4000001), + THIEF_DISORDER(4001002), + THIEF_DARK_SIGHT(4001003), + THIEF_DOUBLE_STAB(4001334), + THIEF_LUCKY_SEVEN(4001344), + ASSASSIN_CLAW_MASTERY(4100000), + ASSASSIN_CRITICAL_THROW(4100001), + ASSASSIN_SHADOW_RESISTANCE(4100006), + ASSASSIN_CLAW_BOOSTER(4101003), + ASSASSIN_HASTE(4101004), + ASSASSIN_DRAIN(4101005), + HERMIT_ALCHEMIST(4110000), + HERMIT_MESO_UP(4111001), + HERMIT_SHADOW_PARTNER(4111002), + HERMIT_SHADOW_WEB(4111003), + HERMIT_SHADOW_MESO(4111004), + HERMIT_AVENGER(4111005), + HERMIT_FLASH_JUMP(4111006), + HERMIT_DARK_FLARE(4111007), + NIGHTLORD_SHADOW_SHIFTER(4120002), + NIGHTLORD_VENOMOUS_STAR(4120005), + NIGHTLORD_EXPERT_THROWING_STAR_HANDLING(4120010), + NIGHTLORD_MAPLE_WARRIOR(4121000), + NIGHTLORD_TAUNT(4121003), + NIGHTLORD_NINJA_AMBUSH(4121004), + NIGHTLORD_SHADOW_STARS(4121006), + NIGHTLORD_TRIPLE_THROW(4121007), + NIGHTLORD_NINJA_STORM(4121008), + NIGHTLORD_HEROS_WILL(4121009), + BANDIT_DAGGER_MASTERY(4200000), + BANDIT_SHADOW_RESISTANCE(4200006), + BANDIT_DAGGER_BOOSTER(4201002), + BANDIT_HASTE(4201003), + BANDIT_STEAL(4201004), + BANDIT_SAVAGE_BLOW(4201005), + CHIEFBANDIT_SHIELD_MASTERY(4210000), + CHIEFBANDIT_CHAKRA(4211001), + CHIEFBANDIT_ASSAULTER(4211002), + CHIEFBANDIT_PICKPOCKET(4211003), + CHIEFBANDIT_BAND_OF_THIEVES(4211004), + CHIEFBANDIT_MESO_GUARD(4211005), + CHIEFBANDIT_MESO_EXPLOSION(4211006), + CHIEFBANDIT_DARK_FLARE(4211007), + CHIEFBANDIT_SHADOW_PARTNER(4211008), + CHIEFBANDIT_FLASH_JUMP(4211009), + SHADOWER_SHADOW_SHIFTER(4220002), + SHADOWER_VENOMOUS_STAB(4220005), + SHADOWER_MESO_MASTERY(4220009), + SHADOWER_MAPLE_WARRIOR(4221000), + SHADOWER_ASSASSINATE(4221001), + SHADOWER_TAUNT(4221003), + SHADOWER_NINJA_AMBUSH(4221004), + SHADOWER_SMOKESCREEN(4221006), + SHADOWER_BOOMERANG_STEP(4221007), + SHADOWER_HEROS_WILL(4221008), + DB1_KATARA_MASTERY(4300000), + DB1_TRIPLE_STAB(4301001), + DB1_KATARA_BOOSTER(4301002), + DB2_SHADOW_RESISTANCE(4310004), + DB2_SELF_HASTE(4311001), + DB2_FATAL_BLOW(4311002), + DB2_SLASH_STORM(4311003), + DB3_TORNADO_SPIN(4321000), + DB3_TORNADO_SPIN_ATTACK(4321001), + DB3_FLASHBANG(4321002), + DB3_FLASH_JUMP(4321003), + DB4_ADVANCED_DARK_SIGHT(4330001), + DB4_BLOODY_STORM(4331000), + DB4_MIRROR_IMAGE(4331002), + DB4_OWL_SPIRIT(4331003), + DB4_UPPER_STAB(4331004), + DB4_FLYING_ASSAULTER(4331005), + DB5_VENOM(4340001), + DB5_MAPLE_WARRIOR(4341000), + DB5_FINAL_CUT(4341002), + DB5_MONSTER_BOMB(4341003), + DB5_SUDDEN_RAID(4341004), + DB5_CHAINS_OF_HELL(4341005), + DB5_MIRRORED_TARGET(4341006), + DB5_THORNS(4341007), + DB5_HEROS_WILL(4341008), + PIRATE_BULLET_TIME(5000000), + PIRATE_FLASH_FIST(5001001), + PIRATE_SOMMERSAULT_KICK(5001002), + PIRATE_DOUBLE_SHOT(5001003), + PIRATE_DASH(5001005), + BRAWLER_KNUCKLE_MASTERY(5100001), + BRAWLER_CRITICAL_PUNCH(5100008), + BRAWLER_HP_BOOST(5100009), + BRAWLER_BACKSPIN_BLOW(5101002), + BRAWLER_DOUBLE_UPPERCUT(5101003), + BRAWLER_CORKSCREW_BLOW(5101004), + BRAWLER_MP_RECOVERY(5101005), + BRAWLER_KNUCKLE_BOOSTER(5101006), + BRAWLER_OAK_BARREL(5101007), + MARAUDER_STUN_MASTERY(5110000), + MARAUDER_ENERGY_CHARGE(5110001), + MARAUDER_BRAWLING_MASTERY(5110008), + MARAUDER_ENERGY_BLAST(5111002), + MARAUDER_ENERGY_DRAIN(5111004), + MARAUDER_TRANSFORMATION(5111005), + MARAUDER_SHOCKWAVE(5111006), + MARAUDER_ROLL_OF_THE_DICE(5111007), + BUCCANEER_PIRATES_REVENGE(5120011), + BUCCANEER_MAPLE_WARRIOR(5121000), + BUCCANEER_DRAGON_STRIKE(5121001), + BUCCANEER_ENERGY_ORB(5121002), + BUCCANEER_SUPER_TRANSFORMATION(5121003), + BUCCANEER_DEMOLITION(5121004), + BUCCANEER_SNATCH(5121005), + BUCCANEER_BARRAGE(5121007), + BUCCANEER_PIRATES_RAGE(5121008), + BUCCANEER_SPEED_INFUSION(5121009), + BUCCANEER_TIME_LEAP(5121010), + GUNSLINGER_GUN_MASTERY(5200000), + GUNSLINGER_CRITICAL_SHOT(5200007), + GUNSLINGER_INVISIBLE_SHOT(5201001), + GUNSLINGER_GRENADE(5201002), + GUNSLINGER_GUN_BOOSTER(5201003), + GUNSLINGER_BLANK_SHOT(5201004), + GUNSLINGER_WINGS(5201005), + GUNSLINGER_RECOIL_SHOT(5201006), + OUTLAW_BURST_FIRE(5210000), + OUTLAW_OCTOPUS(5211001), + OUTLAW_GAVIOTA(5211002), + OUTLAW_FLAMETHROWER(5211004), + OUTLAW_ICE_SPLITTER(5211005), + OUTLAW_HOMING_BEACON(5211006), + OUTLAW_ROLL_OF_THE_DICE(5211007), + CORSAIR_ELEMENTAL_BOOST(5220001), + CORSAIR_WRATH_OF_THE_OCTOPI(5220002), + CORSAIR_BULLSEYE(5220011), + CORSAIR_PIRATES_REVENGE(5220012), + CORSAIR_MAPLE_WARRIOR(5221000), + CORSAIR_AIR_STRIKE(5221003), + CORSAIR_RAPID_FIRE(5221004), + CORSAIR_BATTLESHIP(5221006), + CORSAIR_BATTLESHIP_CANNON(5221007), + CORSAIR_BATTLESHIP_TORPEDO(5221008), + CORSAIR_HYPNOTIZE(5221009), + CORSAIR_HEROS_WILL(5221010), + CORSAIR_BATTLESHIP_DURABILITY(5221999), //TODO generatethis + SHROOMLEAFBRIGADIER_(8001000), + SHROOMLEAFBRIGADIER__(8001001), + GM_HASTE_NORMAL(9001000), + GM_SUPER_DRAGON_ROAR(9001001), + GM_TELEPORT(9001002), + GM_BLESS(9001003), + GM_HIDE(9001004), + GM_RESURRECTION(9001005), + GM_SUPER_DRAGON_ROAR_1(9001006), + GM_TELEPORT_1(9001007), + GM_HYPER_BODY(9001008), + GM_ADMIN_ANTIMACRO(9001009), + SUPERGM_HEAL_DISPEL(9101000), + SUPERGM_HASTE_SUPER(9101001), + SUPERGM_HOLY_SYMBOL(9101002), + SUPERGM_BLESS(9101003), + SUPERGM_HIDE(9101004), + SUPERGM_RESURRECTION(9101005), + SUPERGM_SUPER_DRAGON_ROAR(9101006), + SUPERGM_TELEPORT(9101007), + SUPERGM_HYPER_BODY(9101008), + NOBLESSE_BLESSING_OF_THE_FAIRY(10000012), + NOBLESSE_HELPER(10000013), + NOBLESSE_FOLLOW_THE_LEAD(10000018), + NOBLESSE_THREE_SNAILS(10001000), + NOBLESSE_RECOVERY(10001001), + NOBLESSE_NIMBLE_FEET(10001002), + NOBLESSE_LEGENDARY_SPIRIT(10001003), + NOBLESSE_MONSTER_RIDER(10001004), + NOBLESSE_ECHO_OF_HERO(10001005), + NOBLESSE_JUMP_DOWN(10001006), + NOBLESSE_MAKER(10001007), + NOBLESSE_BAMBOO_THRUST(10001009), + NOBLESSE_INVINCIBLE_BARRIER(10001010), + NOBLESSE_METEO_SHOWER(10001011), + NOBLESSE_SPACESHIP(10001014), + NOBLESSE_SPACE_DASH(10001015), + NOBLESSE_SPACE_BEAM(10001016), + NOBLESSE_YETI_RIDER(10001019), + NOBLESSE_RAGE_OF_PHARAOH(10001020), + NOBLESSE_YETI_MOUNT(10001022), + NOBLESSE_WITCHS_BROOMSTICK(10001023), + NOBLESSE_CHARGE_WOODEN_PONY(10001025), + NOBLESSE_SOARING(10001026), + NOBLESSE_CROCO(10001027), + NOBLESSE_BLACK_SCOOTER(10001028), + NOBLESSE_PINK_SCOOTER(10001029), + NOBLESSE_NIMBUS_CLOUD(10001030), + NOBLESSE_BALROG(10001031), + NOBLESSE_(10001033), + NOBLESSE_ZD_TIGER(10001034), + NOBLESSE_MIST_BALROG(10001035), + NOBLESSE_LION(10001036), + NOBLESSE_UNICORN(10001037), + NOBLESSE_LOW_RIDER(10001038), + NOBLESSE_RED_TRUCK(10001039), + NOBLESSE_GARGOYLE(10001040), + NOBLESSE_SHINJO(10001042), + NOBLESSE_ORANGE_MUSHROOM(10001044), + NOBLESSE_HELICOPTER(10001045), + NOBLESSE_SPACESHIP_1(10001046), + NOBLESSE_SPACE_DASH_1(10001047), + NOBLESSE_SPACE_BEAM_1(10001048), + NOBLESSE_NIGHTMARE(10001049), + NOBLESSE_YETI(10001050), + NOBLESSE_OSTRICH(10001051), + NOBLESSE_PINK_BEAR_HOTAIR_BALLOON(10001052), + NOBLESSE_TRANSFORMATION_ROBOT(10001053), + NOBLESSE_CHICKEN(10001054), + NOBLESSE_MOTORCYCLE(10001063), + NOBLESSE_POWER_SUIT(10001064), + NOBLESSE_OS4_SHUTTLE(10001065), + NOBLESSE_VISITOR_MELEE_ATTACK(10001066), + NOBLESSE_VISITOR_RANGE_ATTACK(10001067), + NOBLESSE_OWL(10001069), + NOBLESSE_MOTHERSHIP(10001070), + NOBLESSE_OS3A_MACHINE(10001071), + NOBLESSE_DECENT_HASTE(10008000), + NOBLESSE_DECENT_MYSTIC_DOOR(10008001), + NOBLESSE_DECENT_SHARP_EYES(10008002), + NOBLESSE_DECENT_HYPER_BODY(10008003), + NOBLESSE_PIGS_WEAKNESS(10009000), + NOBLESSE_STUMPS_WEAKNESS(10009001), + NOBLESSE_SLIMES_WEAKNESS(10009002), + DW1_HP_BOOST(11000005), + DW1_IRON_BODY(11001001), + DW1_POWER_STRIKE(11001002), + DW1_SLASH_BLAST(11001003), + DW1_SOUL(11001004), + DW2_SWORD_MASTERY(11100000), + DW2_SWORD_BOOSTER(11101001), + DW2_FINAL_ATTACK(11101002), + DW2_RAGE(11101003), + DW2_SOUL_BLADE(11101004), + DW2_SOUL_RUSH(11101005), + DW3_MP_RECOVERY_RATE_ENHANCEMENT(11110000), + DW3_ADVANCED_COMBO(11110005), + DW3_COMBO_ATTACK(11111001), + DW3_PANIC(11111002), + DW3_COMA(11111003), + DW3_BRANDISH(11111004), + DW3_SOUL_DRIVER(11111006), + DW3_SOUL_CHARGE(11111007), + BW1_MP_BOOST(12000005), + BW1_MAGIC_GUARD(12001001), + BW1_MAGIC_ARMOR(12001002), + BW1_MAGIC_CLAW(12001003), + BW1_FLAME(12001004), + BW2_SPELL_MASTERY(12100007), + BW2_MEDITATION(12101000), + BW2_SLOW(12101001), + BW2_FIRE_ARROW(12101002), + BW2_TELEPORT(12101003), + BW2_SPELL_BOOSTER(12101004), + BW2_ELEMENTAL_RESET(12101005), + BW2_FIRE_PILLAR(12101006), + BW3_ELEMENTAL_RESISTANCE(12110000), + BW3_ELEMENT_AMPLIFICATION(12110001), + BW3_SEAL(12111002), + BW3_METEOR_SHOWER(12111003), + BW3_IFRIT(12111004), + BW3_FLAME_GEAR(12111005), + BW3_FIRE_STRIKE(12111006), + WA1_CRITICAL_SHOT(13000000), + WA1_THE_EYE_OF_AMAZON(13000001), + WA1_FOCUS(13001002), + WA1_DOUBLE_SHOT(13001003), + WA1_STORM(13001004), + WA2_BOW_MASTERY(13100000), + WA2_THRUST(13100004), + WA2_BOW_BOOSTER(13101001), + WA2_FINAL_ATTACK(13101002), + WA2_SOUL_ARROW(13101003), + WA2_STORM_BREAK(13101005), + WA2_WIND_WALK(13101006), + WA3_BOW_EXPERT(13110003), + WA3_ARROW_RAIN(13111000), + WA3_STRAFE(13111001), + WA3_HURRICANE(13111002), + WA3_PUPPET(13111004), + WA3_EAGLE_EYE(13111005), + WA3_WIND_PIERCING(13111006), + WA3_WIND_SHOT(13111007), + NW1_NIMBLE_BODY(14000000), + NW1_KEEN_EYES(14000001), + NW1_DISORDER(14001002), + NW1_DARK_SIGHT(14001003), + NW1_LUCKY_SEVEN(14001004), + NW1_DARKNESS(14001005), + NW2_CLAW_MASTERY(14100000), + NW2_CRITICAL_THROW(14100001), + NW2_VANISH(14100005), + NW2_CLAW_BOOSTER(14101002), + NW2_HASTE(14101003), + NW2_FLASH_JUMP(14101004), + NW2_VAMPIRE(14101006), + NW3_ALCHEMIST(14110003), + NW3_VENOM(14110004), + NW3_SHADOW_PARTNER(14111000), + NW3_SHADOW_WEB(14111001), + NW3_AVENGER(14111002), + NW3_TRIPLE_THROW(14111005), + NW3_POISON_BOMB(14111006), + TB1_QUICK_MOTION(15000000), + TB1_STRAIGHT(15001001), + TB1_SOMERSAULT_KICK(15001002), + TB1_DASH(15001003), + TB1_LIGHTNING(15001004), + TB2_KNUCKLE_MASTERY(15100001), + TB2_ENERGY_CHARGE(15100004), + TB2_HP_BOOST(15100007), + TB2_KNUCKLE_BOOSTER(15101002), + TB2_CORKSCREW_BLOW(15101003), + TB2_ENERGY_BLAST(15101005), + TB2_LIGHTNING_CHARGE(15101006), + TB3_CRITICAL_PUNCH(15110000), + TB3_ENERGY_DRAIN(15111001), + TB3_TRANSFORMATION(15111002), + TB3_SHOCKWAVE(15111003), + TB3_BARRAGE(15111004), + TB3_SPEED_INFUSION(15111005), + TB3_SPARK(15111006), + TB3_SHARK_WAVE(15111007), + LEGEND_BLESSING_OF_THE_FAIRY(20000012), + LEGEND_TUTORIAL_SKILL(20000014), + LEGEND_TUTORIAL_SKILL_1(20000015), + LEGEND_TUTORIAL_SKILL_2(20000016), + LEGEND_TUTORIAL_SKILL_3(20000017), + LEGEND_TUTORIAL_SKILL_4(20000018), + LEGEND_FOLLOW_THE_LEAD(20000024), + LEGEND_THREE_SNAILS(20001000), + LEGEND_RECOVERY(20001001), + LEGEND_AGILE_BODY(20001002), + LEGEND_LEGENDARY_SPIRIT(20001003), + LEGEND_MONSTER_RIDER(20001004), + LEGEND_ECHO_OF_HERO(20001005), + LEGEND_JUMP_DOWN(20001006), + LEGEND_MAKER(20001007), + LEGEND_BAMBOO_THRUST(20001009), + LEGEND_INVINCIBLE_BARRIER(20001010), + LEGEND_METEO_SHOWER(20001011), + LEGEND_HELPER(20001013), + LEGEND_YETI_RIDER(20001019), + LEGEND_RAGE_OF_PHARAOH(20001020), + LEGEND_YETI_MOUNT(20001022), + LEGEND_WITCHS_BROOMSTICK(20001023), + LEGEND_CHARGE_WOODEN_PONY(20001025), + LEGEND_SOARING(20001026), + LEGEND_CROCO(20001027), + LEGEND_BLACK_SCOOTER(20001028), + LEGEND_PINK_SCOOTER(20001029), + LEGEND_NIMBUS_CLOUD(20001030), + LEGEND_BALROG(20001031), + LEGEND_(20001033), + LEGEND_ZD_TIGER(20001034), + LEGEND_MIST_BALROG(20001035), + LEGEND_LION(20001036), + LEGEND_UNICORN(20001037), + LEGEND_LOW_RIDER(20001038), + LEGEND_RED_TRUCK(20001039), + LEGEND_GARGOYLE(20001040), + LEGEND_SHINJO(20001042), + LEGEND_ORANGE_MUSHROOM(20001044), + LEGEND_HELICOPTER(20001045), + LEGEND_SPACESHIP(20001046), + LEGEND_SPACE_DASH(20001047), + LEGEND_SPACE_BEAM(20001048), + LEGEND_NIGHTMARE(20001049), + LEGEND_YETI(20001050), + LEGEND_OSTRICH(20001051), + LEGEND_PINK_BEAR_HOTAIR_BALLOON(20001052), + LEGEND_TRANSFORMATION_ROBOT(20001053), + LEGEND_CHICKEN(20001054), + LEGEND_MOTORCYCLE(20001063), + LEGEND_POWER_SUIT(20001064), + LEGEND_OS4_SHUTTLE(20001065), + LEGEND_VISITOR_MELEE_ATTACK(20001066), + LEGEND_VISITOR_RANGE_ATTACK(20001067), + LEGEND_OWL(20001069), + LEGEND_MOTHERSHIP(20001070), + LEGEND_OS3A_MACHINE(20001071), + LEGEND_DECENT_HASTE(20008000), + LEGEND_DECENT_MYSTIC_DOOR(20008001), + LEGEND_DECENT_SHARP_EYES(20008002), + LEGEND_DECENT_HYPER_BODY(20008003), + LEGEND_PIGS_WEAKNESS(20009000), + LEGEND_STUMPS_WEAKNESS(20009001), + LEGEND_SLIMES_WEAKNESS(20009002), + EVANBEGINNER_BLESSING_OF_THE_FAIRY(20010012), + EVANBEGINNER_THREE_SNAILS(20011000), + EVANBEGINNER_RECOVER(20011001), + EVANBEGINNER_NIMBLE_FEET(20011002), + EVANBEGINNER_LEGENDARY_SPIRIT(20011003), + EVANBEGINNER_MONSTER_RIDER(20011004), + EVANBEGINNER_HEROS_ECHO(20011005), + EVANBEGINNER_JUMP_DOWN(20011006), + EVANBEGINNER_MAKER(20011007), + EVANBEGINNER_BAMBOO_THRUST(20011009), + EVANBEGINNER_INVINCIBLE_BARRIER(20011010), + EVANBEGINNER_METEO_SHOWER(20011011), + EVANBEGINNER_YETI_RIDER(20011018), + EVANBEGINNER_WITCHS_BROOMSTICK(20011019), + EVANBEGINNER_RAGE_OF_PHARAOH(20011020), + EVANBEGINNER_FOLLOW_THE_LEAD(20011024), + EVANBEGINNER_CHARGE_WOODEN_PONY(20011025), + EVANBEGINNER_SOARING(20011026), + EVANBEGINNER_CROCO(20011027), + EVANBEGINNER_BLACK_SCOOTER(20011028), + EVANBEGINNER_PINK_SCOOTER(20011029), + EVANBEGINNER_NIMBUS_CLOUD(20011030), + EVANBEGINNER_BALROG(20011031), + EVANBEGINNER_RACE_KART(20011033), + EVANBEGINNER_ZD_TIGER(20011034), + EVANBEGINNER_MIST_BALROG(20011035), + EVANBEGINNER_LION(20011036), + EVANBEGINNER_UNICORN(20011037), + EVANBEGINNER_LOW_RIDER(20011038), + EVANBEGINNER_RED_TRUCK(20011039), + EVANBEGINNER_GARGOYLE(20011040), + EVANBEGINNER_SHINJO(20011042), + EVANBEGINNER_ORANGE_MUSHROOM(20011044), + EVANBEGINNER_HELICOPTER(20011045), + EVANBEGINNER_SPACESHIP(20011046), + EVANBEGINNER_SPACE_DASH(20011047), + EVANBEGINNER_SPACE_BEAM(20011048), + EVANBEGINNER_NIGHTMARE(20011049), + EVANBEGINNER_YETI(20011050), + EVANBEGINNER_OSTRICH(20011051), + EVANBEGINNER_PINK_BEAR_HOTAIR_BALLOON(20011052), + EVANBEGINNER_TRANSFORMATION_ROBOT(20011053), + EVANBEGINNER_CHICKEN(20011054), + EVANBEGINNER_MOTORCYCLE(20011063), + EVANBEGINNER_POWER_SUIT(20011064), + EVANBEGINNER_OS4_SHUTTLE(20011065), + EVANBEGINNER_VISITOR_MELEE_ATTACK(20011066), + EVANBEGINNER_VISITOR_RANGE_ATTACK(20011067), + EVANBEGINNER_OWL(20011069), + EVANBEGINNER_MOTHERSHIP(20011070), + EVANBEGINNER_OS3A_MACHINE(20011071), + EVANBEGINNER_DECENT_HASTE(20018000), + EVANBEGINNER_DECENT_MYSTIC_DOOR(20018001), + EVANBEGINNER_DECENT_SHARP_EYES(20018002), + EVANBEGINNER_DECENT_HYPER_BODY(20018003), + EVANBEGINNER_PIGS_WEAKNESS(20019000), + EVANBEGINNER_STUMPS_WEAKNESS(20019001), + EVANBEGINNER_SLIMES_WEAKNESS(20019002), + ARAN1_COMBO_ABILITY(21000000), + ARAN1_DOUBLE_SWING(21000002), + ARAN1_COMBAT_STEP(21001001), + ARAN1_POLEARM_BOOSTER(21001003), + ARAN2_POLEARM_MASTERY(21100000), + ARAN2_TRIPLE_SWING(21100001), + ARAN2_FINAL_CHARGE(21100002), + ARAN2_COMBO_SMASH(21100004), + ARAN2_COMBO_DRAIN(21100005), + ARAN2_BODY_PRESSURE(21101003), + ARAN3_COMBO_CRITICAL(21110000), + ARAN3_FULL_SWING(21110002), + ARAN3_FINAL_TOSS(21110003), + ARAN3_COMBO_FENRIR(21110004), + ARAN3_ROLLING_SPIN(21110006), + ARAN3_HIDDEN_FULL_SWING_DOUBLE_SWING(21110007), + ARAN3_HIDDEN_FULL_SWING_TRIPLE_SWING(21110008), + ARAN3_SMART_KNOCKBACK(21111001), + ARAN3_SNOW_CHARGE(21111005), + ARAN4_HIGH_MASTERY(21120001), + ARAN4_OVER_SWING(21120002), + ARAN4_HIGH_DEFENSE(21120004), + ARAN4_FINAL_BLOW(21120005), + ARAN4_COMBO_TEMPEST(21120006), + ARAN4_COMBO_BARRIER(21120007), + ARAN4_HIDDEN_OVER_SWING_DOUBLE_SWING(21120009), + ARAN4_HIDDEN_OVER_SWING_TRIPLE_SWING(21120010), + ARAN4_MAPLE_WARRIOR(21121000), + ARAN4_FREEZE_STANDING(21121003), + ARAN4_HEROS_WILL(21121008), + EVAN1_DRAGON_SOUL(22000000), + EVAN1_MAGIC_MISSILE(22001001), + EVAN2_FIRE_CIRCLE(22101000), + EVAN2_TELEPORT(22101001), + EVAN3_LIGHTNING_BOLT(22111000), + EVAN3_MAGIC_GUARD(22111001), + EVAN4_SPELL_MASTERY(22120002), + EVAN4_ICE_BREATH(22121000), + EVAN4_ELEMENTAL_RESET(22121001), + EVAN5_MAGIC_FLARE(22131000), + EVAN5_MAGIC_SHIELD(22131001), + EVAN6_CRITICAL_MAGIC(22140000), + EVAN6_DRAGON_THRUST(22141001), + EVAN6_MAGIC_BOOSTER(22141002), + EVAN6_SLOW(22141003), + EVAN7_MAGIC_AMPLIFICATION(22150000), + EVAN7_FIRE_BREATH(22151001), + EVAN7_KILLER_WINGS(22151002), + EVAN7_MAGIC_RESISTANCE(22151003), + EVAN8_DRAGON_FURY(22160000), + EVAN8_EARTHQUAKE(22161001), + EVAN8_PHANTOM_IMPRINT(22161002), + EVAN8_RECOVERY_AURA(22161003), + EVAN9_MAGIC_MASTERY(22170001), + EVAN9_MAPLE_WARRIOR(22171000), + EVAN9_ILLUSION(22171002), + EVAN9_FLAME_WHEEL(22171003), + EVAN9_HEROS_WILL(22171004), + EVAN10_BLESSING_OF_THE_ONYX(22181000), + EVAN10_BLAZE(22181001), + EVAN10_DARK_FOG(22181002), + EVAN10_SOUL_STONE(22181003), + CITIZEN_POTION_MASTERY(30000002), + CITIZEN_BLESSING_OF_THE_FAIRY(30000012), + CITIZEN_DEADLY_CRITS(30000022), + CITIZEN_CRYSTAL_THROW(30001000), + CITIZEN_INFILTRATE(30001001), + CITIZEN_LEGENDARY_SPIRIT(30001003), + CITIZEN_MONSTER_RIDING(30001004), + CITIZEN_HEROS_ECHO(30001005), + CITIZEN_TEST(30001006), + CITIZEN_MAKER(30001007), + CITIZEN_BAMBOO_RAIN(30001009), + CITIZEN_INVINCIBILITY(30001010), + CITIZEN_POWER_EXPLOSION(30001011), + CITIZEN_SPACESHIP(30001013), + CITIZEN_SPACE_DASH(30001014), + CITIZEN_SPACE_BEAM(30001015), + CITIZEN_YETI_MOUNT(30001017), + CITIZEN_YETI_MOUNT_1(30001018), + CITIZEN_WITCHS_BROOMSTICK(30001019), + CITIZEN_RAGE_OF_PHARAOH(30001020), + CITIZEN_FOLLOW_THE_LEAD(30001024), + CITIZEN_CHARGE_TOY_TROJAN(30001025), + CITIZEN_SOARING(30001026), + CITIZEN_CROCO(30001027), + CITIZEN_BLACK_SCOOTER(30001028), + CITIZEN_PINK_SCOOTER(30001029), + CITIZEN_NIMBUS_CLOUD(30001030), + CITIZEN_BALROG(30001031), + CITIZEN_RACE_KART(30001033), + CITIZEN_ZD_TIGER(30001034), + CITIZEN_MIST_BALROG(30001035), + CITIZEN_LION(30001036), + CITIZEN_UNICORN(30001037), + CITIZEN_LOW_RIDER(30001038), + CITIZEN_RED_TRUCK(30001039), + CITIZEN_GARGOYLE(30001040), + CITIZEN_SHINJO(30001042), + CITIZEN_ORANGE_MUSHROOM(30001044), + CITIZEN_NIGHTMARE(30001049), + CITIZEN_YETI(30001050), + CITIZEN_OSTRICH(30001051), + CITIZEN_PINK_BEAR_HOTAIR_BALLOON(30001052), + CITIZEN_TRANSFORMED_ROBOT(30001053), + CITIZEN_CAPTURE(30001061), + CITIZEN_CALL_OF_THE_HUNTER(30001062), + CITIZEN_MOTORCYCLE(30001063), + CITIZEN_POWER_SUIT(30001064), + CITIZEN_OS4_SHUTTLE(30001065), + CITIZEN_VISITOR_MELEE_ATTACK(30001066), + CITIZEN_VISITOR_RANGE_ATTACK(30001067), + CITIZEN_MECHANIC_DASH(30001068), + CITIZEN_OWL(30001069), + CITIZEN_MOTHERSHIP(30001070), + CITIZEN_OS3A_MACHINE(30001071), + CITIZEN_DECENT_HASTE(30008000), + CITIZEN_DECENT_MYSTIC_DOOR(30008001), + CITIZEN_DECENT_SHARP_EYES(30008002), + CITIZEN_DECENT_HYPER_BODY(30008003), + TRIPLE_BLOW(32001000), + THE_FINISHER(32001001), + TELEPORT(32001002), + DARK_AURA(32001003), + STAFF_MASTERY(32100006), + QUAD_BLOW(32101000), + DARK_CHAIN(32101001), + BLUE_AURA(32101002), + YELLOW_AURA(32101003), + BLOOD_DRAIN(32101004), + STAFF_BOOST(32101005), + ADVANCED_BLUE_AURA(32110000), + BATTLE_MASTERY(32110001), + QUINTUPLE_BLOW(32111002), + DARK_SHOCK(32111003), + CONVERSION(32111004), + BODY_BOOST(32111005), + SUMMON_REAPER_BUFF(32111006), + TELEPORT_MASTERY(32111010), + ADVANCED_DARK_CHAIN(32111011), + ADVANCED_DARK_AURA(32120000), + ADVANCED_YELLOW_AURA(32120001), + ENERGIZE(32120009), + FINISHING_BLOW(32121002), + TWISTER_SPIN(32121003), + DARK_GENESIS(32121004), + STANCE(32121005), + PARTY_SHIELD(32121006), + MAPLE_WARRIOR(32121007), + HEROS_WILL(32121008), + WH1_TRIPLE_SHOT(33001000), + WH1_JAGUAR_RIDER(33001001), + WH1_JAG_JUMP(33001002), + WH1_CROSSBOW_BOOSTER(33001003), + WH2_CROSSBOW_MASTERY(33100000), + WH2_FINAL_ATTACK(33100009), + WH2_RICOCHET(33101001), + WH2_JAGUAR_RAWR(33101002), + WH2_SOUL_ARROW_CROSSBOW(33101003), + WH2_ITS_RAINING_MINES(33101004), + WH2_JAGUAROSHI(33101005), + WH2_JAGUAROSHI_1(33101006), + WH2_JAGUAROSHI_2(33101007), + WH2_ITS_RAINING_MINESHIDDEN_SELFDESTRUCT(33101008), + WH3_JAGUAR_BOOST(33110000), + WH3_ENDURING_FIRE(33111001), + WH3_DASH_N_SLASH(33111002), + WH3_WILD_TRAP(33111003), + WH3_BLIND(33111004), + WH3_SILVER_HAWK(33111005), + WH3_SWIPE(33111006), + WH4_CROSSBOW_EXPERT(33120000), + WH4_WILD_INSTINCT(33120010), + WH4_EXPLODING_ARROWS(33121001), + WH4_SONIC_ROAR(33121002), + WH4_SHARP_EYES(33121004), + WH4_STINK_BOMB_SHOT(33121005), + WH4_FELINE_BERSERK(33121006), + WH4_MAPLE_WARRIOR(33121007), + WH4_HEROS_WILL(33121008), + WH4_WILD_ARROW_BLAST(33121009), + MECH1_FLAME_LAUNCHER(35001001), + MECH1_MECH_PROTOTYPE(35001002), + MECH1_ME07_DRILLHANDS(35001003), + MECH1_GATLING_GUN(35001004), + MECH2_MECHANIC_MASTERY(35100000), + MECH2_HEAVY_WEAPON_MASTERY(35100008), + MECH2_ATOMIC_HAMMER(35101003), + MECH2_ROCKET_BOOSTER(35101004), + MECH2_OPEN_PORTAL_GX9(35101005), + MECH2_MECHANIC_RAGE(35101006), + MECH2_PERFECT_ARMOR(35101007), + MECH2_ENHANCED_FLAME_LAUNCHER(35101009), + MECH2_ENHANCED_GATLING_GUN(35101010), + MECH3_METAL_FIST_MASTERY(35110014), + MECH3_SATELLITE(35111001), + MECH3_ROCK_N_SHOCK(35111002), + MECH3_MECH_SIEGE_MODE(35111004), + MECH3_ACCELERATION_BOT_EX7(35111005), + MECH3_SATELLITE_1(35111009), + MECH3_SATELLITE_2(35111010), + MECH3_HEALING_ROBOT_HLX(35111011), + MECH3_ROLL_OF_THE_DICE(35111013), + MECH3_PUNCH_LAUNCHER(35111015), + MECH4_EXTREME_MECH(35120000), + MECH4_ROBOT_MASTERY(35120001), + MECH4_GIANT_ROBOT_SG88(35121003), + MECH4_MECH_MISSILE_TANK(35121005), + MECH4_SATELLITE_SAFETY(35121006), + MECH4_MAPLE_WARRIOR(35121007), + MECH4_HEROS_WILL(35121008), + MECH4_BOTS_N_TOTS(35121009), + MECH4_AMPLIFIER_ROBOT_AF11(35121010), + MECH4_UNK(35121011), + MECH4_LASER_BLAST(35121012), + MECH4_MECH_SIEGE_MODE(35121013), + INSTANT_DEATH(90000000), + KNOCK_DOWN(90001001), + SLOW(90001002), + POISON(90001003), + DARKNESS(90001004), + SEAL(90001005), + FREEZE(90001006); + private final int id; + + SkillId(int id) { + this.id = id; + } + + public int getId() { + return id; + } + + public boolean isNone() { + return this == SkillId.NONE; + } + + public static SkillId fromValue(int value) { + //TODO + return SkillId.NONE; + } + + + public SkillCategory category() { + return switch (this) { + case SkillId.HERMIT_FLASH_JUMP, SkillId.CHIEFBANDIT_FLASH_JUMP, SkillId.DB3_FLASH_JUMP, + SkillId.DW2_SOUL_RUSH, SkillId.NW2_FLASH_JUMP, SkillId.WH1_JAG_JUMP -> SkillCategory.BoundJump; + case SkillId.ARAN1_COMBAT_STEP, SkillId.CITIZEN_MECHANIC_DASH -> SkillCategory.CombatStep; + case SkillId.BEGINNER_TEST, SkillId.NOBLESSE_JUMP_DOWN, SkillId.LEGEND_JUMP_DOWN, + SkillId.EVANBEGINNER_JUMP_DOWN, SkillId.CITIZEN_TEST -> SkillCategory.DamageMeter; + case SkillId.BEGINNER_SOARING, SkillId.NOBLESSE_SOARING, SkillId.LEGEND_SOARING, + SkillId.EVANBEGINNER_SOARING, SkillId.CITIZEN_SOARING -> SkillCategory.Flying; + case SkillId.CLERIC_HEAL -> SkillCategory.Heal; + case SkillId.DB5_CHAINS_OF_HELL -> SkillCategory.HookAndHit; + case SkillId.MAGE_ENERGY_BOLT, SkillId.MAGE_MAGIC_CLAW, SkillId.FP1_FIRE_ARROW, SkillId.FP1_POISON_BREATH, + SkillId.FP2_POISON_MIST, SkillId.FP2_ELEMENT_COMPOSITION, SkillId.FP3_FIRE_DEMON, SkillId.FP3_PARALYZE, + SkillId.FP3_METEOR_SHOWER, SkillId.IL1_COLD_BEAM, SkillId.IL1_THUNDER_BOLT, SkillId.IL2_ICE_STRIKE, + SkillId.IL2_THUNDER_SPEAR, SkillId.IL2_ELEMENT_COMPOSITION, SkillId.IL3_ICE_DEMON, + SkillId.IL3_CHAIN_LIGHTNING, SkillId.IL3_BLIZZARD, SkillId.CLERIC_HOLY_ARROW, + SkillId.PRIEST_SHINING_RAY, SkillId.BISHOP_ANGEL_RAY, SkillId.BISHOP_GENESIS, SkillId.BW1_MAGIC_CLAW, + SkillId.BW2_FIRE_ARROW, SkillId.BW2_FIRE_PILLAR, SkillId.BW3_METEOR_SHOWER, SkillId.BW3_FLAME_GEAR, + SkillId.BW3_FIRE_STRIKE, SkillId.EVAN1_MAGIC_MISSILE, SkillId.EVAN2_FIRE_CIRCLE, + SkillId.EVAN3_LIGHTNING_BOLT, SkillId.EVAN5_MAGIC_FLARE, SkillId.EVAN6_DRAGON_THRUST, + SkillId.EVAN7_KILLER_WINGS, SkillId.EVAN8_EARTHQUAKE, SkillId.EVAN8_PHANTOM_IMPRINT, + SkillId.EVAN9_ILLUSION, SkillId.EVAN9_FLAME_WHEEL, SkillId.EVAN10_BLAZE, SkillId.EVAN10_DARK_FOG, + SkillId.DARK_CHAIN, SkillId.DARK_SHOCK, SkillId.ADVANCED_DARK_CHAIN, SkillId.DARK_GENESIS -> + SkillCategory.MagicAttack; + case SkillId.BEGINNER_BAMBOO_RAIN, SkillId.BEGINNER_RAGE_OF_PHARAOH, SkillId.BEGINNER_VISITOR_MELEE_ATTACK, + SkillId.BEGINNER_VISITOR_RANGE_ATTACK, SkillId.WARRIOR_POWER_STRIKE, SkillId.WARRIOR_SLASH_BLAST, + SkillId.FIGHTER_GROUND_SMASH, SkillId.CRUSADER_SHOUT, SkillId.CRUSADER_BRANDISH, + SkillId.HERO_MONSTER_MAGNET, SkillId.HERO_INTREPID_SLASH, SkillId.PAGE_GROUND_SMASH, + SkillId.PALADIN_HEAVENS_HAMMER, SkillId.SPEARNMAN_GROUND_SMASH, SkillId.DK_DRAGON_BUSTER, + SkillId.DRK_MONSTER_MAGNET, SkillId.BOWMASTER_VENGEANCE, SkillId.THIEF_DISORDER, + SkillId.THIEF_DOUBLE_STAB, SkillId.NIGHTLORD_NINJA_STORM, SkillId.BANDIT_STEAL, + SkillId.BANDIT_SAVAGE_BLOW, SkillId.CHIEFBANDIT_ASSAULTER, SkillId.CHIEFBANDIT_BAND_OF_THIEVES, + SkillId.SHADOWER_ASSASSINATE, SkillId.SHADOWER_BOOMERANG_STEP, SkillId.DB1_TRIPLE_STAB, + SkillId.DB2_FATAL_BLOW, SkillId.DB2_SLASH_STORM, SkillId.DB3_TORNADO_SPIN_ATTACK, + SkillId.DB4_BLOODY_STORM, SkillId.DB4_OWL_SPIRIT, SkillId.DB4_UPPER_STAB, SkillId.DB4_FLYING_ASSAULTER, + SkillId.DB5_SUDDEN_RAID, SkillId.PIRATE_FLASH_FIST, SkillId.PIRATE_SOMMERSAULT_KICK, + SkillId.BRAWLER_BACKSPIN_BLOW, SkillId.BRAWLER_DOUBLE_UPPERCUT, SkillId.MARAUDER_ENERGY_BLAST, + SkillId.MARAUDER_ENERGY_DRAIN, SkillId.MARAUDER_SHOCKWAVE, SkillId.BUCCANEER_DRAGON_STRIKE, + SkillId.BUCCANEER_DEMOLITION, SkillId.BUCCANEER_SNATCH, SkillId.BUCCANEER_BARRAGE, + SkillId.GUNSLINGER_BLANK_SHOT, SkillId.CORSAIR_AIR_STRIKE, SkillId.GM_SUPER_DRAGON_ROAR, + SkillId.NOBLESSE_BAMBOO_THRUST, SkillId.NOBLESSE_RAGE_OF_PHARAOH, + SkillId.NOBLESSE_VISITOR_MELEE_ATTACK, SkillId.NOBLESSE_VISITOR_RANGE_ATTACK, SkillId.DW1_POWER_STRIKE, + SkillId.DW1_SLASH_BLAST, SkillId.DW3_BRANDISH, SkillId.DW3_SOUL_DRIVER, SkillId.NW1_DISORDER, + SkillId.TB1_STRAIGHT, SkillId.TB1_SOMERSAULT_KICK, SkillId.TB2_ENERGY_BLAST, SkillId.TB3_ENERGY_DRAIN, + SkillId.TB3_SHOCKWAVE, SkillId.TB3_BARRAGE, SkillId.LEGEND_BAMBOO_THRUST, + SkillId.LEGEND_RAGE_OF_PHARAOH, SkillId.LEGEND_VISITOR_MELEE_ATTACK, + SkillId.LEGEND_VISITOR_RANGE_ATTACK, SkillId.EVANBEGINNER_BAMBOO_THRUST, + SkillId.EVANBEGINNER_RAGE_OF_PHARAOH, SkillId.EVANBEGINNER_VISITOR_MELEE_ATTACK, + SkillId.EVANBEGINNER_VISITOR_RANGE_ATTACK, SkillId.CITIZEN_BAMBOO_RAIN, + SkillId.CITIZEN_RAGE_OF_PHARAOH, SkillId.CITIZEN_VISITOR_MELEE_ATTACK, + SkillId.CITIZEN_VISITOR_RANGE_ATTACK, SkillId.WH3_DASH_N_SLASH, SkillId.WH3_SWIPE, + SkillId.WH4_SONIC_ROAR, SkillId.MECH1_ME07_DRILLHANDS, SkillId.MECH2_ATOMIC_HAMMER -> + SkillCategory.MeleeAttack; + case SkillId.CHIEFBANDIT_MESO_EXPLOSION -> SkillCategory.MesoExplosion; + case SkillId.CITIZEN_CAPTURE -> SkillCategory.MobCapture; + case SkillId.DB3_FLASHBANG -> SkillCategory.NotPrepareBomb; + case SkillId.MECH2_OPEN_PORTAL_GX9 -> SkillCategory.OpenGate; + case SkillId.FP2_EXPLOSION, SkillId.FP3_BIG_BANG, SkillId.IL3_BIG_BANG, SkillId.BISHOP_BIG_BANG, + SkillId.BOWMASTER_HURRICANE, SkillId.MARKSMAN_PIERCING_ARROW, SkillId.CHIEFBANDIT_CHAKRA, + SkillId.DB5_FINAL_CUT, SkillId.DB5_MONSTER_BOMB, SkillId.BRAWLER_CORKSCREW_BLOW, + SkillId.GUNSLINGER_GRENADE, SkillId.CORSAIR_RAPID_FIRE, SkillId.WA3_HURRICANE, SkillId.NW3_POISON_BOMB, + SkillId.TB2_CORKSCREW_BLOW, SkillId.EVAN4_ICE_BREATH, SkillId.EVAN7_FIRE_BREATH, + SkillId.WH2_JAGUAROSHI, SkillId.WH4_WILD_ARROW_BLAST, SkillId.MECH1_FLAME_LAUNCHER, + SkillId.MECH2_ENHANCED_FLAME_LAUNCHER -> SkillCategory.Prepare; + case SkillId.EVAN8_RECOVERY_AURA -> SkillCategory.RecoveryAura; + case SkillId.MECH3_MECH_SIEGE_MODE, SkillId.MECH4_GIANT_ROBOT_SG88, SkillId.MECH4_MECH_MISSILE_TANK -> + SkillCategory.RepeatSkill; + case SkillId.MECH2_ROCKET_BOOSTER -> SkillCategory.RocketBooster; + case SkillId.BOWMAN_ARROW_BLOW, SkillId.BOWMAN_DOUBLE_SHOT, SkillId.HUNTER_POWER_KNOCKBACK, + SkillId.HUNTER_ARROW_BOMB_BOW, SkillId.RANGER_INFERNO, SkillId.RANGER_ARROW_RAIN, + SkillId.RANGER_STRAFE, SkillId.BOWMASTER_DRAGONS_BREATH, SkillId.CROSSBOWMAN_POWER_KNOCKBACK, + SkillId.CROSSBOWMAN_IRON_ARROW_CROSSBOW, SkillId.SNIPER_BLIZZARD, SkillId.SNIPER_ARROW_ERUPTION, + SkillId.SNIPER_STRAFE, SkillId.MARKSMAN_DRAGONS_BREATH, SkillId.MARKSMAN_SNIPE, + SkillId.THIEF_LUCKY_SEVEN, SkillId.ASSASSIN_DRAIN, SkillId.HERMIT_SHADOW_MESO, SkillId.HERMIT_AVENGER, + SkillId.NIGHTLORD_TAUNT, SkillId.NIGHTLORD_TRIPLE_THROW, SkillId.SHADOWER_TAUNT, + SkillId.PIRATE_DOUBLE_SHOT, SkillId.BUCCANEER_ENERGY_ORB, SkillId.GUNSLINGER_INVISIBLE_SHOT, + SkillId.GUNSLINGER_RECOIL_SHOT, SkillId.OUTLAW_BURST_FIRE, SkillId.OUTLAW_FLAMETHROWER, + SkillId.OUTLAW_ICE_SPLITTER, SkillId.OUTLAW_HOMING_BEACON, SkillId.CORSAIR_BULLSEYE, + SkillId.CORSAIR_HYPNOTIZE, SkillId.DW2_SOUL_BLADE, SkillId.WA1_DOUBLE_SHOT, SkillId.WA2_STORM_BREAK, + SkillId.WA3_ARROW_RAIN, SkillId.WA3_STRAFE, SkillId.WA3_WIND_PIERCING, SkillId.WA3_WIND_SHOT, + SkillId.NW1_LUCKY_SEVEN, SkillId.NW2_VAMPIRE, SkillId.NW3_AVENGER, SkillId.NW3_TRIPLE_THROW, + SkillId.TB3_SHARK_WAVE, SkillId.ARAN2_COMBO_SMASH, SkillId.ARAN3_COMBO_FENRIR, + SkillId.ARAN4_COMBO_TEMPEST, SkillId.WH1_TRIPLE_SHOT, SkillId.WH2_RICOCHET, SkillId.WH2_JAGUAR_RAWR, + SkillId.WH2_JAGUAROSHI_2, SkillId.WH3_ENDURING_FIRE, SkillId.WH4_EXPLODING_ARROWS, + SkillId.WH4_STINK_BOMB_SHOT, SkillId.MECH1_GATLING_GUN, SkillId.MECH2_ENHANCED_GATLING_GUN, + SkillId.MECH3_PUNCH_LAUNCHER, SkillId.MECH4_LASER_BLAST -> SkillCategory.ShootAttack; + case SkillId.SHADOWER_SMOKESCREEN -> SkillCategory.SmokeShell; + case SkillId.BEGINNER_RECOVERY, SkillId.BEGINNER_NIMBLE_FEET, SkillId.BEGINNER_MONSTER_RIDER, + SkillId.BEGINNER_INVINCIBILITY, SkillId.BEGINNER_POWER_EXPLOSION, SkillId.BEGINNER_SPACE_BEAM_1, + SkillId.BEGINNER_DECENT_HASTE, SkillId.BEGINNER_DECENT_SHARP_EYES, SkillId.BEGINNER_DECENT_HYPER_BODY, + SkillId.WARRIOR_IRON_BODY, SkillId.FIGHTER_RAGE, SkillId.FIGHTER_POWER_GUARD, + SkillId.CRUSADER_COMBO_ATTACK, SkillId.CRUSADER_MAGIC_CRASH, SkillId.HERO_MAPLE_WARRIOR, + SkillId.HERO_POWER_STANCE, SkillId.HERO_ENRAGE, SkillId.PAGE_THREATEN, SkillId.PAGE_POWER_GUARD, + SkillId.WK_MAGIC_CRASH, SkillId.WK_HP_RECOVERY, SkillId.WK_COMBAT_ORDERS, + SkillId.PALADIN_MAPLE_WARRIOR, SkillId.PALADIN_POWER_STANCE, SkillId.SPEARNMAN_IRON_WILL, + SkillId.SPEARNMAN_HYPER_BODY, SkillId.DK_MAGIC_CRASH, SkillId.DK_DRAGON_BLOOD, + SkillId.DRK_MAPLE_WARRIOR, SkillId.DRK_POWER_STANCE, SkillId.MAGE_MAGIC_GUARD, + SkillId.MAGE_MAGIC_ARMOR, SkillId.FP1_MEDITATION, SkillId.FP1_SLOW, SkillId.FP2_SEAL, + SkillId.FP2_TELEPORT_MASTERY, SkillId.FP3_MAPLE_WARRIOR, SkillId.FP3_MANA_REFLECTION, + SkillId.FP3_INFINITY, SkillId.IL1_MEDITATION, SkillId.IL1_SLOW, SkillId.IL2_SEAL, + SkillId.IL2_TELEPORT_MASTERY, SkillId.IL3_MAPLE_WARRIOR, SkillId.IL3_MANA_REFLECTION, + SkillId.IL3_INFINITY, SkillId.CLERIC_INVINCIBLE, SkillId.CLERIC_BLESS, SkillId.PRIEST_DISPEL, + SkillId.PRIEST_HOLY_SYMBOL, SkillId.PRIEST_DOOM, SkillId.PRIEST_TELEPORT_MASTERY, + SkillId.BISHOP_MAPLE_WARRIOR, SkillId.BISHOP_MANA_REFLECTION, SkillId.BISHOP_INFINITY, + SkillId.BISHOP_HOLY_SHIELD, SkillId.BISHOP_RESURRECTION, SkillId.BOWMAN_FOCUS, + SkillId.BOWMASTER_MAPLE_WARRIOR, SkillId.BOWMASTER_SHARP_EYES, SkillId.BOWMASTER_HAMSTRING, + SkillId.BOWMASTER_CONCENTRATE, SkillId.MARKSMAN_MAPLE_WARRIOR, SkillId.MARKSMAN_SHARP_EYES, + SkillId.MARKSMAN_BLIND, SkillId.THIEF_DARK_SIGHT, SkillId.ASSASSIN_HASTE, SkillId.HERMIT_ALCHEMIST, + SkillId.HERMIT_MESO_UP, SkillId.HERMIT_SHADOW_PARTNER, SkillId.HERMIT_SHADOW_WEB, + SkillId.NIGHTLORD_MAPLE_WARRIOR, SkillId.NIGHTLORD_NINJA_AMBUSH, SkillId.BANDIT_HASTE, + SkillId.CHIEFBANDIT_PICKPOCKET, SkillId.CHIEFBANDIT_MESO_GUARD, SkillId.CHIEFBANDIT_SHADOW_PARTNER, + SkillId.SHADOWER_MAPLE_WARRIOR, SkillId.SHADOWER_NINJA_AMBUSH, SkillId.DB2_SELF_HASTE, + SkillId.DB3_TORNADO_SPIN, SkillId.DB4_MIRROR_IMAGE, SkillId.DB5_MAPLE_WARRIOR, SkillId.DB5_THORNS, + SkillId.PIRATE_DASH, SkillId.BRAWLER_MP_RECOVERY, SkillId.BRAWLER_OAK_BARREL, + SkillId.MARAUDER_ROLL_OF_THE_DICE, SkillId.BUCCANEER_MAPLE_WARRIOR, SkillId.BUCCANEER_SPEED_INFUSION, + SkillId.BUCCANEER_TIME_LEAP, SkillId.OUTLAW_ROLL_OF_THE_DICE, SkillId.CORSAIR_MAPLE_WARRIOR, + SkillId.CORSAIR_BATTLESHIP, SkillId.GM_HASTE_NORMAL, SkillId.SUPERGM_HIDE, SkillId.NOBLESSE_RECOVERY, + SkillId.NOBLESSE_NIMBLE_FEET, SkillId.NOBLESSE_MONSTER_RIDER, SkillId.NOBLESSE_INVINCIBLE_BARRIER, + SkillId.NOBLESSE_METEO_SHOWER, SkillId.NOBLESSE_SPACE_BEAM_1, SkillId.NOBLESSE_DECENT_HASTE, + SkillId.NOBLESSE_DECENT_SHARP_EYES, SkillId.NOBLESSE_DECENT_HYPER_BODY, SkillId.DW1_IRON_BODY, + SkillId.DW2_RAGE, SkillId.DW3_COMBO_ATTACK, SkillId.BW1_MAGIC_GUARD, SkillId.BW1_MAGIC_ARMOR, + SkillId.BW2_MEDITATION, SkillId.BW2_SLOW, SkillId.BW3_SEAL, SkillId.WA1_FOCUS, SkillId.WA2_WIND_WALK, + SkillId.NW1_DARK_SIGHT, SkillId.NW2_HASTE, SkillId.NW3_ALCHEMIST, SkillId.NW3_SHADOW_PARTNER, + SkillId.NW3_SHADOW_WEB, SkillId.TB1_DASH, SkillId.TB3_SPEED_INFUSION, SkillId.LEGEND_RECOVERY, + SkillId.LEGEND_AGILE_BODY, SkillId.LEGEND_MONSTER_RIDER, SkillId.LEGEND_INVINCIBLE_BARRIER, + SkillId.LEGEND_METEO_SHOWER, SkillId.LEGEND_SPACE_BEAM, SkillId.LEGEND_DECENT_HASTE, + SkillId.LEGEND_DECENT_SHARP_EYES, SkillId.LEGEND_DECENT_HYPER_BODY, SkillId.EVANBEGINNER_RECOVER, + SkillId.EVANBEGINNER_NIMBLE_FEET, SkillId.EVANBEGINNER_MONSTER_RIDER, + SkillId.EVANBEGINNER_INVINCIBLE_BARRIER, SkillId.EVANBEGINNER_METEO_SHOWER, + SkillId.EVANBEGINNER_SPACE_BEAM, SkillId.EVANBEGINNER_DECENT_HASTE, + SkillId.EVANBEGINNER_DECENT_SHARP_EYES, SkillId.EVANBEGINNER_DECENT_HYPER_BODY, + SkillId.ARAN2_COMBO_DRAIN, SkillId.ARAN2_BODY_PRESSURE, SkillId.ARAN3_SMART_KNOCKBACK, + SkillId.ARAN4_COMBO_BARRIER, SkillId.ARAN4_MAPLE_WARRIOR, SkillId.ARAN4_FREEZE_STANDING, + SkillId.EVAN3_MAGIC_GUARD, SkillId.EVAN5_MAGIC_SHIELD, SkillId.EVAN6_SLOW, + SkillId.EVAN7_MAGIC_RESISTANCE, SkillId.EVAN9_MAPLE_WARRIOR, SkillId.EVAN10_BLESSING_OF_THE_ONYX, + SkillId.EVAN10_SOUL_STONE, SkillId.CITIZEN_INFILTRATE, SkillId.CITIZEN_INVINCIBILITY, + SkillId.CITIZEN_POWER_EXPLOSION, SkillId.CITIZEN_DECENT_HASTE, SkillId.CITIZEN_DECENT_SHARP_EYES, + SkillId.CITIZEN_DECENT_HYPER_BODY, SkillId.TELEPORT_MASTERY, SkillId.MAPLE_WARRIOR, SkillId.WH3_BLIND, + SkillId.WH4_SHARP_EYES, SkillId.WH4_MAPLE_WARRIOR, SkillId.MECH1_MECH_PROTOTYPE, + SkillId.MECH2_PERFECT_ARMOR, SkillId.MECH3_ROLL_OF_THE_DICE, SkillId.MECH4_SATELLITE_SAFETY, + SkillId.MECH4_MAPLE_WARRIOR -> SkillCategory.StatChange; + case SkillId.BEGINNER_ECHO_OF_HERO, SkillId.SUPERGM_HEAL_DISPEL, SkillId.SUPERGM_HASTE_SUPER, + SkillId.SUPERGM_HOLY_SYMBOL, SkillId.SUPERGM_BLESS, SkillId.SUPERGM_RESURRECTION, + SkillId.SUPERGM_HYPER_BODY, SkillId.NOBLESSE_ECHO_OF_HERO, SkillId.LEGEND_ECHO_OF_HERO, + SkillId.EVANBEGINNER_HEROS_ECHO, SkillId.CITIZEN_HEROS_ECHO -> SkillCategory.StatChangeAdmin; + case SkillId.DRK_BEHOLDER, SkillId.FP3_IFRIT, SkillId.IL3_ELQUINES, SkillId.PRIEST_SUMMON_DRAGON, + SkillId.BISHOP_BAHAMUT, SkillId.RANGER_PUPPET, SkillId.RANGER_SILVER_HAWK, SkillId.BOWMASTER_PHOENIX, + SkillId.SNIPER_PUPPET, SkillId.SNIPER_GOLDEN_EAGLE, SkillId.MARKSMAN_FROSTPREY, + SkillId.HERMIT_DARK_FLARE, SkillId.CHIEFBANDIT_DARK_FLARE, SkillId.OUTLAW_OCTOPUS, + SkillId.OUTLAW_GAVIOTA, SkillId.CORSAIR_WRATH_OF_THE_OCTOPI, SkillId.DW1_SOUL, SkillId.BW1_FLAME, + SkillId.BW3_IFRIT, SkillId.WA1_STORM, SkillId.WA3_PUPPET, SkillId.NW1_DARKNESS, SkillId.TB1_LIGHTNING, + SkillId.WH3_WILD_TRAP, SkillId.WH3_SILVER_HAWK, SkillId.MECH3_SATELLITE, SkillId.MECH3_ROCK_N_SHOCK, + SkillId.MECH3_ACCELERATION_BOT_EX7, SkillId.MECH3_SATELLITE_1, SkillId.MECH3_SATELLITE_2, + SkillId.MECH3_HEALING_ROBOT_HLX, SkillId.MECH4_BOTS_N_TOTS, SkillId.MECH4_AMPLIFIER_ROBOT_AF11 -> + SkillCategory.Summon; + case SkillId.CITIZEN_CALL_OF_THE_HUNTER -> SkillCategory.SummonMonster; + case SkillId.FP1_TELEPORT, SkillId.IL1_TELEPORT, SkillId.CLERIC_TELEPORT, SkillId.SHROOMLEAFBRIGADIER__, + SkillId.GM_TELEPORT, SkillId.BW2_TELEPORT, SkillId.EVAN2_TELEPORT, SkillId.TELEPORT -> + SkillCategory.Teleport; + case SkillId.BEGINNER_DECENT_MYSTIC_DOOR, SkillId.PRIEST_MYSTIC_DOOR, SkillId.NOBLESSE_DECENT_MYSTIC_DOOR, + SkillId.LEGEND_DECENT_MYSTIC_DOOR, SkillId.EVANBEGINNER_DECENT_MYSTIC_DOOR, + SkillId.CITIZEN_DECENT_MYSTIC_DOOR -> SkillCategory.TownPortal; + case SkillId.CORSAIR_BATTLESHIP_CANNON, SkillId.CORSAIR_BATTLESHIP_TORPEDO -> + SkillCategory.VehicleShootAttack; + case SkillId.FIGHTER_WEAPON_BOOSTER, SkillId.PAGE_WEAPON_BOOSTER, SkillId.SPEARNMAN_WEAPON_BOOSTER, + SkillId.FP2_SPELL_BOOSTER, SkillId.IL2_SPELL_BOOSTER, SkillId.HUNTER_BOW_BOOSTER, + SkillId.CROSSBOWMAN_CROSSBOW_BOOSTER, SkillId.ASSASSIN_CLAW_BOOSTER, SkillId.BANDIT_DAGGER_BOOSTER, + SkillId.DB1_KATARA_BOOSTER, SkillId.BRAWLER_KNUCKLE_BOOSTER, SkillId.GUNSLINGER_GUN_BOOSTER, + SkillId.DW2_SWORD_BOOSTER, SkillId.BW2_SPELL_BOOSTER, SkillId.WA2_BOW_BOOSTER, + SkillId.NW2_CLAW_BOOSTER, SkillId.TB2_KNUCKLE_BOOSTER, SkillId.ARAN1_POLEARM_BOOSTER, + SkillId.EVAN6_MAGIC_BOOSTER, SkillId.STAFF_BOOST, SkillId.WH1_CROSSBOW_BOOSTER, + SkillId.MECH2_MECHANIC_RAGE -> SkillCategory.WeaponBooster; + default -> SkillCategory.None; + }; + } + + + public int getRoot() { + return getId() / 10000; + } + + public int getType() { + return getId() % 10000; + } + public int getJobId() { + return getId() / 10000; + } + + public boolean hasTargetFlag(SkillTargetFlags flag) { + return (getTargetFlags() & flag.getValue()) != 0; + } + + public int getTargetFlags() { + return switch (this) { + case SkillId.BEGINNER_RECOVERY, SkillId.BEGINNER_NIMBLE_FEET, SkillId.BEGINNER_MONSTER_RIDER, + SkillId.BEGINNER_INVINCIBILITY, SkillId.BEGINNER_POWER_EXPLOSION, SkillId.BEGINNER_SPACE_BEAM_1, + SkillId.BEGINNER_DECENT_HASTE, SkillId.WARRIOR_IRON_BODY, SkillId.FIGHTER_POWER_GUARD, + SkillId.CRUSADER_COMBO_ATTACK, SkillId.HERO_POWER_STANCE, SkillId.HERO_ENRAGE, + SkillId.PAGE_POWER_GUARD, SkillId.WK_HP_RECOVERY, SkillId.PALADIN_POWER_STANCE, + SkillId.DK_DRAGON_BLOOD, SkillId.DRK_POWER_STANCE, SkillId.MAGE_MAGIC_GUARD, + SkillId.MAGE_MAGIC_ARMOR, SkillId.FP2_TELEPORT_MASTERY, SkillId.FP3_MANA_REFLECTION, + SkillId.FP3_INFINITY, SkillId.IL2_TELEPORT_MASTERY, SkillId.IL3_MANA_REFLECTION, + SkillId.IL3_INFINITY, SkillId.CLERIC_INVINCIBLE, SkillId.PRIEST_TELEPORT_MASTERY, + SkillId.BISHOP_MANA_REFLECTION, SkillId.BISHOP_INFINITY, SkillId.BOWMAN_FOCUS, + SkillId.BOWMASTER_HAMSTRING, SkillId.BOWMASTER_CONCENTRATE, SkillId.MARKSMAN_BLIND, + SkillId.THIEF_DARK_SIGHT, SkillId.HERMIT_ALCHEMIST, SkillId.HERMIT_SHADOW_PARTNER, + SkillId.CHIEFBANDIT_PICKPOCKET, SkillId.CHIEFBANDIT_MESO_GUARD, SkillId.CHIEFBANDIT_SHADOW_PARTNER, + SkillId.DB2_SELF_HASTE, SkillId.DB3_TORNADO_SPIN, SkillId.DB4_MIRROR_IMAGE, SkillId.PIRATE_DASH, + SkillId.BRAWLER_MP_RECOVERY, SkillId.BRAWLER_OAK_BARREL, SkillId.MARAUDER_ROLL_OF_THE_DICE, + SkillId.OUTLAW_ROLL_OF_THE_DICE, SkillId.CORSAIR_BATTLESHIP, SkillId.GM_HASTE_NORMAL, + SkillId.SUPERGM_HIDE, SkillId.NOBLESSE_RECOVERY, SkillId.NOBLESSE_NIMBLE_FEET, + SkillId.NOBLESSE_MONSTER_RIDER, SkillId.NOBLESSE_INVINCIBLE_BARRIER, SkillId.NOBLESSE_METEO_SHOWER, + SkillId.NOBLESSE_SPACE_BEAM_1, SkillId.NOBLESSE_DECENT_HASTE, SkillId.DW1_IRON_BODY, + SkillId.DW3_COMBO_ATTACK, SkillId.BW1_MAGIC_GUARD, SkillId.BW1_MAGIC_ARMOR, SkillId.WA1_FOCUS, + SkillId.WA2_WIND_WALK, SkillId.NW1_DARK_SIGHT, SkillId.NW3_ALCHEMIST, SkillId.NW3_SHADOW_PARTNER, + SkillId.TB1_DASH, SkillId.LEGEND_RECOVERY, SkillId.LEGEND_AGILE_BODY, SkillId.LEGEND_MONSTER_RIDER, + SkillId.LEGEND_INVINCIBLE_BARRIER, SkillId.LEGEND_METEO_SHOWER, SkillId.LEGEND_SPACE_BEAM, + SkillId.LEGEND_DECENT_HASTE, SkillId.EVANBEGINNER_RECOVER, SkillId.EVANBEGINNER_NIMBLE_FEET, + SkillId.EVANBEGINNER_MONSTER_RIDER, SkillId.EVANBEGINNER_INVINCIBLE_BARRIER, + SkillId.EVANBEGINNER_METEO_SHOWER, SkillId.EVANBEGINNER_SPACE_BEAM, + SkillId.EVANBEGINNER_DECENT_HASTE, SkillId.ARAN2_COMBO_DRAIN, SkillId.ARAN2_BODY_PRESSURE, + SkillId.ARAN3_SMART_KNOCKBACK, SkillId.ARAN4_FREEZE_STANDING, SkillId.EVAN3_MAGIC_GUARD, + SkillId.EVAN6_SLOW, SkillId.CITIZEN_INFILTRATE, SkillId.CITIZEN_INVINCIBILITY, + SkillId.CITIZEN_POWER_EXPLOSION, SkillId.CITIZEN_DECENT_HASTE, SkillId.TELEPORT_MASTERY, + SkillId.WH3_BLIND, SkillId.MECH1_MECH_PROTOTYPE, SkillId.MECH2_PERFECT_ARMOR, + SkillId.MECH3_ROLL_OF_THE_DICE, SkillId.MECH4_SATELLITE_SAFETY -> SkillTargetFlags.Default.getValue(); + case SkillId.CRUSADER_MAGIC_CRASH, SkillId.PAGE_THREATEN, SkillId.WK_MAGIC_CRASH, + SkillId.DK_MAGIC_CRASH, SkillId.FP1_SLOW, SkillId.FP2_SEAL, SkillId.IL1_SLOW, SkillId.IL2_SEAL, + SkillId.PRIEST_DOOM, SkillId.HERMIT_SHADOW_WEB, SkillId.NIGHTLORD_NINJA_AMBUSH, + SkillId.SHADOWER_NINJA_AMBUSH, SkillId.BW2_SLOW, SkillId.BW3_SEAL, SkillId.NW3_SHADOW_WEB -> + SkillTargetFlags.Mobs.getValue(); + case SkillId.PRIEST_DISPEL -> SkillTargetFlags.Mobs.getValue() | SkillTargetFlags.Party.getValue(); + case SkillId.BEGINNER_DECENT_SHARP_EYES, SkillId.BEGINNER_DECENT_HYPER_BODY, SkillId.FIGHTER_RAGE, + SkillId.HERO_MAPLE_WARRIOR, SkillId.WK_COMBAT_ORDERS, SkillId.PALADIN_MAPLE_WARRIOR, + SkillId.SPEARNMAN_IRON_WILL, SkillId.SPEARNMAN_HYPER_BODY, SkillId.DRK_MAPLE_WARRIOR, + SkillId.FP1_MEDITATION, SkillId.FP3_MAPLE_WARRIOR, SkillId.IL1_MEDITATION, + SkillId.IL3_MAPLE_WARRIOR, SkillId.CLERIC_BLESS, SkillId.PRIEST_HOLY_SYMBOL, + SkillId.BISHOP_MAPLE_WARRIOR, SkillId.BISHOP_HOLY_SHIELD, SkillId.BISHOP_RESURRECTION, + SkillId.BOWMASTER_MAPLE_WARRIOR, SkillId.BOWMASTER_SHARP_EYES, SkillId.MARKSMAN_MAPLE_WARRIOR, + SkillId.MARKSMAN_SHARP_EYES, SkillId.ASSASSIN_HASTE, SkillId.HERMIT_MESO_UP, + SkillId.NIGHTLORD_MAPLE_WARRIOR, SkillId.BANDIT_HASTE, SkillId.SHADOWER_MAPLE_WARRIOR, + SkillId.DB5_MAPLE_WARRIOR, SkillId.DB5_THORNS, SkillId.BUCCANEER_MAPLE_WARRIOR, + SkillId.BUCCANEER_SPEED_INFUSION, SkillId.BUCCANEER_TIME_LEAP, SkillId.CORSAIR_MAPLE_WARRIOR, + SkillId.NOBLESSE_DECENT_SHARP_EYES, SkillId.NOBLESSE_DECENT_HYPER_BODY, SkillId.DW2_RAGE, + SkillId.BW2_MEDITATION, SkillId.NW2_HASTE, SkillId.TB3_SPEED_INFUSION, + SkillId.LEGEND_DECENT_SHARP_EYES, SkillId.LEGEND_DECENT_HYPER_BODY, + SkillId.EVANBEGINNER_DECENT_SHARP_EYES, SkillId.EVANBEGINNER_DECENT_HYPER_BODY, + SkillId.ARAN4_COMBO_BARRIER, SkillId.ARAN4_MAPLE_WARRIOR, SkillId.EVAN5_MAGIC_SHIELD, + SkillId.EVAN7_MAGIC_RESISTANCE, SkillId.EVAN9_MAPLE_WARRIOR, SkillId.EVAN10_BLESSING_OF_THE_ONYX, + SkillId.EVAN10_SOUL_STONE, SkillId.CITIZEN_DECENT_SHARP_EYES, SkillId.CITIZEN_DECENT_HYPER_BODY, + SkillId.MAPLE_WARRIOR, SkillId.WH4_SHARP_EYES, SkillId.WH4_MAPLE_WARRIOR, + SkillId.MECH4_MAPLE_WARRIOR -> SkillTargetFlags.Party.getValue(); + default -> SkillTargetFlags.None.getValue(); + }; + } + + public boolean hasMastery() { + return switch (this) { + case SkillId.HERO_ADVANCED_COMBO_ATTACK, SkillId.HERO_ACHILLES, SkillId.HERO_MAPLE_WARRIOR, + SkillId.HERO_MONSTER_MAGNET, SkillId.HERO_POWER_STANCE, SkillId.HERO_RUSH, + SkillId.HERO_INTREPID_SLASH, SkillId.HERO_ENRAGE, SkillId.HERO_HEROS_WILL, + SkillId.PALADIN_ACHILLES, SkillId.PALADIN_GUARDIAN, SkillId.PALADIN_ADVANCED_CHARGE, + SkillId.PALADIN_MAPLE_WARRIOR, SkillId.PALADIN_POWER_STANCE, SkillId.PALADIN_DIVINE_CHARGE, + SkillId.PALADIN_RUSH, SkillId.PALADIN_BLAST, SkillId.PALADIN_HEAVENS_HAMMER, + SkillId.PALADIN_HEROS_WILL, SkillId.DRK_ACHILLES, SkillId.DRK_BERSERK, + SkillId.DRK_AURA_OF_THE_BEHOLDER, SkillId.DRK_HEX_OF_THE_BEHOLDER, SkillId.DRK_MAPLE_WARRIOR, + SkillId.DRK_MONSTER_MAGNET, SkillId.DRK_POWER_STANCE, SkillId.DRK_RUSH, SkillId.DRK_BEHOLDER, + SkillId.DRK_HEROS_WILL, SkillId.FP3_MAPLE_WARRIOR, SkillId.FP3_BIG_BANG, + SkillId.FP3_MANA_REFLECTION, SkillId.FP3_FIRE_DEMON, SkillId.FP3_INFINITY, SkillId.FP3_IFRIT, + SkillId.FP3_PARALYZE, SkillId.FP3_METEOR_SHOWER, SkillId.FP3_HEROS_WILL, SkillId.IL3_MAPLE_WARRIOR, + SkillId.IL3_BIG_BANG, SkillId.IL3_MANA_REFLECTION, SkillId.IL3_ICE_DEMON, SkillId.IL3_INFINITY, + SkillId.IL3_ELQUINES, SkillId.IL3_CHAIN_LIGHTNING, SkillId.IL3_BLIZZARD, SkillId.IL3_HEROS_WILL, + SkillId.BISHOP_MAPLE_WARRIOR, SkillId.BISHOP_BIG_BANG, SkillId.BISHOP_MANA_REFLECTION, + SkillId.BISHOP_BAHAMUT, SkillId.BISHOP_INFINITY, SkillId.BISHOP_HOLY_SHIELD, + SkillId.BISHOP_RESURRECTION, SkillId.BISHOP_ANGEL_RAY, SkillId.BISHOP_GENESIS, + SkillId.BISHOP_HEROS_WILL, SkillId.BOWMASTER_BOW_EXPERT, SkillId.BOWMASTER_MARKSMANSHIP, + SkillId.BOWMASTER_MAPLE_WARRIOR, SkillId.BOWMASTER_SHARP_EYES, SkillId.BOWMASTER_DRAGONS_BREATH, + SkillId.BOWMASTER_HURRICANE, SkillId.BOWMASTER_PHOENIX, SkillId.BOWMASTER_HAMSTRING, + SkillId.BOWMASTER_CONCENTRATE, SkillId.BOWMASTER_HEROS_WILL, SkillId.MARKSMAN_MARKSMAN_BOOST, + SkillId.MARKSMAN_ULTIMATE_STRAFE, SkillId.MARKSMAN_MAPLE_WARRIOR, SkillId.MARKSMAN_PIERCING_ARROW, + SkillId.MARKSMAN_SHARP_EYES, SkillId.MARKSMAN_DRAGONS_BREATH, SkillId.MARKSMAN_FROSTPREY, + SkillId.MARKSMAN_BLIND, SkillId.MARKSMAN_SNIPE, SkillId.MARKSMAN_HEROS_WILL, + SkillId.NIGHTLORD_SHADOW_SHIFTER, SkillId.NIGHTLORD_VENOMOUS_STAR, SkillId.NIGHTLORD_MAPLE_WARRIOR, + SkillId.NIGHTLORD_TAUNT, SkillId.NIGHTLORD_NINJA_AMBUSH, SkillId.NIGHTLORD_SHADOW_STARS, + SkillId.NIGHTLORD_TRIPLE_THROW, SkillId.NIGHTLORD_NINJA_STORM, SkillId.NIGHTLORD_HEROS_WILL, + SkillId.SHADOWER_SHADOW_SHIFTER, SkillId.SHADOWER_VENOMOUS_STAB, SkillId.SHADOWER_MAPLE_WARRIOR, + SkillId.SHADOWER_ASSASSINATE, SkillId.SHADOWER_TAUNT, SkillId.SHADOWER_NINJA_AMBUSH, + SkillId.SHADOWER_SMOKESCREEN, SkillId.SHADOWER_BOOMERANG_STEP, SkillId.SHADOWER_HEROS_WILL, + SkillId.DB2_SLASH_STORM, SkillId.DB3_TORNADO_SPIN, SkillId.DB4_MIRROR_IMAGE, + SkillId.DB4_FLYING_ASSAULTER, SkillId.DB5_VENOM, SkillId.DB5_MAPLE_WARRIOR, SkillId.DB5_FINAL_CUT, + SkillId.DB5_MONSTER_BOMB, SkillId.DB5_SUDDEN_RAID, SkillId.DB5_CHAINS_OF_HELL, + SkillId.DB5_MIRRORED_TARGET, SkillId.DB5_THORNS, SkillId.DB5_HEROS_WILL, + SkillId.BUCCANEER_MAPLE_WARRIOR, SkillId.BUCCANEER_DRAGON_STRIKE, SkillId.BUCCANEER_ENERGY_ORB, + SkillId.BUCCANEER_SUPER_TRANSFORMATION, SkillId.BUCCANEER_DEMOLITION, SkillId.BUCCANEER_SNATCH, + SkillId.BUCCANEER_BARRAGE, SkillId.BUCCANEER_PIRATES_RAGE, SkillId.BUCCANEER_SPEED_INFUSION, + SkillId.BUCCANEER_TIME_LEAP, SkillId.CORSAIR_ELEMENTAL_BOOST, SkillId.CORSAIR_WRATH_OF_THE_OCTOPI, + SkillId.CORSAIR_BULLSEYE, SkillId.CORSAIR_MAPLE_WARRIOR, SkillId.CORSAIR_AIR_STRIKE, + SkillId.CORSAIR_RAPID_FIRE, SkillId.CORSAIR_BATTLESHIP, SkillId.CORSAIR_BATTLESHIP_CANNON, + SkillId.CORSAIR_BATTLESHIP_TORPEDO, SkillId.CORSAIR_HYPNOTIZE, SkillId.CORSAIR_HEROS_WILL, + SkillId.ARAN4_HIGH_MASTERY, SkillId.ARAN4_OVER_SWING, SkillId.ARAN4_HIGH_DEFENSE, + SkillId.ARAN4_FINAL_BLOW, SkillId.ARAN4_COMBO_TEMPEST, SkillId.ARAN4_COMBO_BARRIER, + SkillId.ARAN4_HIDDEN_OVER_SWING_DOUBLE_SWING, SkillId.ARAN4_HIDDEN_OVER_SWING_TRIPLE_SWING, + SkillId.ARAN4_MAPLE_WARRIOR, SkillId.ARAN4_FREEZE_STANDING, SkillId.ARAN4_HEROS_WILL, + SkillId.ADVANCED_DARK_AURA, SkillId.ADVANCED_YELLOW_AURA, SkillId.ENERGIZE, SkillId.FINISHING_BLOW, + SkillId.TWISTER_SPIN, SkillId.DARK_GENESIS, SkillId.STANCE, SkillId.PARTY_SHIELD, + SkillId.MAPLE_WARRIOR, SkillId.HEROS_WILL, SkillId.WH4_CROSSBOW_EXPERT, SkillId.WH4_WILD_INSTINCT, + SkillId.WH4_EXPLODING_ARROWS, SkillId.WH4_SONIC_ROAR, SkillId.WH4_SHARP_EYES, + SkillId.WH4_STINK_BOMB_SHOT, SkillId.WH4_FELINE_BERSERK, SkillId.WH4_MAPLE_WARRIOR, + SkillId.WH4_HEROS_WILL, SkillId.WH4_WILD_ARROW_BLAST, SkillId.MECH4_EXTREME_MECH, + SkillId.MECH4_ROBOT_MASTERY, SkillId.MECH4_GIANT_ROBOT_SG88, SkillId.MECH4_MECH_MISSILE_TANK, + SkillId.MECH4_SATELLITE_SAFETY, SkillId.MECH4_MAPLE_WARRIOR, SkillId.MECH4_HEROS_WILL, + SkillId.MECH4_BOTS_N_TOTS, SkillId.MECH4_AMPLIFIER_ROBOT_AF11, SkillId.MECH4_UNK, + SkillId.MECH4_LASER_BLAST, SkillId.MECH4_MECH_SIEGE_MODE -> true; + default -> false; + }; + } + + public boolean isAntiRepeat() { + return switch (this) { + case SkillId.WARRIOR_IRON_BODY, SkillId.FIGHTER_RAGE, SkillId.CRUSADER_MAGIC_CRASH, + SkillId.HERO_MAPLE_WARRIOR, SkillId.PAGE_THREATEN, SkillId.WK_MAGIC_CRASH, SkillId.WK_HP_RECOVERY, + SkillId.PALADIN_MAPLE_WARRIOR, SkillId.SPEARNMAN_IRON_WILL, SkillId.SPEARNMAN_HYPER_BODY, + SkillId.DK_MAGIC_CRASH, SkillId.DRK_MAPLE_WARRIOR, SkillId.FP1_MEDITATION, SkillId.FP1_SLOW, + SkillId.FP3_MAPLE_WARRIOR, SkillId.IL1_MEDITATION, SkillId.IL1_SLOW, SkillId.IL3_MAPLE_WARRIOR, + SkillId.CLERIC_BLESS, SkillId.PRIEST_DISPEL, SkillId.PRIEST_HOLY_SYMBOL, + SkillId.BISHOP_MAPLE_WARRIOR, SkillId.BISHOP_HOLY_SHIELD, SkillId.BOWMASTER_MAPLE_WARRIOR, + SkillId.BOWMASTER_SHARP_EYES, SkillId.MARKSMAN_MAPLE_WARRIOR, SkillId.ASSASSIN_HASTE, + SkillId.HERMIT_MESO_UP, SkillId.NIGHTLORD_MAPLE_WARRIOR, SkillId.BANDIT_HASTE, + SkillId.SHADOWER_MAPLE_WARRIOR, SkillId.DB2_SELF_HASTE, SkillId.DB5_MAPLE_WARRIOR, + SkillId.DB5_THORNS, SkillId.MARAUDER_ROLL_OF_THE_DICE, SkillId.BUCCANEER_MAPLE_WARRIOR, + SkillId.BUCCANEER_SPEED_INFUSION, SkillId.OUTLAW_ROLL_OF_THE_DICE, SkillId.CORSAIR_MAPLE_WARRIOR, + SkillId.DW1_IRON_BODY, SkillId.DW2_RAGE, SkillId.BW2_MEDITATION, SkillId.BW2_SLOW, + SkillId.NW2_HASTE, SkillId.TB3_SPEED_INFUSION, SkillId.ARAN4_MAPLE_WARRIOR, SkillId.EVAN6_SLOW, + SkillId.EVAN9_MAPLE_WARRIOR, SkillId.EVAN10_BLESSING_OF_THE_ONYX, SkillId.CONVERSION, + SkillId.MAPLE_WARRIOR, SkillId.WH4_MAPLE_WARRIOR, SkillId.MECH3_ROLL_OF_THE_DICE -> true; + default -> false; + }; + } + + boolean isMapleWarrior() { + return switch (this) { + case SkillId.HERO_MAPLE_WARRIOR, SkillId.PALADIN_MAPLE_WARRIOR, SkillId.DRK_MAPLE_WARRIOR, + SkillId.FP3_MAPLE_WARRIOR, SkillId.IL3_MAPLE_WARRIOR, SkillId.BISHOP_MAPLE_WARRIOR, + SkillId.BOWMASTER_MAPLE_WARRIOR, SkillId.MARKSMAN_MAPLE_WARRIOR, SkillId.NIGHTLORD_MAPLE_WARRIOR, + SkillId.SHADOWER_MAPLE_WARRIOR, SkillId.DB5_MAPLE_WARRIOR, SkillId.BUCCANEER_MAPLE_WARRIOR, + SkillId.CORSAIR_MAPLE_WARRIOR, SkillId.ARAN4_MAPLE_WARRIOR, SkillId.EVAN9_MAPLE_WARRIOR, + SkillId.MAPLE_WARRIOR, SkillId.WH4_MAPLE_WARRIOR, SkillId.MECH4_MAPLE_WARRIOR -> true; + default -> false; + }; + } +} + + diff --git a/src/main/java/kinoko/meta/SkillTargetFlags.java b/src/main/java/kinoko/meta/SkillTargetFlags.java new file mode 100644 index 00000000..67f9c8c9 --- /dev/null +++ b/src/main/java/kinoko/meta/SkillTargetFlags.java @@ -0,0 +1,27 @@ +package kinoko.meta; + +public enum SkillTargetFlags { + None(0), + Default(1), + Party(2), + Mobs(4); + + + private final int value; + SkillTargetFlags(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public static SkillTargetFlags fromValue(int value) { + for (SkillTargetFlags flag : values()) { + if (flag.value == value) { + return flag; + } + } + return None; + } +} diff --git a/src/main/java/kinoko/packet/user/UserLocal.java b/src/main/java/kinoko/packet/user/UserLocal.java index 5af2b4b7..4b7d8b53 100644 --- a/src/main/java/kinoko/packet/user/UserLocal.java +++ b/src/main/java/kinoko/packet/user/UserLocal.java @@ -1,5 +1,6 @@ package kinoko.packet.user; +import kinoko.meta.SkillId; import kinoko.server.dialog.UIType; import kinoko.server.header.OutHeader; import kinoko.server.packet.OutPacket; @@ -113,9 +114,9 @@ public static OutPacket chatMsg(ChatType type, String text) { return outPacket; } - public static OutPacket timeBombAttack(int skillId, int x, int y, int impactDegree, int damage) { + public static OutPacket timeBombAttack(SkillId skillId, int x, int y, int impactDegree, int damage) { final OutPacket outPacket = OutPacket.of(OutHeader.UserTimeBombAttack); - outPacket.encodeInt(skillId); // nSkillID + outPacket.encodeSkillId(skillId); // nSkillID outPacket.encodeInt(x); // nTimeBombX outPacket.encodeInt(y); // nTimeBombY outPacket.encodeInt(impactDegree); // nUserImpactDeg @@ -133,9 +134,9 @@ public static OutPacket requestExJablin() { return OutPacket.of(OutHeader.UserRequestExJablin); } - public static OutPacket skillCooltimeSet(int skillId, int remainSeconds) { + public static OutPacket skillCooltimeSet(SkillId skillId, int remainSeconds) { final OutPacket outPacket = OutPacket.of(OutHeader.SkillCooltimeSet); - outPacket.encodeInt(skillId); + outPacket.encodeSkillId(skillId); outPacket.encodeShort(remainSeconds); // usRemainSec return outPacket; } diff --git a/src/main/java/kinoko/packet/user/UserRemote.java b/src/main/java/kinoko/packet/user/UserRemote.java index 835b588b..4aefa93b 100644 --- a/src/main/java/kinoko/packet/user/UserRemote.java +++ b/src/main/java/kinoko/packet/user/UserRemote.java @@ -1,5 +1,6 @@ package kinoko.packet.user; +import kinoko.meta.SkillId; import kinoko.server.header.OutHeader; import kinoko.server.packet.OutPacket; import kinoko.util.BitFlag; @@ -32,9 +33,9 @@ public static OutPacket attack(User user, Attack attack) { outPacket.encodeByte(user.getLevel()); // nLevel outPacket.encodeByte(attack.slv); if (attack.slv != 0) { - outPacket.encodeInt(attack.skillId); + outPacket.encodeSkillId(attack.skillId); } - if (attack.skillId == Bowman.STRAFE_MM) { + if (attack.skillId == SkillId.SNIPER_STRAFE) { outPacket.encodeByte(attack.passiveSlv); // nPassiveSLV if (attack.passiveSlv != 0) { outPacket.encodeInt(attack.passiveSkillId); // nSkillID @@ -52,7 +53,7 @@ public static OutPacket attack(User user, Attack attack) { continue; } outPacket.encodeByte(ai.actionAndDir); - if (attack.skillId == Thief.MESO_EXPLOSION) { + if (attack.skillId == SkillId.CHIEFBANDIT_MESO_EXPLOSION) { outPacket.encodeByte(ai.attackCount); for (int i = 0; i < ai.attackCount; i++) { outPacket.encodeInt(ai.damage[i]); @@ -70,7 +71,7 @@ public static OutPacket attack(User user, Attack attack) { } if (SkillConstants.isMagicKeydownSkill(attack.skillId)) { outPacket.encodeInt(attack.keyDown); // tKeyDown - } else if (attack.skillId == WildHunter.JAGUAR_OSHI_ATTACK) { + } else if (attack.skillId == SkillId.WH2_JAGUAROSHI_2) { outPacket.encodeInt(attack.swallowMobTemplateId); // dwSwallowMobTemplateID } } @@ -232,7 +233,7 @@ public static OutPacket throwGrenade(User user, Skill skill) { outPacket.encodeInt(skill.positionX); outPacket.encodeInt(skill.positionY); outPacket.encodeInt(skill.keyDown); // tKeyDown - outPacket.encodeInt(skill.skillId); // nSkillID + outPacket.encodeSkillId(skill.skillId); // nSkillID outPacket.encodeInt(skill.slv); // nSLV return outPacket; } diff --git a/src/main/java/kinoko/packet/world/WvsContext.java b/src/main/java/kinoko/packet/world/WvsContext.java index 41c3c492..5f825efa 100644 --- a/src/main/java/kinoko/packet/world/WvsContext.java +++ b/src/main/java/kinoko/packet/world/WvsContext.java @@ -89,7 +89,7 @@ public static OutPacket changeSkillRecordResult(List skillRecords, outPacket.encodeByte(exclRequest); // bool -> bExclRequestSent = 0 outPacket.encodeShort(skillRecords.size()); for (SkillRecord sr : skillRecords) { - outPacket.encodeInt(sr.getSkillId()); // nSkillID + outPacket.encodeSkillId(sr.getSkillId()); // nSkillID outPacket.encodeInt(sr.getSkillLevel()); outPacket.encodeInt(sr.getMasterLevel()); outPacket.encodeFT(FileTime.DEFAULT_TIME); // dateExpire diff --git a/src/main/java/kinoko/provider/SkillProvider.java b/src/main/java/kinoko/provider/SkillProvider.java index 6e81d64d..0b1be535 100644 --- a/src/main/java/kinoko/provider/SkillProvider.java +++ b/src/main/java/kinoko/provider/SkillProvider.java @@ -1,5 +1,6 @@ package kinoko.provider; +import kinoko.meta.SkillId; import kinoko.provider.mob.MobSkillType; import kinoko.provider.skill.MorphInfo; import kinoko.provider.skill.SkillInfo; @@ -43,8 +44,8 @@ public static List getSkillsForJob(Job job) { return jobSkills.getOrDefault(job, List.of()); } - public static Optional getSkillInfoById(int skillId) { - return Optional.ofNullable(skillInfos.get(skillId)); + public static Optional getSkillInfoById(SkillId skillId) { + return Optional.ofNullable(skillInfos.get(skillId.getId())); } public static Optional getMobSkillInfoById(int skillId) { diff --git a/src/main/java/kinoko/provider/item/ItemMakeInfo.java b/src/main/java/kinoko/provider/item/ItemMakeInfo.java index 530ac2a1..751ea2eb 100644 --- a/src/main/java/kinoko/provider/item/ItemMakeInfo.java +++ b/src/main/java/kinoko/provider/item/ItemMakeInfo.java @@ -1,5 +1,6 @@ package kinoko.provider.item; +import kinoko.meta.SkillId; import kinoko.provider.ProviderError; import kinoko.provider.WzProvider; import kinoko.provider.wz.serialize.WzProperty; @@ -98,7 +99,7 @@ public List> getRandomReward() { public boolean canCreateItem(User user, boolean catalyst, List gems) { final InventoryManager im = user.getInventoryManager(); - final int makerSkillId = SkillConstants.getNoviceSkillAsRace(Beginner.MAKER, user.getJob()); + final SkillId makerSkillId = SkillConstants.getNoviceSkillAsRace(SkillId.BEGINNER_MAKER, user.getJob()); if (getReqSkillLevel() != 0 && user.getSkillLevel(makerSkillId) < getReqSkillLevel()) { return false; } diff --git a/src/main/java/kinoko/provider/quest/QuestSkillData.java b/src/main/java/kinoko/provider/quest/QuestSkillData.java index e11dae2b..bc7187a8 100644 --- a/src/main/java/kinoko/provider/quest/QuestSkillData.java +++ b/src/main/java/kinoko/provider/quest/QuestSkillData.java @@ -1,5 +1,6 @@ package kinoko.provider.quest; +import kinoko.meta.SkillId; import kinoko.provider.ProviderError; import kinoko.provider.WzProvider; import kinoko.provider.wz.serialize.WzProperty; @@ -7,13 +8,13 @@ import java.util.*; public final class QuestSkillData { - private final int skillId; + private final SkillId skillId; private final int skillLevel; private final int masterLevel; private final boolean onlyMasterLevel; private final Set jobs; - public QuestSkillData(int skillId, int skillLevel, int masterLevel, boolean onlyMasterLevel, Set jobs) { + public QuestSkillData(SkillId skillId, int skillLevel, int masterLevel, boolean onlyMasterLevel, Set jobs) { this.skillId = skillId; this.skillLevel = skillLevel; this.masterLevel = masterLevel; @@ -21,7 +22,7 @@ public QuestSkillData(int skillId, int skillLevel, int masterLevel, boolean only this.jobs = jobs; } - public int getSkillId() { + public SkillId getSkillId() { return skillId; } @@ -55,7 +56,7 @@ public static List resolveSkillData(WzProperty skillList) { jobs.add(WzProvider.getInteger(jobEntry.getValue())); } skills.add(new QuestSkillData( - WzProvider.getInteger(skillProp.get("id")), + SkillId.fromValue(WzProvider.getInteger(skillProp.get("id"))), WzProvider.getInteger(skillProp.get("skillLevel")), WzProvider.getInteger(skillProp.get("masterLevel")), WzProvider.getInteger(skillProp.get("onlyMasterLevel"), 0) != 0, diff --git a/src/main/java/kinoko/provider/quest/act/QuestSkillAct.java b/src/main/java/kinoko/provider/quest/act/QuestSkillAct.java index 69ed5435..b2052bd6 100644 --- a/src/main/java/kinoko/provider/quest/act/QuestSkillAct.java +++ b/src/main/java/kinoko/provider/quest/act/QuestSkillAct.java @@ -1,5 +1,6 @@ package kinoko.provider.quest.act; +import kinoko.meta.SkillId; import kinoko.packet.world.WvsContext; import kinoko.provider.SkillProvider; import kinoko.provider.quest.QuestSkillData; @@ -44,7 +45,7 @@ public boolean doAct(User user, int rewardIndex) { if (!qsd.getJobs().contains(user.getJob())) { continue; } - final int skillId = qsd.getSkillId(); + final SkillId skillId = qsd.getSkillId(); final Optional skillInfoResult = SkillProvider.getSkillInfoById(skillId); if (skillInfoResult.isEmpty()) { return false; diff --git a/src/main/java/kinoko/provider/quest/check/QuestSkillCheck.java b/src/main/java/kinoko/provider/quest/check/QuestSkillCheck.java index 7b58dd26..6745305e 100644 --- a/src/main/java/kinoko/provider/quest/check/QuestSkillCheck.java +++ b/src/main/java/kinoko/provider/quest/check/QuestSkillCheck.java @@ -1,5 +1,6 @@ package kinoko.provider.quest.check; +import kinoko.meta.SkillId; import kinoko.provider.ProviderError; import kinoko.provider.WzProvider; import kinoko.provider.wz.serialize.WzProperty; @@ -10,9 +11,9 @@ import java.util.Map; public final class QuestSkillCheck implements QuestCheck { - private final Map skills; + private final Map skills; - public QuestSkillCheck(Map skills) { + public QuestSkillCheck(Map skills) { this.skills = skills; } @@ -28,12 +29,12 @@ public boolean check(User user) { } public static QuestSkillCheck from(WzProperty skillList) throws ProviderError { - final Map skills = new HashMap<>(); + final Map skills = new HashMap<>(); for (var skillEntry : skillList.getItems().entrySet()) { if (!(skillEntry.getValue() instanceof WzProperty skillProp)) { throw new ProviderError("Failed to resolve quest skill prop"); } - final int skillId = WzProvider.getInteger(skillProp.get("id")); + final SkillId skillId = SkillId.fromValue(WzProvider.getInteger(skillProp.get("id"))); final boolean acquire = WzProvider.getInteger(skillProp.get("acquire"), 0) != 0; skills.put(skillId, acquire); } diff --git a/src/main/java/kinoko/provider/skill/SkillInfo.java b/src/main/java/kinoko/provider/skill/SkillInfo.java index 0f1aaff5..3475436c 100644 --- a/src/main/java/kinoko/provider/skill/SkillInfo.java +++ b/src/main/java/kinoko/provider/skill/SkillInfo.java @@ -1,5 +1,6 @@ package kinoko.provider.skill; +import kinoko.meta.SkillId; import kinoko.provider.ProviderError; import kinoko.provider.WzProvider; import kinoko.provider.wz.serialize.WzProperty; @@ -19,7 +20,7 @@ import java.util.stream.IntStream; public final class SkillInfo { - private final int skillId; + private final SkillId skillId; private final int maxLevel; private final int masterLevel; private final boolean invisible; @@ -36,7 +37,7 @@ public final class SkillInfo { private final int skillEntryCrc; private final List levelDataCrc; - public SkillInfo(int skillId, int maxLevel, int masterLevel, boolean invisible, boolean combatOrders, boolean psd, List psdSkills, List action, ActionType statAction, Map> stats, List rects, ElementAttribute elemAttr, Map summonedAttack) { + public SkillInfo(SkillId skillId, int maxLevel, int masterLevel, boolean invisible, boolean combatOrders, boolean psd, List psdSkills, List action, ActionType statAction, Map> stats, List rects, ElementAttribute elemAttr, Map summonedAttack) { this.skillId = skillId; this.maxLevel = maxLevel; this.masterLevel = masterLevel; @@ -59,7 +60,7 @@ public SkillInfo(int skillId, int maxLevel, int masterLevel, boolean invisible, .toList(); } - public int getSkillId() { + public SkillId getSkillId() { return skillId; } @@ -141,10 +142,10 @@ public int getBulletCon(int slv) { } public int getHpCon(User user, int slv, int keyDown) { - final int skillId = getSkillId(); - if (skillId == Warrior.SACRIFICE || skillId == Warrior.DRAGON_ROAR || skillId == Pirate.MP_RECOVERY) { + final SkillId skillId = getSkillId(); + if (skillId == SkillId.DK_SACRIFICE || skillId == SkillId.DK_DRAGON_ROAR || skillId == SkillId.BRAWLER_MP_RECOVERY) { return user.getMaxHp() * getValue(SkillStat.x, slv) / 100; - } else if (skillId == Thief.FINAL_CUT) { + } else if (skillId == SkillId.DB5_FINAL_CUT) { final int percentage = getValue(SkillStat.x, slv) * keyDown / SkillConstants.getMaxGaugeTime(skillId); return user.getMaxHp() * percentage / 100; } @@ -155,8 +156,8 @@ public int getMpCon(User user, int slv) { // CSkillInfo::CheckConsumeForActiveSkill int mpCon = getValue(SkillStat.mpCon, slv); // Check element amplification - final int amplificationSkill = SkillConstants.getAmplificationSkill(user.getJob()); - if (amplificationSkill != 0) { + final SkillId amplificationSkill = SkillConstants.getAmplificationSkill(user.getJob()); + if (!amplificationSkill.isNone()) { final int incMpCon = user.getSkillStatValue(amplificationSkill, SkillStat.x); if (incMpCon > 0) { mpCon = incMpCon * mpCon / 100; @@ -262,7 +263,7 @@ private static SkillInfo fromStatic(int skillId, WzProperty skillProp) throws Pr final ElementAttribute elemAttr = resolveElemAttr(skillProp); final Map summonedAttack = resolveSummonedAttack(skillProp); return new SkillInfo( - skillId, + SkillId.fromValue(skillId), maxLevel, WzProvider.getInteger(skillProp.get("masterLevel"), 0), WzProvider.getInteger(skillProp.get("invisible"), 0) != 0, @@ -327,7 +328,7 @@ private static SkillInfo fromComputed(int skillId, WzProperty skillProp) throws final ElementAttribute elemAttr = resolveElemAttr(skillProp); final Map summonedAttack = resolveSummonedAttack(skillProp); return new SkillInfo( - skillId, + SkillId.fromValue(skillId), maxLevel, WzProvider.getInteger(skillProp.get("masterLevel"), 0), WzProvider.getInteger(skillProp.get("invisible"), 0) != 0, diff --git a/src/main/java/kinoko/script/common/ScriptManager.java b/src/main/java/kinoko/script/common/ScriptManager.java index 7f949a10..c3be7aa1 100644 --- a/src/main/java/kinoko/script/common/ScriptManager.java +++ b/src/main/java/kinoko/script/common/ScriptManager.java @@ -1,5 +1,6 @@ package kinoko.script.common; +import kinoko.meta.SkillId; import kinoko.provider.reward.Reward; import kinoko.server.event.EventState; import kinoko.server.event.EventType; @@ -62,9 +63,9 @@ public interface ScriptManager { void setAvatar(int look); - void addSkill(int skillId, int skillLevel, int masterLevel); + void addSkill(SkillId skillId, int skillLevel, int masterLevel); - void removeSkill(int skillId); + void removeSkill(SkillId skillId); void addSp(int jobLevel, int skillPoint); diff --git a/src/main/java/kinoko/script/common/ScriptManagerImpl.java b/src/main/java/kinoko/script/common/ScriptManagerImpl.java index 256ba63a..c0eb1a40 100644 --- a/src/main/java/kinoko/script/common/ScriptManagerImpl.java +++ b/src/main/java/kinoko/script/common/ScriptManagerImpl.java @@ -1,5 +1,6 @@ package kinoko.script.common; +import kinoko.meta.SkillId; import kinoko.packet.field.FieldEffectPacket; import kinoko.packet.field.FieldPacket; import kinoko.packet.field.NpcPacket; @@ -372,7 +373,7 @@ public void setAvatar(int look) { } @Override - public void addSkill(int skillId, int skillLevel, int masterLevel) { + public void addSkill(SkillId skillId, int skillLevel, int masterLevel) { final Optional skillInfoResult = SkillProvider.getSkillInfoById(skillId); if (skillInfoResult.isEmpty()) { throw new ScriptError("Could not resolve skill info for skill ID : %d", skillId); @@ -390,7 +391,7 @@ public void addSkill(int skillId, int skillLevel, int masterLevel) { } @Override - public void removeSkill(int skillId) { + public void removeSkill(SkillId skillId) { final Optional skillRecordResult = user.getSkillManager().getSkill(skillId); if (skillRecordResult.isEmpty()) { return; diff --git a/src/main/java/kinoko/script/quest/AranQuest.java b/src/main/java/kinoko/script/quest/AranQuest.java index 8dcf4804..dee33fcf 100644 --- a/src/main/java/kinoko/script/quest/AranQuest.java +++ b/src/main/java/kinoko/script/quest/AranQuest.java @@ -1,5 +1,6 @@ package kinoko.script.quest; +import kinoko.meta.SkillId; import kinoko.packet.user.UserLocal; import kinoko.script.common.Script; import kinoko.script.common.ScriptHandler; @@ -134,7 +135,7 @@ public static void q21703e(ScriptManager sm) { sm.sayNext("Are you reluctant to leave your instructor? *Sniff sniff* I'm so moved, but you can't stop here. You are destined for bigger and better things!"); return; } - sm.addSkill(21000000, 0, 10); // Combo Ability + sm.addSkill(SkillId.ARAN1_COMBO_ABILITY, 0, 10); // Combo Ability sm.addExp(2000); sm.forceCompleteQuest(21703); sm.sayNext("(You remembered the #bCombo Ability#k skill! You were skeptical of the training at first, since the old man suffers from Alzheimer's and all, but boy, was it effective!)", ScriptMessageParam.PLAYER_AS_SPEAKER); diff --git a/src/main/java/kinoko/script/quest/AranTutorial.java b/src/main/java/kinoko/script/quest/AranTutorial.java index ab322c4d..70a4def0 100644 --- a/src/main/java/kinoko/script/quest/AranTutorial.java +++ b/src/main/java/kinoko/script/quest/AranTutorial.java @@ -1,5 +1,6 @@ package kinoko.script.quest; +import kinoko.meta.SkillId; import kinoko.packet.user.UserLocal; import kinoko.provider.reward.Reward; import kinoko.script.common.Script; @@ -201,8 +202,8 @@ public static void aranTutorOut1(ScriptManager sm) { if (!sm.hasQuestStarted(21000)) { sm.message("You can only exit after you accept the quest from Athena Pierce, who is to your right."); } else { - sm.addSkill(20000017, 1, 1); - sm.addSkill(20000018, 1, 1); + sm.addSkill(SkillId.LEGEND_TUTORIAL_SKILL_3, 1, 1); + sm.addSkill(SkillId.LEGEND_TUTORIAL_SKILL_4, 1, 1); sm.playPortalSE(); sm.warp(914000200, "east00"); } @@ -212,8 +213,8 @@ public static void aranTutorOut1(ScriptManager sm) { public static void aranTutorOut2(ScriptManager sm) { // Black Road : Burning Forest 1 (914000200) // west00 (1305, -1) - sm.addSkill(20000014, 1, 1); - sm.addSkill(20000015, 1, 1); + sm.addSkill(SkillId.LEGEND_TUTORIAL_SKILL, 1, 1); + sm.addSkill(SkillId.LEGEND_TUTORIAL_SKILL_1, 1, 1); sm.playPortalSE(); sm.warp(914000210, "east00"); } @@ -222,7 +223,7 @@ public static void aranTutorOut2(ScriptManager sm) { public static void aranTutorOut3(ScriptManager sm) { // Black Road : Burning Forest 2 (914000210) // west00 (-133, 0) - sm.addSkill(20000016, 1, 1); + sm.addSkill(SkillId.LEGEND_TUTORIAL_SKILL_2, 1, 1); sm.playPortalSE(); sm.warp(914000220, "east00"); } @@ -372,11 +373,11 @@ public static void q21001e(ScriptManager sm) { @Script("iceCave") public static void iceCave(ScriptManager sm) { // Snow Island : Ice Cave (140090000) - sm.removeSkill(20000014); - sm.removeSkill(20000015); - sm.removeSkill(20000016); - sm.removeSkill(20000017); - sm.removeSkill(20000018); + sm.removeSkill(SkillId.LEGEND_TUTORIAL_SKILL); + sm.removeSkill(SkillId.LEGEND_TUTORIAL_SKILL_1); + sm.removeSkill(SkillId.LEGEND_TUTORIAL_SKILL_2); + sm.removeSkill(SkillId.LEGEND_TUTORIAL_SKILL_3); + sm.removeSkill(SkillId.LEGEND_TUTORIAL_SKILL_4); sm.reservedEffect("Effect/Direction1.img/aranTutorial/ClickLilin"); } diff --git a/src/main/java/kinoko/script/quest/EvanQuest.java b/src/main/java/kinoko/script/quest/EvanQuest.java index e011102c..abd1c62d 100644 --- a/src/main/java/kinoko/script/quest/EvanQuest.java +++ b/src/main/java/kinoko/script/quest/EvanQuest.java @@ -1,5 +1,6 @@ package kinoko.script.quest; +import kinoko.meta.SkillId; import kinoko.packet.world.WvsContext; import kinoko.provider.reward.Reward; import kinoko.script.common.Script; @@ -590,7 +591,7 @@ public static void q22102s(ScriptManager sm) { sm.forceCompleteQuest(22102); sm.setJob(Job.EVAN_3); //sm.addSkill(22111001, 0, 5); // Magic Guard GMS-like, NX Mastery Books are fucking memes - sm.addSkill(22111001, 0, 20); // Magic Guard + sm.addSkill(SkillId.EVAN3_MAGIC_GUARD, 0, 20); // Magic Guard sm.addInventorySlots(InventoryType.EQUIP, 4); sm.addInventorySlots(InventoryType.ETC, 4); } @@ -614,8 +615,8 @@ public static void q22105s(ScriptManager sm) { // Dragon Master 6th Job Advancement (22105 - start) sm.forceCompleteQuest(22105); sm.setJob(Job.EVAN_6); - sm.addSkill(22140000, 0, 15); // Critical Magic - sm.addSkill(22141002, 0, 20); // Magic Booster + sm.addSkill(SkillId.EVAN6_CRITICAL_MAGIC, 0, 15); // Critical Magic + sm.addSkill(SkillId.EVAN6_MAGIC_BOOSTER, 0, 20); // Magic Booster //sm.addSkill(22140000, 0, 5); // Critical Magic GMS-like, NX Mastery Books are fucking memes //sm.addSkill(22140002, 0, 5); // Magic Booster GMS-like, NX Mastery Books are fucking memes } @@ -641,10 +642,10 @@ public static void q22108s(ScriptManager sm) { // Dragon Master 9th Job Advancement (22108 - start) sm.forceCompleteQuest(22108); sm.setJob(Job.EVAN_9); - sm.addSkill(22170001, 0, 30); // Magic Mastery - sm.addSkill(22171003, 0, 30); // Flame Wheel - sm.addSkill(22171000, 0, 30); // Maple Warrior - sm.addSkill(22171002, 0, 30); // Illusion + sm.addSkill(SkillId.EVAN9_MAGIC_MASTERY, 0, 30); // Magic Mastery + sm.addSkill(SkillId.EVAN9_FLAME_WHEEL, 0, 30); // Flame Wheel + sm.addSkill(SkillId.EVAN9_MAPLE_WARRIOR, 0, 30); // Maple Warrior + sm.addSkill(SkillId.EVAN9_ILLUSION, 0, 30); // Illusion //sm.addSkill(22171000, 0, 10); // Maple Warrior //sm.addSkill(22171002, 0, 10); // Illusion sm.addInventorySlots(InventoryType.EQUIP, 4); @@ -656,12 +657,12 @@ public static void q22109s(ScriptManager sm) { // Dragon Master 10th Job Advancement (22109 - start) sm.forceCompleteQuest(22109); sm.setJob(Job.EVAN_10); - sm.addSkill(22181000, 0, 30); // Blessing of the Onyx - sm.addSkill(22181001, 0, 30); // Blaze + sm.addSkill(SkillId.EVAN10_BLESSING_OF_THE_ONYX, 0, 30); // Blessing of the Onyx + sm.addSkill(SkillId.EVAN10_BLAZE, 0, 30); // Blaze //sm.addSkill(22181000, 0, 10); // Blessing of the Onyx //sm.addSkill(22181001, 0, 10); // Blaze - sm.addSkill(22181002, 0, 30); // Dark Fog - sm.addSkill(22181003, 0, 20); // Soul Stone + sm.addSkill(SkillId.EVAN10_DARK_FOG, 0, 30); // Dark Fog + sm.addSkill(SkillId.EVAN10_SOUL_STONE, 0, 20); // Soul Stone } @Script("q2344s") diff --git a/src/main/java/kinoko/script/quest/ResistanceQuest.java b/src/main/java/kinoko/script/quest/ResistanceQuest.java index 8dbc8119..e7905e58 100644 --- a/src/main/java/kinoko/script/quest/ResistanceQuest.java +++ b/src/main/java/kinoko/script/quest/ResistanceQuest.java @@ -1,5 +1,6 @@ package kinoko.script.quest; +import kinoko.meta.SkillId; import kinoko.packet.user.QuestPacket; import kinoko.script.common.Script; import kinoko.script.common.ScriptHandler; @@ -226,8 +227,8 @@ public static void q23012e(ScriptManager sm) { return; } sm.setJob(Job.WILD_HUNTER_1); - sm.addSkill(30001061, 1, 0); - sm.addSkill(30001062, 1, 0); + sm.addSkill(SkillId.CITIZEN_CAPTURE, 1, 0); + sm.addSkill(SkillId.CITIZEN_CALL_OF_THE_HUNTER, 1, 0); sm.forceCompleteQuest(23012); sm.sayNext("Well, well! Congratulations! You're now an official member of the Resistance and a Wild Hunter. Hop on your mount, move like the wind, and slay all enemies who get in your way!"); sm.sayPrev("Now, a warning. Don't lure the Black Wings' attention to you by telling people you're a Wild Hunter. I'll be your \"teacher\" from now on. This IS a school after all, right? I'll give you special lessons to turn you into the best Wild Hunter ever!"); @@ -246,7 +247,7 @@ public static void q23013e(ScriptManager sm) { return; } sm.setJob(Job.MECHANIC_1); - sm.addSkill(30001068, 1, 0); + sm.addSkill(SkillId.CITIZEN_MECHANIC_DASH, 1, 0); sm.forceCompleteQuest(23013); sm.sayNext("Welcome to the Resistance. From now on, you are a Mechanic. As one who works with machines, use every method available to defeat the enemies before you!"); sm.sayBoth("We have to be careful that our identity is not revealed to the Black Wings. So from now on, refer to me as teacher. You will pretend to be a student who is coming here for extracurricular lessons. It's during these lessons that I will teach you to become a strong Mechanic."); @@ -463,7 +464,8 @@ public static void q23052s(ScriptManager sm) { return; } sm.setJob(Job.BATTLE_MAGE_4); - sm.addSkill(32120000, 0, 10); + //TODO + /*sm.addSkill(32120000, 0, 10); sm.addSkill(32120001, 0, 10); sm.addSkill(32120009, 0, 10); sm.addSkill(32121002, 0, 10); @@ -471,7 +473,7 @@ public static void q23052s(ScriptManager sm) { sm.addSkill(32121004, 0, 10); sm.addSkill(32121005, 0, 10); sm.addSkill(32121006, 0, 10); - sm.addSkill(32121007, 0, 10); + sm.addSkill(32121007, 0, 10);*/ sm.forceCompleteQuest(23052); sm.sayNext("I've advanced you. I've also given you some sills that I know of but haven't mastered yet. I have a hunch that you'll be able to master them. After all, you are the most skilled member of the Resistance now!"); sm.sayBoth("Could this be my last lesson with you? Nah, can't be. You may be stronger, but I'm still smarter. I'm sure there's plenty more you can learn from me. So I'll see you at your next lesson... whenever that is..."); @@ -493,7 +495,7 @@ public static void q23053s(ScriptManager sm) { return; } sm.setJob(Job.WILD_HUNTER_4); - sm.addSkill(33120000, 0, 10); + /*sm.addSkill(33120000, 0, 10); sm.addSkill(33120010, 0, 10); sm.addSkill(33121001, 0, 10); sm.addSkill(33121002, 0, 10); @@ -501,7 +503,8 @@ public static void q23053s(ScriptManager sm) { sm.addSkill(33121005, 0, 10); sm.addSkill(33121006, 0, 10); sm.addSkill(33121007, 0, 10); - sm.addSkill(33121009, 0, 10); + sm.addSkill(33121009, 0, 10);*/ + //TODO sm.forceCompleteQuest(23053); sm.sayNext("I've advanced you. I've also given you some sills that I know of but haven't mastered yet. I have a hunch that you'll be able to master them. After all, you are the most skilled member of the Resistance now!"); sm.sayBoth("And with that, my lessons have... NOT come to an end. I can still be pretty useful, you know. There's more I can teach you. Plus, we're friends, right? So I'll see you at your next lesson... Whenever that might be..."); @@ -523,7 +526,7 @@ public static void q23054s(ScriptManager sm) { return; } sm.setJob(Job.MECHANIC_4); - sm.addSkill(35120000, 0, 30); + /*sm.addSkill(35120000, 0, 30); sm.addSkill(35120001, 0, 15); sm.addSkill(35121003, 0, 10); sm.addSkill(35121005, 0, 10); @@ -531,7 +534,8 @@ public static void q23054s(ScriptManager sm) { sm.addSkill(35121007, 0, 10); sm.addSkill(35121009, 0, 10); sm.addSkill(35121010, 0, 10); - sm.addSkill(35121012, 0, 10); + sm.addSkill(35121012, 0, 10);*/ + //TODO sm.forceCompleteQuest(23054); sm.sayNext("I've advanced you. I've also given you some sills that I know of but haven't mastered yet. I have a hunch that you'll be able to master them. After all, you are the most skilled member of the Resistance now."); sm.sayBoth("With this, the end of my lessons has... neared. Though you are stronger than I am, there are a lot of things you can still learn from me. I will see you at our next lesson... Whenever that may be..."); diff --git a/src/main/java/kinoko/server/command/AdminCommands.java b/src/main/java/kinoko/server/command/AdminCommands.java index 46a87387..98b09725 100644 --- a/src/main/java/kinoko/server/command/AdminCommands.java +++ b/src/main/java/kinoko/server/command/AdminCommands.java @@ -1,5 +1,6 @@ package kinoko.server.command; +import kinoko.meta.SkillId; import kinoko.packet.user.DragonPacket; import kinoko.packet.user.UserLocal; import kinoko.packet.user.UserRemote; @@ -308,7 +309,7 @@ public static void find(User user, String[] args) { } } } - final Optional skillInfoResult = SkillProvider.getSkillInfoById(skillId); + final Optional skillInfoResult = SkillProvider.getSkillInfoById(SkillId.fromValue(skillId)); if (skillInfoResult.isEmpty()) { user.write(MessagePacket.system("Could not find skill with %s : %s", isNumber ? "ID" : "name", query)); return; @@ -737,7 +738,7 @@ public static void job(User user, String[] args) { @Command("skill") @Arguments({ "skill ID", "skill level" }) public static void skill(User user, String[] args) { - final int skillId = Integer.parseInt(args[1]); + final SkillId skillId = SkillId.fromValue(Integer.parseInt(args[1])); final int slv = Integer.parseInt(args[2]); final Optional skillInfoResult = SkillProvider.getSkillInfoById(skillId); if (skillInfoResult.isEmpty()) { @@ -904,7 +905,7 @@ public static void jaguar(User user, String[] args) { public static void cd(User user, String[] args) { final var iter = user.getSkillManager().getSkillCooltimes().keySet().iterator(); while (iter.hasNext()) { - final int skillId = iter.next(); + final SkillId skillId = iter.next(); user.write(UserLocal.skillCooltimeSet(skillId, 0)); iter.remove(); } @@ -938,7 +939,7 @@ public static void max(User user, String[] args) { final SkillManager sm = user.getSkillManager(); final List removedRecords = new ArrayList<>(); for (SkillRecord skillRecord : sm.getSkillRecords()) { - if (JobConstants.isBeginnerJob(SkillConstants.getSkillRoot(skillRecord.getSkillId()))) { + if (JobConstants.isBeginnerJob(skillRecord.getSkillId().getRoot())) { continue; } skillRecord.setSkillLevel(0); diff --git a/src/main/java/kinoko/server/dialog/shop/ShopDialog.java b/src/main/java/kinoko/server/dialog/shop/ShopDialog.java index 13b01a63..6403c303 100644 --- a/src/main/java/kinoko/server/dialog/shop/ShopDialog.java +++ b/src/main/java/kinoko/server/dialog/shop/ShopDialog.java @@ -1,5 +1,6 @@ package kinoko.server.dialog.shop; +import kinoko.meta.SkillId; import kinoko.packet.field.FieldPacket; import kinoko.packet.world.WvsContext; import kinoko.provider.ItemProvider; @@ -217,16 +218,16 @@ public static ShopDialog from(NpcTemplate npcTemplate) { } private static int getIncSlotMax(User user, int itemId) { - int skillId = 0; + SkillId skillId = SkillId.NONE; if (ItemConstants.isJavelinItem(itemId)) { - if (user.getSkillLevel(Thief.CLAW_MASTERY) > 0) { - skillId = Thief.CLAW_MASTERY; - } else if (user.getSkillLevel(NightWalker.CLAW_MASTERY) > 0) { - skillId = NightWalker.CLAW_MASTERY; + if (user.getSkillLevel(SkillId.ASSASSIN_CLAW_MASTERY) > 0) { + skillId = SkillId.ASSASSIN_CLAW_MASTERY; + } else if (user.getSkillLevel(SkillId.NW2_CLAW_MASTERY) > 0) { + skillId = SkillId.NW2_CLAW_MASTERY; } } else if (ItemConstants.isPelletItem(itemId)) { - if (user.getSkillLevel(Pirate.GUN_MASTERY) > 0) { - skillId = Pirate.GUN_MASTERY; + if (user.getSkillLevel(SkillId.GUNSLINGER_GUN_MASTERY) > 0) { + skillId = SkillId.GUNSLINGER_GUN_MASTERY; } } return user.getSkillStatValue(skillId, SkillStat.y); diff --git a/src/main/java/kinoko/server/migration/MigrationInfo.java b/src/main/java/kinoko/server/migration/MigrationInfo.java index 893cbafe..a6d18c49 100644 --- a/src/main/java/kinoko/server/migration/MigrationInfo.java +++ b/src/main/java/kinoko/server/migration/MigrationInfo.java @@ -1,5 +1,6 @@ package kinoko.server.migration; +import kinoko.meta.SkillId; import kinoko.server.ServerConfig; import kinoko.server.packet.InPacket; import kinoko.server.packet.OutPacket; @@ -175,7 +176,7 @@ public static MigrationInfo from(User user, int targetChannelId) { // Filter summoned final Map> summoned = new HashMap<>(); for (var entry : user.getSummoned().entrySet()) { - if (SkillConstants.isSummonMigrateSkill(entry.getKey())) { + if (SkillConstants.isSummonMigrateSkill(SkillId.fromValue(entry.getKey()))) { summoned.put(entry.getKey(), entry.getValue()); } } diff --git a/src/main/java/kinoko/server/netty/ChannelServerHandler.java b/src/main/java/kinoko/server/netty/ChannelServerHandler.java index f92c4c41..770849d3 100644 --- a/src/main/java/kinoko/server/netty/ChannelServerHandler.java +++ b/src/main/java/kinoko/server/netty/ChannelServerHandler.java @@ -190,7 +190,7 @@ private void handlePartyResult(InPacket inPacket) { // Cancel party aura target.resetTemporaryStat(CharacterTemporaryStat.AURA_STAT); if (target.getSecondaryStat().hasOption(CharacterTemporaryStat.Aura)) { - BattleMage.cancelPartyAura(target, target.getSecondaryStat().getOption(CharacterTemporaryStat.Aura).rOption); + BattleMage.cancelPartyAura(target, target.getSecondaryStat().getOption(CharacterTemporaryStat.Aura).getSkillId()); } // Set party info and update members target.setPartyInfo(partyInfo); diff --git a/src/main/java/kinoko/server/packet/InPacket.java b/src/main/java/kinoko/server/packet/InPacket.java index c8d62550..d20bc555 100644 --- a/src/main/java/kinoko/server/packet/InPacket.java +++ b/src/main/java/kinoko/server/packet/InPacket.java @@ -1,5 +1,7 @@ package kinoko.server.packet; +import kinoko.meta.SkillId; + public interface InPacket { byte peekByte(); @@ -13,6 +15,8 @@ default boolean decodeBoolean() { int decodeInt(); + SkillId decodeSkillId(); + long decodeLong(); byte[] decodeArray(int length); diff --git a/src/main/java/kinoko/server/packet/NioBufferInPacket.java b/src/main/java/kinoko/server/packet/NioBufferInPacket.java index adb5ac6e..b8ab15d8 100644 --- a/src/main/java/kinoko/server/packet/NioBufferInPacket.java +++ b/src/main/java/kinoko/server/packet/NioBufferInPacket.java @@ -1,5 +1,6 @@ package kinoko.server.packet; +import kinoko.meta.SkillId; import kinoko.util.Util; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -37,6 +38,11 @@ public int decodeInt() { return buffer.getInt(); } + @Override + public SkillId decodeSkillId() { + return SkillId.fromValue(this.decodeInt()); + } + @Override public long decodeLong() { return buffer.getLong(); diff --git a/src/main/java/kinoko/server/packet/NioBufferOutPacket.java b/src/main/java/kinoko/server/packet/NioBufferOutPacket.java index a55849a3..8c40bff0 100644 --- a/src/main/java/kinoko/server/packet/NioBufferOutPacket.java +++ b/src/main/java/kinoko/server/packet/NioBufferOutPacket.java @@ -1,5 +1,6 @@ package kinoko.server.packet; +import kinoko.meta.SkillId; import kinoko.server.header.OutHeader; import kinoko.util.Util; import org.apache.logging.log4j.LogManager; @@ -54,6 +55,11 @@ public void encodeInt(int value) { getBuffer().putInt(value); } + @Override + public void encodeSkillId(SkillId skillId) { + this.encodeInt(skillId.getId()); + } + @Override public void encodeLong(long value) { ensureSize(8); diff --git a/src/main/java/kinoko/server/packet/OutPacket.java b/src/main/java/kinoko/server/packet/OutPacket.java index 38689a80..f408f997 100644 --- a/src/main/java/kinoko/server/packet/OutPacket.java +++ b/src/main/java/kinoko/server/packet/OutPacket.java @@ -1,5 +1,6 @@ package kinoko.server.packet; +import kinoko.meta.SkillId; import kinoko.server.header.CentralHeader; import kinoko.server.header.OutHeader; import kinoko.util.FileTime; @@ -29,6 +30,8 @@ default void encodeShort(int value) { void encodeInt(int value); + void encodeSkillId(SkillId skillId); + default void encodeInt(long value) { encodeInt((int) value); } diff --git a/src/main/java/kinoko/util/tool/JsonExporter.java b/src/main/java/kinoko/util/tool/JsonExporter.java index 3c5e3242..5a393fa6 100644 --- a/src/main/java/kinoko/util/tool/JsonExporter.java +++ b/src/main/java/kinoko/util/tool/JsonExporter.java @@ -115,7 +115,7 @@ private static void exportClasses() throws IOException { JSONObject skillObject = new JSONObject(); skillObject.put("id", si.getSkillId()); - final SkillStringInfo skillStringInfo = StringProvider.getSkillString(si.getSkillId()); + final SkillStringInfo skillStringInfo = StringProvider.getSkillString(si.getSkillId().getId()); if (skillStringInfo != null) { skillObject.put("name", skillStringInfo.getName()); skillObject.put("desc", skillStringInfo.getDesc()); diff --git a/src/main/java/kinoko/world/field/UserPool.java b/src/main/java/kinoko/world/field/UserPool.java index 2368c61c..81f44431 100644 --- a/src/main/java/kinoko/world/field/UserPool.java +++ b/src/main/java/kinoko/world/field/UserPool.java @@ -1,5 +1,6 @@ package kinoko.world.field; +import kinoko.meta.SkillId; import kinoko.packet.field.FieldPacket; import kinoko.packet.field.MobPacket; import kinoko.packet.field.NpcPacket; @@ -178,7 +179,7 @@ public synchronized boolean removeUser(User user) { field.getSummonedPool().removeSummoned(user, summoned); } // Remove from user - if (!SkillConstants.isSummonMigrateSkill(entry.getKey())) { + if (!SkillConstants.isSummonMigrateSkill(SkillId.fromValue(entry.getKey()))) { iter.remove(); } } @@ -195,7 +196,7 @@ public synchronized boolean removeUser(User user) { // Remove party aura user.resetTemporaryStat(CharacterTemporaryStat.AURA_STAT); if (user.getSecondaryStat().hasOption(CharacterTemporaryStat.Aura)) { - BattleMage.cancelPartyAura(user, user.getSecondaryStat().getOption(CharacterTemporaryStat.Aura).rOption); + BattleMage.cancelPartyAura(user, user.getSecondaryStat().getOption(CharacterTemporaryStat.Aura).getSkillId()); } return true; } @@ -207,7 +208,7 @@ public void updateUsers(Instant now) { // Expire temporary stat user.resetTemporaryStat((cts, option) -> now.isAfter(option.getExpireTime())); // Expire skill cooltimes - for (int skillId : user.expireSkillCooltime(now)) { + for (SkillId skillId : user.expireSkillCooltime(now)) { user.write(UserLocal.skillCooltimeSet(skillId, 0)); } // Update pets diff --git a/src/main/java/kinoko/world/field/affectedarea/AffectedArea.java b/src/main/java/kinoko/world/field/affectedarea/AffectedArea.java index fed95bcd..adbdccd7 100644 --- a/src/main/java/kinoko/world/field/affectedarea/AffectedArea.java +++ b/src/main/java/kinoko/world/field/affectedarea/AffectedArea.java @@ -1,5 +1,6 @@ package kinoko.world.field.affectedarea; +import kinoko.meta.SkillId; import kinoko.provider.SkillProvider; import kinoko.provider.skill.ElementAttribute; import kinoko.provider.skill.SkillInfo; @@ -22,13 +23,14 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; +import java.util.Objects; import java.util.Optional; public final class AffectedArea extends FieldObjectImpl implements Encodable { private static final Logger log = LogManager.getLogger(AffectedArea.class); private final AffectedAreaType type; private final FieldObject owner; - private final int skillId; + private final SkillId skillId; private final int skillLevel; private final int delay; private final int interval; @@ -36,7 +38,7 @@ public final class AffectedArea extends FieldObjectImpl implements Encodable { private final ElementAttribute elemAttr; private final Instant expireTime; - public AffectedArea(AffectedAreaType type, FieldObject owner, int skillId, int skillLevel, int delay, int interval, Rect rect, ElementAttribute elemAttr, Instant expireTime) { + public AffectedArea(AffectedAreaType type, FieldObject owner, SkillId skillId, int skillLevel, int delay, int interval, Rect rect, ElementAttribute elemAttr, Instant expireTime) { this.type = type; this.owner = owner; this.skillId = skillId; @@ -56,7 +58,7 @@ public FieldObject getOwner() { return owner; } - public int getSkillId() { + public SkillId getSkillId() { return skillId; } @@ -85,28 +87,26 @@ public Instant getExpireTime() { } public void handleUserInside(User user) { - switch (skillId) { - case Evan.RECOVERY_AURA -> { - final int partyId = ((User) owner).getPartyId(); - if (user.getCharacterId() == owner.getId() || (partyId != 0 && user.getPartyId() == partyId)) { - final Optional skillInfoResult = SkillProvider.getSkillInfoById(skillId); - if (skillInfoResult.isEmpty()) { - log.error("Failed to resolve skill info for affected area : {}", skillId); - return; - } - final SkillInfo si = skillInfoResult.get(); - double recoveryRate = si.getValue(SkillStat.x, skillLevel) / 100.0; - recoveryRate = recoveryRate * (interval * ServerConfig.FIELD_TICK_INTERVAL) / si.getDuration(skillLevel); - user.addMp((int) (recoveryRate * user.getMaxMp())); + if (Objects.requireNonNull(skillId) == SkillId.EVAN8_RECOVERY_AURA) { + final int partyId = ((User) owner).getPartyId(); + if (user.getCharacterId() == owner.getId() || (partyId != 0 && user.getPartyId() == partyId)) { + final Optional skillInfoResult = SkillProvider.getSkillInfoById(skillId); + if (skillInfoResult.isEmpty()) { + log.error("Failed to resolve skill info for affected area : {}", skillId); + return; } + final SkillInfo si = skillInfoResult.get(); + double recoveryRate = si.getValue(SkillStat.x, skillLevel) / 100.0; + recoveryRate = recoveryRate * (interval * ServerConfig.FIELD_TICK_INTERVAL) / si.getDuration(skillLevel); + user.addMp((int) (recoveryRate * user.getMaxMp())); } } } public void handleMobInside(Mob mob) { switch (skillId) { - case Magician.POISON_MIST, BlazeWizard.FLAME_GEAR, NightWalker.POISON_BOMB -> { - if (mob.getHp() == 1 || mob.getMobStat().hasBurnedInfo(owner.getId(), skillId)) { + case SkillId.FP2_POISON_MIST, SkillId.BW3_FLAME_GEAR, SkillId.NW3_POISON_BOMB -> { + if (mob.getHp() == 1 || mob.getMobStat().hasBurnedInfo(owner.getId(), skillId.getId())) { return; } final Optional skillInfoResult = SkillProvider.getSkillInfoById(skillId); @@ -124,7 +124,7 @@ public void encode(OutPacket outPacket) { outPacket.encodeInt(getId()); // dwID outPacket.encodeInt(type.getValue()); // nType outPacket.encodeInt(owner.getId()); // dwOwnerID - outPacket.encodeInt(skillId); // nSkillID + outPacket.encodeSkillId(skillId); // nSkillID outPacket.encodeByte(skillLevel); // nSLV outPacket.encodeShort(delay); // tStart = get_update_time() + 100 * delay outPacket.encodeInt(rect.getLeft()); // rcArea->left @@ -146,7 +146,8 @@ public static AffectedArea userSkill(User owner, SkillInfo si, int slv, int dela } public static AffectedArea buff(User owner, int itemId, Rect rect, Instant expireTime) { - return new AffectedArea(AffectedAreaType.Buff, owner, itemId, 0, 0, 0, owner.getRelativeRect(rect), ElementAttribute.PHYSICAL, expireTime); + //TODO fix skill id + return new AffectedArea(AffectedAreaType.Buff, owner, SkillId.NONE, 0, 0, 0, owner.getRelativeRect(rect), ElementAttribute.PHYSICAL, expireTime); } public static AffectedArea from(AffectedAreaType affectedAreaType, User owner, SkillInfo si, int slv, int delay, int interval, int x, int y) { diff --git a/src/main/java/kinoko/world/field/mob/BurnedInfo.java b/src/main/java/kinoko/world/field/mob/BurnedInfo.java index 7624a6e2..e712a7d8 100644 --- a/src/main/java/kinoko/world/field/mob/BurnedInfo.java +++ b/src/main/java/kinoko/world/field/mob/BurnedInfo.java @@ -102,7 +102,7 @@ public static BurnedInfo from(User user, SkillInfo si, int slv, int skillDamage, final int duration = si.getValue(SkillStat.dotTime, slv) * 1000; return new BurnedInfo( user.getCharacterId(), - si.getSkillId(), + si.getSkillId().getId(), (int) Math.clamp(damage, 1.0, GameConstants.DAMAGE_MAX), interval, duration / interval diff --git a/src/main/java/kinoko/world/field/mob/Mob.java b/src/main/java/kinoko/world/field/mob/Mob.java index 109befee..1cb0e212 100644 --- a/src/main/java/kinoko/world/field/mob/Mob.java +++ b/src/main/java/kinoko/world/field/mob/Mob.java @@ -1,5 +1,6 @@ package kinoko.world.field.mob; +import kinoko.meta.SkillId; import kinoko.packet.field.FieldEffectPacket; import kinoko.packet.field.MobPacket; import kinoko.packet.world.BroadcastPacket; @@ -587,8 +588,8 @@ private Optional createDrop(User owner, Reward reward) { if (money <= 0) { return Optional.empty(); } - if (owner.getSkillLevel(Thief.MESO_MASTERY) > 0) { - final double multiplier = (owner.getSkillStatValue(Thief.MESO_MASTERY, SkillStat.mesoR) + 100) / 100.0; + if (owner.getSkillLevel(SkillId.SHADOWER_MESO_MASTERY) > 0) { + final double multiplier = (owner.getSkillStatValue(SkillId.SHADOWER_MESO_MASTERY, SkillStat.mesoR) + 100) / 100.0; money = (int) (money * multiplier); } if (owner.getSecondaryStat().hasOption(CharacterTemporaryStat.MesoUp)) { diff --git a/src/main/java/kinoko/world/field/mob/MobStatOption.java b/src/main/java/kinoko/world/field/mob/MobStatOption.java index a6201581..8825e188 100644 --- a/src/main/java/kinoko/world/field/mob/MobStatOption.java +++ b/src/main/java/kinoko/world/field/mob/MobStatOption.java @@ -1,5 +1,6 @@ package kinoko.world.field.mob; +import kinoko.meta.SkillId; import kinoko.server.packet.OutPacket; import kinoko.util.Encodable; @@ -40,6 +41,10 @@ public static MobStatOption of(int nOption, int rOption, int tOption) { return new MobStatOption(nOption, rOption, tOption); } + public static MobStatOption of(int nOption, SkillId skillId, int tOption) { + return MobStatOption.of(nOption, skillId.getId(), tOption); + } + public static MobStatOption ofMobSkill(int nOption, int skillId, int slv, int tOption) { final int rOption = skillId | (slv << 16); return new MobStatOption(nOption, rOption, tOption); diff --git a/src/main/java/kinoko/world/field/summoned/Summoned.java b/src/main/java/kinoko/world/field/summoned/Summoned.java index 98af50b9..a2b8d1cf 100644 --- a/src/main/java/kinoko/world/field/summoned/Summoned.java +++ b/src/main/java/kinoko/world/field/summoned/Summoned.java @@ -1,5 +1,6 @@ package kinoko.world.field.summoned; +import kinoko.meta.SkillId; import kinoko.provider.map.Foothold; import kinoko.provider.skill.SkillInfo; import kinoko.util.Rect; @@ -126,9 +127,9 @@ public static Summoned from(SkillInfo si, int slv, SummonedMoveAbility moveAbili return Summoned.from(si.getSkillId(), slv, moveAbility, assistType, Instant.now().plus(si.getDuration(slv), ChronoUnit.MILLIS)); } - public static Summoned from(int skillId, int slv, SummonedMoveAbility moveAbility, SummonedAssistType assistType, Instant expireTime) { + public static Summoned from(SkillId skillId, int slv, SummonedMoveAbility moveAbility, SummonedAssistType assistType, Instant expireTime) { return new Summoned( - skillId, + skillId.getId(), slv, moveAbility, assistType, diff --git a/src/main/java/kinoko/world/job/cygnus/DawnWarrior.java b/src/main/java/kinoko/world/job/cygnus/DawnWarrior.java index 084762bd..9a440518 100644 --- a/src/main/java/kinoko/world/job/cygnus/DawnWarrior.java +++ b/src/main/java/kinoko/world/job/cygnus/DawnWarrior.java @@ -1,5 +1,6 @@ package kinoko.world.job.cygnus; +import kinoko.meta.SkillId; import kinoko.provider.SkillProvider; import kinoko.provider.skill.SkillInfo; import kinoko.world.field.Field; @@ -40,16 +41,16 @@ public static void handleAttack(User user, Mob mob, Attack attack, int delay) { public static void handleSkill(User user, Skill skill) { final SkillInfo si = SkillProvider.getSkillInfoById(skill.skillId).orElseThrow(); - final int skillId = skill.skillId; + final SkillId skillId = skill.skillId; final int slv = skill.slv; final Field field = user.getField(); switch (skillId) { - case FINAL_ATTACK: - user.setTemporaryStat(CharacterTemporaryStat.SoulMasterFinal, TemporaryStatOption.of(1, skillId, si.getDuration(slv))); + case SkillId.DW2_FINAL_ATTACK: + user.setTemporaryStat(CharacterTemporaryStat.SoulMasterFinal, TemporaryStatOption.of(1, skillId.getId(), si.getDuration(slv))); return; - case SOUL_CHARGE: - user.setTemporaryStat(CharacterTemporaryStat.WeaponCharge, TemporaryStatOption.of(1, skillId, si.getDuration(slv))); + case SkillId.DW3_SOUL_CHARGE: + user.setTemporaryStat(CharacterTemporaryStat.WeaponCharge, TemporaryStatOption.of(1, skillId.getId(), si.getDuration(slv))); return; } log.error("Unhandled skill {}", skill.skillId); diff --git a/src/main/java/kinoko/world/job/cygnus/ThunderBreaker.java b/src/main/java/kinoko/world/job/cygnus/ThunderBreaker.java index ee1ae596..68c90a4e 100644 --- a/src/main/java/kinoko/world/job/cygnus/ThunderBreaker.java +++ b/src/main/java/kinoko/world/job/cygnus/ThunderBreaker.java @@ -1,5 +1,6 @@ package kinoko.world.job.cygnus; +import kinoko.meta.SkillId; import kinoko.provider.SkillProvider; import kinoko.provider.skill.SkillInfo; import kinoko.world.field.Field; @@ -41,11 +42,11 @@ public static void handleAttack(User user, Mob mob, Attack attack, int delay) { public static void handleSkill(User user, Skill skill) { final SkillInfo si = SkillProvider.getSkillInfoById(skill.skillId).orElseThrow(); - final int skillId = skill.skillId; + final SkillId skillId = skill.skillId; final int slv = skill.slv; final Field field = user.getField(); - switch (skillId) { + switch (skillId.getId()) { case LIGHTNING_CHARGE: user.setTemporaryStat(CharacterTemporaryStat.WeaponCharge, TemporaryStatOption.of(1, skillId, si.getDuration(slv))); return; diff --git a/src/main/java/kinoko/world/job/cygnus/WindArcher.java b/src/main/java/kinoko/world/job/cygnus/WindArcher.java index b77ef772..6f88b7bf 100644 --- a/src/main/java/kinoko/world/job/cygnus/WindArcher.java +++ b/src/main/java/kinoko/world/job/cygnus/WindArcher.java @@ -1,5 +1,6 @@ package kinoko.world.job.cygnus; +import kinoko.meta.SkillId; import kinoko.provider.SkillProvider; import kinoko.provider.skill.SkillInfo; import kinoko.world.field.Field; @@ -41,11 +42,11 @@ public static void handleAttack(User user, Mob mob, Attack attack, int delay) { public static void handleSkill(User user, Skill skill) { final SkillInfo si = SkillProvider.getSkillInfoById(skill.skillId).orElseThrow(); - final int skillId = skill.skillId; + final SkillId skillId = skill.skillId; final int slv = skill.slv; final Field field = user.getField(); - switch (skillId) { + switch (skillId.getId()) { case FINAL_ATTACK: user.setTemporaryStat(CharacterTemporaryStat.WindBreakerFinal, TemporaryStatOption.of(1, skillId, si.getDuration(slv))); return; diff --git a/src/main/java/kinoko/world/job/explorer/Bowman.java b/src/main/java/kinoko/world/job/explorer/Bowman.java index ade21496..5c8a45e0 100644 --- a/src/main/java/kinoko/world/job/explorer/Bowman.java +++ b/src/main/java/kinoko/world/job/explorer/Bowman.java @@ -1,5 +1,6 @@ package kinoko.world.job.explorer; +import kinoko.meta.SkillId; import kinoko.provider.SkillProvider; import kinoko.provider.skill.SkillInfo; import kinoko.provider.skill.SkillStat; @@ -89,11 +90,11 @@ public final class Bowman extends SkillProcessor { public static void handleAttack(User user, Mob mob, Attack attack, int delay) { final SkillInfo si = SkillProvider.getSkillInfoById(attack.skillId).orElseThrow(); - final int skillId = attack.skillId; + final SkillId skillId = attack.skillId; final int slv = attack.slv; final Field field = user.getField(); - switch (skillId) { + switch (skillId.getId()) { case ARROW_BOMB: case SILVER_HAWK: case GOLDEN_EAGLE: @@ -120,11 +121,11 @@ public static void handleAttack(User user, Mob mob, Attack attack, int delay) { public static void handleSkill(User user, Skill skill) { final SkillInfo si = SkillProvider.getSkillInfoById(skill.skillId).orElseThrow(); - final int skillId = skill.skillId; + final SkillId skillId = skill.skillId; final int slv = skill.slv; final Field field = user.getField(); - switch (skillId) { + switch (skillId.getId()) { case SILVER_HAWK: case GOLDEN_EAGLE: case PHOENIX: diff --git a/src/main/java/kinoko/world/job/explorer/Magician.java b/src/main/java/kinoko/world/job/explorer/Magician.java index 6635ceac..443f5a6e 100644 --- a/src/main/java/kinoko/world/job/explorer/Magician.java +++ b/src/main/java/kinoko/world/job/explorer/Magician.java @@ -1,5 +1,6 @@ package kinoko.world.job.explorer; +import kinoko.meta.SkillId; import kinoko.packet.world.MessagePacket; import kinoko.packet.world.WvsContext; import kinoko.provider.SkillProvider; @@ -126,11 +127,11 @@ public final class Magician extends SkillProcessor { public static void handleAttack(User user, Mob mob, Attack attack, int delay) { final SkillInfo si = SkillProvider.getSkillInfoById(attack.skillId).orElseThrow(); - final int skillId = attack.skillId; + final SkillId skillId = attack.skillId; final int slv = attack.slv; final Field field = user.getField(); - switch (skillId) { + switch (skillId.getId()) { case THUNDER_SPEAR: case SHINING_RAY: if (!mob.isBoss() && Util.succeedProp(si.getValue(SkillStat.prop, slv))) { @@ -166,12 +167,12 @@ public static void handleAttack(User user, Mob mob, Attack attack, int delay) { public static void handleSkill(User user, Skill skill) { final SkillInfo si = SkillProvider.getSkillInfoById(skill.skillId).orElseThrow(); - final int skillId = skill.skillId; + final SkillId skillId = skill.skillId; final int slv = skill.slv; final int buffedDuration = getBuffedDuration(user, si.getDuration(slv)); final Field field = user.getField(); - switch (skillId) { + switch (skillId.getId()) { // COMMON case MANA_REFLECTION_FP: case MANA_REFLECTION_IL: @@ -242,7 +243,7 @@ public static void handleSkill(User user, Skill skill) { case MYSTIC_DOOR: final Optional townPortalResult = field.getTownPortalPool().createFieldPortal( user, - skillId, + skillId.getId(), skill.positionX, skill.positionY, Instant.now().plus(si.getDuration(slv), ChronoUnit.MILLIS) diff --git a/src/main/java/kinoko/world/job/explorer/Pirate.java b/src/main/java/kinoko/world/job/explorer/Pirate.java index 5884c7d1..e2ae8948 100644 --- a/src/main/java/kinoko/world/job/explorer/Pirate.java +++ b/src/main/java/kinoko/world/job/explorer/Pirate.java @@ -1,5 +1,6 @@ package kinoko.world.job.explorer; +import kinoko.meta.SkillId; import kinoko.packet.field.MobPacket; import kinoko.packet.user.UserLocal; import kinoko.packet.user.UserRemote; @@ -100,46 +101,46 @@ public final class Pirate extends SkillProcessor { public static void handleAttack(User user, Mob mob, Attack attack, int delay) { final SkillInfo si = SkillProvider.getSkillInfoById(attack.skillId).orElseThrow(); - final int skillId = attack.skillId; + final SkillId skillId = attack.skillId; final int slv = attack.slv; final Field field = user.getField(); switch (skillId) { - case BACKSPIN_BLOW: - case DOUBLE_UPPERCUT: - case SNATCH: - case BLANK_SHOT: + case SkillId.BRAWLER_BACKSPIN_BLOW: + case SkillId.BRAWLER_DOUBLE_UPPERCUT: + case SkillId.BUCCANEER_SNATCH: + case SkillId.GUNSLINGER_BLANK_SHOT: if (!mob.isBoss()) { mob.setTemporaryStat(MobTemporaryStat.Stun, MobStatOption.of(1, skillId, si.getDuration(slv)), delay); } break; - case ENERGY_BLAST: + case SkillId.MARAUDER_ENERGY_BLAST: if (!mob.isBoss() && Util.succeedProp(si.getValue(SkillStat.prop, slv))) { mob.setTemporaryStat(MobTemporaryStat.Stun, MobStatOption.of(1, skillId, si.getDuration(slv)), delay); } break; - case GRENADE: + case SkillId.GUNSLINGER_GRENADE: mob.setBurnedInfo(BurnedInfo.from(user, si, slv, mob), delay); break; - case GAVIOTA: - user.removeSummoned((summoned) -> summoned.getSkillId() == skillId); + case SkillId.OUTLAW_GAVIOTA: + user.removeSummoned((summoned) -> summoned.getSkillId() == skillId.getId()); break; - case FLAMETHROWER: - final int dot = si.getValue(SkillStat.dot, slv) + user.getSkillStatValue(ELEMENTAL_BOOST, SkillStat.x); + case SkillId.OUTLAW_FLAMETHROWER: + final int dot = si.getValue(SkillStat.dot, slv) + user.getSkillStatValue(SkillId.CORSAIR_ELEMENTAL_BOOST, SkillStat.x); mob.setBurnedInfo(BurnedInfo.from(user, si, slv, dot, mob), delay); break; - case ICE_SPLITTER: - final int time = si.getValue(SkillStat.time, slv) + user.getSkillStatValue(ELEMENTAL_BOOST, SkillStat.y); + case SkillId.OUTLAW_ICE_SPLITTER: + final int time = si.getValue(SkillStat.time, slv) + user.getSkillStatValue(SkillId.CORSAIR_ELEMENTAL_BOOST, SkillStat.y); mob.setTemporaryStat(MobTemporaryStat.Freeze, MobStatOption.of(1, skillId, time * 1000), delay); break; - case HOMING_BEACON: - case BULLSEYE: + case SkillId.OUTLAW_HOMING_BEACON: + case SkillId.CORSAIR_BULLSEYE: if (user.getSecondaryStat().hasOption(CharacterTemporaryStat.GuidedBullet)) { user.resetTemporaryStat(Set.of(CharacterTemporaryStat.GuidedBullet)); } - user.setTemporaryStat(CharacterTemporaryStat.GuidedBullet, TemporaryStatOption.ofTwoState(CharacterTemporaryStat.GuidedBullet, skillId == BULLSEYE ? si.getValue(SkillStat.x, slv) : 1, skillId, mob.getId())); + user.setTemporaryStat(CharacterTemporaryStat.GuidedBullet, TemporaryStatOption.ofTwoState(CharacterTemporaryStat.GuidedBullet, skillId == SkillId.CORSAIR_BULLSEYE ? si.getValue(SkillStat.x, slv) : 1, skillId.getId(), mob.getId())); break; - case HYPNOTIZE: + case SkillId.CORSAIR_HYPNOTIZE: if (!mob.isBoss() && Util.succeedProp(si.getValue(SkillStat.prop, slv))) { mob.setTemporaryStat(MobTemporaryStat.Dazzle, MobStatOption.of(1, skillId, si.getDuration(slv)), delay); if (mob.getController() != user) { @@ -154,36 +155,36 @@ public static void handleAttack(User user, Mob mob, Attack attack, int delay) { public static void handleSkill(User user, Skill skill) { final SkillInfo si = SkillProvider.getSkillInfoById(skill.skillId).orElseThrow(); - final int skillId = skill.skillId; + final SkillId skillId = skill.skillId; final int slv = skill.slv; final Field field = user.getField(); switch (skillId) { // COMMON - case ROLL_OF_THE_DICE_BUCC: - case ROLL_OF_THE_DICE_SAIR: + case SkillId.OUTLAW_ROLL_OF_THE_DICE: + case SkillId.MARAUDER_ROLL_OF_THE_DICE: final int roll = Util.getRandom(1, 6); user.write(UserLocal.effect(Effect.skillAffectedSelect(roll, skillId, slv))); field.broadcastPacket(UserRemote.effect(user, Effect.skillAffectedSelect(roll, skillId, slv)), user); if (roll != 1) { final DiceInfo diceInfo = DiceInfo.from(roll, si, slv); - user.setTemporaryStat(CharacterTemporaryStat.Dice, TemporaryStatOption.ofDice(roll, skillId, si.getDuration(slv), diceInfo)); + user.setTemporaryStat(CharacterTemporaryStat.Dice, TemporaryStatOption.ofDice(roll, skillId.getId(), si.getDuration(slv), diceInfo)); } return; // BUCC - case MP_RECOVERY: + case SkillId.BRAWLER_MP_RECOVERY: final int hp = user.getMaxHp() * si.getValue(SkillStat.x, slv) / 100; user.addMp(hp * si.getValue(SkillStat.y, slv) / 100); return; - case OAK_BARREL: + case SkillId.BRAWLER_OAK_BARREL: user.setTemporaryStat(CharacterTemporaryStat.Morph, TemporaryStatOption.of(si.getValue(SkillStat.morph, slv), skillId, si.getDuration(slv))); return; - case TIME_LEAP: + case SkillId.BUCCANEER_TIME_LEAP: final var iter = user.getSkillManager().getSkillCooltimes().keySet().iterator(); while (iter.hasNext()) { - final int toReset = iter.next(); - if (toReset != TIME_LEAP) { + final SkillId toReset = iter.next(); + if (toReset != SkillId.BUCCANEER_TIME_LEAP) { user.write(UserLocal.skillCooltimeSet(toReset, 0)); iter.remove(); } @@ -191,23 +192,23 @@ public static void handleSkill(User user, Skill skill) { return; // SAIR - case GRENADE: + case SkillId.GUNSLINGER_GRENADE: // Handled in attack return; - case OCTOPUS: - case WRATH_OF_THE_OCTOPI: + case SkillId.OUTLAW_OCTOPUS: + case SkillId.CORSAIR_WRATH_OF_THE_OCTOPI: final Summoned octopus = Summoned.from(si, slv, SummonedMoveAbility.STOP, SummonedAssistType.ATTACK); octopus.setPosition(field, skill.positionX, skill.positionY, skill.summonLeft); user.addSummoned(octopus); return; - case GAVIOTA: + case SkillId.OUTLAW_GAVIOTA: final Summoned gaviota = Summoned.from(si, slv, SummonedMoveAbility.FLY, SummonedAssistType.ATTACK); gaviota.setPosition(field, skill.positionX, skill.positionY, skill.summonLeft); user.addSummoned(gaviota); return; - case BATTLESHIP: + case SkillId.CORSAIR_BATTLESHIP: user.setTemporaryStat(Map.of( - CharacterTemporaryStat.RideVehicle, TemporaryStatOption.ofTwoState(CharacterTemporaryStat.RideVehicle, SkillConstants.BATTLESHIP_VEHICLE, skillId, 0), + CharacterTemporaryStat.RideVehicle, TemporaryStatOption.ofTwoState(CharacterTemporaryStat.RideVehicle, SkillConstants.BATTLESHIP_VEHICLE, skillId.getId(), 0), CharacterTemporaryStat.EPAD, TemporaryStatOption.of(si.getValue(SkillStat.epad, slv), skillId, 0), CharacterTemporaryStat.EMHP, TemporaryStatOption.of(si.getValue(SkillStat.emhp, slv), skillId, 0), CharacterTemporaryStat.EMMP, TemporaryStatOption.of(si.getValue(SkillStat.emmp, slv), skillId, 0), @@ -221,18 +222,18 @@ public static void handleSkill(User user, Skill skill) { } public static int getBattleshipDurability(User user) { - final Instant cooltime = user.getSkillManager().getSkillCooltimes().get(SkillConstants.BATTLESHIP_DURABILITY); + final Instant cooltime = user.getSkillManager().getSkillCooltimes().get(SkillId.CORSAIR_BATTLESHIP_DURABILITY); if (cooltime != null) { return (int) cooltime.getEpochSecond(); } else { // get_max_durability_of_vehicle - return 300 * user.getLevel() + 500 * (user.getSkillLevel(BATTLESHIP) - 72); + return 300 * user.getLevel() + 500 * (user.getSkillLevel(SkillId.CORSAIR_BATTLESHIP) - 72); } } public static void setBattleshipDurability(User user, int durability) { final Instant cooltime = Instant.ofEpochSecond(durability); - user.getSkillManager().getSkillCooltimes().put(SkillConstants.BATTLESHIP_DURABILITY, cooltime); - user.write(UserLocal.skillCooltimeSet(SkillConstants.BATTLESHIP_DURABILITY, durability)); + user.getSkillManager().getSkillCooltimes().put(SkillId.CORSAIR_BATTLESHIP_DURABILITY, cooltime); + user.write(UserLocal.skillCooltimeSet(SkillId.CORSAIR_BATTLESHIP_DURABILITY, durability)); } } \ No newline at end of file diff --git a/src/main/java/kinoko/world/job/explorer/Thief.java b/src/main/java/kinoko/world/job/explorer/Thief.java index f80187ec..285ef150 100644 --- a/src/main/java/kinoko/world/job/explorer/Thief.java +++ b/src/main/java/kinoko/world/job/explorer/Thief.java @@ -1,5 +1,6 @@ package kinoko.world.job.explorer; +import kinoko.meta.SkillId; import kinoko.packet.field.MobPacket; import kinoko.provider.SkillProvider; import kinoko.provider.skill.SkillInfo; @@ -129,11 +130,11 @@ public final class Thief extends SkillProcessor { public static void handleAttack(User user, Mob mob, Attack attack, int delay) { final SkillInfo si = SkillProvider.getSkillInfoById(attack.skillId).orElseThrow(); - final int skillId = attack.skillId; + final SkillId skillId = attack.skillId; final int slv = attack.slv; final Field field = user.getField(); - switch (skillId) { + switch (skillId.getId()) { case SHADOW_MESO: if (!mob.isBoss()) { mob.resetTemporaryStat(Set.of(MobTemporaryStat.PGuardUp, MobTemporaryStat.MGuardUp)); @@ -180,11 +181,11 @@ public static void handleAttack(User user, Mob mob, Attack attack, int delay) { public static void handleSkill(User user, Skill skill) { final SkillInfo si = SkillProvider.getSkillInfoById(skill.skillId).orElseThrow(); - final int skillId = skill.skillId; + final SkillId skillId = skill.skillId; final int slv = skill.slv; final Field field = user.getField(); - switch (skillId) { + switch (skillId.getId()) { case DARK_FLARE_NL: case DARK_FLARE_SHAD: final Summoned darkFlare = Summoned.from(si, slv, SummonedMoveAbility.STOP, SummonedAssistType.ATTACK_COUNTER); @@ -197,7 +198,7 @@ public static void handleSkill(User user, Skill skill) { final int damage = (int) Math.clamp(CalcDamage.calcDamageMax(user) * si.getValue(SkillStat.damage, slv) / 100, 1.0, GameConstants.DAMAGE_MAX); final int dotCount = si.getValue(SkillStat.time, slv); // duration / interval skill.forEachAffectedMob(field, (mob) -> { - mob.setBurnedInfo(new BurnedInfo(user.getCharacterId(), skillId, damage, 1000, dotCount), 0); + mob.setBurnedInfo(new BurnedInfo(user.getCharacterId(), skillId.getId(), damage, 1000, dotCount), 0); }); return; @@ -227,10 +228,10 @@ public static void handleSkill(User user, Skill skill) { // DB case TORNADO_SPIN: - user.setTemporaryStat(CharacterTemporaryStat.Dash_Speed, TemporaryStatOption.ofTwoState(CharacterTemporaryStat.Dash_Speed, si.getValue(SkillStat.x, slv), skillId, si.getDuration(slv))); + user.setTemporaryStat(CharacterTemporaryStat.Dash_Speed, TemporaryStatOption.ofTwoState(CharacterTemporaryStat.Dash_Speed, si.getValue(SkillStat.x, slv), skillId.getId(), si.getDuration(slv))); return; case MIRRORED_TARGET: - final Summoned summoned = new Summoned(skillId, slv, SummonedMoveAbility.STOP, SummonedAssistType.NONE, user.getCharacterData().getAvatarLook(), Instant.now().plus(si.getDuration(slv), ChronoUnit.MILLIS)); + final Summoned summoned = new Summoned(skillId.getId(), slv, SummonedMoveAbility.STOP, SummonedAssistType.NONE, user.getCharacterData().getAvatarLook(), Instant.now().plus(si.getDuration(slv), ChronoUnit.MILLIS)); summoned.setPosition(field, skill.positionX, skill.positionY, skill.summonLeft); summoned.setHp(si.getValue(SkillStat.x, slv)); user.addSummoned(summoned); @@ -242,7 +243,7 @@ public static void handleSkill(User user, Skill skill) { return; case MONSTER_BOMB: skill.forEachAffectedMob(field, (mob) -> { - field.broadcastPacket(MobPacket.mobAffected(mob, skillId, 0)); + field.broadcastPacket(MobPacket.mobAffected(mob, skillId.getId(), 0)); mob.setTemporaryStat(MobTemporaryStat.TimeBomb, MobStatOption.of(1, skillId, si.getDuration(slv) + ServerConfig.FIELD_TICK_INTERVAL), 0); // for MobTimeBombEnd check }); return; diff --git a/src/main/java/kinoko/world/job/explorer/Warrior.java b/src/main/java/kinoko/world/job/explorer/Warrior.java index 9f98a331..b3be379f 100644 --- a/src/main/java/kinoko/world/job/explorer/Warrior.java +++ b/src/main/java/kinoko/world/job/explorer/Warrior.java @@ -1,5 +1,6 @@ package kinoko.world.job.explorer; +import kinoko.meta.SkillId; import kinoko.packet.user.UserLocal; import kinoko.packet.user.UserRemote; import kinoko.provider.SkillProvider; @@ -27,6 +28,7 @@ import java.util.Optional; public final class Warrior extends SkillProcessor { + // WARRIOR public static final int HP_BOOST = 1000006; public static final int IRON_BODY = 1001003; @@ -121,23 +123,21 @@ public final class Warrior extends SkillProcessor { public static void handleAttack(User user, Mob mob, Attack attack, int delay) { final SkillInfo si = SkillProvider.getSkillInfoById(attack.skillId).orElseThrow(); - final int skillId = attack.skillId; + final SkillId skillId = attack.skillId; final int slv = attack.slv; switch (skillId) { - case MONSTER_MAGNET_HERO: - case MONSTER_MAGNET_DRK: + case SkillId.HERO_MONSTER_MAGNET, SkillId.DRK_MONSTER_MAGNET: if (!mob.isBoss()) { mob.setTemporaryStat(MobTemporaryStat.Stun, MobStatOption.of(1, skillId, si.getDuration(slv)), delay); } return; - case SHOUT: - case CHARGED_BLOW: + case SkillId.CRUSADER_SHOUT, SkillId.WK_CHARGED_BLOW: if (!mob.isBoss() && Util.succeedProp(si.getValue(SkillStat.prop, slv))) { mob.setTemporaryStat(MobTemporaryStat.Stun, MobStatOption.of(1, skillId, si.getDuration(slv)), delay); } break; - case BLAST: + case SkillId.PALADIN_BLAST: if (!mob.isBoss() && Util.succeedProp(si.getValue(SkillStat.prop, slv))) { mob.damage(user, mob.getHp(), delay); } @@ -147,40 +147,35 @@ public static void handleAttack(User user, Mob mob, Attack attack, int delay) { public static void handleSkill(User user, Skill skill) { final SkillInfo si = SkillProvider.getSkillInfoById(skill.skillId).orElseThrow(); - final int skillId = skill.skillId; + final SkillId skillId = skill.skillId; final int slv = skill.slv; final Field field = user.getField(); switch (skillId) { // COMMON - case POWER_GUARD_HERO: - case POWER_GUARD_PALADIN: + case SkillId.FIGHTER_POWER_GUARD, SkillId.PAGE_POWER_GUARD: user.setTemporaryStat(CharacterTemporaryStat.PowerGuard, TemporaryStatOption.of(si.getValue(SkillStat.x, slv), skillId, si.getDuration(slv))); return; - case MAGIC_CRASH_HERO: - case MAGIC_CRASH_PALADIN: - case MAGIC_CRASH_DRK: + case SkillId.CRUSADER_MAGIC_CRASH, SkillId.WK_MAGIC_CRASH, SkillId.DK_MAGIC_CRASH: skill.forEachAffectedMob(field, (mob) -> { if (Util.succeedProp(si.getValue(SkillStat.prop, slv))) { mob.setTemporaryStat(MobTemporaryStat.MagicCrash, MobStatOption.of(1, skillId, si.getDuration(slv)), 0); } }); return; - case POWER_STANCE_HERO: - case POWER_STANCE_PALADIN: - case POWER_STANCE_DRK: + case SkillId.HERO_POWER_STANCE, SkillId.PALADIN_POWER_STANCE, SkillId.DRK_POWER_STANCE: user.setTemporaryStat(CharacterTemporaryStat.Stance, TemporaryStatOption.of(si.getValue(SkillStat.prop, slv), skillId, si.getDuration(slv))); return; // HERO - case ENRAGE: + case SkillId.HERO_ENRAGE: final int nEnrage = si.getValue(SkillStat.x, slv) * 100 + si.getValue(SkillStat.mobCount, slv); // damR = n / 100, nCount = n % 100 user.setTemporaryStat(CharacterTemporaryStat.Enrage, TemporaryStatOption.of(nEnrage, skillId, si.getDuration(slv))); resetComboCounter(user); return; // PALADIN - case THREATEN: + case SkillId.PAGE_THREATEN: skill.forEachAffectedMob(field, (mob) -> { if (!mob.isBoss()) { mob.setTemporaryStat(Map.of( @@ -191,52 +186,50 @@ public static void handleSkill(User user, Skill skill) { } }); return; - case HP_RECOVERY: + case SkillId.WK_HP_RECOVERY: final int hpRecovery = user.getMaxHp() * si.getValue(SkillStat.x, slv) / 100; user.addHp(hpRecovery); user.write(UserLocal.effect(Effect.incDecHpEffect(hpRecovery))); field.broadcastPacket(UserRemote.effect(user, Effect.incDecHpEffect(hpRecovery)), user); return; - case COMBAT_ORDERS: + case SkillId.WK_COMBAT_ORDERS: user.setTemporaryStat(CharacterTemporaryStat.CombatOrders, TemporaryStatOption.of(si.getValue(SkillStat.x, slv), skillId, si.getDuration(slv))); return; - case FIRE_CHARGE: - case ICE_CHARGE: - case DIVINE_CHARGE: + case SkillId.WK_FIRE_CHARGE, SkillId.WK_ICE_CHARGE, SkillId.PALADIN_DIVINE_CHARGE: user.setTemporaryStat(CharacterTemporaryStat.WeaponCharge, TemporaryStatOption.of(1, skillId, si.getDuration(slv))); return; - case LIGHTNING_CHARGE: + case SkillId.WK_LIGHTNING_CHARGE: user.setTemporaryStat(CharacterTemporaryStat.AssistCharge, TemporaryStatOption.of(1, skillId, si.getDuration(slv))); return; // DARK KNIGHT - case IRON_WILL: + case SkillId.SPEARNMAN_IRON_WILL: user.setTemporaryStat(Map.of( CharacterTemporaryStat.PDD, TemporaryStatOption.of(si.getValue(SkillStat.pdd, slv), skillId, si.getDuration(slv)), CharacterTemporaryStat.MDD, TemporaryStatOption.of(si.getValue(SkillStat.mdd, slv), skillId, si.getDuration(slv)) )); return; - case HYPER_BODY: + case SkillId.SPEARNMAN_HYPER_BODY: user.setTemporaryStat(Map.of( CharacterTemporaryStat.MaxHP, TemporaryStatOption.of(si.getValue(SkillStat.x, slv), skillId, si.getDuration(slv)), CharacterTemporaryStat.MaxMP, TemporaryStatOption.of(si.getValue(SkillStat.x, slv), skillId, si.getDuration(slv)) )); return; - case DRAGON_BLOOD: + case SkillId.DK_DRAGON_BLOOD: user.setTemporaryStat(Map.of( CharacterTemporaryStat.DragonBlood, TemporaryStatOption.of(si.getValue(SkillStat.x, slv), skillId, si.getDuration(slv)), CharacterTemporaryStat.PAD, TemporaryStatOption.of(si.getValue(SkillStat.pad, slv), skillId, si.getDuration(slv)) )); user.setSchedule(skillId, Instant.now().plus(1, ChronoUnit.SECONDS)); // -x HP every sec return; - case AURA_OF_THE_BEHOLDER: + case SkillId.DRK_AURA_OF_THE_BEHOLDER: final int healAmount = si.getValue(SkillStat.hp, slv); user.addHp(healAmount); user.write(UserLocal.effect(Effect.incDecHpEffect(healAmount))); field.broadcastPacket(UserRemote.effect(user, Effect.incDecHpEffect(healAmount)), user); handleBeholderEffect(user); return; - case HEX_OF_THE_BEHOLDER: + case SkillId.DRK_HEX_OF_THE_BEHOLDER: switch (skill.summonBuffType) { case 0 -> { user.setTemporaryStat(CharacterTemporaryStat.EPDD, TemporaryStatOption.of(si.getValue(SkillStat.epdd, slv), skillId, si.getDuration(slv))); // BUFF_PDD @@ -260,7 +253,7 @@ public static void handleSkill(User user, Skill skill) { } handleBeholderEffect(user); return; - case BEHOLDER: + case SkillId.DRK_BEHOLDER: final int beholderDuration = si.getValue(SkillStat.x, slv) * 60 * 1000; // x min final Summoned beholder = Summoned.from(skillId, slv, SummonedMoveAbility.WALK, SummonedAssistType.HEAL, Instant.now().plus(beholderDuration, ChronoUnit.MILLIS)); beholder.setPosition(user.getField(), skill.positionX, skill.positionY, skill.summonLeft); @@ -279,7 +272,7 @@ public static void resetComboCounter(User user) { } public static void handleBerserkEffect(User user) { - final int skillId = Warrior.BERSERK; + final SkillId skillId = SkillId.DRK_BERSERK; final int slv = user.getSkillLevel(skillId); if (slv == 0) { return; @@ -290,7 +283,7 @@ public static void handleBerserkEffect(User user) { } public static boolean isBerserkEffect(User user) { - final int skillId = Warrior.BERSERK; + final SkillId skillId = SkillId.DRK_BERSERK; final int slv = user.getSkillLevel(skillId); if (slv == 0) { return false; @@ -306,7 +299,7 @@ public static boolean isBerserkEffect(User user) { } public static void handleBeholderEffect(User user) { - final int skillId = Warrior.BEHOLDER; + final SkillId skillId = SkillId.DRK_BEHOLDER; final Effect beholderEffect = Effect.skillAffected(skillId, user.getSkillLevel(skillId)); user.write(UserLocal.effect(beholderEffect)); user.getField().broadcastPacket(UserRemote.effect(user, beholderEffect), user); diff --git a/src/main/java/kinoko/world/job/legend/Aran.java b/src/main/java/kinoko/world/job/legend/Aran.java index 2843618e..9f20b832 100644 --- a/src/main/java/kinoko/world/job/legend/Aran.java +++ b/src/main/java/kinoko/world/job/legend/Aran.java @@ -1,5 +1,6 @@ package kinoko.world.job.legend; +import kinoko.meta.SkillId; import kinoko.provider.SkillProvider; import kinoko.provider.skill.SkillInfo; import kinoko.provider.skill.SkillStat; @@ -66,11 +67,11 @@ public final class Aran extends SkillProcessor { public static void handleAttack(User user, Mob mob, Attack attack, int delay) { final SkillInfo si = SkillProvider.getSkillInfoById(attack.skillId).orElseThrow(); - final int skillId = attack.skillId; + final SkillId skillId = attack.skillId; final int slv = attack.slv; final Field field = user.getField(); - switch (skillId) { + switch (skillId.getId()) { case BODY_PRESSURE: if (!mob.isBoss() && Util.succeedProp(si.getValue(SkillStat.prop, slv))) { mob.setTemporaryStat(Map.of( @@ -94,11 +95,11 @@ public static void handleAttack(User user, Mob mob, Attack attack, int delay) { public static void handleSkill(User user, Skill skill) { final SkillInfo si = SkillProvider.getSkillInfoById(skill.skillId).orElseThrow(); - final int skillId = skill.skillId; + final SkillId skillId = skill.skillId; final int slv = skill.slv; final Field field = user.getField(); - switch (skillId) { + switch (skillId.getId()) { case COMBO_DRAIN: user.setTemporaryStat(CharacterTemporaryStat.ComboDrain, TemporaryStatOption.of(si.getValue(SkillStat.x, slv), skillId, si.getDuration(slv))); return; diff --git a/src/main/java/kinoko/world/job/legend/Evan.java b/src/main/java/kinoko/world/job/legend/Evan.java index 7211ed9d..0d8fae87 100644 --- a/src/main/java/kinoko/world/job/legend/Evan.java +++ b/src/main/java/kinoko/world/job/legend/Evan.java @@ -1,5 +1,6 @@ package kinoko.world.job.legend; +import kinoko.meta.SkillId; import kinoko.packet.user.UserLocal; import kinoko.packet.user.UserRemote; import kinoko.provider.SkillProvider; @@ -81,11 +82,11 @@ public final class Evan extends SkillProcessor { public static void handleAttack(User user, Mob mob, Attack attack, int delay) { final SkillInfo si = SkillProvider.getSkillInfoById(attack.skillId).orElseThrow(); - final int skillId = attack.skillId; + final SkillId skillId = attack.skillId; final int slv = attack.slv; final Field field = user.getField(); - switch (skillId) { + switch (skillId.getId()) { case ICE_BREATH: if (!mob.isBoss() && Util.succeedProp(si.getValue(SkillStat.prop, slv))) { mob.setTemporaryStat(MobTemporaryStat.Freeze, MobStatOption.of(1, skillId, si.getDuration(slv)), delay); @@ -101,7 +102,7 @@ public static void handleAttack(User user, Mob mob, Attack attack, int delay) { if (user.getSecondaryStat().hasOption(CharacterTemporaryStat.GuidedBullet)) { user.resetTemporaryStat(Set.of(CharacterTemporaryStat.GuidedBullet)); } - user.setTemporaryStat(CharacterTemporaryStat.GuidedBullet, TemporaryStatOption.ofTwoState(CharacterTemporaryStat.GuidedBullet, 1, skillId, mob.getId())); + user.setTemporaryStat(CharacterTemporaryStat.GuidedBullet, TemporaryStatOption.ofTwoState(CharacterTemporaryStat.GuidedBullet, 1, skillId.getId(), mob.getId())); break; case PHANTOM_IMPRINT: mob.setTemporaryStat(MobTemporaryStat.Weakness, MobStatOption.of(si.getValue(SkillStat.x, slv), skillId, si.getDuration(slv)), delay); @@ -111,11 +112,11 @@ public static void handleAttack(User user, Mob mob, Attack attack, int delay) { public static void handleSkill(User user, Skill skill) { final SkillInfo si = SkillProvider.getSkillInfoById(skill.skillId).orElseThrow(); - final int skillId = skill.skillId; + final SkillId skillId = skill.skillId; final int slv = skill.slv; final Field field = user.getField(); - switch (skill.skillId) { + switch (skill.skillId.getId()) { case MAGIC_SHIELD: user.setTemporaryStat(CharacterTemporaryStat.MagicShield, TemporaryStatOption.of(si.getValue(SkillStat.x, slv), skillId, si.getDuration(slv))); return; @@ -145,7 +146,7 @@ public static void handleSkill(User user, Skill skill) { } public static void handleDragonFuryEffect(User user) { - final int skillId = Evan.DRAGON_FURY; + final SkillId skillId = SkillId.EVAN8_DRAGON_FURY; final int slv = user.getSkillLevel(skillId); if (slv == 0) { return; @@ -156,7 +157,7 @@ public static void handleDragonFuryEffect(User user) { } public static boolean isDragonFury(User user) { - final int skillId = Evan.DRAGON_FURY; + final SkillId skillId = SkillId.EVAN8_DRAGON_FURY; final int slv = user.getSkillLevel(skillId); if (slv == 0) { return false; diff --git a/src/main/java/kinoko/world/job/resistance/BattleMage.java b/src/main/java/kinoko/world/job/resistance/BattleMage.java index cd912c5a..de551041 100644 --- a/src/main/java/kinoko/world/job/resistance/BattleMage.java +++ b/src/main/java/kinoko/world/job/resistance/BattleMage.java @@ -1,5 +1,6 @@ package kinoko.world.job.resistance; +import kinoko.meta.SkillId; import kinoko.provider.SkillProvider; import kinoko.provider.skill.SkillInfo; import kinoko.provider.skill.SkillStat; @@ -68,7 +69,7 @@ public final class BattleMage extends SkillProcessor { public static void handleAttack(User user, Mob mob, Attack attack, int delay) { final SkillInfo si = SkillProvider.getSkillInfoById(attack.skillId).orElseThrow(); - final int skillId = attack.skillId; + final SkillId skillId = attack.skillId; final int slv = attack.slv; final Field field = user.getField(); @@ -89,11 +90,11 @@ public static void handleAttack(User user, Mob mob, Attack attack, int delay) { public static void handleSkill(User user, Skill skill) { final SkillInfo si = SkillProvider.getSkillInfoById(skill.skillId).orElseThrow(); - final int skillId = skill.skillId; + final SkillId skillId = skill.skillId; final int slv = skill.slv; final Field field = user.getField(); - switch (skillId) { + switch (skillId.getId()) { case DARK_AURA: case YELLOW_AURA: case BLUE_AURA: @@ -147,11 +148,11 @@ public static void handleSkill(User user, Skill skill) { log.error("Unhandled skill {}", skill.skillId); } - public static int getAdvancedAuraSkill(User user, int skillId) { - final int advancedAuraSkill = switch (skillId) { - case DARK_AURA -> ADVANCED_DARK_AURA; - case BLUE_AURA -> ADVANCED_BLUE_AURA; - case YELLOW_AURA -> ADVANCED_YELLOW_AURA; + public static SkillId getAdvancedAuraSkill(User user, SkillId skillId) { + final SkillId advancedAuraSkill = switch (skillId) { + case SkillId.DARK_AURA -> SkillId.ADVANCED_DARK_AURA; + case SkillId.BLUE_AURA -> SkillId.ADVANCED_BLUE_AURA; + case SkillId.YELLOW_AURA -> SkillId.ADVANCED_YELLOW_AURA; default -> skillId; }; if (user.getSkillLevel(advancedAuraSkill) > 0) { @@ -160,7 +161,7 @@ public static int getAdvancedAuraSkill(User user, int skillId) { return skillId; } - public static void cancelPartyAura(User user, int skillId) { + public static void cancelPartyAura(User user, SkillId skillId) { final CharacterTemporaryStat cts = SkillConstants.getStatByAuraSkill(skillId); if (cts == null) { log.error("Could not resolve CTS while trying to cancel aura skill ID : {}", skillId); diff --git a/src/main/java/kinoko/world/job/resistance/Citizen.java b/src/main/java/kinoko/world/job/resistance/Citizen.java index 2635198a..bd23559e 100644 --- a/src/main/java/kinoko/world/job/resistance/Citizen.java +++ b/src/main/java/kinoko/world/job/resistance/Citizen.java @@ -1,6 +1,7 @@ package kinoko.world.job.resistance; +import kinoko.meta.SkillId; import kinoko.packet.field.MobPacket; import kinoko.packet.user.UserLocal; import kinoko.packet.world.WvsContext; @@ -48,11 +49,11 @@ public final class Citizen extends SkillProcessor { public static void handleSkill(User user, Skill skill) { final SkillInfo si = SkillProvider.getSkillInfoById(skill.skillId).orElseThrow(); - final int skillId = skill.skillId; + final SkillId skillId = skill.skillId; final int slv = skill.slv; final Field field = user.getField(); - switch (skillId) { + switch (skillId.getId()) { case Citizen.INFILTRATE: user.setTemporaryStat(Map.of( CharacterTemporaryStat.Speed, TemporaryStatOption.of(si.getValue(SkillStat.speed, slv), skillId, si.getDuration(slv)), diff --git a/src/main/java/kinoko/world/job/resistance/Mechanic.java b/src/main/java/kinoko/world/job/resistance/Mechanic.java index b0ff33d0..11b59450 100644 --- a/src/main/java/kinoko/world/job/resistance/Mechanic.java +++ b/src/main/java/kinoko/world/job/resistance/Mechanic.java @@ -1,5 +1,6 @@ package kinoko.world.job.resistance; +import kinoko.meta.SkillId; import kinoko.packet.field.FieldPacket; import kinoko.packet.user.UserLocal; import kinoko.packet.user.UserPacket; @@ -78,11 +79,11 @@ public final class Mechanic extends SkillProcessor { public static void handleAttack(User user, Mob mob, Attack attack, int delay) { final SkillInfo si = SkillProvider.getSkillInfoById(attack.skillId).orElseThrow(); - final int skillId = attack.skillId; + final SkillId skillId = attack.skillId; final int slv = attack.slv; final Field field = user.getField(); - switch (skillId) { + switch (skillId.getId()) { case ATOMIC_HAMMER: if (!mob.isBoss() && Util.succeedProp(si.getValue(SkillStat.prop, slv))) { mob.setTemporaryStat(MobTemporaryStat.Stun, MobStatOption.of(1, skillId, si.getDuration(slv)), delay); @@ -98,19 +99,19 @@ public static void handleAttack(User user, Mob mob, Attack attack, int delay) { public static void handleSkill(User user, Skill skill) { final SkillInfo si = SkillProvider.getSkillInfoById(skill.skillId).orElseThrow(); - final int skillId = skill.skillId; + final SkillId skillId = skill.skillId; final int slv = skill.slv; final int summonDuration = getSummonDuration(user, si.getDuration(slv)); final Field field = user.getField(); - switch (skillId) { + switch (skillId.getId()) { // MECH case MECH_PROTOTYPE: handleMech(user, skillId); return; case MECH_SIEGE_MODE: - final int mechanicMode = user.getSecondaryStat().getOption(CharacterTemporaryStat.Mechanic).rOption; - handleMech(user, mechanicMode == MECH_MISSILE_TANK ? MECH_SIEGE_MODE_2 : MECH_SIEGE_MODE); + final SkillId mechanicMode = user.getSecondaryStat().getOption(CharacterTemporaryStat.Mechanic).getSkillId(); + handleMech(user, mechanicMode == SkillId.MECH4_MECH_MISSILE_TANK ? SkillId.MECH4_MECH_SIEGE_MODE : SkillId.MECH3_MECH_SIEGE_MODE); return; case MECH_MISSILE_TANK: handleMech(user, skillId); @@ -120,7 +121,7 @@ public static void handleSkill(User user, Skill skill) { // BUFFS case PERFECT_ARMOR: if (user.getSecondaryStat().hasOption(CharacterTemporaryStat.ManaReflection)) { - user.resetTemporaryStat(skillId); + user.resetTemporaryStat(skillId.getId()); } else { user.setTemporaryStat(CharacterTemporaryStat.ManaReflection, TemporaryStatOption.of(slv, skillId, 0)); } @@ -131,7 +132,7 @@ public static void handleSkill(User user, Skill skill) { field.broadcastPacket(UserRemote.effect(user, Effect.skillAffectedSelect(roll, skillId, slv)), user); if (roll != 1) { final DiceInfo diceInfo = DiceInfo.from(roll, si, slv); - user.setTemporaryStat(CharacterTemporaryStat.Dice, TemporaryStatOption.ofDice(roll, skillId, si.getDuration(slv), diceInfo)); + user.setTemporaryStat(CharacterTemporaryStat.Dice, TemporaryStatOption.ofDice(roll, skillId.getId(), si.getDuration(slv), diceInfo)); } return; case SATELLITE_SAFETY: @@ -233,7 +234,7 @@ public static void handleSkill(User user, Skill skill) { case BOTS_N_TOTS: if (skill.isSummonedSkill()) { // Create sub-summon - final Summoned botsAndTotsSummon = Summoned.from(BOTS_N_TOTS_SUMMON, slv, SummonedMoveAbility.WALK_RANDOM, SummonedAssistType.ATTACK, Instant.now().plus(getSummonDuration(user, 5000), ChronoUnit.MILLIS)); // 5 second base duration + final Summoned botsAndTotsSummon = Summoned.from(SkillId.MECH4_BOTS_N_TOTS, slv, SummonedMoveAbility.WALK_RANDOM, SummonedAssistType.ATTACK, Instant.now().plus(getSummonDuration(user, 5000), ChronoUnit.MILLIS)); // 5 second base duration botsAndTotsSummon.setPosition(field, skill.summoned.getX(), skill.summoned.getY(), skill.summoned.isLeft()); user.addSummoned(botsAndTotsSummon); } else { @@ -257,8 +258,8 @@ public static void handleSkill(User user, Skill skill) { log.error("Unhandled skill {}", skill.skillId); } - public static void handleMech(User user, int skillId) { - final int statSkillId = user.getSkillLevel(EXTREME_MECH) > 0 ? EXTREME_MECH : MECH_PROTOTYPE; + public static void handleMech(User user, SkillId skillId) { + final SkillId statSkillId = user.getSkillLevel(SkillId.MECH4_EXTREME_MECH) > 0 ? SkillId.MECH4_EXTREME_MECH : SkillId.MECH1_MECH_PROTOTYPE; final int slv = user.getSkillLevel(statSkillId); final Optional skillInfoResult = SkillProvider.getSkillInfoById(statSkillId); if (skillInfoResult.isEmpty()) { @@ -267,7 +268,7 @@ public static void handleMech(User user, int skillId) { } final SkillInfo si = skillInfoResult.get(); user.setTemporaryStat(Map.of( - CharacterTemporaryStat.RideVehicle, TemporaryStatOption.ofTwoState(CharacterTemporaryStat.RideVehicle, SkillConstants.MECHANIC_VEHICLE, skillId, 0), + CharacterTemporaryStat.RideVehicle, TemporaryStatOption.ofTwoState(CharacterTemporaryStat.RideVehicle, SkillConstants.MECHANIC_VEHICLE, skillId.getId(), 0), CharacterTemporaryStat.Mechanic, TemporaryStatOption.of(slv, skillId, 0), CharacterTemporaryStat.EMHP, TemporaryStatOption.of(si.getValue(SkillStat.emhp, slv), skillId, 0), CharacterTemporaryStat.EMMP, TemporaryStatOption.of(si.getValue(SkillStat.emmp, slv), skillId, 0), @@ -288,8 +289,8 @@ public static void handleRemoveAccelerationBot(Summoned summoned) { private static int getSummonDuration(User user, int duration) { // Increased duration from Robot Mastery + tick interval for self-destruct - if (user.getSkillLevel(ROBOT_MASTERY) > 0) { - return duration + (user.getSkillStatValue(ROBOT_MASTERY, SkillStat.y) * 1000) + ServerConfig.FIELD_TICK_INTERVAL; + if (user.getSkillLevel(SkillId.MECH4_ROBOT_MASTERY) > 0) { + return duration + (user.getSkillStatValue(SkillId.MECH4_ROBOT_MASTERY, SkillStat.y) * 1000) + ServerConfig.FIELD_TICK_INTERVAL; } return duration + ServerConfig.FIELD_TICK_INTERVAL; } diff --git a/src/main/java/kinoko/world/job/resistance/WildHunter.java b/src/main/java/kinoko/world/job/resistance/WildHunter.java index a220f07f..515a9a8a 100644 --- a/src/main/java/kinoko/world/job/resistance/WildHunter.java +++ b/src/main/java/kinoko/world/job/resistance/WildHunter.java @@ -1,5 +1,6 @@ package kinoko.world.job.resistance; +import kinoko.meta.SkillId; import kinoko.provider.SkillProvider; import kinoko.provider.skill.SkillInfo; import kinoko.provider.skill.SkillStat; @@ -66,11 +67,11 @@ public final class WildHunter extends SkillProcessor { public static void handleAttack(User user, Mob mob, Attack attack, int delay) { final SkillInfo si = SkillProvider.getSkillInfoById(attack.skillId).orElseThrow(); - final int skillId = attack.skillId; + final SkillId skillId = attack.skillId; final int slv = attack.slv; final Field field = user.getField(); - switch (skillId) { + switch (skillId.getId()) { case RICOCHET: case DASH_N_SLASH: case SILVER_HAWK: @@ -98,13 +99,13 @@ public static void handleAttack(User user, Mob mob, Attack attack, int delay) { public static void handleSkill(User user, Skill skill) { final SkillInfo si = SkillProvider.getSkillInfoById(skill.skillId).orElseThrow(); - final int skillId = skill.skillId; + final SkillId skillId = skill.skillId; final int slv = skill.slv; final Field field = user.getField(); - switch (skillId) { + switch (skillId.getId()) { case JAGUAR_RIDER: - user.setTemporaryStat(CharacterTemporaryStat.RideVehicle, TemporaryStatOption.ofTwoState(CharacterTemporaryStat.RideVehicle, user.getWildHunterInfo().getRidingItem(), skillId, 0)); + user.setTemporaryStat(CharacterTemporaryStat.RideVehicle, TemporaryStatOption.ofTwoState(CharacterTemporaryStat.RideVehicle, user.getWildHunterInfo().getRidingItem(), skillId.getId(), 0)); return; case ITS_RAINING_MINES: user.setTemporaryStat(CharacterTemporaryStat.Mine, TemporaryStatOption.of(1, skillId, si.getDuration(slv))); diff --git a/src/main/java/kinoko/world/skill/Attack.java b/src/main/java/kinoko/world/skill/Attack.java index c050ce0c..3bfae06c 100644 --- a/src/main/java/kinoko/world/skill/Attack.java +++ b/src/main/java/kinoko/world/skill/Attack.java @@ -1,5 +1,6 @@ package kinoko.world.skill; +import kinoko.meta.SkillId; import kinoko.server.header.OutHeader; import kinoko.world.job.resistance.BattleMage; @@ -13,7 +14,7 @@ public final class Attack { public byte mask; public byte flag; - public int skillId; + public SkillId skillId; public int slv; public byte combatOrders; public int keyDown; @@ -102,8 +103,8 @@ public boolean isShootAttack() { } public boolean isMagicAttack() { - switch (skillId) { - case BattleMage.TRIPLE_BLOW: + /* + case BattleMage.TRIPLE_BLOW: case BattleMage.QUAD_BLOW: case BattleMage.QUINTUPLE_BLOW: case BattleMage.FINISHING_BLOW: @@ -112,9 +113,14 @@ public boolean isMagicAttack() { case BattleMage.THE_FINISHER_QUAD_BLOW: case BattleMage.THE_FINISHER_QUINTUPLE_BLOW: case BattleMage.THE_FINISHER_FINISHING_BLOW: - return true; - } - return getHeaderType() == OutHeader.UserMagicAttack; + */ + + //TODO + return switch (skillId) { + case SkillId.TRIPLE_BLOW, SkillId.QUAD_BLOW, SkillId.QUINTUPLE_BLOW, SkillId.FINISHING_BLOW, + SkillId.THE_FINISHER -> true; + default -> getHeaderType() == OutHeader.UserMagicAttack; + }; } @Override diff --git a/src/main/java/kinoko/world/skill/PassiveSkillData.java b/src/main/java/kinoko/world/skill/PassiveSkillData.java index 40aecc91..cb478935 100644 --- a/src/main/java/kinoko/world/skill/PassiveSkillData.java +++ b/src/main/java/kinoko/world/skill/PassiveSkillData.java @@ -1,5 +1,6 @@ package kinoko.world.skill; +import kinoko.meta.SkillId; import kinoko.provider.SkillProvider; import kinoko.provider.skill.SkillInfo; import kinoko.provider.skill.SkillStat; @@ -176,9 +177,9 @@ public void setFrom(BasicStat bs, SecondaryStat ss, SkillManager sm) { continue; } final SkillInfo si = skillInfoResult.get(); - if (si.isPsd() && (si.getSkillId() != Mechanic.PERFECT_ARMOR || ss.getRidingVehicle() == SkillConstants.MECHANIC_VEHICLE)) { - if (si.getSkillId() == Mechanic.MECH_SIEGE_MODE_2) { - addPassiveSkillData(si, SkillManager.getSkillLevel(ss, sm, Mechanic.MECH_SIEGE_MODE)); + if (si.isPsd() && (si.getSkillId() != SkillId.MECH2_PERFECT_ARMOR || ss.getRidingVehicle() == SkillConstants.MECHANIC_VEHICLE)) { + if (si.getSkillId() == SkillId.MECH4_MECH_SIEGE_MODE) { + addPassiveSkillData(si, SkillManager.getSkillLevel(ss, sm, SkillId.MECH3_MECH_SIEGE_MODE)); } else if (skillRecord.getSkillLevel() > 0) { addPassiveSkillData(si, skillRecord.getSkillLevel()); } @@ -187,9 +188,9 @@ public void setFrom(BasicStat bs, SecondaryStat ss, SkillManager sm) { // Special handling for Mech: Siege Mode if (JobConstants.isMechanicJob(bs.getJob())) { - if (SkillManager.getSkillLevel(ss, sm, Mechanic.MECH_SIEGE_MODE) > 0) { - final Optional skillInfoResult = SkillProvider.getSkillInfoById(Mechanic.MECH_SIEGE_MODE_2); - skillInfoResult.ifPresent(skillInfo -> addPassiveSkillData(skillInfo, SkillManager.getSkillLevel(ss, sm, Mechanic.MECH_SIEGE_MODE))); + if (SkillManager.getSkillLevel(ss, sm, SkillId.MECH3_MECH_SIEGE_MODE) > 0) { + final Optional skillInfoResult = SkillProvider.getSkillInfoById(SkillId.MECH4_MECH_SIEGE_MODE); + skillInfoResult.ifPresent(skillInfo -> addPassiveSkillData(skillInfo, SkillManager.getSkillLevel(ss, sm, SkillId.MECH3_MECH_SIEGE_MODE))); } } diff --git a/src/main/java/kinoko/world/skill/Skill.java b/src/main/java/kinoko/world/skill/Skill.java index d9112866..a956c6e3 100644 --- a/src/main/java/kinoko/world/skill/Skill.java +++ b/src/main/java/kinoko/world/skill/Skill.java @@ -1,5 +1,6 @@ package kinoko.world.skill; +import kinoko.meta.SkillId; import kinoko.world.field.Field; import kinoko.world.field.mob.Mob; import kinoko.world.field.summoned.Summoned; @@ -10,7 +11,7 @@ import java.util.function.Consumer; public final class Skill { - public int skillId; + public SkillId skillId; public int slv; public int positionX; diff --git a/src/main/java/kinoko/world/skill/SkillConstants.java b/src/main/java/kinoko/world/skill/SkillConstants.java index 781b4295..e0bfdea9 100644 --- a/src/main/java/kinoko/world/skill/SkillConstants.java +++ b/src/main/java/kinoko/world/skill/SkillConstants.java @@ -1,37 +1,22 @@ package kinoko.world.skill; +import kinoko.meta.SkillId; +import kinoko.meta.SkillTargetFlags; import kinoko.provider.skill.ElementAttribute; import kinoko.util.Rect; import kinoko.world.job.Job; import kinoko.world.job.JobConstants; -import kinoko.world.job.cygnus.*; -import kinoko.world.job.explorer.*; import kinoko.world.job.legend.Aran; -import kinoko.world.job.legend.Evan; -import kinoko.world.job.resistance.BattleMage; -import kinoko.world.job.resistance.Citizen; -import kinoko.world.job.resistance.Mechanic; -import kinoko.world.job.resistance.WildHunter; import kinoko.world.user.stat.CharacterTemporaryStat; import java.util.List; +import java.util.Optional; public final class SkillConstants { - public static final List SECONDARY_STAT_SKILLS = List.of( - Thief.NIMBLE_BODY, - NightWalker.NIMBLE_BODY, - Pirate.BULLET_TIME, // PirateQuickMotion - ThunderBreaker.QUICK_MOTION, // StrikerQuickMotion - Evan.DRAGON_SOUL, - Beginner.BLESSING_OF_THE_FAIRY, - Noblesse.BLESSING_OF_THE_FAIRY, - Citizen.BLESSING_OF_THE_FAIRY, - Aran.BLESSING_OF_THE_FAIRY, - Evan.BLESSING_OF_THE_FAIRY - ); - public static final List WILD_HUNTER_JAGUARS = List.of( - 1932015, 1932030, 1932031, 1932032, 1932033, 1932036 - ); + public static final List SECONDARY_STAT_SKILLS = List.of(SkillId.NW1_NIMBLE_BODY, SkillId.NW1_NIMBLE_BODY, SkillId.PIRATE_BULLET_TIME, // PirateQuickMotion + SkillId.TB1_QUICK_MOTION, // StrikerQuickMotion + SkillId.EVAN1_DRAGON_SOUL, SkillId.BEGINNER_BLESSING_OF_THE_FAIRY, SkillId.NOBLESSE_BLESSING_OF_THE_FAIRY, SkillId.CITIZEN_BLESSING_OF_THE_FAIRY, SkillId.EVANBEGINNER_BLESSING_OF_THE_FAIRY, SkillId.LEGEND_BLESSING_OF_THE_FAIRY); + public static final List WILD_HUNTER_JAGUARS = List.of(1932015, 1932030, 1932031, 1932032, 1932033, 1932036); public static final int MECHANIC_VEHICLE = 1932016; public static final int BATTLESHIP_VEHICLE = 1932000; public static final int BATTLESHIP_DURABILITY = 5221999; @@ -39,300 +24,208 @@ public final class SkillConstants { public static final Rect DARK_FLARE_RANGE = Rect.of(-400, -200, 400, 200); public static final Rect MONSTER_BOMB_RANGE = Rect.of(-220, -150, 220, 0); - public static int getSkillRoot(int skillId) { - return skillId / 10000; - } - public static int getNoviceSkillAsRace(int skillId, int jobId) { - if (skillId == Beginner.FOLLOW_THE_LEAD) { + public static SkillId getNoviceSkillAsRace(SkillId skillId, int jobId) { + if (skillId == SkillId.BEGINNER_FOLLOW_THE_LEAD) { return switch (JobConstants.getNoviceSkillRootFromJob(jobId)) { - case 1000 -> Noblesse.FOLLOW_THE_LEAD; - case 2000 -> Aran.FOLLOW_THE_LEAD; - case 2001 -> Evan.FOLLOW_THE_LEAD; - case 3000 -> Citizen.FOLLOW_THE_LEAD; - default -> Beginner.FOLLOW_THE_LEAD; + case 1000 -> SkillId.NOBLESSE_FOLLOW_THE_LEAD; + case 2000 -> SkillId.LEGEND_FOLLOW_THE_LEAD; + case 2001 -> SkillId.EVANBEGINNER_FOLLOW_THE_LEAD; + case 3000 -> SkillId.CITIZEN_FOLLOW_THE_LEAD; + default -> SkillId.BEGINNER_FOLLOW_THE_LEAD; }; } if (JobConstants.isEvanJob(jobId)) { - return skillId + 20010000; + //return skillId + 20010000; + return SkillId.NONE;// TODO } else { - return skillId + 10000000 * (jobId / 1000); + //return skillId + 10000000 * (jobId / 1000); + return SkillId.NONE;//TODO } } - public static int getItemBonusRateSkill(int jobId) { + public static SkillId getItemBonusRateSkill(int jobId) { if (JobConstants.isNightLordJob(jobId)) { - return Thief.ALCHEMIST; + return SkillId.HERMIT_ALCHEMIST; } else if (JobConstants.isNightWalkerJob(jobId)) { - return NightWalker.ALCHEMIST; + return SkillId.NW3_ALCHEMIST; } else if (JobConstants.isResistanceJob(jobId)) { - return Citizen.POTION_MASTERY; + return SkillId.CITIZEN_POTION_MASTERY; } - return 0; + return SkillId.NONE; } - public static int getEnhancedBasicsSkill(int jobId) { + public static SkillId getEnhancedBasicsSkill(int jobId) { if (JobConstants.isHeroJob(jobId)) { - return Warrior.ENHANCED_BASICS_HERO; + return SkillId.FIGHTER_ENHANCED_BASICS; } else if (JobConstants.isPaladinJob(jobId)) { - return Warrior.ENHANCED_BASICS_PALADIN; + return SkillId.PAGE_ENHANCED_BASICS; } else if (JobConstants.isDarkKnightJob(jobId)) { - return Warrior.ENHANCED_BASICS_DRK; + return SkillId.SPEARNMAN_ENHANCED_BASICS; } else if (JobConstants.isBowmasterJob(jobId)) { - return Bowman.ENHANCED_BASICS_BM; + return SkillId.HUNTER_ENHANCED_BASICS; } else if (JobConstants.isMarksmanJob(jobId)) { - return Bowman.ENHANCED_BASICS_MM; + return SkillId.CROSSBOWMAN_ENHANCED_BASICS; } else { - return 0; + return SkillId.NONE; } } - public static int getComboAttackSkill(int jobId) { - return JobConstants.isCygnusJob(jobId) ? DawnWarrior.COMBO_ATTACK : Warrior.COMBO_ATTACK; + public static SkillId getComboAttackSkill(int jobId) { + return JobConstants.isCygnusJob(jobId) ? SkillId.DW3_COMBO_ATTACK : SkillId.CRUSADER_COMBO_ATTACK; } - public static int getAdvancedComboSkill(int jobId) { - return JobConstants.isCygnusJob(jobId) ? DawnWarrior.ADVANCED_COMBO : Warrior.ADVANCED_COMBO_ATTACK; + public static SkillId getAdvancedComboSkill(int jobId) { + return JobConstants.isCygnusJob(jobId) ? SkillId.HERO_ADVANCED_COMBO_ATTACK : SkillId.DW3_ADVANCED_COMBO; } - public static int getMpEaterSkill(int jobId) { + public static SkillId getMpEaterSkill(int jobId) { if (JobConstants.isFirePoisonJob(jobId)) { - return Magician.MP_EATER_FP; + return SkillId.FP1_MP_EATER; } else if (JobConstants.isIceLightningJob(jobId)) { - return Magician.MP_EATER_IL; + return SkillId.IL1_MP_EATER; } else if (JobConstants.isBishopJob(jobId)) { - return Magician.MP_EATER_BISH; + return SkillId.CLERIC_MP_EATER; } else { - return 0; + return SkillId.NONE; } } - public static int getBuffMasterySkill(int jobId) { + public static SkillId getBuffMasterySkill(int jobId) { if (JobConstants.isFirePoisonJob(jobId)) { - return Magician.BUFF_MASTERY_FP; + return SkillId.FP3_BUFF_MASTERY; } else if (JobConstants.isIceLightningJob(jobId)) { - return Magician.BUFF_MASTERY_IL; + return SkillId.IL3_BUFF_MASTERY; } else if (JobConstants.isBishopJob(jobId)) { - return Magician.BUFF_MASTERY_BISH; + return SkillId.BISHOP_BUFF_MASTERY; } else { - return 0; + return SkillId.NONE; } } - public static int getAmplificationSkill(int jobId) { + public static SkillId getAmplificationSkill(int jobId) { if (JobConstants.isFirePoisonJob(jobId)) { - return Magician.ELEMENT_AMPLIFICATION_FP; + return SkillId.FP2_ELEMENT_AMPLIFICATION; } else if (JobConstants.isIceLightningJob(jobId)) { - return Magician.ELEMENT_AMPLIFICATION_IL; + return SkillId.IL2_ELEMENT_AMPLIFICATION; } else if (JobConstants.isBlazeWizardJob(jobId)) { - return BlazeWizard.ELEMENT_AMPLIFICATION; + return SkillId.BW3_ELEMENT_AMPLIFICATION; } else if (JobConstants.isEvanJob(jobId)) { - return Evan.MAGIC_AMPLIFICATION; + return SkillId.EVAN7_MAGIC_AMPLIFICATION; } else { - return 0; + return SkillId.NONE; } } - public static int getMortalBlowSkill(int jobId) { + public static SkillId getMortalBlowSkill(int jobId) { if (JobConstants.isBowmasterJob(jobId)) { - return Bowman.MORTAL_BLOW_BM; + return SkillId.RANGER_MORTAL_BLOW; } else if (JobConstants.isMarksmanJob(jobId)) { - return Bowman.MORTAL_BLOW_MM; + return SkillId.SNIPER_MORTAL_BLOW; } else { - return 0; + return SkillId.NONE; } } - public static int getVenomSkill(int jobId) { + public static SkillId getVenomSkill(int jobId) { if (JobConstants.isNightLordJob(jobId)) { - return Thief.VENOMOUS_STAR; + return SkillId.NIGHTLORD_VENOMOUS_STAR; + } else if (JobConstants.isNightWalkerJob(jobId)) { + return SkillId.NW3_VENOM; } else if (JobConstants.isShadowerJob(jobId)) { - return Thief.VENOMOUS_STAB; + return SkillId.SHADOWER_VENOMOUS_STAB; } else if (JobConstants.isDualJob(jobId)) { - return Thief.VENOM_DB; + return SkillId.DB5_VENOM; } else { - return 0; + return SkillId.NONE; } } - public static int getEnergyChargeSkill(int jobId) { - return JobConstants.isCygnusJob(jobId) ? ThunderBreaker.ENERGY_CHARGE : Pirate.ENERGY_CHARGE; + public static SkillId getEnergyChargeSkill(int jobId) { + return JobConstants.isCygnusJob(jobId) ? SkillId.TB2_ENERGY_CHARGE : SkillId.MARAUDER_ENERGY_CHARGE; } - public static int getPiratesRevengeSkill(int jobId) { + public static SkillId getPiratesRevengeSkill(int jobId) { if (JobConstants.isBuccaneerJob(jobId)) { - return Pirate.PIRATES_REVENGE_BUCC; + return SkillId.BUCCANEER_PIRATES_REVENGE; } else if (JobConstants.isCorsairJob(jobId)) { - return Pirate.PIRATES_REVENGE_SAIR; + return SkillId.CORSAIR_PIRATES_REVENGE; } else { - return 0; + return SkillId.NONE; } } - public static ElementAttribute getElementByWeaponChargeSkill(int skillId) { - switch (skillId) { - case Warrior.FIRE_CHARGE: - return ElementAttribute.FIRE; - case Warrior.ICE_CHARGE: - case Aran.SNOW_CHARGE: - return ElementAttribute.ICE; - case Warrior.LIGHTNING_CHARGE: - case ThunderBreaker.LIGHTNING_CHARGE: - return ElementAttribute.LIGHT; - case Warrior.DIVINE_CHARGE: - case DawnWarrior.SOUL_CHARGE: - return ElementAttribute.HOLY; - default: - return ElementAttribute.PHYSICAL; - } + public static ElementAttribute getElementByWeaponChargeSkill(SkillId skillId) { + return switch (skillId) { + case SkillId.WK_FIRE_CHARGE -> ElementAttribute.FIRE; + case SkillId.WK_ICE_CHARGE, SkillId.ARAN3_SNOW_CHARGE -> ElementAttribute.ICE; + case SkillId.WK_LIGHTNING_CHARGE, SkillId.TB2_LIGHTNING_CHARGE -> ElementAttribute.LIGHT; + case SkillId.PALADIN_DIVINE_CHARGE, SkillId.DW3_SOUL_CHARGE -> ElementAttribute.HOLY; + default -> ElementAttribute.PHYSICAL; + }; } - public static CharacterTemporaryStat getStatByAuraSkill(int skillId) { - switch (skillId) { - case BattleMage.DARK_AURA: - case BattleMage.ADVANCED_DARK_AURA: - return CharacterTemporaryStat.DarkAura; - case BattleMage.BLUE_AURA: - case BattleMage.ADVANCED_BLUE_AURA: - return CharacterTemporaryStat.BlueAura; - case BattleMage.YELLOW_AURA: - case BattleMage.ADVANCED_YELLOW_AURA: - return CharacterTemporaryStat.YellowAura; - default: - return null; - } + public static CharacterTemporaryStat getStatByAuraSkill(SkillId skillId) { + return switch (skillId) { + case SkillId.DARK_AURA, SkillId.ADVANCED_DARK_AURA -> CharacterTemporaryStat.DarkAura; + case SkillId.BLUE_AURA, SkillId.ADVANCED_BLUE_AURA -> CharacterTemporaryStat.BlueAura; + case SkillId.YELLOW_AURA, SkillId.ADVANCED_YELLOW_AURA -> CharacterTemporaryStat.YellowAura; + default -> null; + }; } - public static boolean isBeginnerSpAddableSkill(int skillId) { - final int skillRoot = getSkillRoot(skillId); + public static boolean isBeginnerSpAddableSkill(SkillId skillId) { + final int skillRoot = skillId.getRoot(); if (!JobConstants.isBeginnerJob(skillRoot)) { return false; } else if (skillRoot == Job.CITIZEN.getJobId()) { - return skillId == Citizen.POTION_MASTERY || skillId == Citizen.CRYSTAL_THROW || skillId == Citizen.INFILTRATE; + return skillId == SkillId.CITIZEN_POTION_MASTERY || skillId == SkillId.CITIZEN_CRYSTAL_THROW || skillId == SkillId.CITIZEN_INFILTRATE; } - final int skillType = skillId % 10000; + final int skillType = skillId.getType(); return skillType == 1000 || skillType == 1001 || skillType == 1002; } - public static boolean isTeleportSkill(int skillId) { - switch (skillId) { - case Magician.TELEPORT_FP: - case Magician.TELEPORT_IL: - case Magician.TELEPORT_BISH: - case BlazeWizard.TELEPORT: - case Evan.TELEPORT: - case BattleMage.TELEPORT: - return true; - default: - return false; - } + public static boolean isTeleportSkill(SkillId skillId) { + return switch (skillId) { + case SkillId.FP1_TELEPORT, SkillId.IL1_TELEPORT, SkillId.CLERIC_TELEPORT, SkillId.BW2_TELEPORT, + SkillId.EVAN2_TELEPORT, SkillId.TELEPORT -> true; + default -> false; + }; } - public static boolean isThrowBombSkill(int skillId) { - switch (skillId) { - case Thief.MONSTER_BOMB: - case Pirate.GRENADE: - case NightWalker.POISON_BOMB: - return true; - default: - return false; - } + public static boolean isThrowBombSkill(SkillId skillId) { + return switch (skillId) { + case SkillId.DB5_MONSTER_BOMB, SkillId.GUNSLINGER_GRENADE, SkillId.NW3_POISON_BOMB -> true; + default -> false; + }; } - public static boolean isNoConsumeAttack(int skillId) { + public static boolean isNoConsumeAttack(SkillId skillId) { if (SkillConstants.isThrowBombSkill(skillId)) { return true; } - switch (skillId) { - case Thief.TORNADO_SPIN_ATTACK: - case Thief.CHAINS_OF_HELL: - case BattleMage.TWISTER_SPIN: - case Mechanic.MECH_SIEGE_MODE: - case Mechanic.MECH_MISSILE_TANK: - case Mechanic.GIANT_ROBOT_SG_88: - case Mechanic.MECH_SIEGE_MODE_2: - return true; - default: - return false; - } + return switch (skillId) { + case SkillId.DB3_TORNADO_SPIN_ATTACK, SkillId.DB5_CHAINS_OF_HELL, SkillId.TWISTER_SPIN, + SkillId.MECH3_MECH_SIEGE_MODE, SkillId.MECH4_MECH_MISSILE_TANK, SkillId.MECH4_GIANT_ROBOT_SG88, + SkillId.MECH4_MECH_SIEGE_MODE -> true; + default -> false; + }; } - public static boolean isNoCooltimeSkill(int skillId) { + public static boolean isNoCooltimeSkill(SkillId skillId) { // Cooltime for these skills require special handling - switch (skillId) { - case Pirate.BATTLESHIP: - case Mechanic.ROCK_N_SHOCK: - case Mechanic.SATELLITE_SAFETY: - return true; - default: - return false; - } + return switch (skillId) { + case SkillId.CORSAIR_BATTLESHIP, SkillId.MECH3_ROCK_N_SHOCK, SkillId.MECH4_SATELLITE_SAFETY -> true; + default -> false; + }; } - public static boolean isPartySkill(int skillId) { - if (skillId == Magician.HEAL) { - // CUserLocal::DoActiveSkill_Heal - return true; - } - // Usages of CUserLocal::DoActiveSkill_StatChange with dwTargetFlag & 2 (SCT_Party) - switch (skillId) { - // CUserLocal::DoActiveSkill - case Warrior.RAGE: - case Warrior.COMBAT_ORDERS: - case Warrior.IRON_WILL: - case Warrior.HYPER_BODY: - case Magician.MEDITATION_FP: - case Magician.MEDITATION_IL: - case Magician.BLESS: - case Magician.DISPEL: - case Magician.HOLY_SYMBOL: - case Magician.HOLY_SHIELD: - case Magician.RESURRECTION: - case Bowman.SHARP_EYES_BM: - case Bowman.SHARP_EYES_MM: - case Thief.HASTE_NL: - case Thief.HASTE_SHAD: - case Thief.MESO_UP: - case Thief.THORNS: - case Pirate.SPEED_INFUSION: - case Pirate.TIME_LEAP: - case DawnWarrior.RAGE: - case BlazeWizard.MEDITATION: - case NightWalker.HASTE: - case ThunderBreaker.SPEED_INFUSION: - case Aran.COMBO_BARRIER: - case Evan.MAGIC_SHIELD: - case Evan.MAGIC_RESISTANCE: - case Evan.BLESSING_OF_THE_ONYX: - case Evan.SOUL_STONE: - case WildHunter.SHARP_EYES_WH: - case Warrior.MAPLE_WARRIOR_HERO: - case Warrior.MAPLE_WARRIOR_PALADIN: - case Warrior.MAPLE_WARRIOR_DRK: - case Magician.MAPLE_WARRIOR_FP: - case Magician.MAPLE_WARRIOR_IL: - case Magician.MAPLE_WARRIOR_BISH: - case Bowman.MAPLE_WARRIOR_BM: - case Bowman.MAPLE_WARRIOR_MM: - case Thief.MAPLE_WARRIOR_NL: - case Thief.MAPLE_WARRIOR_SHAD: - case Thief.MAPLE_WARRIOR_DB: - case Pirate.MAPLE_WARRIOR_BUCC: - case Pirate.MAPLE_WARRIOR_SAIR: - case Aran.MAPLE_WARRIOR_ARAN: - case Evan.MAPLE_WARRIOR_EVAN: - case BattleMage.MAPLE_WARRIOR_BAM: - case WildHunter.MAPLE_WARRIOR_WH: - case Mechanic.MAPLE_WARRIOR_MECH: - case WildHunter.JAGUAR_OSHI_DIGESTED: // CUserLocal::TryDoingSwallowBuff - return true; - default: - return false; - } + public static boolean isPartySkill(SkillId skillId) { + return skillId.hasTargetFlag(SkillTargetFlags.Party); } - public static boolean isEncodePositionSkill(int skillId) { + public static boolean isEncodePositionSkill(SkillId skillId) { if (isAntiRepeatBuffSkill(skillId)) { // CUserLocal::SendSkillUseRequest return true; @@ -341,82 +234,32 @@ public static boolean isEncodePositionSkill(int skillId) { // CUserLocal::DoActiveSkill_Summon return true; } - switch (skillId) { - case Thief.SMOKESCREEN, BattleMage.PARTY_SHIELD: // CUserLocal::DoActiveSkill_SmokeShell - case Magician.MYSTIC_DOOR: // CUserLocal::DoActiveSkill_TownPortal - case Evan.RECOVERY_AURA: // CUserLocal::DoActiveSkill_RecoverAura - case Citizen.CALL_OF_THE_HUNTER: // CUserLocal::DoActiveSkill_SummonMonster - case Mechanic.OPEN_PORTAL_GX_9: // CUserLocal::DoActiveSkill_OpenGate - return true; - default: - return false; - } + return switch (skillId) { // CUserLocal::DoActiveSkill_SmokeShell + // CUserLocal::DoActiveSkill_TownPortal + // CUserLocal::DoActiveSkill_RecoverAura + // CUserLocal::DoActiveSkill_SummonMonster + case SkillId.SHADOWER_SMOKESCREEN, SkillId.PARTY_SHIELD, SkillId.PRIEST_MYSTIC_DOOR, + SkillId.EVAN8_RECOVERY_AURA, SkillId.CITIZEN_CALL_OF_THE_HUNTER, + SkillId.MECH2_OPEN_PORTAL_GX9 -> // CUserLocal::DoActiveSkill_OpenGate + true; + default -> false; + }; } - public static boolean isAntiRepeatBuffSkill(int skillId) { - switch (skillId) { - case 1001003: - case 1101006: - case 1111007: - case 1121000: - case 1201006: - case 1211009: - case 1211010: - case 1221000: - case 1301006: - case 1301007: - case 1311007: - case 1321000: - case 2101001: - case 2101003: - case 2121000: - case 2201001: - case 2201003: - case 2221000: - case 2301004: - case 2311001: - case 2311003: - case 2321000: - case 2321005: - case 3121000: - case 3121002: - case 3221000: - case 4101004: - case 4111001: - case 4121000: - case 4201003: - case 4221000: - case 4311001: - case 4341000: - case 4341007: - case 5111007: - case 5121000: - case 5121009: - case 5211007: - case 5221000: - case 11001001: - case 11101003: - case 12101000: - case 12101001: - case 14101003: - case 15111005: - case 21121000: - case 22141003: - case 22171000: - case 22181000: - case 32111004: - case 32121007: - case 33121007: - case 35111013: - return true; - default: - return false; - } + public static boolean isAntiRepeatBuffSkill(SkillId skillId) { + return switch (skillId.getId()) { + case 1001003, 1101006, 1111007, 1121000, 1201006, 1211009, 1211010, 1221000, 1301006, 1301007, 1311007, + 1321000, 2101001, 2101003, 2121000, 2201001, 2201003, 2221000, 2301004, 2311001, 2311003, 2321000, + 2321005, 3121000, 3121002, 3221000, 4101004, 4111001, 4121000, 4201003, 4221000, 4311001, 4341000, + 4341007, 5111007, 5121000, 5121009, 5211007, 5221000, 11001001, 11101003, 12101000, 12101001, 14101003, + 15111005, 21121000, 22141003, 22171000, 22181000, 32111004, 32121007, 33121007, 35111013 -> true; + default -> false; + }; } - public static boolean isSummonSkill(int skillId) { + public static boolean isSummonSkill(SkillId skillId) { // Usages of CUserLocal::DoActiveSkill_Summon - switch (skillId) { + /*switch (skillId) { // CUserLocal::DoActiveSkill case Warrior.BEHOLDER: case Magician.IFRIT: @@ -457,11 +300,13 @@ public static boolean isSummonSkill(int skillId) { return true; default: return false; - } + }*/ + //TODO + return false; } - public static boolean isSummonMigrateSkill(int skillId) { - switch (skillId) { + public static boolean isSummonMigrateSkill(SkillId skillId) { + /*switch (skillId) { case Warrior.BEHOLDER: case Magician.IFRIT: case Magician.ELQUINES: @@ -486,42 +331,33 @@ public static boolean isSummonMigrateSkill(int skillId) { return true; default: return false; - } + }*/ + + //TODO + return false; } - public static boolean isSummonMultipleSkill(int skillId) { - switch (skillId) { - case BattleMage.SUMMON_REAPER_BUFF: - case WildHunter.ITS_RAINING_MINES_HIDDEN: - case Mechanic.ROCK_N_SHOCK: - case Mechanic.HEALING_ROBOT_H_LX: - case Mechanic.BOTS_N_TOTS_SUMMON: - return true; - default: - return false; - } + public static boolean isSummonMultipleSkill(SkillId skillId) { + return switch (skillId) { + case SkillId.SUMMON_REAPER_BUFF, SkillId.WH2_ITS_RAINING_MINES, SkillId.MECH3_ROCK_N_SHOCK, + SkillId.MECH3_HEALING_ROBOT_HLX, SkillId.MECH4_BOTS_N_TOTS -> true; + default -> false; + }; } - public static boolean isShootSkillNotUsingShootingWeapon(int skillId) { - switch (skillId) { - case Thief.TAUNT_NL: - case Thief.TAUNT_SHAD: - case Pirate.ENERGY_ORB: - case DawnWarrior.SOUL_BLADE: - case ThunderBreaker.SPARK: - case ThunderBreaker.SHARK_WAVE: - case Aran.COMBO_SMASH: - case Aran.COMBO_FENRIR: - case Aran.COMBO_TEMPEST: - case WildHunter.JAGUAR_OSHI_ATTACK: - return true; - default: - return false; - } + public static boolean isShootSkillNotUsingShootingWeapon(SkillId skillId) { + return switch (skillId) { + case SkillId.NIGHTLORD_TAUNT, SkillId.SHADOWER_TAUNT, SkillId.BUCCANEER_ENERGY_ORB, SkillId.DW2_SOUL_BLADE, + SkillId.TB3_SPARK, SkillId.TB3_SHARK_WAVE, SkillId.ARAN2_COMBO_SMASH, SkillId.ARAN3_COMBO_FENRIR, + SkillId.ARAN4_COMBO_TEMPEST, SkillId.WH2_JAGUAROSHI_2 -> true; + default -> false; + }; } - public static boolean isShootSkillNotConsumingBullet(int skillId) { - if (isShootSkillNotUsingShootingWeapon(skillId)) { + public static boolean isShootSkillNotConsumingBullet(SkillId skillId) { + //TODO + return false; + /*if (isShootSkillNotUsingShootingWeapon(skillId)) { return true; } switch (skillId) { @@ -543,112 +379,61 @@ public static boolean isShootSkillNotConsumingBullet(int skillId) { return true; default: return false; - } + }*/ } - public static boolean isMagicKeydownSkill(int skillId) { - return switch (skillId) { + public static boolean isMagicKeydownSkill(SkillId skillId) { + return switch (skillId.getId()) { case 2121001, 2221001, 2321001, 22121000, 22151001 -> true; default -> false; }; } - public static boolean isKeydownSkill(int skillId) { - switch (skillId) { - case 2121001: - case 2221001: - case 2321001: - case 3121004: - case 3221001: - case 4341002: - case 4341003: - case 5101004: - case 5201002: - case 5221004: - case 13111002: - case 14111006: - case 15101003: - case 22121000: - case 22151001: - case 33101005: - case 33121009: - case 35001001: - case 35101009: - return true; - default: - return false; - } + public static boolean isKeydownSkill(SkillId skillId) { + return switch (skillId.getId()) { + case 2121001, 2221001, 2321001, 3121004, 3221001, 4341002, 4341003, 5101004, 5201002, 5221004, 13111002, + 14111006, 15101003, 22121000, 22151001, 33101005, 33121009, 35001001, 35101009 -> true; + default -> false; + }; } - public static int getMaxGaugeTime(int skillId) { + public static int getMaxGaugeTime(SkillId skillId) { if (!isKeydownSkill(skillId)) { return 0; } - switch (skillId) { - case 2121001: - case 2221001: - case 2321001: - case 5101004: - case 5201002: - case 14111006: - case 15101003: - return 1000; - case 3121004: - case 5221004: - case 13111002: - case 33121009: - case 35001001: - case 35101009: - return 2000; - case 3221001: - case 33101005: - return 900; - case 4341002: - return 600; - case 4341003: - return 1200; - case 22121000: - case 22151001: - return 500; - default: - return 0; - } + return switch (skillId.getId()) { + case 2121001, 2221001, 2321001, 5101004, 5201002, 14111006, 15101003 -> 1000; + case 3121004, 5221004, 13111002, 33121009, 35001001, 35101009 -> 2000; + case 3221001, 33101005 -> 900; + case 4341002 -> 600; + case 4341003 -> 1200; + case 22121000, 22151001 -> 500; + default -> 0; + }; } - public static int getComboAbilitySkill(int jobId) { - return jobId != 2000 ? Aran.COMBO_ABILITY : 20000017; // tutorial skill + public static SkillId getComboAbilitySkill(int jobId) { + return jobId != 2000 ? SkillId.ARAN1_COMBO_ABILITY : SkillId.LEGEND_TUTORIAL_SKILL_3; // tutorial skill } - public static int getRequiredComboCount(int skillId) { - switch (skillId) { - case Aran.COMBO_SMASH: - case Aran.COMBO_DRAIN: - return 100; - case Aran.COMBO_FENRIR: - return 100; - case Aran.COMBO_TEMPEST: - case Aran.COMBO_BARRIER: - return 200; - default: - return 0; - } + public static int getRequiredComboCount(SkillId skillId) { + return switch (skillId) { + case SkillId.ARAN2_COMBO_SMASH, SkillId.ARAN2_COMBO_DRAIN -> 100; + case SkillId.ARAN3_COMBO_FENRIR -> 100; + case SkillId.ARAN4_COMBO_TEMPEST, SkillId.ARAN4_COMBO_BARRIER -> 200; + default -> 0; + }; } - public static boolean isDualAddDamageExceptSkill(int skillId) { - return skillId >= 4341002 && skillId <= 4341004; + public static boolean isDualAddDamageExceptSkill(SkillId skillId) { + return skillId.getId() >= 4341002 && skillId.getId() <= 4341004; } - public static boolean isJaguarMeleeAttackSkill(int skillId) { - switch (skillId) { - case 33101002: - case 33101007: - case 33111002: - case 33111006: - case 33121002: - return true; - default: - return false; - } + public static boolean isJaguarMeleeAttackSkill(SkillId skillId) { + return switch (skillId.getId()) { + case 33101002, 33101007, 33111002, 33111006, 33121002 -> true; + default -> false; + }; } public static boolean isNotSwallowableMob(int mobTemplateId) { @@ -656,45 +441,25 @@ public static boolean isNotSwallowableMob(int mobTemplateId) { return mobType >= 90 && (mobType <= 95 || mobType == 97) || mobTemplateId / 10000 == 999; } - public static boolean isIgnoreMasterLevelForCommon(int skillId) { - switch (skillId) { - case 1120012: - case 1220013: - case 1320011: - case 2120009: - case 2220009: - case 2320010: - case 3120010: - case 3120011: - case 3220009: - case 3220010: - case 4120010: - case 4220009: - case 5120011: - case 5220012: - case 32120009: - case 33120010: - return true; - default: - return false; - } + public static boolean isIgnoreMasterLevelForCommon(SkillId skillId) { + return switch (skillId.getId()) { + case 1120012, 1220013, 1320011, 2120009, 2220009, 2320010, 3120010, 3120011, 3220009, 3220010, 4120010, + 4220009, 5120011, 5220012, 32120009, 33120010 -> true; + default -> false; + }; } - public static boolean isSkillNeedMasterLevel(int skillId) { + public static boolean isSkillNeedMasterLevel(SkillId skillId) { if (isIgnoreMasterLevelForCommon(skillId)) { return false; } - final int jobId = skillId / 10000; + final int jobId = skillId.getJobId(); if (JobConstants.isEvanJob(jobId)) { final int jobLevel = JobConstants.getJobLevel(jobId); - return jobLevel == 9 || jobLevel == 10 || skillId == 22111001 || skillId == 22141002 || skillId == 22140000; + return jobLevel == 9 || jobLevel == 10 || skillId.getId() == 22111001 || skillId.getId() == 22141002 || skillId.getId() == 22140000; } if (JobConstants.isDualJob(jobId)) { - return JobConstants.getJobLevel(jobId) == 4 || - skillId == 4311003 || - skillId == 4321000 || - skillId == 4331002 || - skillId == 4331005; + return JobConstants.getJobLevel(jobId) == 4 || skillId.getId() == 4311003 || skillId.getId() == 4321000 || skillId.getId() == 4331002 || skillId.getId() == 4331005; } if (jobId == 100 * (jobId / 100)) { return false; diff --git a/src/main/java/kinoko/world/skill/SkillManager.java b/src/main/java/kinoko/world/skill/SkillManager.java index 4d53584e..57686598 100644 --- a/src/main/java/kinoko/world/skill/SkillManager.java +++ b/src/main/java/kinoko/world/skill/SkillManager.java @@ -1,5 +1,6 @@ package kinoko.world.skill; +import kinoko.meta.SkillId; import kinoko.provider.SkillProvider; import kinoko.provider.skill.SkillInfo; import kinoko.world.user.stat.CharacterTemporaryStat; @@ -12,9 +13,9 @@ import java.util.Optional; public final class SkillManager { - private final Map skillRecords = new HashMap<>(); - private final Map skillCooltimes = new HashMap<>(); - private final Map skillSchedules = new HashMap<>(); + private final Map skillRecords = new HashMap<>(); + private final Map skillCooltimes = new HashMap<>(); + private final Map skillSchedules = new HashMap<>(); // SKILL RECORD METHODS -------------------------------------------------------------------------------------------- @@ -22,7 +23,7 @@ public List getSkillRecords() { return skillRecords.values().stream().toList(); } - public Optional getSkill(int skillId) { + public Optional getSkill(SkillId skillId) { return Optional.ofNullable(skillRecords.get(skillId)); } @@ -30,30 +31,30 @@ public void addSkill(SkillRecord skillRecord) { skillRecords.put(skillRecord.getSkillId(), skillRecord); } - public void removeSkill(int skillId) { + public void removeSkill(SkillId skillId) { skillRecords.remove(skillId); } // SKILL COOLTIME METHODS ------------------------------------------------------------------------------------------ - public Map getSkillCooltimes() { + public Map getSkillCooltimes() { return skillCooltimes; } - public boolean hasSkillCooltime(int skillId) { + public boolean hasSkillCooltime(SkillId skillId) { final Instant nextAvailable = skillCooltimes.get(skillId); return nextAvailable != null && nextAvailable.isAfter(Instant.now()); } - public void setSkillCooltime(int skillId, Instant nextAvailable) { + public void setSkillCooltime(SkillId skillId, Instant nextAvailable) { skillCooltimes.put(skillId, nextAvailable); } // STATIC METHODS -------------------------------------------------------------------------------------------------- - public static int getSkillLevel(SecondaryStat ss, SkillManager sm, int skillId) { + public static int getSkillLevel(SecondaryStat ss, SkillManager sm, SkillId skillId) { final SkillRecord skillRecord = sm.skillRecords.get(skillId); if (skillRecord == null || skillRecord.getSkillLevel() == 0) { return 0; diff --git a/src/main/java/kinoko/world/skill/SkillProcessor.java b/src/main/java/kinoko/world/skill/SkillProcessor.java index e75e95ed..09144f1d 100644 --- a/src/main/java/kinoko/world/skill/SkillProcessor.java +++ b/src/main/java/kinoko/world/skill/SkillProcessor.java @@ -1,5 +1,6 @@ package kinoko.world.skill; +import kinoko.meta.SkillId; import kinoko.packet.user.UserLocal; import kinoko.packet.user.UserRemote; import kinoko.provider.SkillProvider; @@ -47,7 +48,8 @@ public abstract class SkillProcessor { public static void processAttack(User user, Mob mob, Attack attack, int delay) { final SkillInfo si = SkillProvider.getSkillInfoById(attack.skillId).orElseThrow(); - final int skillId = attack.skillId; + //TODO + final int skillId = attack.skillId.getId(); final int slv = attack.slv; final Field field = user.getField(); @@ -91,18 +93,21 @@ public static void processAttack(User user, Mob mob, Attack attack, int delay) { return; } - final int skillRoot = SkillConstants.getSkillRoot(attack.skillId); + final int skillRoot = attack.skillId.getRoot(); switch (Job.getById(skillRoot)) { - case WARRIOR, FIGHTER, CRUSADER, HERO, PAGE, WHITE_KNIGHT, PALADIN, SPEARMAN, DRAGON_KNIGHT, DARK_KNIGHT -> { + case WARRIOR, FIGHTER, CRUSADER, HERO, PAGE, WHITE_KNIGHT, PALADIN, SPEARMAN, DRAGON_KNIGHT, + DARK_KNIGHT -> { Warrior.handleAttack(user, mob, attack, delay); } - case MAGICIAN, WIZARD_FP, MAGE_FP, ARCH_MAGE_FP, WIZARD_IL, MAGE_IL, ARCH_MAGE_IL, CLERIC, PRIEST, BISHOP -> { + case MAGICIAN, WIZARD_FP, MAGE_FP, ARCH_MAGE_FP, WIZARD_IL, MAGE_IL, ARCH_MAGE_IL, CLERIC, PRIEST, + BISHOP -> { Magician.handleAttack(user, mob, attack, delay); } case ARCHER, HUNTER, RANGER, BOWMASTER, CROSSBOWMAN, SNIPER, MARKSMAN -> { Bowman.handleAttack(user, mob, attack, delay); } - case ROGUE, ASSASSIN, HERMIT, NIGHT_LORD, BANDIT, CHIEF_BANDIT, SHADOWER, BLADE_RECRUIT, BLADE_ACOLYTE, BLADE_SPECIALIST, BLADE_LORD, BLADE_MASTER -> { + case ROGUE, ASSASSIN, HERMIT, NIGHT_LORD, BANDIT, CHIEF_BANDIT, SHADOWER, BLADE_RECRUIT, BLADE_ACOLYTE, + BLADE_SPECIALIST, BLADE_LORD, BLADE_MASTER -> { Thief.handleAttack(user, mob, attack, delay); } case PIRATE, BRAWLER, MARAUDER, BUCCANEER, GUNSLINGER, OUTLAW, CORSAIR -> { @@ -146,11 +151,11 @@ public static void processAttack(User user, Mob mob, Attack attack, int delay) { public static void processSkill(User user, Skill skill) { final SkillInfo si = SkillProvider.getSkillInfoById(skill.skillId).orElseThrow(); - final int skillId = skill.skillId; + final SkillId skillId = skill.skillId; final int slv = skill.slv; final Field field = user.getField(); - switch (skillId) { + switch (skillId.getId()) { // BEGINNER SKILLS ----------------------------------------------------------------------------------------- case Beginner.RECOVERY: case Noblesse.RECOVERY: @@ -174,7 +179,7 @@ public static void processSkill(User user, Skill skill) { log.error("Tried to use Monster Rider skill without a taming mob"); return; } - user.setTemporaryStat(CharacterTemporaryStat.RideVehicle, TemporaryStatOption.ofTwoState(CharacterTemporaryStat.RideVehicle, tamingMobItem.getItemId(), skillId, 0)); + user.setTemporaryStat(CharacterTemporaryStat.RideVehicle, TemporaryStatOption.ofTwoState(CharacterTemporaryStat.RideVehicle, tamingMobItem.getItemId(), skillId.getId(), 0)); return; case Beginner.SOARING: case Noblesse.SOARING: @@ -298,7 +303,7 @@ public static void processSkill(User user, Skill skill) { case Thief.DARK_SIGHT: case NightWalker.DARK_SIGHT: case WindArcher.WIND_WALK: - final CharacterTemporaryStat darkSightStat = skillId == WindArcher.WIND_WALK ? + final CharacterTemporaryStat darkSightStat = skillId == SkillId.WA2_WIND_WALK ? CharacterTemporaryStat.WindWalk : CharacterTemporaryStat.DarkSight; if (slv == si.getMaxLevel()) { @@ -336,8 +341,8 @@ public static void processSkill(User user, Skill skill) { case Pirate.DASH: case ThunderBreaker.DASH: user.setTemporaryStat(Map.of( - CharacterTemporaryStat.Dash_Speed, TemporaryStatOption.ofTwoState(CharacterTemporaryStat.Dash_Speed, si.getValue(SkillStat.x, slv), skillId, si.getDuration(slv)), - CharacterTemporaryStat.Dash_Jump, TemporaryStatOption.ofTwoState(CharacterTemporaryStat.Dash_Jump, si.getValue(SkillStat.y, slv), skillId, si.getDuration(slv)) + CharacterTemporaryStat.Dash_Speed, TemporaryStatOption.ofTwoState(CharacterTemporaryStat.Dash_Speed, si.getValue(SkillStat.x, slv), skillId.getId(), si.getDuration(slv)), + CharacterTemporaryStat.Dash_Jump, TemporaryStatOption.ofTwoState(CharacterTemporaryStat.Dash_Jump, si.getValue(SkillStat.y, slv), skillId.getId(), si.getDuration(slv)) )); return; case Pirate.TRANSFORMATION: @@ -355,7 +360,7 @@ public static void processSkill(User user, Skill skill) { return; case Pirate.SPEED_INFUSION: case ThunderBreaker.SPEED_INFUSION: - user.setTemporaryStat(CharacterTemporaryStat.PartyBooster, TemporaryStatOption.ofTwoState(CharacterTemporaryStat.PartyBooster, si.getValue(SkillStat.x, slv), skillId, si.getDuration(slv))); + user.setTemporaryStat(CharacterTemporaryStat.PartyBooster, TemporaryStatOption.ofTwoState(CharacterTemporaryStat.PartyBooster, si.getValue(SkillStat.x, slv), skillId.getId(), si.getDuration(slv))); return; // COMMON SKILLS ------------------------------------------------------------------------------------------- @@ -455,21 +460,24 @@ public static void processSkill(User user, Skill skill) { } // CLASS SPECIFIC SKILLS --------------------------------------------------------------------------------------- - final int skillRoot = SkillConstants.getSkillRoot(skill.skillId); + final int skillRoot = skill.skillId.getRoot(); switch (Job.getById(skillRoot)) { case CITIZEN -> { Citizen.handleSkill(user, skill); } - case WARRIOR, FIGHTER, CRUSADER, HERO, PAGE, WHITE_KNIGHT, PALADIN, SPEARMAN, DRAGON_KNIGHT, DARK_KNIGHT -> { + case WARRIOR, FIGHTER, CRUSADER, HERO, PAGE, WHITE_KNIGHT, PALADIN, SPEARMAN, DRAGON_KNIGHT, + DARK_KNIGHT -> { Warrior.handleSkill(user, skill); } - case MAGICIAN, WIZARD_FP, MAGE_FP, ARCH_MAGE_FP, WIZARD_IL, MAGE_IL, ARCH_MAGE_IL, CLERIC, PRIEST, BISHOP -> { + case MAGICIAN, WIZARD_FP, MAGE_FP, ARCH_MAGE_FP, WIZARD_IL, MAGE_IL, ARCH_MAGE_IL, CLERIC, PRIEST, + BISHOP -> { Magician.handleSkill(user, skill); } case ARCHER, HUNTER, RANGER, BOWMASTER, CROSSBOWMAN, SNIPER, MARKSMAN -> { Bowman.handleSkill(user, skill); } - case ROGUE, ASSASSIN, HERMIT, NIGHT_LORD, BANDIT, CHIEF_BANDIT, SHADOWER, BLADE_RECRUIT, BLADE_ACOLYTE, BLADE_SPECIALIST, BLADE_LORD, BLADE_MASTER -> { + case ROGUE, ASSASSIN, HERMIT, NIGHT_LORD, BANDIT, CHIEF_BANDIT, SHADOWER, BLADE_RECRUIT, BLADE_ACOLYTE, + BLADE_SPECIALIST, BLADE_LORD, BLADE_MASTER -> { Thief.handleSkill(user, skill); } case PIRATE, BRAWLER, MARAUDER, BUCCANEER, GUNSLINGER, OUTLAW, CORSAIR -> { @@ -512,7 +520,7 @@ public static void processSkill(User user, Skill skill) { } protected static int getBuffedDuration(User user, int duration) { - final int skillId = SkillConstants.getBuffMasterySkill(user.getJob()); + final SkillId skillId = SkillConstants.getBuffMasterySkill(user.getJob()); final int slv = user.getSkillLevel(skillId); if (slv == 0) { return duration; @@ -540,7 +548,7 @@ private static void handleRecovery(User user, Instant now) { return; } final TemporaryStatOption option = user.getSecondaryStat().getOption(CharacterTemporaryStat.Regen); - final int skillId = option.rOption; + final SkillId skillId = option.getSkillId(); if (now.isAfter(user.getSchedule(skillId))) { final int hpRecovery = option.nOption; user.addHp(hpRecovery); @@ -555,12 +563,12 @@ private static void handleDragonBlood(User user, Instant now) { return; } final TemporaryStatOption option = user.getSecondaryStat().getOption(CharacterTemporaryStat.DragonBlood); - final int skillId = option.rOption; + final SkillId skillId = option.getSkillId(); if (now.isAfter(user.getSchedule(skillId))) { final int hpConsume = option.nOption; if (user.getHp() < hpConsume * 4) { // Skill is canceled when you don't have enough HP to be consumed in the next 4 seconds - user.resetTemporaryStat(skillId); + user.resetTemporaryStat(skillId.getId()); return; } user.addHp(-hpConsume); @@ -573,7 +581,7 @@ private static void handleInfinity(User user, Instant now) { return; } final TemporaryStatOption option = user.getSecondaryStat().getOption(CharacterTemporaryStat.Infinity); - final int skillId = option.rOption; + final SkillId skillId = option.getSkillId(); if (now.isAfter(user.getSchedule(skillId))) { final Optional skillInfoResult = SkillProvider.getSkillInfoById(skillId); if (skillInfoResult.isEmpty()) { @@ -598,9 +606,9 @@ private static void handleAura(User user, Instant now) { return; } final TemporaryStatOption option = user.getSecondaryStat().getOption(CharacterTemporaryStat.Aura); - final int skillId = BattleMage.getAdvancedAuraSkill(user, option.rOption); + final SkillId skillId = BattleMage.getAdvancedAuraSkill(user, option.getSkillId()); final int slv = user.getSkillLevel(skillId); - if (now.isAfter(user.getSchedule(option.rOption))) { + if (now.isAfter(user.getSchedule(option.getSkillId()))) { final CharacterTemporaryStat cts = SkillConstants.getStatByAuraSkill(skillId); if (cts == null) { log.error("Could not resolve CTS for aura skill ID : {}", skillId); @@ -631,7 +639,7 @@ private static void handleAura(User user, Instant now) { } }); // Set next schedule - user.setSchedule(option.rOption, now.plus(1, ChronoUnit.SECONDS)); + user.setSchedule(option.getSkillId(), now.plus(1, ChronoUnit.SECONDS)); } } @@ -639,8 +647,8 @@ private static void handleMissileTank(User user, Instant now) { if (!user.getSecondaryStat().hasOption(CharacterTemporaryStat.Mechanic)) { return; } - final int skillId = user.getSecondaryStat().getOption(CharacterTemporaryStat.Mechanic).rOption; - if (skillId != Mechanic.MECH_MISSILE_TANK) { + final SkillId skillId = user.getSecondaryStat().getOption(CharacterTemporaryStat.Mechanic).getSkillId(); + if (skillId != SkillId.MECH4_MECH_MISSILE_TANK) { return; } if (now.isAfter(user.getSchedule(skillId))) { diff --git a/src/main/java/kinoko/world/skill/SkillRecord.java b/src/main/java/kinoko/world/skill/SkillRecord.java index 9baa3b8d..8b8c80e5 100644 --- a/src/main/java/kinoko/world/skill/SkillRecord.java +++ b/src/main/java/kinoko/world/skill/SkillRecord.java @@ -1,15 +1,17 @@ package kinoko.world.skill; +import kinoko.meta.SkillId; + public final class SkillRecord { - private final int skillId; + private final SkillId skillId; private int skillLevel; private int masterLevel; - public SkillRecord(int skillId) { + public SkillRecord(SkillId skillId) { this.skillId = skillId; } - public int getSkillId() { + public SkillId getSkillId() { return skillId; } diff --git a/src/main/java/kinoko/world/user/CharacterData.java b/src/main/java/kinoko/world/user/CharacterData.java index ed9e8e25..5778e401 100644 --- a/src/main/java/kinoko/world/user/CharacterData.java +++ b/src/main/java/kinoko/world/user/CharacterData.java @@ -1,5 +1,6 @@ package kinoko.world.user; +import kinoko.meta.SkillId; import kinoko.server.dialog.miniroom.MiniRoomType; import kinoko.server.packet.OutPacket; import kinoko.util.Encodable; @@ -295,7 +296,7 @@ public void encodeCharacterData(DBChar flag, OutPacket outPacket) { if (flag.hasFlag(DBChar.SKILLRECORD)) { outPacket.encodeShort(skillManager.getSkillRecords().size()); for (SkillRecord sr : skillManager.getSkillRecords()) { - outPacket.encodeInt(sr.getSkillId()); + outPacket.encodeSkillId(sr.getSkillId()); outPacket.encodeInt(sr.getSkillLevel()); outPacket.encodeFT(FileTime.DEFAULT_TIME); // mSkillExpired if (SkillConstants.isSkillNeedMasterLevel(sr.getSkillId())) { @@ -308,18 +309,18 @@ public void encodeCharacterData(DBChar flag, OutPacket outPacket) { final Instant now = Instant.now(); final var iter = skillManager.getSkillCooltimes().entrySet().iterator(); while (iter.hasNext()) { - final Map.Entry entry = iter.next(); - final int skillId = entry.getKey(); + final Map.Entry entry = iter.next(); + final SkillId skillId = entry.getKey(); final Instant end = entry.getValue(); // Battleship durability is stored as cooltime - if (skillId == SkillConstants.BATTLESHIP_DURABILITY) { - cooltimes.put(skillId, end.getEpochSecond()); + if (skillId == SkillId.CORSAIR_BATTLESHIP_DURABILITY) { + cooltimes.put(skillId.getId(), end.getEpochSecond()); } else { if (now.isAfter(end)) { iter.remove(); continue; } - cooltimes.put(skillId, Duration.between(now, end).getSeconds()); + cooltimes.put(skillId.getId(), Duration.between(now, end).getSeconds()); } } diff --git a/src/main/java/kinoko/world/user/User.java b/src/main/java/kinoko/world/user/User.java index e613cf57..51ca798d 100644 --- a/src/main/java/kinoko/world/user/User.java +++ b/src/main/java/kinoko/world/user/User.java @@ -1,6 +1,7 @@ package kinoko.world.user; import kinoko.handler.user.FriendHandler; +import kinoko.meta.SkillId; import kinoko.packet.stage.StagePacket; import kinoko.packet.user.PetPacket; import kinoko.packet.user.UserLocal; @@ -188,12 +189,12 @@ public Map getSchedules() { return schedules; } - public Instant getSchedule(int skillId) { - return schedules.getOrDefault(skillId, Instant.MAX); + public Instant getSchedule(SkillId skillId) { + return schedules.getOrDefault(skillId.getId(), Instant.MAX); } - public void setSchedule(int skillId, Instant nextSchedule) { - schedules.put(skillId, nextSchedule); + public void setSchedule(SkillId skillId, Instant nextSchedule) { + schedules.put(skillId.getId(), nextSchedule); } public byte getFieldKey() { @@ -436,11 +437,11 @@ public void addPop(int pop) { write(WvsContext.statChanged(Stat.POP, newPop, false)); } - public int getSkillLevel(int skillId) { + public int getSkillLevel(SkillId skillId) { return SkillManager.getSkillLevel(getSecondaryStat(), getSkillManager(), skillId); } - public int getSkillStatValue(int skillId, SkillStat stat) { + public int getSkillStatValue(SkillId skillId, SkillStat stat) { final int slv = getSkillLevel(skillId); if (slv == 0) { return 0; @@ -517,7 +518,7 @@ public void resetTemporaryStat(BiPredicate 0) { getSkillManager().setSkillCooltime(skillId, Instant.now().plus(cooltime, ChronoUnit.SECONDS)); } else { @@ -526,14 +527,14 @@ public void setSkillCooltime(int skillId, int cooltime) { write(UserLocal.skillCooltimeSet(skillId, cooltime)); } - public List expireSkillCooltime(Instant now) { - final List resetCooltimes = new ArrayList<>(); + public List expireSkillCooltime(Instant now) { + final List resetCooltimes = new ArrayList<>(); final var iter = getSkillManager().getSkillCooltimes().entrySet().iterator(); while (iter.hasNext()) { - final Map.Entry entry = iter.next(); - final int skillId = entry.getKey(); + final Map.Entry entry = iter.next(); + final SkillId skillId = entry.getKey(); // Battleship durability is stored as cooltime - if (skillId == SkillConstants.BATTLESHIP_DURABILITY) { + if (skillId == SkillId.CORSAIR_BATTLESHIP_DURABILITY) { continue; } // Check skill cooltime and remove @@ -721,8 +722,8 @@ public void updatePets(Instant now) { // SUMMONED METHODS ------------------------------------------------------------------------------------------------ public void addSummoned(Summoned summoned) { - final int skillId = summoned.getSkillId(); - final List summonedList = getSummoned().computeIfAbsent(skillId, (key) -> new ArrayList<>()); + final SkillId skillId = SkillId.fromValue(summoned.getSkillId()); + final List summonedList = getSummoned().computeIfAbsent(skillId.getId(), (key) -> new ArrayList<>()); if (!SkillConstants.isSummonMultipleSkill(skillId) && !summonedList.isEmpty()) { for (Summoned existing : summonedList) { existing.setLeaveType(SummonedLeaveType.NOT_ABLE_MULTIPLE); @@ -755,8 +756,8 @@ public void removeSummoned(Predicate predicate) { } } - public Optional getSummonedBySkillId(int skillId) { - final List summonedList = getSummoned().getOrDefault(skillId, List.of()); + public Optional getSummonedBySkillId(SkillId skillId) { + final List summonedList = getSummoned().getOrDefault(skillId.getId(), List.of()); if (summonedList.isEmpty()) { return Optional.empty(); } diff --git a/src/main/java/kinoko/world/user/effect/Effect.java b/src/main/java/kinoko/world/user/effect/Effect.java index 0df49aae..9e5629ca 100644 --- a/src/main/java/kinoko/world/user/effect/Effect.java +++ b/src/main/java/kinoko/world/user/effect/Effect.java @@ -1,5 +1,6 @@ package kinoko.world.user.effect; +import kinoko.meta.SkillId; import kinoko.server.packet.OutPacket; import kinoko.util.Encodable; import kinoko.world.item.Item; @@ -204,7 +205,7 @@ public static Effect itemMaker(MakerResult makerResult) { return effect; } - public static SkillEffect skillUse(int skillId, int skillLevel, int charLevel) { + public static SkillEffect skillUse(SkillId skillId, int skillLevel, int charLevel) { final SkillEffect effect = new SkillEffect(EffectType.SkillUse); effect.skillId = skillId; effect.skillLevel = skillLevel; @@ -217,13 +218,13 @@ public static SkillEffect skillUse(Skill skill, int charLevel) { effect.skillId = skill.skillId; effect.skillLevel = skill.slv; switch (skill.skillId) { - case Thief.CHAINS_OF_HELL -> { + case SkillId.DB5_CHAINS_OF_HELL -> { effect.left = skill.left; // bLeft if (skill.targetIds != null && skill.targetIds.length > 0) { effect.info = skill.targetIds[0]; // dwMobID } } - case Citizen.CALL_OF_THE_HUNTER -> { + case SkillId.CITIZEN_CALL_OF_THE_HUNTER -> { effect.left = skill.left; // bLeft effect.positionX = skill.positionX; // ptOffset.x effect.positionY = skill.positionY; // ptOffset.x @@ -233,7 +234,7 @@ public static SkillEffect skillUse(Skill skill, int charLevel) { return effect; } - public static SkillEffect skillUseEnable(int skillId, int skillLevel, int charLevel, boolean enable) { + public static SkillEffect skillUseEnable(SkillId skillId, int skillLevel, int charLevel, boolean enable) { final SkillEffect effect = new SkillEffect(EffectType.SkillUse); effect.skillId = skillId; effect.skillLevel = skillLevel; @@ -242,7 +243,7 @@ public static SkillEffect skillUseEnable(int skillId, int skillLevel, int charLe return effect; } - public static SkillEffect skillUseInfo(int skillId, int skillLevel, int charLevel, int info) { + public static SkillEffect skillUseInfo(SkillId skillId, int skillLevel, int charLevel, int info) { final SkillEffect effect = new SkillEffect(EffectType.SkillUse); effect.skillId = skillId; effect.skillLevel = skillLevel; @@ -251,14 +252,14 @@ public static SkillEffect skillUseInfo(int skillId, int skillLevel, int charLeve return effect; } - public static SkillEffect skillAffected(int skillId, int skillLevel) { + public static SkillEffect skillAffected(SkillId skillId, int skillLevel) { final SkillEffect effect = new SkillEffect(EffectType.SkillAffected); effect.skillId = skillId; effect.skillLevel = skillLevel; return effect; } - public static SkillEffect skillAffectedSelect(int select, int skillId, int skillLevel) { + public static SkillEffect skillAffectedSelect(int select, SkillId skillId, int skillLevel) { final SkillEffect effect = new SkillEffect(EffectType.SkillAffected_Select); effect.info = select; effect.skillId = skillId; @@ -266,7 +267,7 @@ public static SkillEffect skillAffectedSelect(int select, int skillId, int skill return effect; } - public static SkillEffect skillSpecial(int skillId, int skillLevel, int positionX, int positionY) { + public static SkillEffect skillSpecial(SkillId skillId, int skillLevel, int positionX, int positionY) { final SkillEffect effect = new SkillEffect(EffectType.SkillAffected_Select); effect.skillId = skillId; effect.skillLevel = skillLevel; diff --git a/src/main/java/kinoko/world/user/effect/SkillEffect.java b/src/main/java/kinoko/world/user/effect/SkillEffect.java index 21d25434..aa3bf40a 100644 --- a/src/main/java/kinoko/world/user/effect/SkillEffect.java +++ b/src/main/java/kinoko/world/user/effect/SkillEffect.java @@ -1,5 +1,6 @@ package kinoko.world.user.effect; +import kinoko.meta.SkillId; import kinoko.server.packet.OutPacket; import kinoko.world.job.explorer.Thief; import kinoko.world.job.explorer.Warrior; @@ -7,7 +8,7 @@ import kinoko.world.job.resistance.Citizen; public final class SkillEffect extends Effect { - public int skillId; + public SkillId skillId; public int skillLevel; public int charLevel; public boolean enable; @@ -25,42 +26,42 @@ public void encode(OutPacket outPacket) { outPacket.encodeByte(type.getValue()); switch (type) { case SkillUse -> { - outPacket.encodeInt(skillId); // nSkillID + outPacket.encodeSkillId(skillId); // nSkillID outPacket.encodeByte(charLevel); // nCharLevel outPacket.encodeByte(skillLevel); // nSLV switch (skillId) { - case Warrior.BERSERK, Evan.DRAGON_FURY -> { + case SkillId.DRK_BERSERK, SkillId.EVAN8_DRAGON_FURY -> { outPacket.encodeByte(enable); // bool -> CUser::LoadDarkForceEffect | CDragon::CreateEffect(1) } - case Thief.CHAINS_OF_HELL -> { + case SkillId.DB5_CHAINS_OF_HELL -> { outPacket.encodeByte(left); // bLeft outPacket.encodeInt(info); // dwMobID } - case Citizen.CALL_OF_THE_HUNTER -> { + case SkillId.CITIZEN_CALL_OF_THE_HUNTER -> { outPacket.encodeByte(left); // bLeft outPacket.encodeShort(positionX); // ptOffset.x outPacket.encodeShort(positionY); // ptOffset.y } - case Citizen.CAPTURE -> { + case SkillId.CITIZEN_CAPTURE -> { outPacket.encodeByte(info); // 0 : monster successfully captured, 1 : capture failed monster hp too high, 2 : monster cannot be captured } } - if (skillId / 10000000 == 9) { // is_unregistered_skill + if (skillId.getId() / 10000000 == 9) { // is_unregistered_skill outPacket.encodeByte(left); // bLeft } } case SkillAffected, SkillSpecialAffected -> { - outPacket.encodeInt(skillId); // nSkillID + outPacket.encodeSkillId(skillId); // nSkillID outPacket.encodeByte(skillLevel); // nSLV } case SkillAffected_Select -> { outPacket.encodeInt(info); // nSelect - outPacket.encodeInt(skillId); // nSkillID + outPacket.encodeSkillId(skillId); // nSkillID outPacket.encodeByte(skillLevel); // nSLV } case SkillSpecial -> { - outPacket.encodeInt(skillId); // nSkillID - if (skillId == Thief.MONSTER_BOMB) { + outPacket.encodeSkillId(skillId); // nSkillID + if (skillId == SkillId.DB5_MONSTER_BOMB) { outPacket.encodeInt(positionX); // nTimeBombX outPacket.encodeInt(positionY); // nTimeBombY outPacket.encodeInt(skillLevel); // nSLV diff --git a/src/main/java/kinoko/world/user/stat/BasicStat.java b/src/main/java/kinoko/world/user/stat/BasicStat.java index 54b8046b..05219d45 100644 --- a/src/main/java/kinoko/world/user/stat/BasicStat.java +++ b/src/main/java/kinoko/world/user/stat/BasicStat.java @@ -1,5 +1,6 @@ package kinoko.world.user.stat; +import kinoko.meta.SkillId; import kinoko.provider.EtcProvider; import kinoko.provider.ItemProvider; import kinoko.provider.SkillProvider; @@ -213,12 +214,12 @@ private int getJaguarRidingMaxHpUp(SecondaryStat ss, SkillManager sm) { if (!SkillConstants.WILD_HUNTER_JAGUARS.contains(ss.getRidingVehicle())) { return 0; } - final Optional skillInfoResult = SkillProvider.getSkillInfoById(WildHunter.JAGUAR_RIDER); + final Optional skillInfoResult = SkillProvider.getSkillInfoById(SkillId.WH1_JAGUAR_RIDER); if (skillInfoResult.isEmpty()) { return 0; } final SkillInfo si = skillInfoResult.get(); - final int slv = SkillManager.getSkillLevel(ss, sm, WildHunter.JAGUAR_RIDER); + final int slv = SkillManager.getSkillLevel(ss, sm, SkillId.WH1_JAGUAR_RIDER); return si.getValue(SkillStat.z, slv); } diff --git a/src/main/java/kinoko/world/user/stat/CalcDamage.java b/src/main/java/kinoko/world/user/stat/CalcDamage.java index 26a75502..4c6a9c7c 100644 --- a/src/main/java/kinoko/world/user/stat/CalcDamage.java +++ b/src/main/java/kinoko/world/user/stat/CalcDamage.java @@ -1,5 +1,6 @@ package kinoko.world.user.stat; +import kinoko.meta.SkillId; import kinoko.provider.ItemProvider; import kinoko.provider.item.ItemInfo; import kinoko.provider.item.ItemInfoType; @@ -71,10 +72,10 @@ public static void calcPDamage(User user, Mob mob, Attack attack, AttackInfo ai) final SecondaryStat ss = user.getSecondaryStat(); final PassiveSkillData psd = user.getPassiveSkillData(); final MobStat ms = mob.getMobStat(); - final int skillId = attack.skillId; - final int noviceSkill = Math.max(skillId - (JobConstants.getNoviceSkillRootFromJob(user.getJob()) * 1000), 0); - final int criticalRate = getCriticalRate(user, attack) + psd.getAdditionCr(skillId); - final int damagePerMob = skillId == Thief.MESO_EXPLOSION ? ai.attackCount : attack.getDamagePerMob(); + final SkillId skillId = attack.skillId; + final int noviceSkill = Math.max(skillId.getId() - (JobConstants.getNoviceSkillRootFromJob(user.getJob()) * 1000), 0); + final int criticalRate = getCriticalRate(user, attack) + psd.getAdditionCr(skillId.getId()); + final int damagePerMob = skillId == SkillId.CHIEFBANDIT_MESO_EXPLOSION ? ai.attackCount : attack.getDamagePerMob(); // Process attack info int counter = 0; for (int i = 0; i < damagePerMob; i++) { @@ -95,12 +96,12 @@ public static void calcPDamage(User user, Mob mob, Attack attack, AttackInfo ai) assertDamage(1, ai.damage[i]); continue; } - if (skillId == Aran.COMBO_TEMPEST) { + if (skillId == SkillId.ARAN4_COMBO_TEMPEST) { if (!mob.isBoss()) { continue; } } - if (skillId == Bowman.SNIPE) { // 33121003 does not exist + if (skillId == SkillId.MARKSMAN_SNIPE) { // 33121003 does not exist if (!mob.isBoss()) { final int fixDamage = (int) (999_999.0 - getRand(ai.random[counter++ % 7], 10000.0, 0.0)); assertDamage(fixDamage, ai.damage[i]); @@ -109,7 +110,7 @@ public static void calcPDamage(User user, Mob mob, Attack attack, AttackInfo ai) } continue; } - if (skillId == Thief.NINJA_STORM || skillId == Aran.ROLLING_SPIN) { + if (skillId == SkillId.NIGHTLORD_NINJA_STORM || skillId == SkillId.ARAN3_ROLLING_SPIN) { final double rand = getRand(ai.random[counter % 7], 100.0, 0.0); final int prop = user.getSkillStatValue(skillId, SkillStat.prop); if (prop <= rand) { @@ -118,8 +119,8 @@ public static void calcPDamage(User user, Mob mob, Attack attack, AttackInfo ai) } } counter++; - if ((ms.hasOption(MobTemporaryStat.Freeze) && skillId == Bowman.STRAFE_MM && attack.isShootAttack() && i == 0 && !mob.isBoss()) || - (skillId == Thief.OWL_SPIRIT && i == 0 && !mob.isBoss())) { + if ((ms.hasOption(MobTemporaryStat.Freeze) && skillId == SkillId.SNIPER_STRAFE && attack.isShootAttack() && i == 0 && !mob.isBoss()) || + (skillId == SkillId.DB4_OWL_SPIRIT && i == 0 && !mob.isBoss())) { final double rand = getRand(ai.random[counter++ % 7], 0.0, 100.0); final int prop = user.getSkillStatValue(skillId, SkillStat.prop); if (rand < prop) { @@ -127,7 +128,7 @@ public static void calcPDamage(User user, Mob mob, Attack attack, AttackInfo ai) continue; } } - if (attack.getHeaderType() != OutHeader.UserBodyAttack && skillId != 0 && ss.hasOption(CharacterTemporaryStat.Seal)) { + if (attack.getHeaderType() != OutHeader.UserBodyAttack && !skillId.isNone() && ss.hasOption(CharacterTemporaryStat.Seal)) { continue; } final int mobEva = Math.clamp(mob.getTemplate().getEva() + mob.getMobStat().getOption(MobTemporaryStat.EVA).nOption, 0, 9999); @@ -139,8 +140,8 @@ public static void calcPDamage(User user, Mob mob, Attack attack, AttackInfo ai) continue; } } - if (skillId != 0) { - if (skillId == Warrior.HEAVENS_HAMMER) { + if (!skillId.isNone()) { + if (skillId == SkillId.PALADIN_HEAVENS_HAMMER) { continue; } final int fixDamage = user.getSkillStatValue(skillId, SkillStat.fixdamage); @@ -161,20 +162,20 @@ public static void calcPDamage(User user, Mob mob, Attack attack, AttackInfo ai) assertDamage(mob.getMaxHp(), mob.getMaxHp()); continue; } - if (skillId == Warrior.RUSH_HERO || - skillId == Warrior.RUSH_PALADIN || - skillId == Warrior.RUSH_DRK || - skillId == Thief.TORNADO_SPIN_ATTACK || - skillId == Warrior.BLAST || - skillId == Thief.FLYING_ASSAULTER || - skillId == Thief.SLASH_STORM || - skillId == Thief.BLOODY_STORM) { + if (skillId == SkillId.HERO_RUSH || + skillId == SkillId.PALADIN_RUSH || + skillId == SkillId.DRK_RUSH || + skillId == SkillId.DB3_TORNADO_SPIN_ATTACK || + skillId == SkillId.PALADIN_BLAST || + skillId == SkillId.DB4_FLYING_ASSAULTER || + skillId == SkillId.DB2_SLASH_STORM || + skillId == SkillId.DB4_BLOODY_STORM) { counter++; } // Adjust Random Damage counter++; // Check Critical - if (attack.skillId != Thief.ASSASSINATE || attack.getAction() != ActionType.ASSASSINATIONS.getValue()) { + if (attack.skillId != SkillId.SHADOWER_ASSASSINATE || attack.getAction() != ActionType.ASSASSINATIONS.getValue()) { if (user.getCalcDamage().isNextAttackCritical() || (criticalRate > 0 && criticalRate > getRand(ai.random[counter++ % 7], 0.0, 100.0))) { ai.critical[i] = 1; @@ -184,7 +185,7 @@ criticalRate > getRand(ai.random[counter++ % 7], 0.0, 100.0))) { } if (attack.isShadowPartner() && ss.hasOption(CharacterTemporaryStat.ShadowPartner) && ss.getOption(CharacterTemporaryStat.ShadowPartner).rOption != Thief.MIRROR_IMAGE) { - if (skillId != Thief.TAUNT_NL && skillId != Thief.TAUNT_SHAD && i >= damagePerMob / 2) { + if (skillId != SkillId.NIGHTLORD_TAUNT && skillId != SkillId.SHADOWER_TAUNT && i >= damagePerMob / 2) { ai.critical[i] = ai.critical[i - damagePerMob / 2]; } } @@ -192,7 +193,7 @@ criticalRate > getRand(ai.random[counter++ % 7], 0.0, 100.0))) { counter++; // cd->boss.nProb } if (!ms.hasOption(MobTemporaryStat.HardSkin) || ai.critical[i] != 0) { - if (skillId == Thief.SHADOW_MESO) { + if (skillId == SkillId.HERMIT_SHADOW_MESO) { counter++; // nMoneyCon counter++; // nProp } @@ -209,8 +210,8 @@ public static void calcMDamage(User user, Mob mob, Attack attack, AttackInfo ai) // CalcDamage::MDamage final SecondaryStat ss = user.getSecondaryStat(); final MobStat ms = mob.getMobStat(); - final int skillId = attack.skillId; - final int noviceSkill = Math.max(skillId - (JobConstants.getNoviceSkillRootFromJob(user.getJob()) * 1000), 0); + final SkillId skillId = attack.skillId; + final int noviceSkill = Math.max(skillId.getId() - (JobConstants.getNoviceSkillRootFromJob(user.getJob()) * 1000), 0); final int criticalRate = getCriticalRate(user, attack); final int damagePerMob = attack.getDamagePerMob(); // Process attack info @@ -238,7 +239,7 @@ public static void calcMDamage(User user, Mob mob, Attack attack, AttackInfo ai) assertDamage(0, ai.damage[i]); continue; } - if (skillId != 0) { + if (!skillId.isNone()) { final int fixDamage = user.getSkillStatValue(skillId, SkillStat.fixdamage); if (noviceSkill == 1066 || noviceSkill == 1067 || fixDamage != 0) { assertDamage(fixDamage, ai.damage[i]); @@ -320,59 +321,59 @@ private static int getCriticalRate(User user, Attack attack) { // ignore cd->critical.nProb final int comboCount = user.getSecondaryStat().getOption(CharacterTemporaryStat.ComboAbilityBuff).nOption; if (comboCount > 0) { - final int comboCriticalSkillId = user.getJob() != 2000 ? Aran.COMBO_CRITICAL : 20000018; + final SkillId comboCriticalSkillId = user.getJob() != 2000 ? SkillId.ARAN3_COMBO_CRITICAL : SkillId.LEGEND_TUTORIAL_SKILL_4; final int stacks = Math.min(comboCount / 10, user.getSkillStatValue(comboCriticalSkillId, SkillStat.x)); criticalRate += stacks * user.getSkillStatValue(comboCriticalSkillId, SkillStat.y); } criticalRate += user.getSecondaryStat().getItemCriR(); criticalRate += user.getPassiveSkillData().getCr(); if (SkillConstants.WILD_HUNTER_JAGUARS.contains(user.getSecondaryStat().getRidingVehicle())) { - criticalRate += user.getSkillStatValue(WildHunter.JAGUAR_RIDER, SkillStat.w); + criticalRate += user.getSkillStatValue(SkillId.WH1_JAGUAR_RIDER, SkillStat.w); } if (JobConstants.isEvanJob(user.getJob())) { - criticalRate += user.getSkillStatValue(Evan.CRITICAL_MAGIC, SkillStat.prop); + criticalRate += user.getSkillStatValue(SkillId.EVAN6_CRITICAL_MAGIC, SkillStat.prop); } return criticalRate; } - private static int getCriticalSkillId(User user, Attack attack) { + private static SkillId getCriticalSkillId(User user, Attack attack) { // get_critical_skill_level if (attack.getAction() == ActionType.ASSASSINATIONS.getValue()) { - return Thief.ASSASSINATE; + return SkillId.SHADOWER_ASSASSINATE; } if (JobConstants.isResistanceJob(user.getJob())) { - return Citizen.DEADLY_CRITS; + return SkillId.CITIZEN_DEADLY_CRITS; } final Item weapon = user.getInventoryManager().getEquipped().getItem(BodyPart.WEAPON.getValue()); if (weapon == null) { - return 0; + return SkillId.NONE; } switch (WeaponType.getByItemId(weapon.getItemId())) { case BOW, CROSSBOW -> { if (!attack.isShootAttack()) { - return 0; + return SkillId.NONE; } if (JobConstants.isCygnusJob(user.getJob())) { - return WindArcher.CRITICAL_SHOT; + return SkillId.WA1_CRITICAL_SHOT; } else { - return Bowman.CRITICAL_SHOT; + return SkillId.BOWMAN_CRITICAL_SHOT; } } case THROWINGGLOVE -> { if (!attack.isShootAttack()) { - return 0; + return SkillId.NONE; } if (JobConstants.isCygnusJob(user.getJob())) { - return NightWalker.CRITICAL_THROW; + return SkillId.NW2_CRITICAL_THROW; } else { - return Thief.CRITICAL_THROW; + return SkillId.ASSASSIN_CRITICAL_THROW; } } case KNUCKLE -> { - return Pirate.CRITICAL_PUNCH; + return SkillId.TB3_CRITICAL_PUNCH; } } - return 0; + return SkillId.NONE; } @@ -463,7 +464,7 @@ public static int getPad(User user) { // nComboAbilityBuff final int comboAbilityBuff = ss.getOption(CharacterTemporaryStat.ComboAbilityBuff).nOption; if (comboAbilityBuff != 0) { - final int comboSkillId = SkillConstants.getComboAbilitySkill(user.getJob()); // tutorial skill? + final SkillId comboSkillId = SkillConstants.getComboAbilitySkill(user.getJob()); // tutorial skill? final int maxStacks = user.getSkillStatValue(comboSkillId, SkillStat.x); final int stacks = Math.max(comboAbilityBuff / 10, maxStacks); pad += stacks * user.getSkillStatValue(comboSkillId, SkillStat.y); @@ -487,7 +488,7 @@ public static int getMad(User user) { // nMAD + incMAD + nPsdMADX int mad = ss.getMad() + ss.getOption(CharacterTemporaryStat.MAD).nOption + psd.getMadX(); // Apply madR - final int dragonFury = Evan.isDragonFury(user) ? user.getSkillStatValue(Evan.DRAGON_FURY, SkillStat.damage) : 0; + final int dragonFury = Evan.isDragonFury(user) ? user.getSkillStatValue(SkillId.DK_DRAGON_FURY, SkillStat.damage) : 0; final int statMadR = ss.getOption(CharacterTemporaryStat.MaxLevelBuff).nOption + ss.getOption(CharacterTemporaryStat.DarkAura).nOption + ss.getOption(CharacterTemporaryStat.SwallowAttackDamage).nOption + @@ -574,103 +575,103 @@ public static int getWeaponMastery(User user, WeaponType weaponType) { // get_weapon_mastery switch (weaponType) { case OH_SWORD, TH_SWORD -> { - int mastery = getMasteryFromSkill(user, Warrior.WEAPON_MASTERY_HERO); + int mastery = getMasteryFromSkill(user, SkillId.FIGHTER_WEAPON_MASTERY); if (mastery > 0) { return mastery; } - mastery = getMasteryFromSkill(user, Warrior.WEAPON_MASTERY_PALADIN); + mastery = getMasteryFromSkill(user, SkillId.PAGE_WEAPON_MASTERY); if (mastery > 0) { if (user.getSecondaryStat().hasOption(CharacterTemporaryStat.WeaponCharge)) { - final int masteryFromCharge = getMasteryFromSkill(user, Warrior.ADVANCED_CHARGE); + final int masteryFromCharge = getMasteryFromSkill(user, SkillId.PALADIN_ADVANCED_CHARGE); if (masteryFromCharge > 0) { return masteryFromCharge; } } return mastery; } - return getMasteryFromSkill(user, DawnWarrior.SWORD_MASTERY); + return getMasteryFromSkill(user, SkillId.DW2_SWORD_MASTERY); } case OH_AXE, TH_AXE -> { - return getMasteryFromSkill(user, Warrior.WEAPON_MASTERY_HERO); + return getMasteryFromSkill(user, SkillId.FIGHTER_WEAPON_MASTERY); } case OH_MACE, TH_MACE -> { - return getMasteryFromSkill(user, Warrior.WEAPON_MASTERY_PALADIN); + return getMasteryFromSkill(user, SkillId.PAGE_WEAPON_MASTERY); } case DAGGER -> { final Item shield = user.getInventoryManager().getEquipped().getItem(BodyPart.SHIELD.getValue()); if (shield != null && WeaponType.getByItemId(shield.getItemId()) == WeaponType.SUB_DAGGER) { - return getMasteryFromSkill(user, Thief.KATARA_MASTERY); + return getMasteryFromSkill(user, SkillId.DB1_KATARA_MASTERY); } else { - return getMasteryFromSkill(user, Thief.DAGGER_MASTERY); + return getMasteryFromSkill(user, SkillId.BANDIT_DAGGER_MASTERY); } } case WAND, STAFF -> { // get_magic_mastery if (JobConstants.isEvanJob(user.getJob())) { - return getMasteryFromSkill(user, Evan.MAGIC_MASTERY, Evan.SPELL_MASTERY); + return getMasteryFromSkill(user, SkillId.EVAN9_MAGIC_MASTERY, SkillId.EVAN4_SPELL_MASTERY); } else if (JobConstants.isBattleMageJob(user.getJob())) { - return getMasteryFromSkill(user, BattleMage.STAFF_MASTERY); + return getMasteryFromSkill(user, SkillId.STAFF_MASTERY); } else if (JobConstants.isBlazeWizardJob(user.getJob())) { - return getMasteryFromSkill(user, BlazeWizard.SPELL_MASTERY); + return getMasteryFromSkill(user, SkillId.BW2_SPELL_MASTERY); } else if (JobConstants.isFirePoisonJob(user.getJob())) { - return getMasteryFromSkill(user, Magician.SPELL_MASTERY_FP); + return getMasteryFromSkill(user, SkillId.FP1_SPELL_MASTERY); } else if (JobConstants.isIceLightningJob(user.getJob())) { - return getMasteryFromSkill(user, Magician.SPELL_MASTERY_IL); + return getMasteryFromSkill(user, SkillId.IL1_SPELL_MASTERY); } else if (JobConstants.isBishopJob(user.getJob())) { - return getMasteryFromSkill(user, Magician.SPELL_MASTERY_BISH); + return getMasteryFromSkill(user, SkillId.CLERIC_SPELL_MASTERY); } } case SPEAR -> { - return getMasteryFromSkill(user, Warrior.WEAPON_MASTERY_DRK) + user.getSecondaryStat().getOption(CharacterTemporaryStat.Beholder).nOption; + return getMasteryFromSkill(user, SkillId.SPEARNMAN_WEAPON_MASTERY) + user.getSecondaryStat().getOption(CharacterTemporaryStat.Beholder).nOption; } case POLEARM -> { if (JobConstants.isAranJob(user.getJob())) { - return getMasteryFromSkill(user, Aran.HIGH_MASTERY, Aran.POLEARM_MASTERY); + return getMasteryFromSkill(user, SkillId.ARAN4_HIGH_MASTERY, SkillId.ARAN2_POLEARM_MASTERY); } else { - return getMasteryFromSkill(user, Warrior.WEAPON_MASTERY_DRK) + user.getSecondaryStat().getOption(CharacterTemporaryStat.Beholder).nOption; + return getMasteryFromSkill(user, SkillId.SPEARNMAN_WEAPON_MASTERY) + user.getSecondaryStat().getOption(CharacterTemporaryStat.Beholder).nOption; } } case BOW -> { if (JobConstants.isCygnusJob(user.getJob())) { - return getMasteryFromSkill(user, WindArcher.BOW_EXPERT, WindArcher.BOW_MASTERY); + return getMasteryFromSkill(user, SkillId.WA3_BOW_EXPERT, SkillId.WA2_BOW_MASTERY); } else { - return getMasteryFromSkill(user, Bowman.BOW_EXPERT, Bowman.BOW_MASTERY); + return getMasteryFromSkill(user, SkillId.BOWMASTER_BOW_EXPERT, SkillId.HUNTER_BOW_MASTERY); } } case CROSSBOW -> { if (JobConstants.isWildHunterJob(user.getJob())) { - return getMasteryFromSkill(user, WildHunter.CROSSBOW_EXPERT, WildHunter.CROSSBOW_MASTERY); + return getMasteryFromSkill(user, SkillId.WH4_CROSSBOW_EXPERT, SkillId.WH2_CROSSBOW_MASTERY); } else { - return getMasteryFromSkill(user, Bowman.MARKSMAN_BOOST, Bowman.CROSSBOW_MASTERY); + return getMasteryFromSkill(user, SkillId.MARKSMAN_MARKSMAN_BOOST, SkillId.CROSSBOWMAN_CROSSBOW_MASTERY); } } case THROWINGGLOVE -> { if (JobConstants.isCygnusJob(user.getJob())) { - return getMasteryFromSkill(user, NightWalker.CLAW_MASTERY); + return getMasteryFromSkill(user, SkillId.NW2_CLAW_MASTERY); } else { - return getMasteryFromSkill(user, Thief.CLAW_MASTERY); + return getMasteryFromSkill(user, SkillId.ASSASSIN_CLAW_MASTERY); } } case KNUCKLE -> { if (JobConstants.isCygnusJob(user.getJob())) { - return getMasteryFromSkill(user, ThunderBreaker.KNUCKLE_MASTERY); + return getMasteryFromSkill(user, SkillId.TB2_KNUCKLE_MASTERY); } else { - return getMasteryFromSkill(user, Pirate.KNUCKLE_MASTERY); + return getMasteryFromSkill(user, SkillId.BRAWLER_KNUCKLE_MASTERY); } } case GUN -> { if (JobConstants.isMechanicJob(user.getJob())) { - return getMasteryFromSkill(user, Mechanic.EXTREME_MECH, Mechanic.MECHANIC_MASTERY); + return getMasteryFromSkill(user, SkillId.MECH4_EXTREME_MECH, SkillId.MECH2_MECHANIC_MASTERY); } else { - return getMasteryFromSkill(user, Pirate.GUN_MASTERY); + return getMasteryFromSkill(user, SkillId.GUNSLINGER_GUN_MASTERY); } } } return 0; } - private static int getMasteryFromSkill(User user, int... skillIds) { - for (int skillId : skillIds) { + private static int getMasteryFromSkill(User user, SkillId... skillIds) { + for (SkillId skillId : skillIds) { final int mastery = user.getSkillStatValue(skillId, SkillStat.mastery); if (mastery > 0) { return mastery; @@ -700,14 +701,14 @@ public static double getDamageAdjustedByElemAttr(User user, double damage, Skill // get_damage_adjusted_by_elemAttr final double adjust = 1.0 - user.getSecondaryStat().getOption(CharacterTemporaryStat.ElementalReset).nOption / 100.0; final double boost = 0.0; // only available through item info.addition.elemBoost, ignore - final int skillId = si.getSkillId(); - if (skillId == Bowman.INFERNO || skillId == Bowman.BLIZZARD) { + final SkillId skillId = si.getSkillId(); + if (skillId == SkillId.RANGER_INFERNO || skillId == SkillId.SNIPER_BLIZZARD) { return getDamageAdjustedByElemAttr(damage, damagedElemAttr.getOrDefault(si.getElemAttr(), DamagedAttribute.NONE), si.getValue(SkillStat.x, slv) / 100.0, boost); - } else if (skillId == Magician.ELEMENT_COMPOSITION_FP) { + } else if (skillId == SkillId.FP2_ELEMENT_COMPOSITION) { final double half = damage * 0.5; // only poison attr gets boost return getDamageAdjustedByElemAttr(half, damagedElemAttr.getOrDefault(ElementAttribute.FIRE, DamagedAttribute.NONE), 1.0, 0.0) + getDamageAdjustedByElemAttr(half, damagedElemAttr.getOrDefault(ElementAttribute.POISON, DamagedAttribute.NONE), 1.0, boost); - } else if (skillId == Magician.ELEMENT_COMPOSITION_IL) { + } else if (skillId == SkillId.IL2_ELEMENT_COMPOSITION) { final double half = damage * 0.5; // only light attr gets boost return getDamageAdjustedByElemAttr(half, damagedElemAttr.getOrDefault(ElementAttribute.ICE, DamagedAttribute.NONE), 1.0, 0.0) + getDamageAdjustedByElemAttr(half, damagedElemAttr.getOrDefault(ElementAttribute.LIGHT, DamagedAttribute.NONE), 1.0, boost); @@ -720,7 +721,7 @@ public static double getDamageAdjustedByChargedElemAttr(User user, double damage if (!user.getSecondaryStat().hasOption(CharacterTemporaryStat.WeaponCharge)) { return damage; } - final int skillId = user.getSecondaryStat().getOption(CharacterTemporaryStat.WeaponCharge).rOption; + final SkillId skillId = user.getSecondaryStat().getOption(CharacterTemporaryStat.WeaponCharge).getSkillId(); final ElementAttribute elemAttr = SkillConstants.getElementByWeaponChargeSkill(skillId); if (elemAttr == ElementAttribute.PHYSICAL) { return damage; @@ -735,7 +736,7 @@ public static double getDamageAdjustedByAssistChargedElemAttr(User user, double if (!user.getSecondaryStat().hasOption(CharacterTemporaryStat.AssistCharge)) { return damage; } - final int skillId = user.getSecondaryStat().getOption(CharacterTemporaryStat.AssistCharge).rOption; + final SkillId skillId = user.getSecondaryStat().getOption(CharacterTemporaryStat.AssistCharge).getSkillId(); final ElementAttribute elemAttr = SkillConstants.getElementByWeaponChargeSkill(skillId); if (elemAttr == ElementAttribute.PHYSICAL) { return damage; diff --git a/src/main/java/kinoko/world/user/stat/SecondaryStat.java b/src/main/java/kinoko/world/user/stat/SecondaryStat.java index 3c13319c..4ec705ef 100644 --- a/src/main/java/kinoko/world/user/stat/SecondaryStat.java +++ b/src/main/java/kinoko/world/user/stat/SecondaryStat.java @@ -1,5 +1,6 @@ package kinoko.world.user.stat; +import kinoko.meta.SkillId; import kinoko.provider.EtcProvider; import kinoko.provider.ItemProvider; import kinoko.provider.SkillProvider; @@ -214,8 +215,8 @@ public void encodeForRemote(BitFlag flag, OutPacket outP outPacket.encodeInt(getOption(cts).nOption); } case WeaponCharge, Stun, Darkness, Seal, Weakness, Curse, ShadowPartner, Attract, BanMap, Barrier, - DojangShield, ReverseInput, RepeatEffect, StopPortion, StopMotion, Fear, Frozen, - SuddenDeath, FinalCut, Mechanic, DarkAura, BlueAura, YellowAura -> { + DojangShield, ReverseInput, RepeatEffect, StopPortion, StopMotion, Fear, Frozen, + SuddenDeath, FinalCut, Mechanic, DarkAura, BlueAura, YellowAura -> { outPacket.encodeInt(getOption(cts).rOption); } case Poison -> { @@ -325,7 +326,7 @@ public void setFrom(BasicStat bs, ForcedStat fs, SecondaryStat ss, SkillManager } // Passive skills - for (int skillId : SkillConstants.SECONDARY_STAT_SKILLS) { + for (SkillId skillId : SkillConstants.SECONDARY_STAT_SKILLS) { final Optional skillInfoResult = SkillProvider.getSkillInfoById(skillId); if (skillInfoResult.isEmpty()) { continue; @@ -336,15 +337,17 @@ public void setFrom(BasicStat bs, ForcedStat fs, SecondaryStat ss, SkillManager continue; } switch (skillId) { - case Thief.NIMBLE_BODY, NightWalker.NIMBLE_BODY, Pirate.BULLET_TIME, ThunderBreaker.QUICK_MOTION -> { + case SkillId.THIEF_NIMBLE_BODY, SkillId.NW1_NIMBLE_BODY, SkillId.PIRATE_BULLET_TIME, + SkillId.TB1_QUICK_MOTION -> { this.acc += si.getValue(SkillStat.x, slv); this.eva += si.getValue(SkillStat.y, slv); } - case Evan.DRAGON_SOUL -> { + case SkillId.EVAN1_DRAGON_SOUL -> { this.mad += si.getValue(SkillStat.mad, slv); } - case Beginner.BLESSING_OF_THE_FAIRY, Noblesse.BLESSING_OF_THE_FAIRY, Citizen.BLESSING_OF_THE_FAIRY, - Aran.BLESSING_OF_THE_FAIRY, Evan.BLESSING_OF_THE_FAIRY -> { + case SkillId.BEGINNER_BLESSING_OF_THE_FAIRY, SkillId.NOBLESSE_BLESSING_OF_THE_FAIRY, + SkillId.CITIZEN_BLESSING_OF_THE_FAIRY, + SkillId.LEGEND_BLESSING_OF_THE_FAIRY, SkillId.EVANBEGINNER_BLESSING_OF_THE_FAIRY -> { this.pad += si.getValue(SkillStat.x, slv); this.mad += si.getValue(SkillStat.y, slv); this.acc += si.getValue(SkillStat.z, slv); @@ -356,7 +359,7 @@ public void setFrom(BasicStat bs, ForcedStat fs, SecondaryStat ss, SkillManager // Combo Ability - description says Weapon/Magic ATT, but should be PDD, MDD final int comboAbilityBuff = ss.getOption(CharacterTemporaryStat.ComboAbilityBuff).nOption; if (comboAbilityBuff != 0) { - final int comboSkillId = SkillConstants.getComboAbilitySkill(bs.getJob()); + final SkillId comboSkillId = SkillConstants.getComboAbilitySkill(bs.getJob()); final Optional skillInfoResult = SkillProvider.getSkillInfoById(comboSkillId); if (skillInfoResult.isPresent()) { final SkillInfo si = skillInfoResult.get(); @@ -371,9 +374,9 @@ public void setFrom(BasicStat bs, ForcedStat fs, SecondaryStat ss, SkillManager // Jaguar Rider if (SkillConstants.WILD_HUNTER_JAGUARS.contains(getRidingVehicle())) { - final int slv = SkillManager.getSkillLevel(ss, sm, WildHunter.JAGUAR_RIDER); + final int slv = SkillManager.getSkillLevel(ss, sm, SkillId.WH1_JAGUAR_RIDER); if (slv > 0) { - SkillProvider.getSkillInfoById(WildHunter.JAGUAR_RIDER).ifPresent((si) -> { + SkillProvider.getSkillInfoById(SkillId.WH1_JAGUAR_RIDER).ifPresent((si) -> { this.eva += si.getValue(SkillStat.y, slv); }); } @@ -383,103 +386,104 @@ public void setFrom(BasicStat bs, ForcedStat fs, SecondaryStat ss, SkillManager final WeaponType wt = WeaponType.getByItemId(weapon != null ? weapon.getItemId() : 0); switch (wt) { case OH_SWORD, TH_SWORD -> { - getStatFromSkill(ss, sm, Warrior.WEAPON_MASTERY_HERO, Warrior.WEAPON_MASTERY_PALADIN, DawnWarrior.SWORD_MASTERY); + getStatFromSkill(ss, sm, SkillId.FIGHTER_WEAPON_MASTERY, SkillId.PAGE_WEAPON_MASTERY, SkillId.DW2_SWORD_MASTERY); } case OH_AXE, TH_AXE -> { - getStatFromSkill(ss, sm, Warrior.WEAPON_MASTERY_HERO); + getStatFromSkill(ss, sm, SkillId.FIGHTER_WEAPON_MASTERY); } case OH_MACE, TH_MACE -> { - getStatFromSkill(ss, sm, Warrior.WEAPON_MASTERY_PALADIN); + getStatFromSkill(ss, sm, SkillId.PAGE_WEAPON_MASTERY); } case DAGGER -> { final Item shield = realEquip.get(BodyPart.SHIELD.getValue()); if (shield != null && WeaponType.getByItemId(shield.getItemId()) == WeaponType.SUB_DAGGER) { - getStatFromSkill(ss, sm, Thief.KATARA_MASTERY); + getStatFromSkill(ss, sm, SkillId.DB1_KATARA_MASTERY); } else { - getStatFromSkill(ss, sm, Thief.DAGGER_MASTERY); + getStatFromSkill(ss, sm, SkillId.BANDIT_DAGGER_MASTERY); } } case SPEAR -> { - getStatFromSkill(ss, sm, Warrior.WEAPON_MASTERY_DRK); + getStatFromSkill(ss, sm, SkillId.SPEARNMAN_WEAPON_MASTERY); } case POLEARM -> { if (JobConstants.isAranJob(bs.getJob())) { - getStatFromSkill(ss, sm, Aran.POLEARM_MASTERY); - getStatFromSkill(ss, sm, Aran.HIGH_MASTERY); + getStatFromSkill(ss, sm, SkillId.ARAN2_POLEARM_MASTERY); + getStatFromSkill(ss, sm, SkillId.ARAN4_HIGH_MASTERY); } else { - getStatFromSkill(ss, sm, Warrior.WEAPON_BOOSTER_DRK); + getStatFromSkill(ss, sm, SkillId.SPEARNMAN_WEAPON_MASTERY); } } case BOW -> { if (JobConstants.isCygnusJob(bs.getJob())) { - getStatFromSkill(ss, sm, WindArcher.BOW_MASTERY); - getStatFromSkill(ss, sm, WindArcher.BOW_EXPERT); + getStatFromSkill(ss, sm, SkillId.WA2_BOW_MASTERY); + getStatFromSkill(ss, sm, SkillId.WA3_BOW_EXPERT); } else { - getStatFromSkill(ss, sm, Bowman.BOW_MASTERY); - getStatFromSkill(ss, sm, Bowman.BOW_EXPERT); + getStatFromSkill(ss, sm, SkillId.HUNTER_BOW_MASTERY); + getStatFromSkill(ss, sm, SkillId.BOWMASTER_BOW_EXPERT); } } case CROSSBOW -> { if (JobConstants.isWildHunterJob(bs.getJob())) { - getStatFromSkill(ss, sm, WildHunter.CROSSBOW_MASTERY); - getStatFromSkill(ss, sm, WildHunter.CROSSBOW_EXPERT); + getStatFromSkill(ss, sm, SkillId.WH2_CROSSBOW_MASTERY); + getStatFromSkill(ss, sm, SkillId.WH4_CROSSBOW_EXPERT); } else { - getStatFromSkill(ss, sm, Bowman.CROSSBOW_MASTERY); - getStatFromSkill(ss, sm, Bowman.MARKSMAN_BOOST); + getStatFromSkill(ss, sm, SkillId.CROSSBOWMAN_CROSSBOW_MASTERY); + getStatFromSkill(ss, sm, SkillId.MARKSMAN_MARKSMAN_BOOST); } } case THROWINGGLOVE -> { if (JobConstants.isCygnusJob(bs.getJob())) { - getStatFromSkill(ss, sm, NightWalker.CLAW_MASTERY); + getStatFromSkill(ss, sm, SkillId.NW2_CLAW_MASTERY); } else { - getStatFromSkill(ss, sm, Thief.CLAW_MASTERY); + getStatFromSkill(ss, sm, SkillId.ASSASSIN_CLAW_MASTERY); } } case KNUCKLE -> { if (JobConstants.isCygnusJob(bs.getJob())) { - getStatFromSkill(ss, sm, ThunderBreaker.KNUCKLE_MASTERY); + getStatFromSkill(ss, sm, SkillId.TB2_KNUCKLE_MASTERY); } else { - getStatFromSkill(ss, sm, Pirate.KNUCKLE_MASTERY); + getStatFromSkill(ss, sm, SkillId.BRAWLER_KNUCKLE_MASTERY); } } case GUN -> { if (JobConstants.isMechanicJob(bs.getJob())) { - getStatFromSkill(ss, sm, Mechanic.EXTREME_MECH, Mechanic.MECHANIC_MASTERY); + getStatFromSkill(ss, sm, SkillId.MECH4_EXTREME_MECH, SkillId.MECH2_MECHANIC_MASTERY); } else { - getStatFromSkill(ss, sm, Pirate.GUN_MASTERY); + getStatFromSkill(ss, sm, SkillId.GUNSLINGER_GUN_MASTERY); } } } // get_magic_mastery if (JobConstants.isEvanJob(bs.getJob())) { - getStatFromSkill(ss, sm, Evan.SPELL_MASTERY); - getStatFromSkill(ss, sm, Evan.MAGIC_MASTERY); + getStatFromSkill(ss, sm, SkillId.EVAN4_SPELL_MASTERY); + getStatFromSkill(ss, sm, SkillId.EVAN9_MAGIC_MASTERY); } else if (JobConstants.isBattleMageJob(bs.getJob())) { - getStatFromSkill(ss, sm, BattleMage.STAFF_MASTERY); + getStatFromSkill(ss, sm, SkillId.STAFF_MASTERY); } else if (JobConstants.isBlazeWizardJob(bs.getJob())) { - getStatFromSkill(ss, sm, BlazeWizard.SPELL_MASTERY); + getStatFromSkill(ss, sm, SkillId.BW2_SPELL_MASTERY); } else if (JobConstants.isFirePoisonJob(bs.getJob())) { - getStatFromSkill(ss, sm, Magician.SPELL_MASTERY_FP); + getStatFromSkill(ss, sm, SkillId.FP1_SPELL_MASTERY); } else if (JobConstants.isIceLightningJob(bs.getJob())) { - getStatFromSkill(ss, sm, Magician.SPELL_MASTERY_IL); + getStatFromSkill(ss, sm, SkillId.IL1_SPELL_MASTERY); } else if (JobConstants.isBishopJob(bs.getJob())) { - getStatFromSkill(ss, sm, Magician.SPELL_MASTERY_BISH); + getStatFromSkill(ss, sm, SkillId.CLERIC_SPELL_MASTERY); } // get_increase_speed if (JobConstants.isBowmasterJob(bs.getJob())) { - getStatFromSkill(ss, sm, Bowman.THRUST_BM); + getStatFromSkill(ss, sm, SkillId.RANGER_THRUST); } else if (JobConstants.isMarksmanJob(bs.getJob())) { - getStatFromSkill(ss, sm, Bowman.THRUST_MM); + getStatFromSkill(ss, sm, SkillId.SNIPER_THRUST); } else if (JobConstants.isWindArcherJob(bs.getJob())) { - getStatFromSkill(ss, sm, WindArcher.THRUST); + getStatFromSkill(ss, sm, SkillId.WA2_THRUST); } if (hasOption(CharacterTemporaryStat.YellowAura)) { - final Optional yellowAuraResult = SkillProvider.getSkillInfoById(getOption(CharacterTemporaryStat.YellowAura).rOption); + final Optional yellowAuraResult = SkillProvider.getSkillInfoById(getOption(CharacterTemporaryStat.YellowAura).getSkillId()); yellowAuraResult.ifPresent((si) -> this.speed += si.getValue(SkillStat.x, getOption(CharacterTemporaryStat.YellowAura).nOption)); if (hasOption(CharacterTemporaryStat.SuperBody)) { - final Optional bodyBoostResult = SkillProvider.getSkillInfoById(BattleMage.BODY_BOOST_YELLOW_AURA); + //TODO BattleMage.BODY_BOOST_YELLOW_AURA + final Optional bodyBoostResult = SkillProvider.getSkillInfoById(SkillId.BODY_BOOST); bodyBoostResult.ifPresent((si) -> this.speed += si.getValue(SkillStat.x, getOption(CharacterTemporaryStat.SuperBody).nOption)); } } @@ -548,8 +552,8 @@ private void applyItemOption(int itemOptionId, int optionLevel) { } } - private void getStatFromSkill(SecondaryStat ss, SkillManager sm, int... skillIds) { - for (int skillId : skillIds) { + private void getStatFromSkill(SecondaryStat ss, SkillManager sm, SkillId... skillIds) { + for (SkillId skillId : skillIds) { final Optional skillInfoResult = SkillProvider.getSkillInfoById(skillId); if (skillInfoResult.isEmpty()) { continue; @@ -559,27 +563,28 @@ private void getStatFromSkill(SecondaryStat ss, SkillManager sm, int... skillIds if (slv == 0) { continue; } - switch (skillId) { + //TODO + /*switch (skillId) { case Warrior.WEAPON_MASTERY_HERO, Warrior.WEAPON_MASTERY_PALADIN, DawnWarrior.SWORD_MASTERY, - Thief.KATARA_MASTERY, Thief.DAGGER_MASTERY, Warrior.WEAPON_MASTERY_DRK, Aran.POLEARM_MASTERY, - WindArcher.BOW_MASTERY, Bowman.BOW_MASTERY, WildHunter.CROSSBOW_MASTERY, - Bowman.CROSSBOW_MASTERY, NightWalker.CLAW_MASTERY, Thief.CLAW_MASTERY, - ThunderBreaker.KNUCKLE_MASTERY, Pirate.KNUCKLE_MASTERY, Mechanic.EXTREME_MECH, - Mechanic.MECHANIC_MASTERY, Pirate.GUN_MASTERY -> { + Thief.KATARA_MASTERY, Thief.DAGGER_MASTERY, Warrior.WEAPON_MASTERY_DRK, Aran.POLEARM_MASTERY, + WindArcher.BOW_MASTERY, Bowman.BOW_MASTERY, WildHunter.CROSSBOW_MASTERY, + Bowman.CROSSBOW_MASTERY, NightWalker.CLAW_MASTERY, Thief.CLAW_MASTERY, + ThunderBreaker.KNUCKLE_MASTERY, Pirate.KNUCKLE_MASTERY, Mechanic.EXTREME_MECH, + Mechanic.MECHANIC_MASTERY, Pirate.GUN_MASTERY -> { this.acc += si.getValue(SkillStat.x, slv); } case Aran.HIGH_MASTERY, WindArcher.BOW_EXPERT, Bowman.BOW_EXPERT, WildHunter.CROSSBOW_EXPERT, - Bowman.MARKSMAN_BOOST -> { + Bowman.MARKSMAN_BOOST -> { this.pad += si.getValue(SkillStat.x, slv); } case Evan.SPELL_MASTERY, Evan.MAGIC_MASTERY, BattleMage.STAFF_MASTERY, BlazeWizard.SPELL_MASTERY, - Magician.SPELL_MASTERY_BISH, Magician.SPELL_MASTERY_IL, Magician.SPELL_MASTERY_FP -> { + Magician.SPELL_MASTERY_BISH, Magician.SPELL_MASTERY_IL, Magician.SPELL_MASTERY_FP -> { this.mad += si.getValue(SkillStat.x, slv); } case Bowman.THRUST_BM, Bowman.THRUST_MM, WindArcher.THRUST -> { this.speed += si.getValue(SkillStat.speed, slv); } - } + }*/ break; } } diff --git a/src/main/java/kinoko/world/user/stat/TemporaryStatOption.java b/src/main/java/kinoko/world/user/stat/TemporaryStatOption.java index c1e5afe8..ad57dbc2 100644 --- a/src/main/java/kinoko/world/user/stat/TemporaryStatOption.java +++ b/src/main/java/kinoko/world/user/stat/TemporaryStatOption.java @@ -1,5 +1,6 @@ package kinoko.world.user.stat; +import kinoko.meta.SkillId; import kinoko.server.packet.OutPacket; import kinoko.util.Encodable; @@ -45,6 +46,12 @@ public TemporaryStatOption update(int newNOption) { ); } + public final SkillId getSkillId() { + //TODO set to none if fails for items and such + return SkillId.fromValue(this.rOption); + } + + public final DiceInfo getDiceInfo() { return diceInfo; } @@ -68,6 +75,10 @@ public static TemporaryStatOption of(int nOption, int rOption, int tOption) { return new TemporaryStatOption(nOption, rOption, tOption); } + public static TemporaryStatOption of(int nOption, SkillId rOption, int tOption) { + return TemporaryStatOption.of(nOption, rOption.getId(), tOption); + } + public static TemporaryStatOption ofMobSkill(int nOption, int skillId, int slv, int tOption) { final int rOption = skillId | (slv << 16); return new TemporaryStatOption(nOption, rOption, tOption);