//:://///////////////////////////////////////////// //:: Skullclan Hunter //:: prc_skullclan.nss //::////////////////////////////////////////////// //:: Check to see which Skullclan Hunter feats a creature //:: has and apply the appropriate bonuses. //::////////////////////////////////////////////// //:: Created By: Stratovarius. //:: Created On: July 12, 2006 //::////////////////////////////////////////////// // To-Do: Use +20 / -20 Item prop vs undead on weapon #include "prc_inc_combat" //modification of GetWeaponAttackBonusProperty - hardcoded to NE Undead //Used to make reduction adjust to match weapon, due to +20/-20 cap int GetUndeadAttackBonusItemProperty(object oWeap) { int iBonus = 0; int iPenalty = 0; int iTemp; int iRace = RACIAL_TYPE_UNDEAD; int iGoodEvil = 0; int iLawChaos = 50; int iAlignSpecific = GetItemPropAlignment(iGoodEvil, iLawChaos); int iAlignGroup; itemproperty ip = GetFirstItemProperty(oWeap); while(GetIsItemPropertyValid(ip)) { iTemp = 0; int iIpType=GetItemPropertyType(ip); switch(iIpType) { case ITEM_PROPERTY_ATTACK_BONUS: case ITEM_PROPERTY_ENHANCEMENT_BONUS: iTemp = GetItemPropertyCostTableValue(ip); break; case ITEM_PROPERTY_DECREASED_ATTACK_MODIFIER: case ITEM_PROPERTY_DECREASED_ENHANCEMENT_MODIFIER: iTemp - GetItemPropertyCostTableValue(ip); break; case ITEM_PROPERTY_ATTACK_BONUS_VS_ALIGNMENT_GROUP: case ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_ALIGNMENT_GROUP: iAlignGroup = GetItemPropertySubType(ip); if (iAlignGroup == ALIGNMENT_NEUTRAL) { if (iAlignGroup == iLawChaos) iTemp = GetItemPropertyCostTableValue(ip); } else if (iAlignGroup == iGoodEvil || iAlignGroup == iLawChaos || iAlignGroup == IP_CONST_ALIGNMENTGROUP_ALL) { iTemp = GetItemPropertyCostTableValue(ip); } break; case ITEM_PROPERTY_ATTACK_BONUS_VS_RACIAL_GROUP: case ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_RACIAL_GROUP: if(GetItemPropertySubType(ip) == iRace ) { iTemp = GetItemPropertyCostTableValue(ip); } break; case ITEM_PROPERTY_ATTACK_BONUS_VS_SPECIFIC_ALIGNMENT: if(GetItemPropertySubType(ip) == iAlignSpecific ) { iTemp = GetItemPropertyCostTableValue(ip); } break; } if (iTemp > iBonus) iBonus = iTemp; else if(iTemp < iPenalty) iPenalty = iTemp; ip = GetNextItemProperty(oWeap); } iBonus -= iPenalty; return iBonus; } //function to clear old penalty vs Undead void ClearOldPenalties(object oPC) { effect eLoop=GetFirstEffect(oPC); while (GetIsEffectValid(eLoop)) { if (GetEffectType(eLoop)==EFFECT_TYPE_ATTACK_DECREASE && GetEffectSubType(eLoop)==SUBTYPE_EXTRAORDINARY && GetEffectDurationType(eLoop)==DURATION_TYPE_PERMANENT && GetEffectSpellId(eLoop) == -1) RemoveEffect(oPC, eLoop); eLoop=GetNextEffect(oPC); } } // * Applies the Skullclan Hunters's immunities on the object's skin. // * iType = IP_CONST_IMMUNITYMISC_* // * sFlag = Flag to check whether the property has already been added void SkullClanImmunity(object oPC, object oSkin, int iType, string sFlag) { if(GetLocalInt(oSkin, sFlag) == TRUE) return; AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyImmunityMisc(iType), oSkin); SetLocalInt(oSkin, sFlag, TRUE); } /*void SkullClanAbilityDrain(object oPC, object oSkin, string sFlag) { if(GetLocalInt(oSkin, sFlag) == TRUE) return; effect eAbil = EffectImmunity(IMMUNITY_TYPE_ABILITY_DECREASE); eAbil = SupernaturalEffect(eAbil); ApplyEffectToObject(DURATION_TYPE_PERMANENT, eAbil, oPC); SetLocalInt(oSkin, sFlag, TRUE); }*/ /*void SkullClanProtectionEvil(object oPC, object oSkin, string sFlag) { if(GetLocalInt(oSkin, sFlag) == TRUE) return; effect eAC = VersusAlignmentEffect(EffectACIncrease(2, AC_DEFLECTION_BONUS), ALIGNMENT_ALL, ALIGNMENT_EVIL); effect eSave = VersusAlignmentEffect(EffectSavingThrowIncrease(SAVING_THROW_ALL, 2), ALIGNMENT_ALL, ALIGNMENT_EVIL); effect eImmune = VersusAlignmentEffect(EffectImmunity(IMMUNITY_TYPE_MIND_SPELLS), ALIGNMENT_ALL, ALIGNMENT_EVIL); effect eLink = EffectLinkEffects(eImmune, eSave); eLink = EffectLinkEffects(eLink, eAC); eLink = SupernaturalEffect(eLink); ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oPC); SetLocalInt(oSkin, sFlag, TRUE); }*/ // This is supposed to pierce all DR on undead only void SkullClanSwordLight(object oPC, object oSkin, string sFlag) { //if(GetLocalInt(oSkin, sFlag) == TRUE) return; object oItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC); RemoveSpecificProperty(oItem, ITEM_PROPERTY_ATTACK_BONUS_VS_RACIAL_GROUP, RACIAL_TYPE_UNDEAD, 20, -1, "", -1, DURATION_TYPE_TEMPORARY); int nBonusVsTarget = GetUndeadAttackBonusItemProperty(oItem); // Because there is no negative item property for attack vs race, we need to use a permanent effect. IPSafeAddItemProperty(oItem, ItemPropertyAttackBonusVsRace(RACIAL_TYPE_UNDEAD, 20), 99999.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE); // Now we check for left hand for duel wielders oItem = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC); if(IPGetIsMeleeWeapon(oItem)) IPSafeAddItemProperty(oItem, ItemPropertyAttackBonusVsRace(RACIAL_TYPE_UNDEAD, 20), 99999.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE); ClearOldPenalties(oPC); if (DEBUG) DoDebug("Bonus vs Undead: " + IntToString(nBonusVsTarget)); SetLocalInt(oSkin, sFlag, TRUE); //if they're not getting any bonuses on weapons, they shouldn't get any penalties either. oItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC); if(oItem == OBJECT_INVALID) return; effect eAB = VersusRacialTypeEffect(EffectAttackDecrease(20 - nBonusVsTarget), RACIAL_TYPE_UNDEAD); eAB = ExtraordinaryEffect(eAB); ApplyEffectToObject(DURATION_TYPE_PERMANENT, eAB, oPC); } void main() { int nEvent = GetRunningEvent(); if(DEBUG) DoDebug("prc_skullclan running, event: " + IntToString(nEvent)); // Get the PC. This is event-dependent object oPC; switch(nEvent) { case EVENT_ITEM_ONHIT: oPC = OBJECT_SELF; break; case EVENT_ONPLAYEREQUIPITEM: oPC = GetItemLastEquippedBy(); break; case EVENT_ONPLAYERUNEQUIPITEM: oPC = GetItemLastUnequippedBy(); break; default: oPC = OBJECT_SELF; } object oSkin = GetPCSkin(oPC); object oItem, oAmmo; int nClass = GetLevelByClass(CLASS_TYPE_SKULLCLAN_HUNTER, oPC); // We aren't being called from any event, instead from EvalPRCFeats if(nEvent == FALSE) { //Apply bonuses accordingly if(nClass >= 3) SkullClanImmunity(oPC, oSkin, IP_CONST_IMMUNITYMISC_FEAR, "SkullClanFear"); //if(nClass >= 4) SkullClanImmunity(oPC, oSkin, IP_CONST_IMMUNITYMISC_DISEASE, "SkullClanDisease"); //if(nClass >= 4) SkullClanProtectionEvil(oPC, oSkin, "SkullClanProtectionEvil"); if(nClass >= 5) SkullClanSwordLight(oPC, oSkin, "SkullClanSwordLight"); //if(nClass >= 7) SkullClanImmunity(oPC, oSkin, IP_CONST_IMMUNITYMISC_PARALYSIS, "SkullClanParalysis"); //if(nClass >= 8 && nClass < 10) SkullClanAbilityDrain(oPC, oSkin, "SkullClanAbilityDrain"); //if(nClass >= 8) SkullClanImmunity(oPC, oSkin, IP_CONST_IMMUNITYMISC_LEVEL_ABIL_DRAIN, "SkullClanAbilityDrain"); //Bioware doesn't have ability and level drain seperately. Damn them. //if(nClass >= 10) SkullClanImmunity(oPC, oSkin, IP_CONST_IMMUNITYMISC_LEVEL_ABIL_DRAIN, "SkullClanLevelDrain"); // Set up the eventhooks, but don't start doing this until the Skullclan Hunter is level 2 if(nClass >= 2) { if(DEBUG) DoDebug("prc_skullclan: Adding eventhooks"); AddEventScript(oPC, EVENT_ONPLAYEREQUIPITEM, "prc_skullclan", TRUE, FALSE); AddEventScript(oPC, EVENT_ONPLAYERUNEQUIPITEM, "prc_skullclan", TRUE, FALSE); } } // We're being called from the OnHit eventhook, so deal the damage else if(nEvent == EVENT_ITEM_ONHIT) { oItem = GetSpellCastItem(); int nItemType = GetBaseItemType(oItem); object oTarget = PRCGetSpellTargetObject(); if(DEBUG) DoDebug("prc_skullclan: OnHit:\n" + "oPC = " + DebugObject2Str(oPC) + "\n" + "oItem = " + DebugObject2Str(oItem) + "\n" + "oTarget = " + DebugObject2Str(oTarget) + "\n" ); // Only applies to weapons if(IPGetIsMeleeWeapon(oItem) || IPGetIsProjectile(oItem)) { // Has to be able to sneak attack // The target must be undead as well if (MyPRCGetRacialType(oTarget) == RACIAL_TYPE_UNDEAD && GetCanSneakAttack(oTarget, oPC)) { // Get the total damage it can do int nDam = d6(GetTotalSneakAttackDice(oPC)); if(DEBUG) DoDebug("prc_skullclan: OnHit Sneak Damage: " + IntToString(nDam)); effect eDam = EffectDamage(nDam, DAMAGE_TYPE_POSITIVE); ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); } }// end if - Item is a melee weapon and Two-Weapon Rend hasn't already been used up for the round }// end if - Running OnHit event // We are called from the OnPlayerEquipItem eventhook. Add OnHitCast: Unique Power to oPC's weapon else if(nEvent == EVENT_ONPLAYEREQUIPITEM) { oPC = GetItemLastEquippedBy(); oItem = GetItemLastEquipped(); if(DEBUG) DoDebug("prc_skullclan - OnEquip");if(DEBUG) DoDebug("Is Ranged? " + IntToString(GetWeaponRanged(oItem))); // Only applies to weapons if(IPGetIsMeleeWeapon(oItem) || GetWeaponRanged(oItem)) { // Add eventhook to the item AddEventScript(oItem, EVENT_ITEM_ONHIT, "prc_skullclan", TRUE, FALSE); // Add the OnHitCastSpell: Unique needed to trigger the event // Makes sure to get ammo if its a ranged weapon IPSafeAddItemProperty(oItem, ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 1), 99999.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE); oAmmo = GetItemInSlot(INVENTORY_SLOT_BOLTS, oPC); IPSafeAddItemProperty(oAmmo, ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 1), 99999.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE); AddEventScript(oAmmo, EVENT_ITEM_ONHIT, "prc_skullclan", TRUE, FALSE); oAmmo = GetItemInSlot(INVENTORY_SLOT_BULLETS, oPC); IPSafeAddItemProperty(oAmmo, ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 1), 99999.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE); AddEventScript(oAmmo, EVENT_ITEM_ONHIT, "prc_skullclan", TRUE, FALSE); oAmmo = GetItemInSlot(INVENTORY_SLOT_ARROWS, oPC); IPSafeAddItemProperty(oAmmo, ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 1), 99999.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE); AddEventScript(oAmmo, EVENT_ITEM_ONHIT, "prc_skullclan", TRUE, FALSE); } } // We are called from the OnPlayerUnEquipItem eventhook. Remove OnHitCast: Unique Power from oPC's weapon else if(nEvent == EVENT_ONPLAYERUNEQUIPITEM) { oPC = GetItemLastUnequippedBy(); oItem = GetItemLastUnequipped(); if(DEBUG) DoDebug("prc_skullclan - OnUnEquip"); // Only applies to weapons if(IPGetIsMeleeWeapon(oItem) || GetWeaponRanged(oItem)) { // Add eventhook to the item RemoveEventScript(oItem, EVENT_ITEM_ONHIT, "prc_skullclan", TRUE, FALSE); // Remove the temporary OnHitCastSpell: Unique // Makes sure to get ammo if its a ranged weapon RemoveSpecificProperty(oItem, ITEM_PROPERTY_ONHITCASTSPELL, IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 0, -1, "", -1, DURATION_TYPE_TEMPORARY); RemoveSpecificProperty(oItem, ITEM_PROPERTY_ATTACK_BONUS_VS_RACIAL_GROUP, RACIAL_TYPE_UNDEAD, 20, -1, "", -1, DURATION_TYPE_TEMPORARY); oAmmo = GetItemInSlot(INVENTORY_SLOT_BOLTS, oPC); RemoveSpecificProperty(oAmmo, ITEM_PROPERTY_ONHITCASTSPELL, IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 0, -1, "", -1, DURATION_TYPE_TEMPORARY); RemoveEventScript(oAmmo, EVENT_ITEM_ONHIT, "prc_skullclan", TRUE, FALSE); oAmmo = GetItemInSlot(INVENTORY_SLOT_BULLETS, oPC); RemoveSpecificProperty(oAmmo, ITEM_PROPERTY_ONHITCASTSPELL, IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 0, -1, "", -1, DURATION_TYPE_TEMPORARY); RemoveEventScript(oAmmo, EVENT_ITEM_ONHIT, "prc_skullclan", TRUE, FALSE); oAmmo = GetItemInSlot(INVENTORY_SLOT_ARROWS, oPC); RemoveSpecificProperty(oAmmo, ITEM_PROPERTY_ONHITCASTSPELL, IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 0, -1, "", -1, DURATION_TYPE_TEMPORARY); RemoveEventScript(oAmmo, EVENT_ITEM_ONHIT, "prc_skullclan", TRUE, FALSE); } } if(DEBUG) DoDebug("prc_skullclan: Exiting"); }