Updated Vow of Poverty. Added Sanctify Ki Strike, Holy Strike, Fist of Heavens, Vow of Abstinence, Vow of Chastity & Gift of Faith. (@fenac). Turned off the Taunt & Parry skills. Re-disabled AC & save bonuses from Tumble & Spellcraft. Updated min() & max() to PRCmin() & PRCmax() to not conflict with similarly named NUI adjacent functions. Set Point Blank Shot to 30' per PnP. Added icon for Chosen of Evil. Started work on Hidden Talent. Created Psionics function cheatsheet. Updated release archive.
340 lines
11 KiB
Plaintext
340 lines
11 KiB
Plaintext
//::///////////////////////////////////////////////
|
|
//:: Summon Familiar
|
|
//:: NW_S2_Familiar
|
|
//:: Copyright (c) 2001 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
This spell summons an Arcane casters familiar
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Preston Watamaniuk
|
|
//:: Created On: Sept 27, 2001
|
|
//:://////////////////////////////////////////////
|
|
|
|
#include "inc_dynconv"
|
|
//#include "inc_dispel"
|
|
#include "prc_inc_assoc"
|
|
#include "prc_inc_template"
|
|
|
|
const int PACKAGE_ELEMENTAL_STR = PACKAGE_ELEMENTAL;
|
|
const int PACKAGE_ELEMENTAL_DEX = PACKAGE_FEY;
|
|
|
|
void BondedSummoner(object oPC);
|
|
void SummonPnPFamiliar(object oPC, int nType);
|
|
void SummonPRCFamiliar(object oPC);
|
|
void DreadNecro(object oPC);
|
|
void MasterShadow(object oPC);
|
|
|
|
void main()
|
|
{
|
|
object oPC = OBJECT_SELF;
|
|
|
|
if(GetLevelByClass(CLASS_TYPE_MASTER_OF_SHADOW, oPC))
|
|
{
|
|
//handles summoning of shadow familiar
|
|
MasterShadow(oPC);
|
|
}
|
|
else if(GetLevelByClass(CLASS_TYPE_BONDED_SUMMONNER, oPC))
|
|
{
|
|
//handles summoning of elemental familiar
|
|
BondedSummoner(oPC);
|
|
}
|
|
else if(GetLevelByClass(CLASS_TYPE_DREAD_NECROMANCER, oPC) > 6)
|
|
{
|
|
//handles dread necromancer familiar
|
|
DreadNecro(oPC);
|
|
}
|
|
else if(GetLevelByClass(CLASS_TYPE_CELEBRANT_SHARESS, oPC))
|
|
{
|
|
//It's a PnP Cat familiar
|
|
SummonPnPFamiliar(oPC, 6);
|
|
}
|
|
else if(GetPRCSwitch(PRC_PNP_FAMILIARS))
|
|
{
|
|
//handles summoning of pnp familiar
|
|
SummonPnPFamiliar(oPC, -1);
|
|
}
|
|
else if(GetPRCSwitch(PRC_FAMILIARS)//the switch is set
|
|
|| (!GetLevelByClass(CLASS_TYPE_WIZARD, oPC)
|
|
&& !GetLevelByClass(CLASS_TYPE_SORCERER, oPC)))//or no bio-ware familiar
|
|
{
|
|
//handles summoning of familiars for PRC classes (witch, hexblade)
|
|
SummonPRCFamiliar(oPC);
|
|
}
|
|
else
|
|
//summon bio-ware familiar
|
|
SummonFamiliar();
|
|
|
|
object oFam;
|
|
int i;
|
|
int bDiabol = GetLevelByClass(CLASS_TYPE_DIABOLIST, oPC) >= 2;
|
|
int bPseudonat = GetHasFeat(FEAT_PSEUDONATURAL_FAMILIAR, oPC);
|
|
for(i = 1; i <= 5; i++)
|
|
{
|
|
oFam = GetAssociateNPC(ASSOCIATE_TYPE_FAMILIAR, oPC, i);
|
|
|
|
if(bDiabol && GetAppearanceType(oFam) != APPEARANCE_TYPE_IMP)
|
|
DestroyAssociate(oFam);
|
|
|
|
if(bPseudonat)
|
|
{
|
|
object oFamSkin = GetPCSkin(oFam);
|
|
ApplyPseudonatural(oFam, oFamSkin);
|
|
}
|
|
}
|
|
}
|
|
|
|
void BondedSummoner(object oPC)
|
|
{
|
|
object oFam = GetAssociateNPC(ASSOCIATE_TYPE_FAMILIAR, oPC, NPC_BONDED_FAMILIAR);
|
|
|
|
//remove previously summoned familiar
|
|
if(GetIsObjectValid(oFam))
|
|
DestroyAssociate(oFam);
|
|
|
|
string sResRef, sElem;
|
|
int nPackage;
|
|
if(GetHasFeat(FEAT_BONDED_AIR, oPC))
|
|
{
|
|
sElem = "air";
|
|
nPackage = PACKAGE_ELEMENTAL_DEX;
|
|
}
|
|
else if(GetHasFeat(FEAT_BONDED_EARTH, oPC))
|
|
{
|
|
sElem = "earth";
|
|
nPackage = PACKAGE_ELEMENTAL_STR;
|
|
}
|
|
else if(GetHasFeat(FEAT_BONDED_FIRE, oPC))
|
|
{
|
|
sElem = "fire";
|
|
nPackage = PACKAGE_ELEMENTAL_DEX;
|
|
}
|
|
else if(GetHasFeat(FEAT_BONDED_WATER, oPC))
|
|
{
|
|
sElem = "water";
|
|
nPackage = PACKAGE_ELEMENTAL_STR;
|
|
}
|
|
|
|
int nLevel = GetLevelByClass(CLASS_TYPE_BONDED_SUMMONNER, oPC);
|
|
|
|
switch(nLevel)
|
|
{
|
|
case 1:
|
|
case 2: sResRef = "x1_s_"+sElem+"small"; break;//this is the 4HD version in the SRD, which is medium
|
|
case 3:
|
|
case 4: sResRef = "prc_s_"+sElem+"large"; break;
|
|
case 5:
|
|
case 6: sResRef = "nw_s_"+sElem+"huge"; break;
|
|
case 7:
|
|
case 8: sResRef = "nw_s_"+sElem+"great"; break;
|
|
case 9:
|
|
case 10: sResRef = "nw_s_"+sElem+"elder"; break;
|
|
}
|
|
|
|
oFam = CreateLocalNPC(oPC, ASSOCIATE_TYPE_FAMILIAR, sResRef, PRCGetSpellTargetLocation(), NPC_BONDED_FAMILIAR);
|
|
AddAssociate(oPC, oFam);
|
|
|
|
//set its name
|
|
string sName = GetFamiliarName(oPC);
|
|
if(sName == "")
|
|
sName = GetName(oPC)+ "'s Familiar";
|
|
SetName(oFam, sName);
|
|
//apply bonus based on level
|
|
int nArcaneLevel = GetPrCAdjustedCasterLevelByType(TYPE_ARCANE) + nLevel/2;
|
|
object oSkin = GetPCSkin(oFam);
|
|
//in all cases
|
|
IPSafeAddItemProperty(oSkin, PRCItemPropertyBonusFeat(ITEM_PROPERTY_IMPROVED_EVASION));
|
|
//9+ levels
|
|
if(nArcaneLevel >= 9)
|
|
IPSafeAddItemProperty(oSkin, ItemPropertyBonusSpellResistance(GetSRByValue(nArcaneLevel+5)));
|
|
//11+ levels
|
|
if(nArcaneLevel >= 11)
|
|
ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(EffectMovementSpeedIncrease(30)), oFam);
|
|
//add their ondeath special
|
|
AddEventScript(oFam, EVENT_NPC_ONDEATH, "prc_bond_death");
|
|
|
|
/*int nAdjustLevel = nArcaneLevel - GetHitDice(oFam);
|
|
int n;
|
|
for(n = 1; nAdjustLevel >= n; n++)
|
|
LevelUpHenchman(oFam, CLASS_TYPE_INVALID, TRUE, nPackage);*/
|
|
|
|
//set it so the spell-share detects it
|
|
SetLocalObject(oPC, "Familiar", oFam);
|
|
}
|
|
|
|
void DreadNecro(object oPC)
|
|
{
|
|
object oFam = GetAssociateNPC(ASSOCIATE_TYPE_FAMILIAR, oPC, NPC_DN_FAMILIAR);
|
|
|
|
//remove previously summoned familiar
|
|
if(GetIsObjectValid(oFam))
|
|
DestroyAssociate(oFam);
|
|
|
|
int bPnP = GetPRCSwitch(PRC_PNP_FAMILIARS);
|
|
int nAlign = GetAlignmentLawChaos(oPC);
|
|
string sResRef;
|
|
if(bPnP)
|
|
{
|
|
sResRef = nAlign == ALIGNMENT_LAWFUL ? "prc_pnpfam_imp" : nAlign == ALIGNMENT_CHAOTIC ? "prc_pnpfam_qust" : "prc_pnpfam_varg";
|
|
}
|
|
else
|
|
{
|
|
int nDNLevel = GetLevelByClass(CLASS_TYPE_DREAD_NECROMANCER, oPC);
|
|
string sTemp = nDNLevel < 10 ? "0"+IntToString(nDNLevel) : IntToString(nDNLevel);
|
|
sResRef = nAlign == ALIGNMENT_LAWFUL ? "NW_FM_IMP"+sTemp : nAlign == ALIGNMENT_CHAOTIC ? "NW_FM_QUAS"+sTemp : "X2_FM_EYE0"+sTemp;
|
|
}
|
|
|
|
oFam = CreateLocalNPC(oPC, ASSOCIATE_TYPE_FAMILIAR, sResRef, PRCGetSpellTargetLocation(), NPC_DN_FAMILIAR);
|
|
|
|
//add the familiar as a henchman
|
|
AddAssociate(oPC, oFam);
|
|
|
|
//set its name
|
|
string sName = GetFamiliarName(oPC);
|
|
if(sName == "")
|
|
sName = GetName(oPC)+ "'s Familiar";
|
|
SetName(oFam, sName);
|
|
|
|
if(bPnP) ApplyPnPFamiliarProperties(oPC, oFam);
|
|
}
|
|
|
|
void SummonPnPFamiliar(object oPC, int nType)
|
|
{
|
|
IncrementRemainingFeatUses(oPC, FEAT_SUMMON_FAMILIAR);
|
|
|
|
//check if already has a familiar
|
|
object oFam = GetAssociateNPC(ASSOCIATE_TYPE_FAMILIAR, oPC, NPC_PNP_FAMILIAR);
|
|
object oFamToken = GetItemPossessedBy(oPC, "prc_pnp_familiar");
|
|
|
|
int nFamiliarType;
|
|
|
|
if (nType > 0)
|
|
nFamiliarType = nType;
|
|
else
|
|
nFamiliarType = GetPersistantLocalInt(oPC, "PnPFamiliarType");
|
|
if(!nFamiliarType)
|
|
{
|
|
StartDynamicConversation("prc_pnp_fam_conv", oPC, DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, TRUE, TRUE, oPC);
|
|
return;
|
|
}
|
|
|
|
if(GetIsObjectValid(oFam))
|
|
{
|
|
//reapply familiar bonuses
|
|
PRCRemoveEffectsFromSpell(oFam, 318);//318 = summon familiar
|
|
}
|
|
else
|
|
{
|
|
if(GetIsObjectValid(oFamToken))
|
|
{
|
|
DestroyObject(oFamToken, 0.1f);
|
|
}
|
|
//spawn the familiar
|
|
string sResRef = Get2DACache("prc_familiar", "BASERESREF", nFamiliarType);
|
|
oFam = CreateLocalNPC(oPC, ASSOCIATE_TYPE_FAMILIAR, sResRef, PRCGetSpellTargetLocation(), NPC_PNP_FAMILIAR);
|
|
|
|
//set its name
|
|
string sName = GetFamiliarName(oPC);
|
|
if(sName == "")
|
|
sName = GetName(oPC)+ "'s Familiar";
|
|
SetName(oFam, sName);
|
|
|
|
//add the familiar as a henchman
|
|
AddAssociate(oPC, oFam);
|
|
}
|
|
|
|
//this is the masters bonus
|
|
effect eBonus = GetMasterBonus(nFamiliarType);
|
|
eBonus = SupernaturalEffect(eBonus);
|
|
if(!GetHasFeatEffect(FEAT_SUMMON_FAMILIAR, oPC))
|
|
{
|
|
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eBonus, oPC);
|
|
CheckIsValidFamiliar(oPC, eBonus);
|
|
}
|
|
|
|
ApplyPnPFamiliarProperties(oPC, oFam);
|
|
if (GetHasFeat(FEAT_SHADOW_FAMILIAR, oPC)) ApplyTemplateToObject(TEMPLATE_DARK, oFam);
|
|
}
|
|
|
|
void SummonPRCFamiliar(object oPC)
|
|
{
|
|
object oFam = GetAssociateNPC(ASSOCIATE_TYPE_FAMILIAR, oPC, NPC_HENCHMAN_COMPANION);
|
|
|
|
//remove previously summoned familiar
|
|
if(GetIsObjectValid(oFam))
|
|
DestroyAssociate(oFam);
|
|
|
|
int nFamiliarType = GetPersistantLocalInt(oPC, "FamiliarType");
|
|
if(!nFamiliarType)
|
|
{
|
|
StartDynamicConversation("prc_pnp_fam_conv", oPC, DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, TRUE, TRUE, oPC);
|
|
IncrementRemainingFeatUses(oPC, FEAT_SUMMON_FAMILIAR);
|
|
return;
|
|
}
|
|
else
|
|
nFamiliarType--;
|
|
|
|
int nFamLevel = GetLevelByClass(CLASS_TYPE_WIZARD);
|
|
nFamLevel = PRCMax(nFamLevel, GetLevelByClass(CLASS_TYPE_SORCERER));
|
|
nFamLevel = PRCMax(nFamLevel, GetLevelByClass(CLASS_TYPE_WITCH));
|
|
nFamLevel = PRCMax(nFamLevel, GetLevelByClass(CLASS_TYPE_HEXBLADE));
|
|
nFamLevel += GetLevelByClass(CLASS_TYPE_ALIENIST);
|
|
if (GetHasFeat(FEAT_SHADOW_FAMILIAR, oPC)) nFamLevel = GetLevelByTypeArcane(oPC) + GetShadowcasterLevel(oPC); // For the purpose of determining familiar abilities that depend on your arcane caster level, your levels in all classes that allow you to cast mysteries or arcane spells stack
|
|
|
|
string sTemp = Get2DACache("hen_familiar", "BASERESREF", nFamiliarType);
|
|
string sResRef = nFamLevel < 10 ? sTemp+"0"+IntToString(nFamLevel) : sTemp+IntToString(nFamLevel);
|
|
|
|
//spawn the familiar
|
|
oFam = CreateLocalNPC(oPC, ASSOCIATE_TYPE_FAMILIAR, sResRef, PRCGetSpellTargetLocation(), NPC_HENCHMAN_COMPANION);
|
|
AddAssociate(oPC, oFam);
|
|
|
|
if (GetHasFeat(FEAT_SHADOW_FAMILIAR, oPC)) ApplyTemplateToObject(TEMPLATE_DARK, oFam);
|
|
|
|
//set its name
|
|
string sName = GetFamiliarName(oPC);
|
|
if(sName == "")
|
|
sName = GetName(oPC)+ "'s Familiar";
|
|
SetName(oFam, sName);
|
|
}
|
|
|
|
void MasterShadow(object oPC)
|
|
{
|
|
object oFam = GetAssociateNPC(ASSOCIATE_TYPE_FAMILIAR, oPC, NPC_MS_ELEMENTAL);
|
|
|
|
//remove previously summoned familiar
|
|
if(GetIsObjectValid(oFam))
|
|
DestroyAssociate(oFam);
|
|
|
|
int nLevel = GetLevelByClass(CLASS_TYPE_MASTER_OF_SHADOW, oPC);
|
|
string sShadow = "shd_shdelem_med";
|
|
if (nLevel >= 10)
|
|
sShadow = "shd_shdelem_med4";
|
|
else if (nLevel >= 7)
|
|
sShadow = "shd_shdelem_med3";
|
|
else if (nLevel >= 4)
|
|
sShadow = "shd_shdelem_med2";
|
|
|
|
oFam = CreateLocalNPC(oPC, ASSOCIATE_TYPE_FAMILIAR, sShadow, PRCGetSpellTargetLocation(), NPC_MS_ELEMENTAL);
|
|
AddAssociate(oPC, oFam);
|
|
//set its name
|
|
string sName = GetFamiliarName(oPC);
|
|
if(sName == "")
|
|
sName = GetName(oPC)+ "'s Shadow Elemental";
|
|
SetName(oFam, sName);
|
|
|
|
itemproperty ipIP;
|
|
object oSkin = GetPCSkin(oFam);
|
|
if (nLevel >= 10)
|
|
ipIP =ItemPropertyDamageImmunity(IP_CONST_DAMAGETYPE_COLD,IP_CONST_DAMAGEIMMUNITY_100_PERCENT);
|
|
else if (nLevel >= 6)
|
|
ipIP =ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_COLD, IP_CONST_DAMAGERESIST_20);
|
|
else if (nLevel >= 4)
|
|
ipIP =ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_COLD, IP_CONST_DAMAGERESIST_10);
|
|
else if (nLevel >= 2)
|
|
ipIP =ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_COLD, IP_CONST_DAMAGERESIST_5);
|
|
|
|
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, FALSE);
|
|
|
|
if (nLevel >= 3) // Grow to size large
|
|
SetCreatureAppearanceType(oFam, APPEARANCE_TYPE_SHADOW_FIEND);
|
|
} |