Updated Release Archive. Fixed Mage-killer prereqs. Removed old LETO & ConvoCC related files. Added organized spell scroll store. Fixed Gloura spellbook. Various TLK fixes. Reorganized Repo. Removed invalid user folders. Added DocGen back in.
305 lines
13 KiB
Plaintext
305 lines
13 KiB
Plaintext
//::///////////////////////////////////////////////
|
|
//:: 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");
|
|
}
|