//:://///////////////////////////////////////////// //:: [Duelist Feats] //:: [prc_duelist.nss] //::////////////////////////////////////////////// //:: Check to see which Duelist feats a creature //:: has and apply the appropriate bonuses. //::////////////////////////////////////////////// //:: Created By: Aaon Graywolf //:: Created On: Dec 20, 2003 //::////////////////////////////////////////////// //:: Fixed By: Stratovarius //:: Fixed On: Sep 05, 2018 //::////////////////////////////////////////////// #include "prc_inc_combat" #include "x0_i0_modes" // * Applies the Duelist's AC bonuses as CompositeBonuses on the object's skin. // * AC bonus is determined by object's int bonus // * iOnOff = TRUE/FALSE void DuelistCannyDefense(object oPC, object oSkin, int iOnOff) { int iIntBonus = GetAbilityModifier(ABILITY_INTELLIGENCE, oPC); // limits bonus to class level as per 3.5e rules. int iDuelistLevel = GetLevelByClass(CLASS_TYPE_DUELIST,oPC); if(iIntBonus > iDuelistLevel) iIntBonus = iDuelistLevel; if(iOnOff){ SetCompositeBonus(oSkin, "CannyDefenseBonus", iIntBonus, ITEM_PROPERTY_AC_BONUS); if(GetLocalInt(oPC, "CannyDefense") != TRUE) SetLocalInt(oPC, "CannyDefense", TRUE); } else { SetCompositeBonus(oSkin, "CannyDefenseBonus", 0, ITEM_PROPERTY_AC_BONUS); if(GetLocalInt(oPC, "CannyDefense") != FALSE) SetLocalInt(oPC, "CannyDefense", FALSE); } } // * Applies the Duelist's reflex bonuses as CompositeBonuses on the object's skin. // Bonus is always 2 void DuelistGrace(object oPC, object oSkin) { if(!GetLocalInt(oPC, "Grace")) { SetCompositeBonus(oSkin, "GraceBonus", 2, ITEM_PROPERTY_SAVING_THROW_BONUS_SPECIFIC, IP_CONST_SAVEBASETYPE_REFLEX); if(GetLocalInt(oPC, "Grace") != TRUE) SetLocalInt(oPC, "Grace", TRUE); } else { SetCompositeBonus(oSkin, "GraceBonus", 0, ITEM_PROPERTY_SAVING_THROW_BONUS_SPECIFIC, IP_CONST_SAVEBASETYPE_REFLEX); if(GetLocalInt(oPC, "Grace") != FALSE) SetLocalInt(oPC, "Grace", FALSE); } } // Incorrect, archived /* void RemoveDuelistPreciseStrike(object oWeap) { int iSlashBonus = GetLocalInt(oWeap,"DuelistPreciseSlash"); if (iSlashBonus) RemoveSpecificProperty(oWeap, ITEM_PROPERTY_DAMAGE_BONUS, IP_CONST_DAMAGETYPE_SLASHING, iSlashBonus, 1, "DuelistPreciseSlash", -1, DURATION_TYPE_TEMPORARY); } void DuelistPreciseStrike(object oPC, object oWeap) { int iSlashBonus = 0; int iDuelistLevel = GetLevelByClass(CLASS_TYPE_DUELIST,oPC); RemoveDuelistPreciseStrike(oWeap); // since new duelist gains it every 5 levels iDuelistLevel /= 5; switch(iDuelistLevel) { case 1: iSlashBonus = IP_CONST_DAMAGEBONUS_1d4; break; case 2: iSlashBonus = IP_CONST_DAMAGEBONUS_2d4; break; case 3: iSlashBonus = IP_CONST_DAMAGEBONUS_3d4; break; case 4: iSlashBonus = IP_CONST_DAMAGEBONUS_4d4; break; case 5: iSlashBonus = IP_CONST_DAMAGEBONUS_5d4; break; case 6: iSlashBonus = IP_CONST_DAMAGEBONUS_6d4; break; } int nDamageType = GetWeaponDamageType(oWeap); if(iSlashBonus) { SetLocalInt(oWeap,"DuelistPreciseSlash",iSlashBonus); // misnomer for simplicity's sake AddItemProperty(DURATION_TYPE_TEMPORARY, ItemPropertyDamageBonus(nDamageType, iSlashBonus), oWeap, 99999.9); } } if(bPStrk > 0 && GetBaseItemType(oLefthand) != BASE_ITEM_SMALLSHIELD && GetBaseItemType(oLefthand) != BASE_ITEM_LARGESHIELD && GetBaseItemType(oLefthand) != BASE_ITEM_TOWERSHIELD && (GetBaseItemType(oWeapon) == BASE_ITEM_RAPIER || GetBaseItemType(oWeapon) == BASE_ITEM_DAGGER || GetBaseItemType(oWeapon) == BASE_ITEM_SHORTSWORD)) DuelistPreciseStrike(oPC, oWeapon); if(GetLocalInt(oPC,"ONEQUIP") == 1) RemoveDuelistPreciseStrike(GetItemLastUnequipped()); if(GetBaseAC(oArmor) != 0 || GetBaseItemType(oLefthand) == BASE_ITEM_SMALLSHIELD || GetBaseItemType(oLefthand) == BASE_ITEM_LARGESHIELD || GetBaseItemType(oLefthand) == BASE_ITEM_TOWERSHIELD) RemoveDuelistPreciseStrike(oWeapon); */ void main() { int nEvent = GetRunningEvent(); object oPC; switch(nEvent) { case EVENT_ITEM_ONHIT: oPC = OBJECT_SELF; break; case EVENT_ONPLAYEREQUIPITEM: oPC = GetItemLastEquippedBy(); break; case EVENT_ONPLAYERUNEQUIPITEM: oPC = GetItemLastUnequippedBy(); break; case EVENT_ONHEARTBEAT: oPC = OBJECT_SELF; break; default: oPC = OBJECT_SELF; } int nDuel = GetLevelByClass(CLASS_TYPE_DUELIST, oPC); object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC); object oLefthand = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC); object oSkin = GetPCSkin(oPC); object oArmor = GetItemInSlot(INVENTORY_SLOT_CHEST, oPC); if(nEvent == FALSE) { //Determine which duelist feats the character has int bCanDef = GetHasFeat(FEAT_CANNY_DEFENSE, oPC); int bGrace = GetHasFeat(FEAT_GRACE, oPC); int iLefthand = GetBaseItemType(oLefthand); //Apply bonuses accordingly if(bCanDef > 0 && GetBaseAC(oArmor) == 0 && GetBaseItemType(oLefthand) != BASE_ITEM_SMALLSHIELD && GetBaseItemType(oLefthand) != BASE_ITEM_LARGESHIELD && GetBaseItemType(oLefthand) != BASE_ITEM_TOWERSHIELD) DuelistCannyDefense(oPC, oSkin, TRUE); else DuelistCannyDefense(oPC, oSkin, FALSE); if(bGrace > 0 && GetBaseAC(oArmor) == 0 && GetBaseItemType(oLefthand) != BASE_ITEM_SMALLSHIELD && GetBaseItemType(oLefthand) != BASE_ITEM_LARGESHIELD && GetBaseItemType(oLefthand) != BASE_ITEM_TOWERSHIELD) DuelistGrace(oPC, oSkin); else DuelistGrace(oPC, oSkin); //Defensive Strike /*if(nDuel >= 7 && GetHasFeat(FEAT_EXPERTISE, oPC)) { if(DEBUG) DoDebug("prc_duelist: Adding eventhooks"); AddEventScript(oPC, EVENT_ONHEARTBEAT, "prc_duelist", TRUE, FALSE); }*/ AddEventScript(oPC, EVENT_ONPLAYEREQUIPITEM, "prc_duelist", TRUE, FALSE); AddEventScript(oPC, EVENT_ONPLAYERUNEQUIPITEM, "prc_duelist", TRUE, FALSE); } // We're being called from the OnHeartbeat eventhook, so check or skip /*if(nEvent == EVENT_ONHEARTBEAT) { // Only applies when using expertise if(GetModeActive(ACTION_MODE_EXPERTISE) || GetActionMode(oPC, ACTION_MODE_EXPERTISE) || GetLastAttackMode(oPC) == COMBAT_MODE_EXPERTISE || GetModeActive(ACTION_MODE_IMPROVED_EXPERTISE) || GetActionMode(oPC, ACTION_MODE_IMPROVED_EXPERTISE) || GetLastAttackMode(oPC) == COMBAT_MODE_IMPROVED_EXPERTISE) { effect eAC = EffectACIncrease(nDuel, AC_DODGE_BONUS); ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eAC, oPC, 6.0); } }// end if - Running OnHeart event*/ else if(nEvent == EVENT_ITEM_ONHIT && !GetIsObjectValid(oLefthand) && nDuel >= 5) // Left hand must be empty, Duelist must be at least level 5 { oWeapon = GetSpellCastItem(); object oTarget = PRCGetSpellTargetObject(); if(DEBUG) DoDebug("prc_duelist: OnHit:\n" + "oPC = " + DebugObject2Str(oPC) + "\n" + "oWeapon = " + DebugObject2Str(oWeapon) + "\n" + "oTarget = " + DebugObject2Str(oTarget) + "\n" ); // Only applies to weapons, target must not be immune to criticals/sneak attacks if(IPGetIsMeleeWeapon(oWeapon) && !GetIsImmune(oTarget, IMMUNITY_TYPE_CRITICAL_HIT) && !GetIsImmune(oTarget, IMMUNITY_TYPE_SNEAK_ATTACK)) { // Calculate Precise Strike damage and apply int nDam = d6(nDuel/5); effect eDam = EffectDamage(nDam, DAMAGE_TYPE_MAGICAL); //Using this because any DR has already taken piercing damage ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); FloatingTextStringOnCreature("Precise Strike Damage: "+IntToString(nDam), oPC, FALSE); }// end if - Item is a melee weapon }// end if - Running OnHit event else if(nEvent == EVENT_ONPLAYEREQUIPITEM && nDuel >= 5) //Duelist has to be at least level 5 { oPC = GetItemLastEquippedBy(); oWeapon = GetItemLastEquipped(); if(DEBUG) DoDebug("prc_duelist - OnEquip\n" + "oPC = " + DebugObject2Str(oPC) + "\n" + "oWeapon = " + DebugObject2Str(oWeapon) + "\n" ); // Only applies to one handed piercing weapons if(GetBaseItemType(oLefthand) != BASE_ITEM_SMALLSHIELD && GetBaseItemType(oLefthand) != BASE_ITEM_LARGESHIELD && GetBaseItemType(oLefthand) != BASE_ITEM_TOWERSHIELD && (GetBaseItemType(oWeapon) == BASE_ITEM_RAPIER || GetBaseItemType(oWeapon) == BASE_ITEM_DAGGER || GetBaseItemType(oWeapon) == BASE_ITEM_SHORTSWORD)) { // Add eventhook to the item AddEventScript(oWeapon, EVENT_ITEM_ONHIT, "prc_duelist", TRUE, FALSE); // Add the OnHitCastSpell: Unique needed to trigger the event IPSafeAddItemProperty(oWeapon, ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 1), 99999.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE); } } // We are called from the OnPlayerUnEquipItem eventhook. Remove OnHitCast: Unique Power from oPC's weapon else if(nEvent == EVENT_ONPLAYERUNEQUIPITEM && nDuel >= 5) //Duelist has to be at least level 5 { oPC = GetItemLastUnequippedBy(); oWeapon = GetItemLastUnequipped(); if(DEBUG) DoDebug("prc_duelist - OnUnEquip\n" + "oPC = " + DebugObject2Str(oPC) + "\n" + "oWeapon = " + DebugObject2Str(oWeapon) + "\n" ); // Only applies to weapons if(IPGetIsMeleeWeapon(oWeapon)) { // Add eventhook to the item RemoveEventScript(oWeapon, EVENT_ITEM_ONHIT, "prc_duelist", TRUE, FALSE); // Remove the temporary OnHitCastSpell: Unique // Makes sure to get ammo if its a ranged weapon RemoveSpecificProperty(oWeapon, ITEM_PROPERTY_ONHITCASTSPELL, IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 0, 1, "", -1, DURATION_TYPE_TEMPORARY); } } }