public static int get_weapon_mastery(Character cd, int nWeaponItemID, int nAttackType, int nSkillID, out int pnACCInc, out int pnPADInc) { pnACCInc = 0; pnPADInc = 0; var mastery = 0; // TODO clean this function up -> ugly af :( switch ((WeaponType)ItemConstants.get_weapon_type(nWeaponItemID)) { case WeaponType.WT_OH_SWORD: case WeaponType.WT_TH_SWORD: if (nAttackType > 0) { if (nSkillID != (int)Skills.SOULMASTER_SOUL_BLADE) { return(mastery); } if (nAttackType != 1) { return(mastery); } } mastery = get_mastery_from_skill(cd, Skills.FIGHTER_WEAPON_MASTERY, out pnACCInc); if (mastery == 0) { mastery = get_mastery_from_skill(cd, Skills.PAGE_WEAPON_MASTERY, out pnACCInc); if (mastery != 0) { if (cd.Stats.SecondaryStats.rWeaponCharge != 0) { var tempmastery = get_mastery_from_skill(cd, Skills.PALADIN_ADVANCED_CHARGE, out var pnSubACCInc); if (tempmastery > 0) { pnACCInc = pnSubACCInc; mastery = tempmastery; } } } else { mastery = get_mastery_from_skill(cd, Skills.SOULMASTER_SWORD_MASTERY, out pnACCInc); } } break; case WeaponType.WT_OH_AXE: case WeaponType.WT_TH_AXE: if (nAttackType != 0) { return(0); } mastery = get_mastery_from_skill(cd, Skills.FIGHTER_WEAPON_MASTERY, out pnACCInc); break; case WeaponType.WT_OH_MACE: case WeaponType.WT_TH_MACE: if (nAttackType != 0) { return(0); } mastery = get_mastery_from_skill(cd, Skills.PAGE_WEAPON_MASTERY, out pnACCInc); if (cd.Stats.SecondaryStats.rWeaponCharge != 0) { var tempmastery = get_mastery_from_skill(cd, Skills.PALADIN_ADVANCED_CHARGE, out var pnSubACCInc); if (tempmastery > 0) { pnACCInc = pnSubACCInc; mastery = tempmastery; } } break; case WeaponType.WT_DAGGER: if (nAttackType != 0) { return(0); } var pSubDaggerItemSlot = cd.EquippedInventoryNormal.Get((short)BodyPart.BP_SHIELD); var bSubDagger = ItemConstants.get_weapon_type(pSubDaggerItemSlot.nItemID) == (int)WeaponType.WT_SUB_DAGGER; mastery = get_mastery_from_skill(cd, bSubDagger ? Skills.DUAL1_DUAL_MASTERY : Skills.THIEF_DAGGER_MASTERY, out pnACCInc); break; case WeaponType.WT_SPEAR: if (nAttackType != 0) { return(0); } mastery = get_mastery_from_skill(cd, Skills.SPEARMAN_WEAPON_MASTERY, out pnACCInc); break; case WeaponType.WT_POLEARM: if (nAttackType != 0 && (nSkillID != (int)Skills.ARAN_COMBO_SMASH && nSkillID != (int)Skills.ARAN_COMBO_FENRIR && nSkillID != (int)Skills.ARAN_COMBO_TEMPEST || nAttackType != 1)) { return(mastery); } if (JobLogic.isAran(cd.Stats.nSubJob)) { mastery = get_mastery_from_skill(cd, Skills.ARAN_POLEARM_MASTERY, out pnACCInc); var highMastery = get_mastery_from_skill(cd, Skills.ARAN_HIGH_MASTERY, out pnPADInc); if (highMastery != 0) { mastery = highMastery; } } else { mastery = get_mastery_from_skill(cd, Skills.SPEARMAN_WEAPON_MASTERY, out pnACCInc); if (cd.Stats.SecondaryStats.rBeholder != 0) { mastery += get_mastery_from_skill(cd, Skills.DARKKNIGHT_BEHOLDER, out _); } } break; case WeaponType.WT_BOW: if (nAttackType != 1) { return(mastery); } int bowexpert; if (JobLogic.IsKOC(cd.Stats.nJob)) { mastery = get_mastery_from_skill(cd, Skills.WINDBREAKER_BOW_MASTERY, out pnACCInc); bowexpert = get_mastery_from_skill(cd, Skills.WINDBREAKER_BOW_EXPERT, out pnPADInc); } else { mastery = get_mastery_from_skill(cd, Skills.HUNTER_BOW_MASTERY, out pnACCInc); bowexpert = get_mastery_from_skill(cd, Skills.BOWMASTER_BOW_EXPERT, out pnPADInc); } if (bowexpert != 0) { mastery = bowexpert; } break; case WeaponType.WT_CROSSBOW: var bWildhunterJob = JobLogic.IsWildhunterJob(cd.Stats.nJob); if (nAttackType != 1 && (!bWildhunterJob || nAttackType != 0)) { return(mastery); } int xbowexpert; if (bWildhunterJob) { mastery = get_mastery_from_skill(cd, Skills.WILDHUNTER_CROSSBOW_MASTERY, out pnACCInc); xbowexpert = get_mastery_from_skill(cd, Skills.WILDHUNTER_CROSSBOW_EXPERT, out pnPADInc); } else { mastery = get_mastery_from_skill(cd, Skills.CROSSBOWMAN_CROSSBOW_MASTERY, out pnACCInc); xbowexpert = get_mastery_from_skill(cd, Skills.CROSSBOWMASTER_CROSSBOW_EXPERT, out pnPADInc); } if (xbowexpert != 0) { mastery = xbowexpert; } break; case WeaponType.WT_THROWINGGLOVE: if (nAttackType != 1 && (nSkillID != (int)Skills.NIGHTWALKER_POISON_BOMB || nAttackType != 0)) { return(mastery); } if (JobLogic.IsKOC(cd.Stats.nJob)) { mastery = get_mastery_from_skill(cd, Skills.NIGHTWALKER_JAVELIN_MASTERY, out pnACCInc); } else { mastery = get_mastery_from_skill(cd, Skills.ASSASSIN_JAVELIN_MASTERY, out pnACCInc); } break; case WeaponType.WT_KNUCKLE: if (nAttackType != 0 && (nSkillID != (int)Skills.VIPER_ENERGY_ORB && nSkillID != (int)Skills.STRIKER_SHARK_WAVE || nAttackType != 1)) { return(mastery); } if (JobLogic.IsKOC(cd.Stats.nJob)) { mastery = get_mastery_from_skill(cd, Skills.STRIKER_KNUCKLE_MASTERY, out pnACCInc); } else { mastery = get_mastery_from_skill(cd, Skills.INFIGHTER_KNUCKLE_MASTERY, out pnACCInc); } break; case WeaponType.WT_GUN: if (nAttackType != 1 && (nSkillID != (int)Skills.CAPTAIN_AIR_STRIKE || nAttackType != 0)) { return(mastery); } if (JobLogic.is_mechanic_job(cd.Stats.nJob)) { mastery = get_mastery_from_skill(cd, Skills.MECHANIC_HN07_UPGRADE, out pnACCInc); if (mastery == 0) { mastery = get_mastery_from_skill(cd, Skills.MECHANIC_HN07, out pnACCInc); } } else { mastery = get_mastery_from_skill(cd, Skills.GUNSLINGER_GUN_MASTERY, out pnACCInc); } break; } return(mastery); }
public static MapleAttack ParseShoot(CInPacket p, Character c) { MapleAttack ret = new MapleAttack(); p.Skip(8); // -1 var tByte1 = p.Decode1(); ret.nDamagePerMob = (byte)(tByte1 & 0xF); ret.nMobCount = (byte)((tByte1 >> 4) & 0xF); //c.SendMessage("Damage per mob " + ret.nDamagePerMob); //c.SendMessage("Mob count " + ret.nMobCount); p.Skip(8); //-1 ret.nSkillID = p.Decode4(); //2017 ret.ValidateSkill(c); if (!ret.bValidAttack) { return(ret); } var skillTemplate = MasterManager.SkillTemplates[ret.nSkillID]; var nCombatOrders = p.Decode1(); // nCombatOrders p.Skip(4); // get_rand(pDrInfo.dr0, 0); p.Skip(4); // CCrc32::GetCrc32(pData, 4u, n, 0, 0); p.Skip(8); ret.tKeyDown = skillTemplate?.is_keydown_skill ?? false?p.Decode4() : -1; ret.nOption = p.Decode1(); //COutPacket::Encode1(&v498, (bSpark << 7) | (bSpiritJavelin << 6) | 8 * bShadowPartner | 4 * bMortalBlow | 2 * bSoulArrow); var bSpark = (ret.nOption & 0x80) != 0; var bSpiritJavelin = (ret.nOption & 0x40) != 0; var bSerial = (ret.nOption & 0x20) != 0; var bShadowPartner = (ret.nOption & 0x8) != 0; var bMortalBlow = (ret.nOption & 0x4) != 0; var bSoulArrow = (ret.nOption & 0x2) != 0; ret.bNextShootExJablin = p.Decode1() > 0; //v339->m_bNextShootExJablin && CUserLocal::CheckApplyExJablin(v339, pSkill, nAttackAction); ret.nActionAndDir = p.Decode2(); ret.bLeft = (ret.nActionAndDir >> 15) & 1; ret.nAction = ret.nActionAndDir & 0x7FFF; //nAttackAction p.Skip(4); //CRC i think ret.nAttackActionType = p.Decode1(); //nAttackSpeed | 16 * nReduceCount ret.nAttackSpeed = p.Decode1(); ret.tAttackTime = p.Decode4(); p.Skip(4); //nPhase ret.nBulletItemPos = p.Decode2(); ret.nBulletCashItemPos = p.Decode2(); var nShootRange0a = p.Decode1(); // nSLV (BMS) ret.bNoItemConsume = skillTemplate?.is_shoot_skill_not_consuming_bullet ?? false; if (!ret.bNoItemConsume) { if (JobLogic.is_mechanic_job(c.Stats.nJob)) { ret.bNoItemConsume = true; } else if (bSoulArrow) { ret.bNoItemConsume = c.Buffs[(int)Skills.HUNTER_SOUL_ARROW_BOW] != null || c.Buffs[(int)Skills.CROSSBOWMAN_SOUL_ARROW_CROSSBOW] != null || c.Buffs[(int)Skills.WINDBREAKER_SOUL_ARROW_BOW] != null || c.Buffs[(int)Skills.WILDHUNTER_SOUL_ARROW_CROSSBOW] != null; } else if (bSpiritJavelin) { if (ret.bNextShootExJablin) { ret.bNextShootExJablin = false; } else { ret.nSpiritJavelinItemID = p.Decode4(); var nBulletType = (ret.nSpiritJavelinItemID % 10000) + 1; c.Buffs.TryGetValue((int)Skills.NIGHTLORD_SPIRIT_JAVELIN, out AbstractBuff secondaryStat_nSpiritJavelin); if (c.InventoryConsume.Get(ret.nBulletItemPos)?.nItemID != ret.nSpiritJavelinItemID) { c.Buffs.Remove((int)Skills.NIGHTLORD_SPIRIT_JAVELIN); // they have to use the same item as they } else { if (secondaryStat_nSpiritJavelin != null && nBulletType != secondaryStat_nSpiritJavelin.Stat[SecondaryStatFlag.SpiritJavelin].nValue) { ret.bValidAttack = false; // PE return(ret); } ret.bNoItemConsume = true; } } } else if (ret.bNextShootExJablin) { ret.bNoItemConsume = true; } } ret.DecodeAttackInfo(p); p.Skip(4); // char pos if (JobLogic.IsWildhunterJob(c.Stats.nJob)) { var m_ptBodyRelMove = p.Decode2(); // unsure what this is used for } p.Skip(4); // another pos.. unsure for what if (ret.nSkillID == (int)Skills.STRIKER_SPARK) { ret.tReserveSpark = p.Decode4(); } return(ret); }