diff --git a/nasher.cfg b/nasher.cfg index ff25eb5..996eb6a 100644 --- a/nasher.cfg +++ b/nasher.cfg @@ -232,6 +232,10 @@ description = "PRC8 version of World of Greyhawk." filter = "prc_nui_scd_inc.nss" filter = "prc_nui_consts.nss" filter = "nw_inc_nui" + filter = "nw_inc_nui" + filter = "inc_infusion.nss" + filter = "nw_inc_gff.nss" + filter = "prc_inc_json.nss" filter = "xchst_inc.nss" [target.rules] @@ -456,7 +460,11 @@ description = "PRC8 merge hakpak for PRC8 version of World of Greyhawk." filter = "prc_nui_scd_inc.nss" filter = "prc_nui_consts.nss" filter = "nw_inc_nui" - filter = "xchst_inc.nss" + filter = "nw_inc_nui" + filter = "inc_infusion.nss" + filter = "nw_inc_gff.nss" + filter = "prc_inc_json.nss" + filter = "xchst_inc.nss" [target.rules] "*" = "src/hakpak/wog_prc8_top/$ext" \ No newline at end of file diff --git a/src/_removed/itempropnew.nss b/src/_removed/itempropnew.nss new file mode 100644 index 0000000..47bd13f --- /dev/null +++ b/src/_removed/itempropnew.nss @@ -0,0 +1,1564 @@ +//:://///////////////////////////////////////////// +//:: Item Property Functions +//:: prc_x2_itemprop +//:: Copyright (c) 2003 Bioware Corp. +//::////////////////////////////////////////////// +/* + + Holds item property and item modification + specific code. + + If you look for anything specific to item + properties, your chances are good to find it + in here. + +*/ +//::////////////////////////////////////////////// +//:: Created By: Georg Zoeller +//:: Created On: 2003-06-05 +//:: Last Update: 2003-10-07 +//::////////////////////////////////////////////// + +/// TK addition: +#include "tk_dispel" + +//void main (){} + +// * The tag of the ip work container, a placeable which has to be set into each +// * module that is using any of the crafting functions. +/* const string X2_IP_WORK_CONTAINER_TAG = "x2_plc_ipbox"; +// * 2da for the AddProperty ItemProperty +const string X2_IP_ADDRPOP_2DA = "des_crft_props" ; +// * 2da for the Poison Weapon Itemproperty +const string X2_IP_POISONWEAPON_2DA = "des_crft_poison" ; +// * 2da for armor appearance +const string X2_IP_ARMORPARTS_2DA = "des_crft_aparts" ; +// * 2da for armor appearance +const string X2_IP_ARMORAPPEARANCE_2DA = "des_crft_appear" ; */ + +// * Base custom token for item modification conversations (do not change unless you want to change the conversation too) +/* const int XP_IP_ITEMMODCONVERSATION_CTOKENBASE = 12220; +const int X2_IP_ITEMMODCONVERSATION_MODE_TAILOR = 0; +const int X2_IP_ITEMMODCONVERSATION_MODE_CRAFT = 1; */ + +// * Number of maximum item properties allowed on most items +/* const int X2_IP_MAX_ITEM_PROPERTIES = 8; */ + +// * Constants used with the armor modification system +/* const int X2_IP_ARMORTYPE_NEXT = 0; +const int X2_IP_ARMORTYPE_PREV = 1; +const int X2_IP_ARMORTYPE_RANDOM = 2; +const int X2_IP_WEAPONTYPE_NEXT = 0; +const int X2_IP_WEAPONTYPE_PREV = 1; +const int X2_IP_WEAPONTYPE_RANDOM = 2; */ + +// * Policy constants for IPSafeAddItemProperty() +/* const int X2_IP_ADDPROP_POLICY_REPLACE_EXISTING = 0; +const int X2_IP_ADDPROP_POLICY_KEEP_EXISTING = 1; +const int X2_IP_ADDPROP_POLICY_IGNORE_EXISTING =2; */ + + +// * removes all itemproperties with matching nItemPropertyType and nItemPropertyDuration +void IPRemoveMatchingItemProperties( object oItem, int nItemPropertyType, int nItemPropertyDuration = DURATION_TYPE_TEMPORARY, int nItemPropertySubType = -1 ); + +// * Removes ALL item properties from oItem matching nItemPropertyDuration +void IPRemoveAllItemProperties( object oItem, int nItemPropertyDuration = DURATION_TYPE_TEMPORARY ); + +// * returns TRUE if item can be equipped. +// * Uses Get2DAString, so do not use in a loop! +int IPGetIsItemEquipable( object oItem ); + +// * Changes the color of an item armor +// * oItem - The armor +// * nColorType - ITEM_APPR_ARMOR_COLOR_* constant +// * nColor - color from 0 to 63 +// * Since oItem is destroyed in the process, the function returns +// * the item created with the color changed +object IPDyeArmor( object oItem, int nColorType, int nColor ); + +// * Returns the container used for item property and appearance modifications in the +// * module. If it does not exist, create it. +object IPGetIPWorkContainer( object oCaller = OBJECT_SELF ); + +// * This function needs to be rather extensive and needs to be updated if there are new +// * ip types we want to use, but it goes into the item property include anyway +itemproperty IPGetItemPropertyByID( int nPropID, int nParam1 = 0, int nParam2 = 0, int nParam3 = 0, int nParam4 = 0 ); + +// * returns TRUE if oItem is a ranged weapon +int IPGetIsRangedWeapon( object oItem ); + +// * return TRUE if oItem is a melee weapon +int IPGetIsMeleeWeapon( object oItem ); + +// * return TRUE if oItem is a projectile (bolt, arrow, etc) +int IPGetIsProjectile( object oItem ); + +// * returns true if weapon is blugeoning (used for poison) +// * This uses Get2DAstring, so it is slow. Avoid using in loops! +int IPGetIsBludgeoningWeapon( object oItem ); + +// * Return the IP_CONST_CASTSPELL_* ID matching to the SPELL_* constant given in nSPELL_ID +// * This uses Get2DAstring, so it is slow. Avoid using in loops! +// * returns -1 if there is no matching property for a spell +int IPGetIPConstCastSpellFromSpellID( int nSpellID ); + +// * Returns TRUE if an item has ITEM_PROPERTY_ON_HIT and the specified nSubType +// * possible values for nSubType can be taken from IPRP_ONHIT.2da +// * popular ones: +// * 5 - Daze 19 - ItemPoison 24 - Vorpal +int IPGetItemHasItemOnHitPropertySubType( object oTarget, int nSubType ); + +// * Returns the number of possible armor part variations for the specified part +// * nPart - ITEM_APPR_ARMOR_MODEL_* constant +// * Uses Get2DAstring, so do not use in loops +int IPGetNumberOfAppearances( int nPart ); + + +// * Returns the next valid appearance type for oArmor +// * nPart - ITEM_APPR_ARMOR_MODEL_* constant +// * Uses Get2DAstring, so do not use in loops +int IPGetNextArmorAppearanceType(object oArmor, int nPart); + +// * Returns the previous valid appearance type for oArmor +// * nPart - ITEM_APPR_ARMOR_MODEL_* constant +// * Uses Get2DAstring, so do not use in loops +int IPGetPrevArmorAppearanceType(object oArmor, int nPart); + +// * Returns a random valid appearance type for oArmor +// * nPart - ITEM_APPR_ARMOR_MODEL_* constant +// * Uses Get2DAstring, so do not use in loops +int IPGetRandomArmorAppearanceType(object oArmor, int nPart); + +// * Returns a new armor based of oArmor with nPartModified +// * nPart - ITEM_APPR_ARMOR_MODEL_* constant of the part to be changed +// * nMode - +// * X2_IP_ARMORTYPE_NEXT - next valid appearance +// * X2_IP_ARMORTYPE_PREV - previous valid apperance; +// * X2_IP_ARMORTYPE_RANDOM - random valid appearance; +// * +// * bDestroyOldOnSuccess - Destroy oArmor in process? +// * Uses Get2DAstring, so do not use in loops +object IPGetModifiedArmor(object oArmor, int nPart, int nMode, int bDestroyOldOnSuccess); + +// * Add an item property in a safe fashion, preventing unwanted stacking +// * Parameters: +// * oItem - the item to add the property to +// * ip - the itemproperty to add +// * fDuration - set 0.0f to add the property permanent, anything else is temporary +// * nAddItemPropertyPolicy - How to handle existing properties. Valid values are: +// * X2_IP_ADDPROP_POLICY_REPLACE_EXISTING - remove any property of the same type, subtype, durationtype before adding; +// * X2_IP_ADDPROP_POLICY_KEEP_EXISTING - do not add if any property with same type, subtype and durationtype already exists; +// * X2_IP_ADDPROP_POLICY_IGNORE_EXISTING - add itemproperty in any case - Do not Use with OnHit or OnHitSpellCast props! +// * +// * bIgnoreDurationType - If set to TRUE, an item property will be considered identical even if the DurationType is different. Be careful when using this +// * with X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, as this could lead to a temporary item property removing a permanent one +// * bIgnoreSubType - If set to TRUE an item property will be considered identical even if the SubType is different. +void IPSafeAddItemProperty(object oItem, itemproperty ip, float fDuration =0.0f, int nAddItemPropertyPolicy = X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, int bIgnoreDurationType = FALSE, int bIgnoreSubType = FALSE); + +// * Wrapper for GetItemHasItemProperty that returns true if +// * oItem has an itemproperty that matches ipCompareTo by Type AND DurationType AND SubType +// * nDurationType = Valid DURATION_TYPE_* or -1 to ignore +// * bIgnoreSubType - If set to TRUE an item property will be considered identical even if the SubType is different. +int IPGetItemHasProperty(object oItem, itemproperty ipCompareTo, int nDurationType, int bIgnoreSubType = FALSE); + +// * returns FALSE it the item has no sequencer property +// * returns number of spells that can be stored in any other case +//int IPGetItemSequencerProperty(object oItem); + +// * returns TRUE if the item has the OnHit:IntelligentWeapon property. +int IPGetIsIntelligentWeapon(object oItem); + +// * Mapping between numbers and power constants for ITEM_PROPERTY_DAMAGE_BONUS +// * returns the appropriate ITEM_PROPERTY_DAMAGE_POWER_* constant for nNumber +int IPGetDamagePowerConstantFromNumber(int nNumber); + +// * returns the appropriate ITEM_PROPERTY_DAMAGE_BONUS_= constant for nNumber +// * Do not pass in any number <1 ! Will return -1 on error +int IPGetDamageBonusConstantFromNumber(int nNumber); + +// * Special Version of Copy Item Properties for use with greater wild shape +// * oOld - Item equipped before polymorphing (source for item props) +// * oNew - Item equipped after polymorphing (target for item props) +// * bWeapon - Must be set TRUE when oOld is a weapon. +void IPWildShapeCopyItemProperties(object oOld, object oNew, int bWeapon = FALSE); + +// * Returns the current enhancement bonus of a weapon (+1 to +20), 0 if there is +// * no enhancement bonus. You can test for a specific type of enhancement bonus +// * by passing the appropritate ITEM_PROPERTY_ENHANCEMENT_BONUS* constant into +// * nEnhancementBonusType +//int IPGetWeaponEnhancementBonus(object oWeapon, int nEnhancementBonusType = ITEM_PROPERTY_ENHANCEMENT_BONUS); + +// * Shortcut function to set the enhancement bonus of a weapon to a certain bonus +// * Specifying bOnlyIfHigher as TRUE will prevent a bonus lower than the requested +// * bonus from being applied. Valid values for nBonus are 1 to 20. +void IPSetWeaponEnhancementBonus(object oWeapon, int nBonus, int bOnlyIfHigher = TRUE); + +// * Shortcut function to upgrade the enhancement bonus of a weapon by the +// * number specified in nUpgradeBy. If the resulting new enhancement bonus +// * would be out of bounds (>+20), it will be set to +20 +void IPUpgradeWeaponEnhancementBonus(object oWeapon, int nUpgradeBy); + +// * Returns TRUE if a character has any item equipped that has the itemproperty +// * defined in nItemPropertyConst in it (ITEM_PROPERTY_* constant) +int IPGetHasItemPropertyOnCharacter(object oPC, int nItemPropertyConst); + +// * Returns an integer with the number of properties present oItem +int IPGetNumberOfItemProperties(object oItem); + + + +//------------------------------------------------------------------------------ +// I M P L E M E N T A T I O N +//------------------------------------------------------------------------------ + +// ---------------------------------------------------------------------------- +// Removes all itemproperties with matching nItemPropertyType and +// nItemPropertyDuration (a DURATION_TYPE_* constant) +// ---------------------------------------------------------------------------- +/* void IPRemoveMatchingItemProperties(object oItem, int nItemPropertyType, int nItemPropertyDuration = DURATION_TYPE_TEMPORARY, int nItemPropertySubType = -1) +{ + itemproperty ip = GetFirstItemProperty(oItem); + + // valid ip? + while (GetIsItemPropertyValid(ip)) + { + // same property type? + if ((GetItemPropertyType(ip) == nItemPropertyType)) + { + // same duration or duration ignored? + if (GetItemPropertyDurationType(ip) == nItemPropertyDuration || nItemPropertyDuration == -1) + { + // same subtype or subtype ignored + if (GetItemPropertySubType(ip) == nItemPropertySubType || nItemPropertySubType == -1) + { */ + // Put a warning into the logfile if someone tries to remove a permanent ip with a temporary one! + /*if (nItemPropertyDuration == DURATION_TYPE_TEMPORARY && GetItemPropertyDurationType(ip) == DURATION_TYPE_PERMANENT) + { + WriteTimestampedLogEntry("prc_x2_itemprop:: IPRemoveMatchingItemProperties() - WARNING: Permanent item property removed by temporary on "+GetTag(oItem)); + } + */ +/* RemoveItemProperty(oItem, ip); + } + } + } + ip = GetNextItemProperty(oItem); + } +} */ + +// ---------------------------------------------------------------------------- +// Removes ALL item properties from oItem matching nItemPropertyDuration +// ---------------------------------------------------------------------------- +/* void IPRemoveAllItemProperties(object oItem, int nItemPropertyDuration = DURATION_TYPE_TEMPORARY) +{ + itemproperty ip = GetFirstItemProperty(oItem); + while (GetIsItemPropertyValid(ip)) + { + if (GetItemPropertyDurationType(ip) == nItemPropertyDuration) + { + RemoveItemProperty(oItem, ip); + } + ip = GetNextItemProperty(oItem); + } +} */ + +// ---------------------------------------------------------------------------- +// returns TRUE if item can be equipped. Uses Get2DAString, so do not use in a loop! +// ---------------------------------------------------------------------------- +/* int IPGetIsItemEquipable(object oItem) +{ + int nBaseType =GetBaseItemType(oItem); + + // fix, if we get BASE_ITEM_INVALID (usually because oItem is invalid), we + // need to make sure that this function returns FALSE + if(nBaseType==BASE_ITEM_INVALID) return FALSE; + + string sResult = Get2DAString("baseitems","EquipableSlots",nBaseType); + return (sResult != "0x00000"); +} */ + +// ---------------------------------------------------------------------------- +// Changes the color of an item armor +// oItem - The armor +// nColorType - ITEM_APPR_ARMOR_COLOR_* constant +// nColor - color from 0 to 63 +// Since oItem is destroyed in the process, the function returns +// the item created with the color changed +// ---------------------------------------------------------------------------- +/* object IPDyeArmor(object oItem, int nColorType, int nColor) +{ + object oRet = CopyItemAndModify(oItem,ITEM_APPR_TYPE_ARMOR_COLOR,nColorType,nColor,TRUE); + DestroyObject(oItem); // remove old item + return oRet; //return new item +} */ + +// ---------------------------------------------------------------------------- +// Returns the container used for item property and appearance modifications in the +// module. If it does not exist, it is created +// ---------------------------------------------------------------------------- +/* object IPGetIPWorkContainer(object oCaller = OBJECT_SELF) +{ + object oRet = GetObjectByTag(X2_IP_WORK_CONTAINER_TAG); + if (oRet == OBJECT_INVALID) + { + oRet = CreateObject(OBJECT_TYPE_PLACEABLE,X2_IP_WORK_CONTAINER_TAG,GetLocation(oCaller)); + effect eInvis = EffectVisualEffect( VFX_DUR_CUTSCENE_INVISIBILITY); + eInvis = ExtraordinaryEffect(eInvis); + ApplyEffectToObject(DURATION_TYPE_PERMANENT,eInvis,oRet); + if (oRet == OBJECT_INVALID) + { + WriteTimestampedLogEntry("prc_x2_itemprop - critical: Missing container with tag " +X2_IP_WORK_CONTAINER_TAG + "!!"); + } + } + + + return oRet; +} + */ +// ---------------------------------------------------------------------------- +// This function needs to be rather extensive and needs to be updated if there are new +// ip types we want to use, but it goes into the item property include anyway +// ---------------------------------------------------------------------------- +/* itemproperty IPGetItemPropertyByID(int nPropID, int nParam1 = 0, int nParam2 = 0, int nParam3 = 0, int nParam4 = 0) +{ + itemproperty ipRet; + + if (nPropID == ITEM_PROPERTY_ABILITY_BONUS) + { + ipRet = ItemPropertyAbilityBonus(nParam1, nParam2); + } + else if (nPropID == ITEM_PROPERTY_AC_BONUS) + { + ipRet = ItemPropertyACBonus(nParam1); + } + else if (nPropID == ITEM_PROPERTY_AC_BONUS_VS_ALIGNMENT_GROUP) + { + ipRet = ItemPropertyACBonusVsAlign(nParam1, nParam2); + } + else if (nPropID == ITEM_PROPERTY_AC_BONUS_VS_DAMAGE_TYPE) + { + ipRet = ItemPropertyACBonusVsDmgType(nParam1, nParam2); + } + else if (nPropID == ITEM_PROPERTY_AC_BONUS_VS_RACIAL_GROUP) + { + ipRet = ItemPropertyACBonusVsRace(nParam1, nParam2); + } + else if (nPropID == ITEM_PROPERTY_AC_BONUS_VS_SPECIFIC_ALIGNMENT) + { + ipRet = ItemPropertyACBonusVsSAlign(nParam1, nParam2); + } + else if (nPropID == ITEM_PROPERTY_ATTACK_BONUS) + { + ipRet = ItemPropertyAttackBonus(nParam1); + } + else if (nPropID == ITEM_PROPERTY_ATTACK_BONUS_VS_ALIGNMENT_GROUP) + { + ipRet = ItemPropertyAttackBonusVsAlign(nParam1, nParam2); + } + else if (nPropID == ITEM_PROPERTY_ATTACK_BONUS_VS_RACIAL_GROUP) + { + ipRet = ItemPropertyAttackBonusVsRace(nParam1, nParam2); + } + else if (nPropID == ITEM_PROPERTY_ATTACK_BONUS_VS_SPECIFIC_ALIGNMENT) + { + ipRet = ItemPropertyAttackBonusVsSAlign(nParam1, nParam2); + } + else if (nPropID == ITEM_PROPERTY_BASE_ITEM_WEIGHT_REDUCTION) + { + ipRet = ItemPropertyWeightReduction(nParam1); + } + else if (nPropID == ITEM_PROPERTY_BONUS_FEAT) + { + ipRet = ItemPropertyBonusFeat(nParam1); + } + else if (nPropID == ITEM_PROPERTY_BONUS_SPELL_SLOT_OF_LEVEL_N) + { + ipRet = ItemPropertyBonusLevelSpell(nParam1, nParam2); + } + else if (nPropID == ITEM_PROPERTY_CAST_SPELL) + { + ipRet = ItemPropertyCastSpell(nParam1, nParam2); + } + else if (nPropID == ITEM_PROPERTY_DAMAGE_BONUS) + { + ipRet = ItemPropertyDamageBonus(nParam1, nParam2); + } + else if (nPropID == ITEM_PROPERTY_DAMAGE_BONUS_VS_ALIGNMENT_GROUP) + { + ipRet = ItemPropertyDamageBonusVsAlign(nParam1, nParam2, nParam3); + } + else if (nPropID == ITEM_PROPERTY_DAMAGE_BONUS_VS_RACIAL_GROUP) + { + ipRet = ItemPropertyDamageBonusVsRace(nParam1, nParam2, nParam3); + } + else if (nPropID == ITEM_PROPERTY_DAMAGE_BONUS_VS_SPECIFIC_ALIGNMENT) + { + ipRet = ItemPropertyDamageBonusVsSAlign(nParam1, nParam2, nParam3); + } + else if (nPropID == ITEM_PROPERTY_DAMAGE_REDUCTION) + { + ipRet = ItemPropertyDamageReduction(nParam1, nParam2); + } + else if (nPropID == ITEM_PROPERTY_DAMAGE_RESISTANCE) + { + ipRet = ItemPropertyDamageResistance(nParam1, nParam2); + } + else if (nPropID == ITEM_PROPERTY_DAMAGE_VULNERABILITY) + { + ipRet = ItemPropertyDamageResistance(nParam1, nParam2); + } + else if (nPropID == ITEM_PROPERTY_DARKVISION) + { + ipRet = ItemPropertyDarkvision(); + } + else if (nPropID == ITEM_PROPERTY_DECREASED_ABILITY_SCORE) + { + ipRet = ItemPropertyDecreaseAbility(nParam1,nParam2); + } + else if (nPropID == ITEM_PROPERTY_DECREASED_AC) + { + ipRet = ItemPropertyDecreaseAC(nParam1,nParam2); + } + else if (nPropID == ITEM_PROPERTY_DECREASED_ATTACK_MODIFIER) + { + ipRet = ItemPropertyAttackPenalty(nParam1); + } + else if (nPropID == ITEM_PROPERTY_DECREASED_ENHANCEMENT_MODIFIER) + { + ipRet = ItemPropertyEnhancementPenalty(nParam1); + } + else if (nPropID == ITEM_PROPERTY_DECREASED_SAVING_THROWS) + { + ipRet = ItemPropertyReducedSavingThrow(nParam1, nParam2); + } + else if (nPropID == ITEM_PROPERTY_DECREASED_SAVING_THROWS_SPECIFIC) + { + ipRet = ItemPropertyBonusSavingThrowVsX(nParam1, nParam2); + } + else if (nPropID == ITEM_PROPERTY_DECREASED_SKILL_MODIFIER) + { + ipRet = ItemPropertyDecreaseSkill(nParam1, nParam2); + } + else if (nPropID == ITEM_PROPERTY_ENHANCED_CONTAINER_REDUCED_WEIGHT) + { + ipRet = ItemPropertyContainerReducedWeight(nParam1); + } + else if (nPropID == ITEM_PROPERTY_ENHANCEMENT_BONUS) + { + ipRet = ItemPropertyEnhancementBonus(nParam1); + } + else if (nPropID == ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_ALIGNMENT_GROUP) + { + ipRet = ItemPropertyEnhancementBonusVsAlign(nParam1,nParam2); + } + else if (nPropID == ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_SPECIFIC_ALIGNEMENT) + { + ipRet = ItemPropertyEnhancementBonusVsSAlign(nParam1,nParam2); + } + else if (nPropID == ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_RACIAL_GROUP) + { + ipRet = ItemPropertyEnhancementBonusVsRace(nParam1,nParam2); + } + else if (nPropID == ITEM_PROPERTY_EXTRA_MELEE_DAMAGE_TYPE) + { + ipRet = ItemPropertyExtraMeleeDamageType(nParam1); + } + else if (nPropID == ITEM_PROPERTY_EXTRA_RANGED_DAMAGE_TYPE) + { + ipRet = ItemPropertyExtraRangeDamageType(nParam1); + } + else if (nPropID == ITEM_PROPERTY_HASTE) + { + ipRet = ItemPropertyHaste(); + } + else if (nPropID == ITEM_PROPERTY_KEEN) + { + ipRet = ItemPropertyKeen(); + } + else if (nPropID == ITEM_PROPERTY_LIGHT) + { + ipRet = ItemPropertyLight(nParam1,nParam2); + } + else if (nPropID == ITEM_PROPERTY_MASSIVE_CRITICALS) + { + ipRet = ItemPropertyMassiveCritical(nParam1); + } + else if (nPropID == ITEM_PROPERTY_NO_DAMAGE) + { + ipRet = ItemPropertyNoDamage(); + } + else if (nPropID == ITEM_PROPERTY_ON_HIT_PROPERTIES) + { + ipRet = ItemPropertyOnHitProps(nParam1, nParam2, nParam3); + } + else if (nPropID == ITEM_PROPERTY_TRAP) + { + ipRet = ItemPropertyTrap(nParam1, nParam2); + } + else if (nPropID == ITEM_PROPERTY_TRUE_SEEING) + { + ipRet = ItemPropertyTrueSeeing(); + } + else if (nPropID == ITEM_PROPERTY_UNLIMITED_AMMUNITION) + { + ipRet = ItemPropertyUnlimitedAmmo(nParam1); + } + else if (nPropID == ITEM_PROPERTY_ONHITCASTSPELL) + { + ipRet = ItemPropertyOnHitCastSpell(nParam1, nParam2); + } + else if (nPropID == ITEM_PROPERTY_ARCANE_SPELL_FAILURE) + { + ipRet = ItemPropertyArcaneSpellFailure(nParam1); + } + + + return ipRet; +} + */ +// ---------------------------------------------------------------------------- +// Returns TRUE if oItem is a projectile +// ---------------------------------------------------------------------------- +/* int IPGetIsProjectile(object oItem) +{ + int nBT = GetBaseItemType(oItem); + return (nBT == BASE_ITEM_ARROW || nBT == BASE_ITEM_BOLT || nBT == BASE_ITEM_BULLET); +} */ + +// ---------------------------------------------------------------------------- +// Returns TRUE if oItem is a ranged weapon +// ---------------------------------------------------------------------------- +/* int IPGetIsRangedWeapon(object oItem) +{ + return GetWeaponRanged(oItem); // doh ! +} + */ + +// ---------------------------------------------------------------------------- +// Returns TRUE if oItem is a melee weapon. +// ---------------------------------------------------------------------------- +/* int IPGetIsMeleeWeapon(object oItem) +{ + int nItemType = GetBaseItemType(oItem); + if ( nItemType < 300 ) + // BioWare weapons. + switch ( nItemType ) + { + case BASE_ITEM_BASTARDSWORD: + case BASE_ITEM_BATTLEAXE: + case BASE_ITEM_CLUB: + case BASE_ITEM_DAGGER: + case BASE_ITEM_DIREMACE: + case BASE_ITEM_DOUBLEAXE: + case BASE_ITEM_DWARVENWARAXE: + case BASE_ITEM_GREATAXE: + case BASE_ITEM_GREATSWORD: + case BASE_ITEM_HALBERD: + case BASE_ITEM_HANDAXE: + case BASE_ITEM_HEAVYFLAIL: + case BASE_ITEM_KAMA: + case BASE_ITEM_KATANA: + case BASE_ITEM_KUKRI: + case BASE_ITEM_LIGHTFLAIL: + case BASE_ITEM_LIGHTHAMMER: + case BASE_ITEM_LIGHTMACE: + case BASE_ITEM_LONGSWORD: + case BASE_ITEM_MAGICSTAFF: + case BASE_ITEM_MORNINGSTAR: + case BASE_ITEM_QUARTERSTAFF: + case BASE_ITEM_RAPIER: + case BASE_ITEM_SCIMITAR: + case BASE_ITEM_SCYTHE: + case BASE_ITEM_SHORTSPEAR: + case BASE_ITEM_SHORTSWORD: + case BASE_ITEM_SICKLE: + case BASE_ITEM_TRIDENT: + case BASE_ITEM_TWOBLADEDSWORD: + case BASE_ITEM_WARHAMMER: + case BASE_ITEM_WHIP: + return TRUE; + } + else + // CEP weapons. + switch ( nItemType ) + { + case 300: // CEP trident + case 301: // heavy pick + case 302: // light pick + case 303: // sai + case 304: // nunchaku + case 305: // falchion + case 308: // sap + case 309: // assassin dagger + case 310: // katar + case 312: // mace2 + case 313: // kukri2 + case 314: // fashion accessory + case 316: // falchion2 + case 317: // heavy mace + case 318: // maul + case 319: // mercurial longsword + case 320: // mercurial greatsword + case 321: // double scimitar + case 322: // goad + case 323: // wind-fire wheel + case 324: // maug double sword + case 330: // longsword2 + return TRUE; + } + + // Default: not a melee weapon. + return FALSE; +} + */ + +// ---------------------------------------------------------------------------- +// Returns TRUE if weapon is a blugeoning weapon +// Uses Get2DAString! +// ---------------------------------------------------------------------------- +/* int IPGetIsBludgeoningWeapon(object oItem) +{ + int nBT = GetBaseItemType(oItem); + int nWeapon = ( StringToInt(Get2DAString("baseitems","WeaponType",nBT))); + // 2 = bludgeoning + return (nWeapon == 2); +} */ + +// ---------------------------------------------------------------------------- +// Return the IP_CONST_CASTSPELL_* ID matching to the SPELL_* constant given +// in nSPELL_ID. +// This uses Get2DAstring, so it is slow. Avoid using in loops! +// returns -1 if there is no matching property for a spell +// ---------------------------------------------------------------------------- +/* int IPGetIPConstCastSpellFromSpellID(int nSpellID) +{ + // look up Spell Property Index + string sTemp = Get2DAString("des_crft_spells","IPRP_SpellIndex",nSpellID); + /* + if (sTemp == "") // invalid nSpellID + { + PrintString("prc_x2_craft.nss::GetIPConstCastSpellFromSpellID called with invalid nSpellID" + IntToString(nSpellID)); + return -1; + } + */ + /*int nSpellPrpIdx = StringToInt(sTemp); + return nSpellPrpIdx; +} */ +// ---------------------------------------------------------------------------- +// Returns TRUE if an item has ITEM_PROPERTY_ON_HIT and the specified nSubType +// possible values for nSubType can be taken from IPRP_ONHIT.2da +// popular ones: +// 5 - Daze +// 19 - ItemPoison +// 24 - Vorpal +// ---------------------------------------------------------------------------- +/* int IPGetItemHasItemOnHitPropertySubType(object oTarget, int nSubType) +{ + if (GetItemHasItemProperty(oTarget,ITEM_PROPERTY_ON_HIT_PROPERTIES)) + { + itemproperty ipTest = GetFirstItemProperty(oTarget); + + // loop over item properties to see if there is already a poison effect + while (GetIsItemPropertyValid(ipTest)) + { + + if (GetItemPropertySubType(ipTest) == nSubType) //19 == onhit poison + { + return TRUE; + } + + ipTest = GetNextItemProperty(oTarget); + + } + } + return FALSE; +} + */ +// ---------------------------------------------------------------------------- +// Returns the number of possible armor part variations for the specified part +// nPart - ITEM_APPR_ARMOR_MODEL_* constant +// Uses Get2DAstring, so do not use in loops +// ---------------------------------------------------------------------------- +/* int IPGetNumberOfArmorAppearances(int nPart) +{ + int nRet; + //SpeakString(Get2DAString(X2_IP_ARMORPARTS_2DA ,"NumParts",nPart)); + nRet = StringToInt(Get2DAString(X2_IP_ARMORPARTS_2DA ,"NumParts",nPart)); + return nRet; +} */ + +// ---------------------------------------------------------------------------- +// (private) +// Returns the previous or next armor appearance type, depending on the specified +// mode (X2_IP_ARMORTYPE_NEXT || X2_IP_ARMORTYPE_PREV) +// ---------------------------------------------------------------------------- +/* int IPGetArmorAppearanceType(object oArmor, int nPart, int nMode) +{ + string sMode; + + switch (nMode) + { + case X2_IP_ARMORTYPE_NEXT : sMode ="Next"; + break; + case X2_IP_ARMORTYPE_PREV : sMode ="Prev"; + break; + } + + int nCurrApp = GetItemAppearance(oArmor,ITEM_APPR_TYPE_ARMOR_MODEL,nPart); + int nRet; + + if (nPart ==ITEM_APPR_ARMOR_MODEL_TORSO) + { + nRet = StringToInt(Get2DAString(X2_IP_ARMORAPPEARANCE_2DA ,sMode,nCurrApp)); + return nRet; + } + else + { + int nMax = IPGetNumberOfArmorAppearances(nPart)-1; // index from 0 .. numparts -1 + int nMin = 1; // this prevents part 0 from being chosen (naked) + + // return a random valid armor tpze + if (nMode == X2_IP_ARMORTYPE_RANDOM) + { + return Random(nMax)+nMin; + } + + else + { + if (nMode == X2_IP_ARMORTYPE_NEXT) + { + // current appearance is max, return min + if (nCurrApp == nMax) + { + return nMin; + } + // current appearance is min, return max -1 + else if (nCurrApp == nMin) + { + nRet = nMin+1; + return nRet; + } + + //SpeakString("next"); + // next + nRet = nCurrApp +1; + return nRet; + } + else // previous + { + // current appearance is max, return nMax-1 + if (nCurrApp == nMax) + { + nRet = nMax--; + return nRet; + } + // current appearance is min, return max + else if (nCurrApp == nMin) + { + return nMax; + } + + //SpeakString("prev"); + + nRet = nCurrApp -1; + return nRet; + } + } + + } + +} + */ +// ---------------------------------------------------------------------------- +// Returns the next valid appearance type for oArmor +// Uses Get2DAstring, so do not use in loops +// ---------------------------------------------------------------------------- +/* int IPGetNextArmorAppearanceType(object oArmor, int nPart) +{ + return IPGetArmorAppearanceType(oArmor, nPart, X2_IP_ARMORTYPE_NEXT ); + +} */ + +// ---------------------------------------------------------------------------- +// Returns the next valid appearance type for oArmor +// Uses Get2DAstring, so do not use in loops +// ---------------------------------------------------------------------------- +/* int IPGetPrevArmorAppearanceType(object oArmor, int nPart) +{ + return IPGetArmorAppearanceType(oArmor, nPart, X2_IP_ARMORTYPE_PREV ); +} */ + +// ---------------------------------------------------------------------------- +// Returns the next valid appearance type for oArmor +// Uses Get2DAstring, so do not use in loops +// ---------------------------------------------------------------------------- +/* int IPGetRandomArmorAppearanceType(object oArmor, int nPart) +{ + return IPGetArmorAppearanceType(oArmor, nPart, X2_IP_ARMORTYPE_RANDOM ); +} */ + +// ---------------------------------------------------------------------------- +// Returns a new armor based of oArmor with nPartModified +// nPart - ITEM_APPR_ARMOR_MODEL_* constant of the part to be changed +// nMode - +// X2_IP_ARMORTYPE_NEXT - next valid appearance +// X2_IP_ARMORTYPE_PREV - previous valid apperance; +// X2_IP_ARMORTYPE_RANDOM - random valid appearance (torso is never changed); +// bDestroyOldOnSuccess - Destroy oArmor in process? +// Uses Get2DAstring, so do not use in loops +// ---------------------------------------------------------------------------- +/* object IPGetModifiedArmor(object oArmor, int nPart, int nMode, int bDestroyOldOnSuccess) +{ + int nNewApp = IPGetArmorAppearanceType(oArmor, nPart, nMode ); + //SpeakString("old: " + IntToString(GetItemAppearance(oArmor,ITEM_APPR_TYPE_ARMOR_MODEL,nPart))); + //SpeakString("new: " + IntToString(nNewApp)); + + object oNew = CopyItemAndModify(oArmor,ITEM_APPR_TYPE_ARMOR_MODEL, nPart, nNewApp,TRUE); + + if (oNew != OBJECT_INVALID) + { + if( bDestroyOldOnSuccess ) + { + DestroyObject(oArmor); + } + return oNew; + } + // Safety fallback, return old armor on failures + return oArmor; +} + */ +// ---------------------------------------------------------------------------- +// Creates a special ring on oCreature that gives +// all weapon and armor proficiencies to the wearer +// Item is set non dropable +// ---------------------------------------------------------------------------- +/* object IPCreateProficiencyFeatItemOnCreature(object oCreature) +{ + // create a simple golden ring + object oRing = CreateItemOnObject("nw_it_mring023",oCreature); + + // just in case + SetDroppableFlag(oRing, FALSE); + + itemproperty ip = ItemPropertyBonusFeat(IP_CONST_FEAT_ARMOR_PROF_HEAVY); + AddItemProperty(DURATION_TYPE_PERMANENT,ip,oRing); + ip = ItemPropertyBonusFeat(IP_CONST_FEAT_ARMOR_PROF_MEDIUM); + AddItemProperty(DURATION_TYPE_PERMANENT,ip,oRing); + ip = ItemPropertyBonusFeat(IP_CONST_FEAT_ARMOR_PROF_LIGHT); + AddItemProperty(DURATION_TYPE_PERMANENT,ip,oRing); + ip = ItemPropertyBonusFeat(IP_CONST_FEAT_WEAPON_PROF_EXOTIC); + AddItemProperty(DURATION_TYPE_PERMANENT,ip,oRing); + ip = ItemPropertyBonusFeat(IP_CONST_FEAT_WEAPON_PROF_MARTIAL); + AddItemProperty(DURATION_TYPE_PERMANENT,ip,oRing); + ip = ItemPropertyBonusFeat(IP_CONST_FEAT_WEAPON_PROF_SIMPLE); + AddItemProperty(DURATION_TYPE_PERMANENT,ip,oRing); + + return oRing; +} + + */ +// ---------------------------------------------------------------------------- +// Add an item property in a safe fashion, preventing unwanted stacking +// Parameters: +// oItem - the item to add the property to +// ip - the itemproperty to add +// fDuration - set 0.0f to add the property permanent, anything else is temporary +// nAddItemPropertyPolicy - How to handle existing properties. Valid values are: +// X2_IP_ADDPROP_POLICY_REPLACE_EXISTING - remove any property of the same type, subtype, durationtype before adding; +// X2_IP_ADDPROP_POLICY_KEEP_EXISTING - do not add if any property with same type, subtype and durationtype already exists; +// X2_IP_ADDPROP_POLICY_IGNORE_EXISTING - add itemproperty in any case - Do not Use with OnHit or OnHitSpellCast props! +// bIgnoreDurationType - If set to TRUE, an item property will be considered identical even if the DurationType is different. Be careful when using this +// with X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, as this could lead to a temporary item property removing a permanent one +// bIgnoreSubType - If set to TRUE an item property will be considered identical even if the SubType is different. +// +// * WARNING: This function is used all over the game. Touch it and break it and the wrath +// of the gods will come down on you faster than you can saz "I didn't do it" +// ---------------------------------------------------------------------------- +/* void IPSafeAddItemProperty(object oItem, itemproperty ip, float fDuration =0.0f, int nAddItemPropertyPolicy = X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, int bIgnoreDurationType = FALSE, int bIgnoreSubType = FALSE) +{ + int nType = GetItemPropertyType(ip); + int nSubType = GetItemPropertySubType(ip); + int nDuration; + // if duration is 0.0f, make the item property permanent + if (fDuration == 0.0f) + { + + nDuration = DURATION_TYPE_PERMANENT; + } else + { + + nDuration = DURATION_TYPE_TEMPORARY; + } + + int nDurationCompare = nDuration; + if (bIgnoreDurationType) + { + nDurationCompare = -1; + } + + if (nAddItemPropertyPolicy == X2_IP_ADDPROP_POLICY_REPLACE_EXISTING) + { + + // remove any matching properties + if (bIgnoreSubType) + { + nSubType = -1; + } + IPRemoveMatchingItemProperties(oItem, nType, nDurationCompare, nSubType ); + } + else if (nAddItemPropertyPolicy == X2_IP_ADDPROP_POLICY_KEEP_EXISTING ) + { + // do not replace existing properties + if(IPGetItemHasProperty(oItem, ip, nDurationCompare, bIgnoreSubType)) + { + return; // item already has property, return + } + } + else //X2_IP_ADDPROP_POLICY_IGNORE_EXISTING + { + + } + + if (nDuration == DURATION_TYPE_PERMANENT) + { + AddItemProperty(nDuration,ip, oItem); + } + else + { + AddItemProperty(nDuration,ip, oItem,fDuration); + } + /// TK addition: + TK_RecordSpellItemProperty(oItem, ip, fDuration); +} + */ +// ---------------------------------------------------------------------------- + +// ---------------------------------------------------------------------------- +/* int IPGetItemHasProperty(object oItem, itemproperty ipCompareTo, int nDurationCompare, int bIgnoreSubType = FALSE) +{ + itemproperty ip = GetFirstItemProperty(oItem); + + //PrintString ("Filter - T:" + IntToString(GetItemPropertyType(ipCompareTo))+ " S: " + IntToString(GetItemPropertySubType(ipCompareTo)) + " (Ignore: " + IntToString (bIgnoreSubType) + ") D:" + IntToString(nDurationCompare)); + while (GetIsItemPropertyValid(ip)) + { + // PrintString ("Testing - T: " + IntToString(GetItemPropertyType(ip))); + if ((GetItemPropertyType(ip) == GetItemPropertyType(ipCompareTo))) + { + //PrintString ("**Testing - S: " + IntToString(GetItemPropertySubType(ip))); + if (GetItemPropertySubType(ip) == GetItemPropertySubType(ipCompareTo) || bIgnoreSubType) + { + // PrintString ("***Testing - d: " + IntToString(GetItemPropertyDurationType(ip))); + if (GetItemPropertyDurationType(ip) == nDurationCompare || nDurationCompare == -1) + { + //PrintString ("***FOUND"); + return TRUE; // if duration is not ignored and durationtypes are equal, true + } + } + } + ip = GetNextItemProperty(oItem); + } + //PrintString ("Not Found"); + return FALSE; +} + */ + +// Returns the targeted object if it is a melee weapon. +// Otherwise returns a melee weapon equipped by the target. +/* object IPGetTargetedOrEquippedMeleeWeapon() +{ + object oTarget = PRCGetSpellTargetObject(); + + // Abort on an invalid target. + if ( oTarget == OBJECT_INVALID ) + return OBJECT_INVALID; + + // See if the target is a melee weapon. + if ( GetObjectType(oTarget) == OBJECT_TYPE_ITEM ) + { + if ( IPGetIsMeleeWeapon(oTarget) ) + return oTarget; + else + // Items cannot euip other items, so we're done. + return OBJECT_INVALID; + } + + // Check the equipped items. + object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget); + if ( oWeapon != OBJECT_INVALID && IPGetIsMeleeWeapon(oWeapon) ) + return oWeapon; + + // Tough to have a weapon in the left hand without one in the right, but... + oWeapon = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget); + if ( oWeapon != OBJECT_INVALID && IPGetIsMeleeWeapon(oWeapon) ) + return oWeapon; + + // Don't forget the creature weapons. + // These are assumed to be melee weapons. + oWeapon = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oTarget); + if ( oWeapon != OBJECT_INVALID ) + return oWeapon; + oWeapon = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oTarget); + if ( oWeapon != OBJECT_INVALID ) + return oWeapon; + oWeapon = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oTarget); + if ( oWeapon != OBJECT_INVALID ) + return oWeapon; + + // Default: no valid weapon target. + return OBJECT_INVALID; +} + */ + +// Returns the targeted item if it is armor. Otherwise, returns the +// armor equipped by the target. +// Shields are counted as armor only if bAllowShields is TRUE. +// (Fixed for WoG) +/* object IPGetTargetedOrEquippedArmor(int bAllowShields = FALSE); +object IPGetTargetedOrEquippedArmor(int bAllowShields = FALSE) +{ + object oTarget = PRCGetSpellTargetObject(); + int nTargetType = GetObjectType(oTarget); + + // Check for a targeted item. + if ( nTargetType == OBJECT_TYPE_ITEM ) + { + // Make sure oTarget is the right kind of item. + int nBaseItem = GetBaseItemType(oTarget); + // Allow armor to be returned. + if ( nBaseItem == BASE_ITEM_ARMOR ) + return oTarget; + else if ( bAllowShields ) + // Allow shields to be returned. + if ( nBaseItem == BASE_ITEM_LARGESHIELD || + nBaseItem == BASE_ITEM_SMALLSHIELD || + nBaseItem == BASE_ITEM_TOWERSHIELD ) + return oTarget; + // else not the right kind of item; do nothing for now. + } + + // Check for a targeted creature. + else if ( nTargetType == OBJECT_TYPE_CREATURE ) + { + // Check for a shield? + if ( bAllowShields ) + { + // Try to return the target's equipped shield. + object oShield = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget); + // Make sure we found a shield. + int nBaseItem = GetBaseItemType(oShield); + if ( nBaseItem == BASE_ITEM_LARGESHIELD || + nBaseItem == BASE_ITEM_SMALLSHIELD || + nBaseItem == BASE_ITEM_TOWERSHIELD ) + // Return the shield. + return oShield; + } + + // Try to return the target's equipped armor. + object oArmor = GetItemInSlot(INVENTORY_SLOT_CHEST, oTarget); + if ( GetBaseItemType(oArmor) == BASE_ITEM_ARMOR ) + return oArmor; + } + + // No armor found on target. + return OBJECT_INVALID; +} + */ +// ---------------------------------------------------------------------------- +// Returns FALSE it the item has no sequencer property +// Returns number of spells that can be stored in any other case +// ---------------------------------------------------------------------------- +/* int IPGetItemSequencerProperty(object oItem) +{ + if (!GetItemHasItemProperty(oItem, ITEM_PROPERTY_CAST_SPELL)) + { + return FALSE; + } + + int nCnt; + itemproperty ip; + + ip = GetFirstItemProperty(oItem); + + while (GetIsItemPropertyValid(ip) && nCnt ==0) + { + if (GetItemPropertyType(ip) ==ITEM_PROPERTY_CAST_SPELL) + { + if(GetItemPropertySubType(ip) == 523) // sequencer 3 + { + nCnt = 3; + } + else if(GetItemPropertySubType(ip) == 522) // sequencer 2 + { + nCnt = 2; + } + else if(GetItemPropertySubType(ip) == 521) // sequencer 1 + { + nCnt = 1; + } + } + ip = GetNextItemProperty(oItem); + } + + return nCnt; +} + */ +/* void IPCopyItemProperties(object oSource, object oTarget, int bIgnoreCraftProps = TRUE) +{ + itemproperty ip = GetFirstItemProperty(oSource); + int nSub; + + while (GetIsItemPropertyValid(ip)) + { + if (GetItemPropertyDurationType(ip) == DURATION_TYPE_PERMANENT) + { + if (bIgnoreCraftProps) + { + if (GetItemPropertyType(ip) ==ITEM_PROPERTY_CAST_SPELL) + { + nSub = GetItemPropertySubType(ip); + // filter crafting properties + if (nSub != 498 && nSub != 499 && nSub != 526 && nSub != 527) + { + AddItemProperty(DURATION_TYPE_PERMANENT,ip,oTarget); + } + } + else + { + AddItemProperty(DURATION_TYPE_PERMANENT,ip,oTarget); + } + } + else + { + AddItemProperty(DURATION_TYPE_PERMANENT,ip,oTarget); + } + } + ip = GetNextItemProperty(oSource); + } +} + */ +/* int IPGetIsIntelligentWeapon(object oItem) +{ + int bRet = FALSE ; + itemproperty ip = GetFirstItemProperty(oItem); + while (GetIsItemPropertyValid(ip)) + { + if (GetItemPropertyType(ip) == ITEM_PROPERTY_ONHITCASTSPELL) + { + if (GetItemPropertySubType(ip) == 135) + { + return TRUE; + } + } + ip = GetNextItemProperty(oItem); + } + return bRet; +} + */ +// ---------------------------------------------------------------------------- +// (private) +// ---------------------------------------------------------------------------- +/* int IPGetWeaponAppearanceType(object oWeapon, int nPart, int nMode) +{ + string sMode; + + switch (nMode) + { + case X2_IP_WEAPONTYPE_NEXT : sMode ="Next"; + break; + case X2_IP_WEAPONTYPE_PREV : sMode ="Prev"; + break; + } + + int nCurrApp = GetItemAppearance(oWeapon,ITEM_APPR_TYPE_WEAPON_MODEL,nPart); + int nRet; + + int nMax = 9;// IPGetNumberOfArmorAppearances(nPart)-1; // index from 0 .. numparts -1 + int nMin = 1; + + // return a random valid armor tpze + if (nMode == X2_IP_WEAPONTYPE_RANDOM) + { + return Random(nMax)+nMin; + } + + else + { + if (nMode == X2_IP_WEAPONTYPE_NEXT) + { + // current appearance is max, return min + if (nCurrApp == nMax) + { + return nMax; + } + // current appearance is min, return max -1 + else if (nCurrApp == nMin) + { + nRet = nMin +1; + return nRet; + } + + //SpeakString("next"); + // next + nRet = nCurrApp +1; + return nRet; + } + else // previous + { + // current appearance is max, return nMax-1 + if (nCurrApp == nMax) + { + nRet = nMax--; + return nRet; + } + // current appearance is min, return max + else if (nCurrApp == nMin) + { + return nMin; + } + + //SpeakString("prev"); + + nRet = nCurrApp -1; + return nRet; + } + + + } +} + */ +// ---------------------------------------------------------------------------- +// Returns a new armor based of oArmor with nPartModified +// nPart - ITEM_APPR_WEAPON_MODEL_* constant of the part to be changed +// nMode - +// X2_IP_WEAPONTYPE_NEXT - next valid appearance +// X2_IP_WEAPONTYPE_PREV - previous valid apperance; +// X2_IP_WEAPONTYPE_RANDOM - random valid appearance (torso is never changed); +// bDestroyOldOnSuccess - Destroy oArmor in process? +// Uses Get2DAstring, so do not use in loops +// ---------------------------------------------------------------------------- +/* object IPGetModifiedWeapon(object oWeapon, int nPart, int nMode, int bDestroyOldOnSuccess) +{ + int nNewApp = IPGetWeaponAppearanceType(oWeapon, nPart, nMode ); + //SpeakString("old: " + IntToString(GetItemAppearance(oWeapon,ITEM_APPR_TYPE_WEAPON_MODEL,nPart))); + //SpeakString("new: " + IntToString(nNewApp)); + object oNew = CopyItemAndModify(oWeapon,ITEM_APPR_TYPE_WEAPON_MODEL, nPart, nNewApp,TRUE); + if (oNew != OBJECT_INVALID) + { + if( bDestroyOldOnSuccess ) + { + DestroyObject(oWeapon); + } + return oNew; + } + // Safety fallback, return old weapon on failures + return oWeapon; +} + + */ +/* object IPCreateAndModifyArmorRobe(object oArmor, int nRobeType) +{ + object oRet = CopyItemAndModify(oArmor,ITEM_APPR_TYPE_ARMOR_MODEL,ITEM_APPR_ARMOR_MODEL_ROBE,nRobeType+2,TRUE); + if (GetIsObjectValid(oRet)) + { + return oRet; + } + else // safety net + { + return oArmor; + } +} */ + +// ---------------------------------------------------------------------------- +// Provide mapping between numbers and power constants for +// ITEM_PROPERTY_DAMAGE_BONUS +// ---------------------------------------------------------------------------- +/* int IPGetDamagePowerConstantFromNumber(int nNumber) +{ + switch (nNumber) + { + case 0: return DAMAGE_POWER_NORMAL; + case 1: return DAMAGE_POWER_PLUS_ONE; + case 2: return DAMAGE_POWER_PLUS_TWO; + case 3: return DAMAGE_POWER_PLUS_THREE; + case 4: return DAMAGE_POWER_PLUS_FOUR; + case 5: return DAMAGE_POWER_PLUS_FIVE; + case 6: return DAMAGE_POWER_PLUS_SIX; + case 7: return DAMAGE_POWER_PLUS_SEVEN; + case 8: return DAMAGE_POWER_PLUS_EIGHT; + case 9: return DAMAGE_POWER_PLUS_NINE; + case 10: return DAMAGE_POWER_PLUS_TEN; + case 11: return DAMAGE_POWER_PLUS_ELEVEN; + case 12: return DAMAGE_POWER_PLUS_TWELVE; + case 13: return DAMAGE_POWER_PLUS_THIRTEEN; + case 14: return DAMAGE_POWER_PLUS_FOURTEEN; + case 15: return DAMAGE_POWER_PLUS_FIFTEEN; + case 16: return DAMAGE_POWER_PLUS_SIXTEEN; + case 17: return DAMAGE_POWER_PLUS_SEVENTEEN; + case 18: return DAMAGE_POWER_PLUS_EIGHTEEN ; + case 19: return DAMAGE_POWER_PLUS_NINTEEN; + case 20: return DAMAGE_POWER_PLUS_TWENTY; + } + + if (nNumber>20) + { + return DAMAGE_POWER_PLUS_TWENTY; + } + else + { + return DAMAGE_POWER_NORMAL; + } +} + */ +// ---------------------------------------------------------------------------- +// Provide mapping between numbers and bonus constants for ITEM_PROPERTY_DAMAGE_BONUS +// Note that nNumber should be > 0! +// ---------------------------------------------------------------------------- +/* int IPGetDamageBonusConstantFromNumber(int nNumber) +{ + switch (nNumber) + { + case 1: return DAMAGE_BONUS_1; + case 2: return DAMAGE_BONUS_2; + case 3: return DAMAGE_BONUS_3; + case 4: return DAMAGE_BONUS_4; + case 5: return DAMAGE_BONUS_5; + case 6: return DAMAGE_BONUS_6; + case 7: return DAMAGE_BONUS_7; + case 8: return DAMAGE_BONUS_8; + case 9: return DAMAGE_BONUS_9; + case 10: return DAMAGE_BONUS_10; + case 11: return DAMAGE_BONUS_11; + case 12: return DAMAGE_BONUS_12; + case 13: return DAMAGE_BONUS_13; + case 14: return DAMAGE_BONUS_14; + case 15: return DAMAGE_BONUS_15; + case 16: return DAMAGE_BONUS_16; + case 17: return DAMAGE_BONUS_17; + case 18: return DAMAGE_BONUS_18; + case 19: return DAMAGE_BONUS_19; + case 20: return DAMAGE_BONUS_20; + + } + + if (nNumber>20) + { + return DAMAGE_BONUS_20; + } + else + { + return -1; + } +} + */ +// ---------------------------------------------------------------------------- +// GZ, Sept. 30 2003 +// Special Version of Copy Item Properties for use with greater wild shape +// oOld - Item equipped before polymorphing (source for item props) +// oNew - Item equipped after polymorphing (target for item props) +// bWeapon - Must be set TRUE when oOld is a weapon. +// ---------------------------------------------------------------------------- +/* void IPWildShapeCopyItemProperties(object oOld, object oNew, int bWeapon = FALSE) +{ + if (GetIsObjectValid(oOld) && GetIsObjectValid(oNew)) + { + itemproperty ip = GetFirstItemProperty(oOld); + while (GetIsItemPropertyValid(ip)) + { + if (bWeapon) + { + if (GetWeaponRanged(oOld) == GetWeaponRanged(oNew) ) + { + AddItemProperty(DURATION_TYPE_PERMANENT,ip,oNew); + } + } + else + { + AddItemProperty(DURATION_TYPE_PERMANENT,ip,oNew); + } + ip = GetNextItemProperty(oOld); + + } + } +} + */ +// ---------------------------------------------------------------------------- +// Returns the current enhancement bonus of a weapon (+1 to +20), 0 if there is +// no enhancement bonus. You can test for a specific type of enhancement bonus +// by passing the appropritate ITEM_PROPERTY_ENHANCEMENT_BONUS* constant into +// nEnhancementBonusType +// ---------------------------------------------------------------------------- +/* int IPGetWeaponEnhancementBonus(object oWeapon, int nEnhancementBonusType = ITEM_PROPERTY_ENHANCEMENT_BONUS) +{ + itemproperty ip = GetFirstItemProperty(oWeapon); + int nFound = 0; + while (nFound == 0 && GetIsItemPropertyValid(ip)) + { + if (GetItemPropertyType(ip) ==nEnhancementBonusType) + { + nFound = GetItemPropertyCostTableValue(ip); + } + ip = GetNextItemProperty(oWeapon); + } + return nFound; +} + */ +// ---------------------------------------------------------------------------- +// Shortcut function to set the enhancement bonus of a weapon to a certain bonus +// Specifying bOnlyIfHigher as TRUE will prevent a bonus lower than the requested +// bonus from being applied. Valid values for nBonus are 1 to 20. +// ---------------------------------------------------------------------------- +/* void IPSetWeaponEnhancementBonus(object oWeapon, int nBonus, int bOnlyIfHigher = TRUE) +{ + int nCurrent = IPGetWeaponEnhancementBonus(oWeapon); + + itemproperty ip = GetFirstItemProperty(oWeapon); + + if (bOnlyIfHigher && nCurrent > nBonus) + { + return; + } + + if (nBonus <1 || nBonus > 20) + { + return; + } + + while (GetIsItemPropertyValid(ip)) + { + if (GetItemPropertyType(ip) ==ITEM_PROPERTY_ENHANCEMENT_BONUS) + { + RemoveItemProperty(oWeapon,ip); + } + ip = GetNextItemProperty(oWeapon); + } + + ip = ItemPropertyEnhancementBonus(nBonus); + AddItemProperty(DURATION_TYPE_PERMANENT,ip,oWeapon); +} + + */ +// ---------------------------------------------------------------------------- +// Shortcut function to upgrade the enhancement bonus of a weapon by the +// number specified in nUpgradeBy. If the resulting new enhancement bonus +// would be out of bounds (>+20), it will be set to +20 +// ---------------------------------------------------------------------------- +void IPUpgradeWeaponEnhancementBonus(object oWeapon, int nUpgradeBy) +{ + int nCurrent = IPGetWeaponEnhancementBonus(oWeapon); + + itemproperty ip = GetFirstItemProperty(oWeapon); + + int nNew = nCurrent + nUpgradeBy; + if (nNew <1 ) + { + nNew = 1; + } + else if (nNew >20) + { + nNew = 20; + } + + while (GetIsItemPropertyValid(ip)) + { + if (GetItemPropertyType(ip) ==ITEM_PROPERTY_ENHANCEMENT_BONUS) + { + RemoveItemProperty(oWeapon,ip); + } + ip = GetNextItemProperty(oWeapon); + } + + ip = ItemPropertyEnhancementBonus(nNew); + AddItemProperty(DURATION_TYPE_PERMANENT,ip,oWeapon); + +} + +int IPGetHasItemPropertyByConst(int nItemProp, object oItem) +{ + itemproperty ip = GetFirstItemProperty(oItem); + while (GetIsItemPropertyValid(ip)) + { + if (GetItemPropertyType(ip) ==nItemProp) + { + return TRUE; + } + ip = GetNextItemProperty(oItem); + } + return FALSE; + +} + +// ---------------------------------------------------------------------------- +// Returns TRUE if a use limitation of any kind is present on oItem +// ---------------------------------------------------------------------------- +int IPGetHasUseLimitation(object oItem) +{ + itemproperty ip = GetFirstItemProperty(oItem); + int nType; + while (GetIsItemPropertyValid(ip)) + { + nType = GetItemPropertyType(ip); + if ( + nType == ITEM_PROPERTY_USE_LIMITATION_ALIGNMENT_GROUP || + nType == ITEM_PROPERTY_USE_LIMITATION_CLASS || + nType == ITEM_PROPERTY_USE_LIMITATION_RACIAL_TYPE || + nType == ITEM_PROPERTY_USE_LIMITATION_SPECIFIC_ALIGNMENT ) + { + return TRUE; + } + ip = GetNextItemProperty(oItem); + } + return FALSE; + +} + +//------------------------------------------------------------------------------ +// GZ, Oct 2003 +// Returns TRUE if a character has any item equipped that has the itemproperty +// defined in nItemPropertyConst in it (ITEM_PROPERTY_* constant) +//------------------------------------------------------------------------------ +int IPGetHasItemPropertyOnCharacter(object oPC, int nItemPropertyConst) +{ + object oWeaponOld = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC); + object oArmorOld = GetItemInSlot(INVENTORY_SLOT_CHEST,oPC); + object oRing1Old = GetItemInSlot(INVENTORY_SLOT_LEFTRING,oPC); + object oRing2Old = GetItemInSlot(INVENTORY_SLOT_RIGHTRING,oPC); + object oAmuletOld = GetItemInSlot(INVENTORY_SLOT_NECK,oPC); + object oCloakOld = GetItemInSlot(INVENTORY_SLOT_CLOAK,oPC); + object oBootsOld = GetItemInSlot(INVENTORY_SLOT_BOOTS,oPC); + object oBeltOld = GetItemInSlot(INVENTORY_SLOT_BELT,oPC); + object oHelmetOld = GetItemInSlot(INVENTORY_SLOT_HEAD,oPC); + object oLeftHand = GetItemInSlot(INVENTORY_SLOT_LEFTHAND,oPC); + + int bHas = IPGetHasItemPropertyByConst(nItemPropertyConst, oWeaponOld); + bHas = bHas || IPGetHasItemPropertyByConst(nItemPropertyConst, oLeftHand); + bHas = bHas || IPGetHasItemPropertyByConst(nItemPropertyConst, oArmorOld); + if (bHas) + return TRUE; + bHas = bHas || IPGetHasItemPropertyByConst(nItemPropertyConst, oRing1Old); + bHas = bHas || IPGetHasItemPropertyByConst(nItemPropertyConst, oRing2Old); + bHas = bHas || IPGetHasItemPropertyByConst(nItemPropertyConst, oAmuletOld); + bHas = bHas || IPGetHasItemPropertyByConst(nItemPropertyConst, oCloakOld); + if (bHas) + return TRUE; + bHas = bHas || IPGetHasItemPropertyByConst(nItemPropertyConst, oBootsOld); + bHas = bHas || IPGetHasItemPropertyByConst(nItemPropertyConst, oBeltOld); + bHas = bHas || IPGetHasItemPropertyByConst(nItemPropertyConst, oHelmetOld); + + return bHas; + +} + +//------------------------------------------------------------------------------ +// GZ, Oct 24, 2003 +// Returns an integer with the number of properties present oItem +//------------------------------------------------------------------------------ +int IPGetNumberOfItemProperties(object oItem) +{ + itemproperty ip = GetFirstItemProperty(oItem); + int nCount = 0; + while (GetIsItemPropertyValid(ip)) + { + nCount++; + ip = GetNextItemProperty(oItem); + } + return nCount; +} diff --git a/src/_removed/nw_ch_ac1.nss b/src/_removed/nw_ch_ac1.nss new file mode 100644 index 0000000..035c49e --- /dev/null +++ b/src/_removed/nw_ch_ac1.nss @@ -0,0 +1,228 @@ +// HCR v3.0.3 - 18th May, 2005 - SE +//:://////////////////////////////////////////////////////////////////////////// +//:: FileName: NW_CH_AC1 +//:://////////////////////////////////////////////////////////////////////////// +/* + Added toggle for 1/2 hp's - 9th January, Sir Elric + Move towards master or wait for him. +*/ +//:://////////////////////////////////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Nov 21, 2001 +//:: Updated On: Jul 25, 2003 - Georg Zoeller +//:://////////////////////////////////////////////////////////////////////////// +#include "X0_INC_HENAI" +#include "X2_INC_SUMMSCALE" +#include "X2_INC_SPELLHOOK" +//:://////////////////////////////////////////////////////////////////////////// +void main() +{ + //SpawnScriptDebugger(); + + // GZ: Fallback for timing issue sometimes preventing epic summoned + // creatures from leveling up to their master's level. There is a timing + // issue with the GetMaster() function not returning the master of a + // creature immediately after spawn. Some code which might appear to make no + // sense has been added to the nw_ch_ac1 and x2_inc_summon files to work + // around this. This code is only run on the first hearbeat. + int nLevel = SSMGetSummonFailedLevelUp(OBJECT_SELF); + if (nLevel != 0) + { + int nRet; + if (nLevel == -1)// Special Shadow Lord treatment. + { + SSMScaleEpicShadowLord(OBJECT_SELF); + } + else if (nLevel == -2) + { + SSMScaleEpicFiendishServant(OBJECT_SELF); + } + else + { + nRet = SSMLevelUpCreature(OBJECT_SELF, nLevel, CLASS_TYPE_INVALID); + if (nRet == FALSE) + WriteTimestampedLogEntry("WARNING - nw_ch_ac1:: could not level up " + GetTag(OBJECT_SELF) + "!"); + } + + // Regardless if the actual levelup worked, we give up here, because we do + // not want to run through this script more than once. + SSMSetSummonLevelUpOK(OBJECT_SELF); + } + + // Check if concentration is required to maintain this creature. + X2DoBreakConcentrationCheck(); + + object oMod = GetModule(); + object oMaster = GetMaster(); + + // HCR - Remark out the following "if" block of code if you want to use the + // alternative method below. + + // *** Start original Real Familiar code. *** + if (GetLocalInt(oMod, "REALFAM") && GetLocalInt(oMod, "REALFAMHP")) + { + if (GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oMaster) == OBJECT_SELF) + { + // Check to see if critter is a familiar. + // If so, limit it to 1/2 hp of master per PHB. + if (GetIsObjectValid(oMaster)) + { + int nMHP = GetMaxHitPoints(); + int nCHP = GetCurrentHitPoints(); + int nMax = (GetMaxHitPoints(oMaster)/2); + if ((nMHP - nCHP) >= nMax) + { + effect eDeath = EffectDeath(FALSE, FALSE); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDeath, OBJECT_SELF); + } + } + } + } + // *** End original Real Familiar code. *** + + // HCR - Unremark this "if" block of code and remark out the above code for + // alternative Familiar hit points. +/* + // *** Start alternate Real Familiar code. *** + if (GetLocalInt(oMod, "REALFAM")) + { + if (GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oMaster) == OBJECT_SELF) + { + // Check to see if critter is a familiar. + // If so, limit it to 1/2 hp of master per PHB. + if (GetIsObjectValid(oMaster)) + { + if (!GetIsResting(oMaster)) + { + int nMHP = GetMaxHitPoints(); + int nCHP = GetCurrentHitPoints(); + int nMax = (GetMaxHitPoints(oMaster)/2); + if (nCHP > nMax) + { + int nDam = (nCHP - nMax); + effect eDam = EffectDamage(nDam); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, OBJECT_SELF); + + if (!GetLocalInt(OBJECT_SELF, "FAMMSG")) + { + SendMessageToPC(oMaster, "Familiar's Hit Points adjusted to 1/2 of master's in accordance with 3rd edition rules."); + SetLocalInt(OBJECT_SELF, "FAMMSG", TRUE); + } + } + } + } + } + } + // *** End alternate Real Familiar code. *** +*/ + + if (!GetAssociateState(NW_ASC_IS_BUSY)) + { + // Seek out and disable undisabled traps. + object oTrap = GetNearestTrapToObject(); + if (bkAttemptToDisarmTrap(oTrap) == TRUE) + return;// Succesful trap found and disarmed. + + if (GetIsObjectValid(oMaster) && + GetCurrentAction() != ACTION_FOLLOW && + GetCurrentAction() != ACTION_DISABLETRAP && + GetCurrentAction() != ACTION_OPENLOCK && + GetCurrentAction() != ACTION_REST && + GetCurrentAction() != ACTION_ATTACKOBJECT) + { + if (!GetIsObjectValid(GetAttackTarget()) && + !GetIsObjectValid(GetAttemptedSpellTarget()) && + !GetIsObjectValid(GetAttemptedAttackTarget()) && + !GetIsObjectValid(GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN))) + { + if (GetIsObjectValid(oMaster) == TRUE) + { + if (GetDistanceToObject(oMaster) > 6.0) + { + if (GetAssociateState(NW_ASC_HAVE_MASTER)) + { + if (!GetIsFighting(OBJECT_SELF)) + { + if (!GetAssociateState(NW_ASC_MODE_STAND_GROUND)) + { + if (GetDistanceToObject(oMaster) > GetFollowDistance()) + { + ClearActions(CLEAR_NW_CH_AC1_49); + + if (GetAssociateState(NW_ASC_AGGRESSIVE_STEALTH) || + GetAssociateState(NW_ASC_AGGRESSIVE_SEARCH)) + { + if (GetAssociateState(NW_ASC_AGGRESSIVE_STEALTH)) + { + //ActionUseSkill(SKILL_HIDE, OBJECT_SELF); + //ActionUseSkill(SKILL_MOVE_SILENTLY,OBJECT_SELF); + } + + if (GetAssociateState(NW_ASC_AGGRESSIVE_SEARCH)) + ActionUseSkill(SKILL_SEARCH, OBJECT_SELF); + + MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Assigning Force Follow Command with Search and/or Stealth"); + ActionForceFollowObject(oMaster, GetFollowDistance()); + } + else + { + MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Assigning Force Follow Normal"); + ActionForceFollowObject(oMaster, GetFollowDistance()); + } + } + } + } + } + } + } + else if (!GetAssociateState(NW_ASC_MODE_STAND_GROUND)) + { + if (GetIsObjectValid(oMaster)) + { + if (GetCurrentAction(oMaster) != ACTION_REST) + { + ClearActions(CLEAR_NW_CH_AC1_81); + + if (GetAssociateState(NW_ASC_AGGRESSIVE_STEALTH) || + GetAssociateState(NW_ASC_AGGRESSIVE_SEARCH)) + { + if (GetAssociateState(NW_ASC_AGGRESSIVE_STEALTH)) + { + //ActionUseSkill(SKILL_HIDE, OBJECT_SELF); + //ActionUseSkill(SKILL_MOVE_SILENTLY,OBJECT_SELF); + } + + if (GetAssociateState(NW_ASC_AGGRESSIVE_SEARCH)) + ActionUseSkill(SKILL_SEARCH, OBJECT_SELF); + + MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Assigning Force Follow Command with Search and/or Stealth"); + ActionForceFollowObject(oMaster, GetFollowDistance()); + } + else + { + MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Assigning Force Follow Normal"); + ActionForceFollowObject(oMaster, GetFollowDistance()); + } + } + } + } + } + else if (!GetIsObjectValid(GetAttackTarget()) && + !GetIsObjectValid(GetAttemptedSpellTarget()) && + !GetIsObjectValid(GetAttemptedAttackTarget()) && + !GetAssociateState(NW_ASC_MODE_STAND_GROUND)) + { + //DetermineCombatRound(); + } + } + + // * If I am dominated, ask for some help. + if (GetHasEffect(EFFECT_TYPE_DOMINATED, OBJECT_SELF) == TRUE && + GetIsEncounterCreature(OBJECT_SELF) == FALSE) + SendForHelp(); + + if (GetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT)) + SignalEvent(OBJECT_SELF, EventUserDefined(1001)); + } +} +//:://////////////////////////////////////////////////////////////////////////// diff --git a/src/_removed/nw_ch_ac2.nss b/src/_removed/nw_ch_ac2.nss new file mode 100644 index 0000000..5dad8ff --- /dev/null +++ b/src/_removed/nw_ch_ac2.nss @@ -0,0 +1,86 @@ +//:://///////////////////////////////////////////// +//:: Associate: On Percieve +//:: NW_CH_AC2 +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Nov 19, 2001 +//::////////////////////////////////////////////// +//:: Overhauled for WoG's AI -- The Krit, August 2012 +//::////////////////////////////////////////////// + +#include "hench_i0_ai" + +void main() +{ + // Petrification blocks reactions. + if ( GetHasEffect(EFFECT_TYPE_PETRIFY) ) + return; + + + object oLastPerceived = GetLastPerceived(); + int bSeen = GetLastPerceptionSeen(); + + + // This is the equivalent of a force conversation bubble, should only be used + // if you want an NPC to say something while he is already engaged in combat. + if ( bSeen && GetSpawnInCondition(NW_FLAG_SPECIAL_COMBAT_CONVERSATION) ) + SpeakOneLinerConversation(); + + + // Do not needlessly interupt combat. + object oLastTarget = GetAttemptedAttackTarget(); + if ( !GetIsObjectValid(oLastTarget) ) + oLastTarget = GetAttackTarget(); + if ( !GetIsObjectValid(oLastTarget) ) + oLastTarget = GetAttemptedSpellTarget(); + if ( GetIsObjectValid(oLastTarget) && oLastTarget != oLastPerceived ) + { } // Do nothing + + else if ( bSeen ) + { + // Cannot see while sleeping. + if ( GetHasEffect(EFFECT_TYPE_SLEEP) ) + return; + + if ( GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL) ) + HenchDetermineSpecialBehavior(); + else if ( GetIsEnemy(oLastPerceived) && !GetIsDead(oLastPerceived) ) + { + if ( !GetAssociateState(NW_ASC_MODE_STAND_GROUND) && + !GetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH) ) + { + SetFacingPoint(GetPosition(oLastPerceived)); + HenchDetermineCombatRound(oLastPerceived); + } + } + // Linked up to the special conversation check to initiate a special + // one-off conversation to get the PC's attention. + else if ( GetSpawnInCondition(NW_FLAG_SPECIAL_CONVERSATION) && + GetIsPC(oLastPerceived) && !GetIsDMPossessed(oLastPerceived) ) + { + ActionStartConversation(OBJECT_SELF); + } + } + + // Maybe trigger search mode? + else if ( GetLastPerceptionVanished() || GetLastPerceptionInaudible() ) + { + if ( !GetObjectSeen(oLastPerceived) && !GetObjectHeard(oLastPerceived) && + !GetIsDead(oLastPerceived) && GetArea(oLastPerceived) == GetArea(OBJECT_SELF) && + GetIsEnemy(oLastPerceived) ) + { + SetEnemyLocation(oLastPerceived); + // add check if target - prevents creature from following the target + // due to ActionAttack without actually perceiving them + if ( GetLocalObject(OBJECT_SELF, "LastTarget") == oLastPerceived ) + { + DeleteLocalObject(OBJECT_SELF, "LastTarget"); + HenchDetermineCombatRound(oLastPerceived, TRUE); + } + } + } + + if ( bSeen && GetSpawnInCondition(NW_FLAG_PERCIEVE_EVENT) ) + SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_PERCEIVE)); +} + diff --git a/src/_removed/nw_ch_ac3.nss b/src/_removed/nw_ch_ac3.nss new file mode 100644 index 0000000..36c7a51 --- /dev/null +++ b/src/_removed/nw_ch_ac3.nss @@ -0,0 +1,47 @@ +//:://///////////////////////////////////////////// +//:: Associate: End of Combat End +//:: NW_CH_AC3 +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Calls the end of combat script every round +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Oct 16, 2001 +//:: Modified By: Deva Winblood +//:: Modified On: Jan 4th, 2008 +//:: Added Support for Mounted Combat Feat Support +//::////////////////////////////////////////////// +//:: Adapted for WoG's AI -- The Krit, August 2012 +//::////////////////////////////////////////////// + + +#include "hench_i0_ai" +#include "X2_inc_spellhook" + + +void main() +{ + DeleteLocalInt(OBJECT_SELF, "AIIntruder"); + + if ( !GetLocalInt(GetModule(), "X3_NO_MOUNTED_COMBAT_FEAT") ) + { // Delete variables on target for mounted combat + DeleteLocalInt(OBJECT_SELF, "bX3_LAST_ATTACK_PHYSICAL"); + DeleteLocalInt(OBJECT_SELF, "nX3_HP_BEFORE"); + DeleteLocalInt(OBJECT_SELF, "bX3_ALREADY_MOUNTED_COMBAT"); + } + + if ( GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL) ) + HenchDetermineSpecialBehavior(); + else if ( !GetSpawnInCondition(NW_FLAG_SET_WARNINGS) ) + HenchmenCombatRound(); + + + if(GetSpawnInCondition(NW_FLAG_END_COMBAT_ROUND_EVENT)) + SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_END_COMBAT_ROUND)); + + // Check if concentration is required to maintain this creature + X2DoBreakConcentrationCheck(); +} + diff --git a/src/_removed/nw_ch_ac4.nss b/src/_removed/nw_ch_ac4.nss new file mode 100644 index 0000000..55a14c5 --- /dev/null +++ b/src/_removed/nw_ch_ac4.nss @@ -0,0 +1,82 @@ +//:://///////////////////////////////////////////// +//:: Associate: On Dialogue +//:: NW_CH_AC4 +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Determines the course of action to be taken + by the generic script after dialogue or a + shout is initiated. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Oct 24, 2001 +//::////////////////////////////////////////////// +//:: Adapted for WoG's AI -- The Krit, August 2012 +//::////////////////////////////////////////////// + + +#include "hench_i0_hensho" + + +// This function checks to make sure no dehibilating effects are on the +// caller that should block talking. +int AbleToTalk(); +int AbleToTalk() +{ + // A fast check, but sometimes gives false negatives. + // (The dying system will sometimes leave a player in a noncommandable state?) + if ( GetCommandable() ) + return TRUE; + + // Not commandable, so check for the specific effects that block talking. + return !GetIsDead(OBJECT_SELF) && + !GetHasEffect(EFFECT_TYPE_CONFUSED) && + !GetHasEffect(EFFECT_TYPE_DOMINATED) && + !GetHasEffect(EFFECT_TYPE_PETRIFY) && + !GetHasEffect(EFFECT_TYPE_PARALYZE) && + !GetHasEffect(EFFECT_TYPE_STUNNED) && + !GetHasEffect(EFFECT_TYPE_FRIGHTENED); +} + + +void main() +{ + object oShouter = GetLastSpeaker(); + + + //DMFI CODE ADDITIONS BEGIN HERE + if ( GetIsPC(oShouter) && !GetIsInCombat() ) + ExecuteScript("dmfi_voice_exe", OBJECT_SELF); + //DMFI CODE ADDITIONS END HERE + + + + // Abort if we cannot respond to shouts. + if ( !AbleToTalk() ) + return; + + + int nMatch = GetListenPatternNumber(); + if ( nMatch != -1 ) + { + // listening pattern matched + object oMaster = GetMaster(); + if ( oMaster != OBJECT_INVALID && oMaster == oShouter ) + { + SetCommandable(TRUE); + HenchChRespondToShout(oShouter, nMatch); + } + } + else if ( GetCurrentAction() != ACTION_OPENLOCK ) + { + ClearAllActions(); + BeginConversation(); + } + + + // Signal user-defined event + if ( GetSpawnInCondition(NW_FLAG_ON_DIALOGUE_EVENT) ) + SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_DIALOGUE)); +} + diff --git a/src/_removed/nw_ch_ac5.nss b/src/_removed/nw_ch_ac5.nss new file mode 100644 index 0000000..d992fec --- /dev/null +++ b/src/_removed/nw_ch_ac5.nss @@ -0,0 +1,63 @@ +//:://///////////////////////////////////////////// +//:: Associate On Attacked +//:: NW_CH_AC5 +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + If already fighting then ignore, else determine + combat round +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Oct 16, 2001 +//::////////////////////////////////////////////// +//::////////////////////////////////////////////// +//:: Modified By: Deva Winblood +//:: Modified On: Jan 4th, 2008 +//:: Added Support for Mounted Combat Feat Support +//::////////////////////////////////////////////// + +#include "hench_i0_ai" + +void main() +{ + if ( !GetLocalInt(GetModule(),"X3_NO_MOUNTED_COMBAT_FEAT") ) + { // set variables on target for mounted combat + SetLocalInt(OBJECT_SELF, "bX3_LAST_ATTACK_PHYSICAL", TRUE); + SetLocalInt(OBJECT_SELF, "nX3_HP_BEFORE", GetCurrentHitPoints(OBJECT_SELF)); + } + + object oAttacker = GetLastAttacker(); + if ( !GetIsObjectValid(oAttacker) || + GetArea(oAttacker) != GetArea(OBJECT_SELF) ) + { + // Don't do anything; invalid attacker. + return; + } + + SpeakString("NW_I_WAS_ATTACKED", TALKVOLUME_SILENT_TALK); + + if ( !GetAssociateState(NW_ASC_IS_BUSY) && !GetIsFighting(OBJECT_SELF) ) + if ( !GetAssociateState(NW_ASC_MODE_STAND_GROUND) ) + { + SetCommandable(TRUE); + + // Our cover is blown, so don't bother with stealth. + if ( GetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH) ) + SetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH, FALSE); + + if ( GetAssociateState(NW_ASC_MODE_DEFEND_MASTER)) + { + object oTarget = GetLastAttacker(GetMaster()); + if ( GetIsObjectValid(oTarget) ) + oAttacker = oTarget; + } + + DetermineCombatRound(oAttacker); + HenchDetermineCombatRound(oAttacker); + } + + if ( GetSpawnInCondition(NW_FLAG_ATTACK_EVENT) ) + SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_ATTACKED)); +} + diff --git a/src/_removed/nw_ch_ac6.nss b/src/_removed/nw_ch_ac6.nss new file mode 100644 index 0000000..14239fe --- /dev/null +++ b/src/_removed/nw_ch_ac6.nss @@ -0,0 +1,107 @@ +//:://///////////////////////////////////////////// +//:: Associate: On Damaged +//:: NW_CH_AC6 +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + If already fighting then ignore, else determine + combat round +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Nov 19, 2001 +//:: Modified By: Deva Winblood +//:: Modified On: Jan 17th, 2008 +//:: Added Support for Mounted Combat Feat Support +//::////////////////////////////////////////////// +//:: Adapted for WoG's AI -- The Krit, August 2012 +//::////////////////////////////////////////////// + +#include "hench_i0_ai" +#include "x3_inc_horse" + +// Determine whether to switch to new attacker +int SwitchTargets(object oCurTarget, object oNewEnemy); + +void main() +{ + object oTarget = GetAttackTarget(); + object oDamager = GetLastDamager(); + object oMe = OBJECT_SELF; + + if ( !GetIsObjectValid(oDamager) ) + // Don't do anything; we don't have a valid damager. + return; + + + if ( !GetLocalInt(GetModule(),"X3_NO_MOUNTED_COMBAT_FEAT") && + GetHasFeat(FEAT_MOUNTED_COMBAT) && HorseGetIsMounted(oMe) ) + { // see if can negate some damage + if ( GetLocalInt(oMe, "bX3_LAST_ATTACK_PHYSICAL") ) + { // last attack was physical + int nHPBefore=GetLocalInt(oMe,"nX3_HP_BEFORE"); + if (!GetLocalInt(oMe, "bX3_ALREADY_MOUNTED_COMBAT")) + { // haven't already had a chance to use this for the round + SetLocalInt(oMe, "bX3_ALREADY_MOUNTED_COMBAT", TRUE); + int nAttackRoll=GetBaseAttackBonus(oDamager)+d20(); + int nRideCheck=GetSkillRank(SKILL_RIDE,oMe)+d20(); + if (nRideCheck>=nAttackRoll&&!GetIsDead(oMe)) + { // averted attack + if (GetIsPC(oDamager)) SendMessageToPC(oDamager,GetName(oMe)+GetStringByStrRef(111991)); + //if (GetIsPC(oMe)) SendMessageToPCByStrRef(oMe,111992); + if (GetCurrentHitPoints(oMe) GetHitDice(oCurTarget) || // The new enemy is of a higher level, or + GetTotalDamageDealt() > GetMaxHitPoints(OBJECT_SELF)/4); // we just received more than 25% of our hp in damage +} + diff --git a/src/_removed/nw_ch_ac7.nss b/src/_removed/nw_ch_ac7.nss new file mode 100644 index 0000000..427b824 --- /dev/null +++ b/src/_removed/nw_ch_ac7.nss @@ -0,0 +1,94 @@ +// HCR v3.0.3 - 18th May, 2005 - SE +//:://////////////////////////////////////////////////////////////////////////// +//:: FileName: NW_CH_AC7 +//:: OnDeath handler for summons, familiars, animal companions, and henchmen. +//:://////////////////////////////////////////////////////////////////////////// +/* + REALFAM is the XP penalty set in hc_defaults, 200 by default - SE +*/ +//:://////////////////////////////////////////////////////////////////////////// +//:://////////////////////////////////////////////////////////////////////////// +// ----------------------------------------------------------------------------- +// The Krit, 2008-01-11 +// Deleting henchmen-specific stuff so the code is easier to manage on WoG. +// (There are no henchmen on this persistent world.) +// Rest of the code has been simplified. +// ----------------------------------------------------------------------------- +//:://////////////////////////////////////////////////////////////////////////// + +#include "HC_Inc" + + +// ----------------------------------------------------------------------------- +// Enforces the XP penalty when oMaster's familiar was killed. +// nXPPen is the amount of XP to lose per sorcerer/wizard level. +void FamiliarXPHit(object oMaster, int nXPPen) +{ + // Clean up a local integer. (See nw_ch_ac1 for its purpose.) + DeleteLocalInt(OBJECT_SELF, "FAMMSG"); + + // Set the death local on the module. + SetLocalInt(GetModule(), "FAMDIED" + GetPlayerID(oMaster), 1); + + // Determine amount of XP penalty set in hc_defaults - 9th Jan, Sir Elric + // Should be per wizard/sorcerer (combined) level -- TK. + nXPPen *= GetLevelByClass(CLASS_TYPE_WIZARD, oMaster) + + GetLevelByClass(CLASS_TYPE_SORCERER, oMaster); + // Halve the penalty on a successful fortitude save. + if ( FortitudeSave(oMaster, 15) > 0 ) + nXPPen /= 2; + + // Apply the XP penalty via the HC script. + SetLocalInt(oMaster, "TAKEXP", nXPPen); + ExecuteScript("hc_takexp", oMaster); +} + + +// ----------------------------------------------------------------------------- +// Enforces the HP penalty when oMaster's familiar was killed. +void FamiliarHPHit(object oMaster) +{ + // Damage is nominally 1d6. + int nDamage = d6(); + + // However, familiar death can never kill the PC, only wound them. + int nCurrentHP = GetCurrentHitPoints(oMaster); + if ( nDamage >= nCurrentHP ) + nDamage = nCurrentHP - 1; + + // Apply the hitpoint damage. + ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDamage), oMaster); +} + + +//:://////////////////////////////////////////////////////////////////////////// +// ----------------------------------------------------------------------------- +void main() +{ + object oMaster = GetMaster(); + + // There is only special handling for the death of a PC's associates. + if ( GetIsPC(oMaster) && !GetIsDM(oMaster) && !GetIsDMPossessed(oMaster) ) + { + // IMPORTANT: If special handling is allowed for associates of NPC's, + // then the next check needs to be more involved. This is because an + // NPC's familiar and/or animal companion is officially a henchman, as + // far as the game engine is concerned. (By-product of the AI.) + + // There is only special handling for familiars. + if ( GetAssociateType(OBJECT_SELF) == ASSOCIATE_TYPE_FAMILIAR ) + { + // Give the PC some feedback regarding the familiar's death. + FloatingTextStrRefOnCreature(63489, oMaster, FALSE); + + // Familiar death hurts the master. + // See whether the penalty is XP or HP. + int nXPPen = GetLocalInt(GetModule(), "REALFAM"); + if ( nXPPen > 0 ) + FamiliarXPHit(oMaster, nXPPen); + else + FamiliarHPHit(oMaster); + } + } +} +//:://////////////////////////////////////////////////////////////////////////// diff --git a/src/_removed/nw_ch_ac8.nss b/src/_removed/nw_ch_ac8.nss new file mode 100644 index 0000000..ef95855 --- /dev/null +++ b/src/_removed/nw_ch_ac8.nss @@ -0,0 +1,34 @@ +//:://///////////////////////////////////////////// +//:: Henchmen: On Disturbed +//:: NW_C2_AC8 +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Determine Combat Round on disturbed. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Oct 16, 2001 +//:://///////////////////////////////////////// + +// * Make me hostile the faction of my last attacker (TEMP) +// AdjustReputation(OBJECT_SELF,GetFaction(GetLastAttacker()),-100); +// * Determined Combat Round + +#include "hench_i0_ai" + +void main() +{ + object oTarget = GetLastDisturbed(); + + if ( !GetIsObjectValid(GetAttemptedAttackTarget()) && + !GetIsObjectValid(GetAttemptedSpellTarget()) ) + { + if ( GetIsObjectValid(oTarget) ) + HenchDetermineCombatRound(oTarget); + } + + if ( GetSpawnInCondition(NW_FLAG_DISTURBED_EVENT) ) + SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_DISTURBED)); +} + diff --git a/src/_removed/nw_ch_ac9.nss b/src/_removed/nw_ch_ac9.nss new file mode 100644 index 0000000..f55192a --- /dev/null +++ b/src/_removed/nw_ch_ac9.nss @@ -0,0 +1,81 @@ +//:://///////////////////////////////////////////// +//:: Associate: On Spawn In +//:: NW_CH_AC9 +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Nov 19, 2001 +//::////////////////////////////////////////////// + +#include "dmfi_db_inc" +#include "X0_INC_HENAI" +void main() +{ + SetAssociateListenPatterns();//Sets up the special henchmen listening patterns + + bkSetListeningPatterns(); // Goes through and sets up which shouts the NPC will listen to. + + SetAssociateState(NW_ASC_POWER_CASTING); + SetAssociateState(NW_ASC_HEAL_AT_50); + SetAssociateState(NW_ASC_RETRY_OPEN_LOCKS); + SetAssociateState(NW_ASC_DISARM_TRAPS); + SetAssociateState(NW_ASC_MODE_DEFEND_MASTER, FALSE); + SetAssociateState(NW_ASC_USE_RANGED_WEAPON, FALSE); //User ranged weapons by default if true. + SetAssociateState(NW_ASC_DISTANCE_2_METERS); + + // April 2002: Summoned monsters, associates and familiars need to stay + // further back due to their size. + int nType = GetAssociateType(OBJECT_SELF); + switch (nType) + { + case ASSOCIATE_TYPE_ANIMALCOMPANION: + case ASSOCIATE_TYPE_DOMINATED: + case ASSOCIATE_TYPE_FAMILIAR: + case ASSOCIATE_TYPE_SUMMONED: + SetAssociateState(NW_ASC_DISTANCE_4_METERS); + break; + + } + +/* if (GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, GetMaster()) == OBJECT_SELF || + GetAssociate(ASSOCIATE_TYPE_DOMINATED, GetMaster()) == OBJECT_SELF || + GetAssociate(ASSOCIATE_TYPE_FAMILIAR, GetMaster()) == OBJECT_SELF || + GetAssociate(ASSOCIATE_TYPE_SUMMONED, GetMaster()) == OBJECT_SELF) + { + SetAssociateState(NW_ASC_DISTANCE_4_METERS); + } +*/ + // * Feb 2003: Set official campaign henchmen to have no inventory + SetLocalInt(OBJECT_SELF, "X0_L_NOTALLOWEDTOHAVEINVENTORY", 10) ; + + //SetAssociateState(NW_ASC_MODE_DEFEND_MASTER); + SetAssociateStartLocation(); + // SPECIAL CONVERSATION SETTTINGS + //SetSpawnInCondition(NW_FLAG_SPECIAL_CONVERSATION); + //SetSpawnInCondition(NW_FLAG_SPECIAL_COMBAT_CONVERSATION); + // This causes the creature to say a special greeting in their conversation file + // upon Perceiving the player. Attach the [NW_D2_GenCheck.nss] script to the desired + // greeting in order to designate it. As the creature is actually saying this to + // himself, don't attach any player responses to the greeting. + + +// CUSTOM USER DEFINED EVENTS +/* + The following settings will allow the user to fire one of the blank user defined events in the NW_D2_DefaultD. Like the + On Spawn In script this script is meant to be customized by the end user to allow for unique behaviors. The user defined + events user 1000 - 1010 +*/ + //SetSpawnInCondition(NW_FLAG_PERCIEVE_EVENT); //OPTIONAL BEHAVIOR - Fire User Defined Event 1002 + //SetSpawnInCondition(NW_FLAG_ATTACK_EVENT); //OPTIONAL BEHAVIOR - Fire User Defined Event 1005 + //SetSpawnInCondition(NW_FLAG_DAMAGED_EVENT); //OPTIONAL BEHAVIOR - Fire User Defined Event 1006 + //SetSpawnInCondition(NW_FLAG_DISTURBED_EVENT); //OPTIONAL BEHAVIOR - Fire User Defined Event 1008 + //SetSpawnInCondition(NW_FLAG_END_COMBAT_ROUND_EVENT); //OPTIONAL BEHAVIOR - Fire User Defined Event 1003 + //SetSpawnInCondition(NW_FLAG_ON_DIALOGUE_EVENT); //OPTIONAL BEHAVIOR - Fire User Defined Event 1004 + //SetSpawnInCondition(NW_FLAG_DEATH_EVENT); //OPTIONAL BEHAVIOR - Fire User Defined Event 1007 //DMFI CODE ADDITIONS BEGIN HERE + SetListening(OBJECT_SELF, TRUE); + SetListenPattern(OBJECT_SELF, "**", LISTEN_PATTERN); //listen to all text + SetLocalInt(OBJECT_SELF, "hls_Listening", 1); //listen to all text + + //DMFI CODE ADDITIONS END HERE +} diff --git a/src/_removed/nw_ch_aca.nss b/src/_removed/nw_ch_aca.nss new file mode 100644 index 0000000..7220af9 --- /dev/null +++ b/src/_removed/nw_ch_aca.nss @@ -0,0 +1,20 @@ +//:://///////////////////////////////////////////// +//:: Default: On Rested +//:: NW_C2_DEFAULTA +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* + Determines the course of action to be taken + after having just rested. +*/ +//::////////////////////////////////////////////// +//:: Created By: Don Moar +//:: Created On: April 28, 2002 +//::////////////////////////////////////////////// +void main() +{ + // enter desired behaviour here + + return; + +} diff --git a/src/_removed/nw_ch_acb.nss b/src/_removed/nw_ch_acb.nss new file mode 100644 index 0000000..09c9a88 --- /dev/null +++ b/src/_removed/nw_ch_acb.nss @@ -0,0 +1,144 @@ +//:://///////////////////////////////////////////// +//:: Henchmen: On Spell Cast At +//:: NW_CH_ACB +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + This determines if the spell just cast at the + target is harmful or not. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Dec 6, 2001 +//::////////////////////////////////////////////// +//::////////////////////////////////////////////// +//:: Modified By: Deva Winblood +//:: Modified On: Jan 4th, 2008 +//:: Added Support for Mounted Combat Feat Support +//::////////////////////////////////////////////// + +#include "hench_i0_ai" +#include "x2_i0_spells" + + +// Wrapper for initiating combat. +void DoCombat(object oTarget = OBJECT_INVALID); +// Returns TRUE if the caller has been told how to deal with this area of effect. +int HandleAOE(int nSpell, object oCaster); + + +void main() +{ + if( GetLastSpellHarmful() ) + { + if ( !GetLocalInt(GetModule(), "X3_NO_MOUNTED_COMBAT_FEAT") ) + { // set variables on target for mounted combat + DeleteLocalInt(OBJECT_SELF, "bX3_LAST_ATTACK_PHYSICAL"); + } // set variables on target for mounted combat + + + object oCaster = GetLastSpellCaster(); + + // ------------------------------------------------------------------ + // If I was hurt by someone in my own faction + // Then clear any hostile feelings I have against them + // After all, we're all just trying to do our job here + // if we singe some eyebrow hair, oh well. + if ( GetFactionEqual(oCaster) ) + { + ClearPersonalReputation(oCaster, OBJECT_SELF); + ClearAllActions(TRUE); + DelayCommand(1.2, ActionDoCommand(HenchDetermineCombatRound())); + } + // ------------------------------------------------------------------ + else + { + // Set this to TRUE once we've decided how to react. + int bReacted = FALSE; + + int nSpell = GetLastSpell(); + if ( MatchAreaOfEffectSpell(nSpell) ) + bReacted = HandleAOE(nSpell, oCaster); + + else if ( GetArea(oCaster) != GetArea(OBJECT_SELF) ) + // Do not react. + bReacted = TRUE; + + else + { + // Our cover's been blown. + if ( GetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH) ) + SetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH, FALSE); + } + + // Attack, but only if we are not already fighting. + if ( !bReacted && !GetIsFighting(OBJECT_SELF) ) + DoCombat(oCaster); + } + } + + if ( GetSpawnInCondition(NW_FLAG_SPELL_CAST_AT_EVENT) ) + SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_SPELL_CAST_AT)); +} + + +// ----------------------------------------------------------------------------- + + +// Wrapper for initiating combat. +void DoCombat(object oTarget = OBJECT_INVALID) +{ + if ( GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL) ) + HenchDetermineSpecialBehavior(oTarget); + else + HenchDetermineCombatRound(oTarget); +} + +// Returns TRUE if the caller has been told how to deal with this area of effect. +int HandleAOE(int nSpell, object oCaster) +{ + int nAI = GetBestAOEBehavior(nSpell); + switch ( nAI ) + { + case X2_SPELL_AOEBEHAVIOR_DISPEL_L: + case X2_SPELL_AOEBEHAVIOR_DISPEL_N: + case X2_SPELL_AOEBEHAVIOR_DISPEL_M: + case X2_SPELL_AOEBEHAVIOR_DISPEL_G: + case X2_SPELL_AOEBEHAVIOR_DISPEL_C: + if ( GetCommandable() ) + { + ActionCastSpellAtLocation(nAI, GetLocation(OBJECT_SELF)); + ActionDoCommand(SetCommandable(TRUE)); + ActionDoCommand(DoCombat()); + SetCommandable(FALSE); + } + return TRUE; + + case X2_SPELL_AOEBEHAVIOR_FLEE: + ClearAllActions(); + if ( GetIsObjectValid(oCaster) ) + ActionForceMoveToObject(oCaster, TRUE, 2.0); + else + ActionMoveToObject(GetMaster(), TRUE, 1.1); + ActionDoCommand(DoCombat()); + return TRUE; + + case X2_SPELL_AOEBEHAVIOR_IGNORE: + // well ... do nothing + return TRUE; + + case X2_SPELL_AOEBEHAVIOR_GUST: + if ( GetCommandable() ) + { + ActionCastSpellAtLocation(SPELL_GUST_OF_WIND, GetLocation(OBJECT_SELF)); + ActionDoCommand(SetCommandable(TRUE)); + ActionDoCommand(DoCombat()); + SetCommandable(FALSE); + } + return TRUE; + } + + // If we make it to here, we do not know what to do. + return FALSE; +} + diff --git a/src/_removed/nw_s0_animdead.nss b/src/_removed/nw_s0_animdead.nss new file mode 100644 index 0000000..81beeb1 --- /dev/null +++ b/src/_removed/nw_s0_animdead.nss @@ -0,0 +1,80 @@ +//:://///////////////////////////////////////////// +//:: Animate Dead +//:://///////////////////////////////////////////// +//:: Animate Dead +//:: NW_S0_AnimDead.nss +//::////////////////////////////////////////////// +/* + Summons a powerful skeleton or zombie depending + on caster level. +*/ + +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + int nMetaMagic = GetMetaMagicFeat(); + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + int nDuration = GetCasterLevel(OBJECT_SELF); + nDuration = 24; + //effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); + + //Metamagic extension if needed + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration * 2; //Duration is +100% + } + string sResRef = ""; + object oBook = GetItemPossessedBy(OBJECT_SELF, "libramofnecroman"); + if ( oBook != OBJECT_INVALID ) + { + sResRef = GetLocalString(oBook, "undead1"); + } + + if ( sResRef == "" ) + { + //Summon the appropriate creature based on the summoner level + if (nCasterLevel <= 5) + { + //Tyrant Fog Zombie + sResRef = "wogsumzombtyr001"; + } + else if ((nCasterLevel >= 6) && (nCasterLevel <= 9)) + { + //Skeleton Warrior + sResRef = "wogsumskelwar002"; + } + else + { + //Skeleton Chieftain + sResRef = "wogsumskelchief1"; + } + } + //Apply the summon visual and summon the two undead. + //ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, GetSpellTargetLocation()); + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); + effect eSummon = EffectSummonCreature(sResRef); + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), HoursToSeconds(nDuration)); +} + diff --git a/src/_removed/nw_s0_bless.nss b/src/_removed/nw_s0_bless.nss new file mode 100644 index 0000000..d898a9c --- /dev/null +++ b/src/_removed/nw_s0_bless.nss @@ -0,0 +1,100 @@ +//:://///////////////////////////////////////////// +//:: Bless +//:: NW_S0_Bless.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + All allies within 30ft of the caster gain a + +1 attack bonus and a +1 save bonus vs fear + effects + + also can be cast on crossbow bolts to bless them + in order to slay rakshasa +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: July 24, 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 20, 2001 +//:: Added Bless item ability: Georg Z, On: June 20, 2001 +#include "NW_I0_SPELLS" + +#include "x2_inc_spellhook" + +void main() +{ + + /* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + + */ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + + // End of Spell Cast Hook + + + //Declare major variables + object oTarget = GetSpellTargetObject(); + int nDuration = 1 + GetCasterLevel(OBJECT_SELF); + + effect eVis = EffectVisualEffect(VFX_IMP_HEAD_HOLY); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); + // ---------------- TARGETED ON BOLT ------------------- + if(GetIsObjectValid(oTarget) && GetObjectType(oTarget) == OBJECT_TYPE_ITEM) + { + // special handling for blessing crossbow bolts that can slay rakshasa's + if (GetBaseItemType(oTarget) == BASE_ITEM_BOLT) + { + SignalEvent(GetItemPossessor(oTarget), EventSpellCastAt(OBJECT_SELF, GetSpellId(), FALSE)); + IPSafeAddItemProperty(oTarget, ItemPropertyOnHitCastSpell(123,1), RoundsToSeconds(nDuration), X2_IP_ADDPROP_POLICY_KEEP_EXISTING ); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, GetItemPossessor(oTarget)); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDur, GetItemPossessor(oTarget), TurnsToSeconds(nDuration)); + return; + } + } + + + effect eImpact = EffectVisualEffect(VFX_FNF_LOS_HOLY_30); + effect eAttack = EffectAttackIncrease(1); + effect eSave = EffectSavingThrowIncrease(SAVING_THROW_ALL, 1, SAVING_THROW_TYPE_FEAR); + + effect eLink = EffectLinkEffects(eAttack, eSave); + eLink = EffectLinkEffects(eLink, eDur); + + int nMetaMagic = GetMetaMagicFeat(); + float fDelay; + //Metamagic duration check + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + + //Apply Impact + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpact, GetSpellTargetLocation()); + + //Get the first target in the radius around the caster + oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(OBJECT_SELF)); + while(GetIsObjectValid(oTarget)) + { + if(GetIsReactionTypeFriendly(oTarget) || GetFactionEqual(oTarget)) + { + fDelay = GetRandomDelay(0.4, 1.1); + //Fire spell cast at event for target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_BLESS, FALSE)); + //Apply VFX impact and bonus effects + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, TurnsToSeconds(nDuration))); + } + //Get the next target in the specified area around the caster + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(OBJECT_SELF)); + } +} + diff --git a/src/_removed/nw_s0_calllghtn.nss b/src/_removed/nw_s0_calllghtn.nss new file mode 100644 index 0000000..4532bd2 --- /dev/null +++ b/src/_removed/nw_s0_calllghtn.nss @@ -0,0 +1,124 @@ +//:://///////////////////////////////////////////// +//:: Call Lightning +//:: NW_S0_CallLghtn.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + This spells smites an area around the caster + with bolts of lightning which strike all enemies. + Bolts do 1d10 per level up 10d10 +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: May 22, 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 20, 2001 + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oCaster = OBJECT_SELF; + object oArea = GetArea(oCaster); + int nCasterLvl = GetCasterLevel(oCaster); + int nMetaMagic = GetMetaMagicFeat(); + int nDamage; + float fDelay; + effect eVis = EffectVisualEffect(VFX_IMP_LIGHTNING_M); + effect eDam; + //Get the spell target location as opposed to the spell target. + location lTarget = GetSpellTargetLocation(); + //Limit Caster level for the purposes of damage + if (nCasterLvl > 10) + { + nCasterLvl = 10; + } + //Declare the spell shape, size and the location. Capture the first target object in the shape. + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, OBJECT_SELF)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_CALL_LIGHTNING)); + //Get the distance between the explosion and the target to calculate delay + fDelay = GetRandomDelay(0.4, 1.75); + if (!MyResistSpell(OBJECT_SELF, oTarget, fDelay)) + { + if(GetWeather(oArea) == WEATHER_CLEAR) { + //Roll damage for each target + nDamage = d6(nCasterLvl); + //Resolve metamagic + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 6 * nCasterLvl; + } + else if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + nDamage / 2; + } + } else { + //Roll damage for each target + nDamage = d10(nCasterLvl); + //Resolve metamagic + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 10 * nCasterLvl; + } + else if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + nDamage / 2; + } + } + if(GetIsAreaInterior(oArea) == TRUE) + { + nDamage = d6(nCasterLvl); + //Resolve metamagic + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 6 * nCasterLvl; + } + else if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + nDamage / 2; + } + } + //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_ELECTRICITY); + //Set the damage effect + eDam = EffectDamage(nDamage, DAMAGE_TYPE_ELECTRICAL); + if(nDamage > 0) + { + // Apply effects to the currently selected target. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + //This visual effect is applied to the target object not the location as above. This visual effect + //represents the flame that erupts on the target not on the ground. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + } + //Select the next target within the spell shape. + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } +} diff --git a/src/_removed/nw_s0_circevilb.nss b/src/_removed/nw_s0_circevilb.nss new file mode 100644 index 0000000..f4788e1 --- /dev/null +++ b/src/_removed/nw_s0_circevilb.nss @@ -0,0 +1,46 @@ +//:://///////////////////////////////////////////// +//:: Magic Cirle Against Evil +//:: NW_S0_CircEvilB +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Remove basic protection from evil effects from + exiting creatures. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Nov 20, 2001 +//::////////////////////////////////////////////// +#include "NW_I0_SPELLS" + +#include "x2_inc_spellhook" + +void main() +{ + //Declare major variables + //Get the object that is exiting the AOE + object oTarget = GetExitingObject(); + int bValid = FALSE; + //Search through the valid effects on the target. + effect eAOE = GetFirstEffect(oTarget); + if(GetHasSpellEffect(SPELL_MAGIC_CIRCLE_AGAINST_EVIL, oTarget)) + { + while (GetIsEffectValid(eAOE)) + { + if (GetEffectCreator(eAOE) == GetAreaOfEffectCreator()) + { + //If the effect was created by the AOE then remove it + if(GetEffectSpellId(eAOE) == SPELL_MAGIC_CIRCLE_AGAINST_EVIL) + { + //Protection is permanent, circle is temporay effect + if(GetEffectDurationType(eAOE) == DURATION_TYPE_PERMANENT) + { + RemoveEffect(oTarget, eAOE); + } + } + } + //Get next effect on the target + eAOE = GetNextEffect(oTarget); + } + } +} diff --git a/src/_removed/nw_s0_circgoodb.nss b/src/_removed/nw_s0_circgoodb.nss new file mode 100644 index 0000000..3473201 --- /dev/null +++ b/src/_removed/nw_s0_circgoodb.nss @@ -0,0 +1,47 @@ +//:://///////////////////////////////////////////// +//:: Magic Cirle Against Good +//:: NW_S0_CircGoodB +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Remove basic protection from good effects from + exiting creatures. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Nov 20, 2001 +//::////////////////////////////////////////////// +#include "NW_I0_SPELLS" + +#include "x2_inc_spellhook" + +void main() +{ + //Declare major variables + //Get the object that is exiting the AOE + object oTarget = GetExitingObject(); + int bValid = FALSE; + effect eAOE; + if(GetHasSpellEffect(SPELL_MAGIC_CIRCLE_AGAINST_GOOD, oTarget)) + { + //Search through the valid effects on the target. + eAOE = GetFirstEffect(oTarget); + while (GetIsEffectValid(eAOE)) + { + if (GetEffectCreator(eAOE) == GetAreaOfEffectCreator()) + { + //If the effect was created by the AOE then remove it + if(GetEffectSpellId(eAOE) == SPELL_MAGIC_CIRCLE_AGAINST_GOOD) + { + //Protection is permanent, circle is temporay effect + if(GetEffectDurationType(eAOE) == DURATION_TYPE_PERMANENT) + { + RemoveEffect(oTarget, eAOE); + } + } + } + //Get next effect on the target + eAOE = GetNextEffect(oTarget); + } + } +} diff --git a/src/_removed/nw_s0_crgrund.nss b/src/_removed/nw_s0_crgrund.nss new file mode 100644 index 0000000..ff1d986 --- /dev/null +++ b/src/_removed/nw_s0_crgrund.nss @@ -0,0 +1,83 @@ +//:://///////////////////////////////////////////// +//:: Create Greater Undead +//:: NW_S0_CrGrUnd.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Summons an undead type pegged to the character's + level. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 12, 2001 +//::////////////////////////////////////////////// + +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + int nMetaMagic = GetMetaMagicFeat(); + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + int nDuration = nCasterLevel; + nDuration = 24; + //effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); + //Make metamagic extend check + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + string sResRef = ""; + object oBook = GetItemPossessedBy(OBJECT_SELF, "libramofnecroman"); + if ( oBook != OBJECT_INVALID ) + { + sResRef = GetLocalString(oBook, "undead3"); + } + + if ( sResRef == "" ) + { + //Determine undead to summon based on level + if (nCasterLevel <= 15) + { + sResRef = "wogsumvampire001"; + } + else if ((nCasterLevel >= 16) && (nCasterLevel <= 17)) + { + sResRef = "wogsumdoomkght01"; + } + else if ((nCasterLevel >= 18) && (nCasterLevel <= 19)) + { + sResRef = "wogsumlich004"; + } + else + { + sResRef = "wogsummumcleric1"; + } + } + //Apply the summon visual and summon the two undead. + //ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, GetSpellTargetLocation()); + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); + effect eSummon = EffectSummonCreature(sResRef); + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), HoursToSeconds(nDuration)); +} + diff --git a/src/_removed/nw_s0_crundead.nss b/src/_removed/nw_s0_crundead.nss new file mode 100644 index 0000000..2e0ffac --- /dev/null +++ b/src/_removed/nw_s0_crundead.nss @@ -0,0 +1,84 @@ +//:://///////////////////////////////////////////// +//:: Create Undead +//:: NW_S0_CrUndead.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Spell summons a Ghoul, Shadow, Ghast, Wight or + Wraith +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 12, 2001 +//::////////////////////////////////////////////// + +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + int nMetaMagic = GetMetaMagicFeat(); + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + int nDuration = nCasterLevel; + nDuration = 24; + + //effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); + //Check for metamagic extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + string sResRef = ""; + object oBook = GetItemPossessedBy(OBJECT_SELF, "libramofnecroman"); + if ( oBook != OBJECT_INVALID ) + { + sResRef = GetLocalString(oBook, "undead2"); + } + + if ( sResRef == "" ) + { + //Set the summoned undead to the appropriate template based on the caster level + if (nCasterLevel <= 11) + { + sResRef = "sogsumghoul001"; + } + else if ((nCasterLevel >= 12) && (nCasterLevel <= 13)) + { + sResRef = "wogsumghoul001"; + } + else if ((nCasterLevel >= 14) && (nCasterLevel <= 15)) + { + sResRef = "wogsumwight002"; // change later + } + else if ((nCasterLevel >= 16)) + { + sResRef = "wogsumspectre001"; + } + } + //Apply the summon visual and summon the two undead. + //ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, GetSpellTargetLocation()); + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); + effect eSummon = EffectSummonCreature(sResRef); + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), HoursToSeconds(nDuration)); +} + diff --git a/src/_removed/nw_s0_curminw.nss b/src/_removed/nw_s0_curminw.nss new file mode 100644 index 0000000..f98dad2 --- /dev/null +++ b/src/_removed/nw_s0_curminw.nss @@ -0,0 +1,43 @@ +//:://///////////////////////////////////////////// +//:: Cure Minor Wounds +//:: NW_S0_CurMinW +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* +// As cure light wounds, except cure minor wounds +// cures only 1 point of damage +*/ +//::////////////////////////////////////////////// +//:: Created By: Noel Borstad +//:: Created On: Oct 18, 2000 +//::////////////////////////////////////////////// +//:: Last Updated By: Preston Watamaniuk, On: Feb 22, 2001 +//:: Last Updated By: Preston Watamaniuk, On: April 6, 2001 + + +#include "NW_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + spellsCure(d4(1), 0, 4, VFX_IMP_SUNSTRIKE, VFX_IMP_HEAD_HEAL, GetSpellId()); +} + diff --git a/src/_removed/nw_s0_curserw.nss b/src/_removed/nw_s0_curserw.nss new file mode 100644 index 0000000..b566498 --- /dev/null +++ b/src/_removed/nw_s0_curserw.nss @@ -0,0 +1,42 @@ +//:://///////////////////////////////////////////// +//:: Cure Serious Wounds +//:: NW_S0_CurSerW +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* +// As cure light wounds, except cure moderate wounds +// cures 3d8 points of damage plus 1 point per caster +// level (up to +15). +*/ +//::////////////////////////////////////////////// +//:: Created By: Noel Borstad +//:: Created On: Oct 18, 2000 +//::////////////////////////////////////////////// +//:: Update Pass By: Preston W, On: July 25, 2001 + +#include "NW_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + spellsCure(d8(3), 15, 24, VFX_IMP_SUNSTRIKE, VFX_IMP_HEALING_L, GetSpellId()); +} + diff --git a/src/_removed/nw_s0_delfirea.nss b/src/_removed/nw_s0_delfirea.nss new file mode 100644 index 0000000..1330077 --- /dev/null +++ b/src/_removed/nw_s0_delfirea.nss @@ -0,0 +1,93 @@ +//:://///////////////////////////////////////////// +//:: Delayed Blast Fireball: On Enter +//:: NW_S0_DelFireA.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + The caster creates a trapped area which detects + the entrance of enemy creatures into 3 m area + around the spell location. When tripped it + causes a fiery explosion that does 1d6 per + caster level up to a max of 20d6 damage. +*/ +//::////////////////////////////////////////////// +//:: Georg: Removed Spellhook, fixed damage cap +//:: Created By: Preston Watamaniuk +//:: Created On: July 27, 2001 +//::////////////////////////////////////////////// + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + //Declare major variables + object oSelf = OBJECT_SELF; + object oTarget = GetEnteringObject(); + object oCaster = GetAreaOfEffectCreator(oSelf); + location lTarget = GetLocation(oSelf); + int nDamage; + int nMetaMagic = GetMetaMagicFeat(); + int nCasterLevel = GetCasterLevel(oCaster); + int nFire = GetLocalInt(oSelf, "NW_SPELL_DELAY_BLAST_FIREBALL"); + //Limit caster level + if (nCasterLevel > 20) + { + nCasterLevel = 20; + } + effect eDam; + effect eExplode = EffectVisualEffect(VFX_FNF_FIREBALL); + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_M); + //Check the faction of the entering object to make sure the entering object is not in the casters faction + if(nFire == 0) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, oSelf)) + { + // WoG special hook -- support for GToI dungeon level. + SetLocalInt(oSelf, "Delayed_spellhook", TRUE); + ExecuteScript(GetLocalString(GetArea(oSelf), "DELAYED_SPELLHOOK_SCRIPT"), oSelf); + SetLocalInt(oSelf, "Delayed_spellhook", FALSE); + + // Flag that an explosion has ocurred. + SetLocalInt(oSelf, "NW_SPELL_DELAY_BLAST_FIREBALL", TRUE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, lTarget); + //Cycle through the targets in the explosion area + oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + while(GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, oSelf)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(oCaster, SPELL_DELAYED_BLAST_FIREBALL)); + //Make SR check + if (!MyResistSpell(oCaster, oTarget)) + { + nDamage = d6(nCasterLevel); + //Enter Metamagic conditions + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 6 * nCasterLevel;//Damage is at max + } + else if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + (nDamage/2);//Damage/Healing is +50% + } + //Change damage according to Reflex, Evasion and Improved Evasion + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_FIRE, oCaster); + if(nDamage > 0) + { + //Set up the damage effect + eDam = EffectDamage(nDamage, DAMAGE_TYPE_FIRE); + //Apply VFX impact and damage effect + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + DelayCommand(0.01, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + } + } + } + //Get next target in the sequence + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } + DestroyObject(oSelf, 1.0); + } + } +} diff --git a/src/_removed/nw_s0_dismagic.nss b/src/_removed/nw_s0_dismagic.nss new file mode 100644 index 0000000..13a4555 --- /dev/null +++ b/src/_removed/nw_s0_dismagic.nss @@ -0,0 +1,89 @@ +//:://///////////////////////////////////////////// +//:: Dispel Magic +//:: NW_S0_DisMagic.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +//:: Attempts to dispel all magic on a targeted +//:: object, or simply the most powerful that it +//:: can on every object in an area if no target +//:: specified. +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Jan 7, 2002 +//:: Updated On: Oct 20, 2003, Georg Zoeller +//::////////////////////////////////////////////// + +#include "x0_i0_spells" +#include "x2_inc_spellhook" + +void main() +{ + + //-------------------------------------------------------------------------- + /* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + */ + //-------------------------------------------------------------------------- + if (!X2PreSpellCastCode()) + { + return; + } + // End of Spell Cast Hook + + effect eVis = EffectVisualEffect(VFX_IMP_BREACH); + effect eImpact = EffectVisualEffect(VFX_FNF_DISPEL); + object oTarget = GetSpellTargetObject(); + location lLocal = GetSpellTargetLocation(); + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + + //-------------------------------------------------------------------------- + // Dispel Magic is capped at caster level 10 + //-------------------------------------------------------------------------- + if(nCasterLevel > 10) + { + nCasterLevel = 10; + } + + if (GetIsObjectValid(oTarget)) + { + //---------------------------------------------------------------------- + // Targeted Dispel - Dispel all + //---------------------------------------------------------------------- + spellsDispelMagic(oTarget, nCasterLevel, eVis, eImpact); + } + else + { + //---------------------------------------------------------------------- + // Area of Effect - Only dispel best effect + //---------------------------------------------------------------------- + + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpact, GetSpellTargetLocation()); + oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, lLocal, FALSE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_AREA_OF_EFFECT | OBJECT_TYPE_PLACEABLE ); + while (GetIsObjectValid(oTarget)) + { + if(GetObjectType(oTarget) == OBJECT_TYPE_AREA_OF_EFFECT) + { + //-------------------------------------------------------------- + // Handle Area of Effects + //-------------------------------------------------------------- + spellsDispelAoE(oTarget, OBJECT_SELF, nCasterLevel); + } + else if (GetObjectType(oTarget) == OBJECT_TYPE_PLACEABLE) + { + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + } + else + { + spellsDispelMagic(oTarget, nCasterLevel, eVis, eImpact, FALSE); + } + + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE,lLocal, FALSE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_AREA_OF_EFFECT | OBJECT_TYPE_PLACEABLE); + } + } +} + + + diff --git a/src/_removed/nw_s0_dismissal.nss b/src/_removed/nw_s0_dismissal.nss new file mode 100644 index 0000000..b6f7a5b --- /dev/null +++ b/src/_removed/nw_s0_dismissal.nss @@ -0,0 +1,75 @@ +//:://///////////////////////////////////////////// +//:: Dismissal +//:: NW_S0_Dismissal.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + All summoned creatures within 30ft of caster + make a save and SR check or be banished +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Oct 22, 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 20, 2001 + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + //Declare major variables + object oMaster; + effect eVis = EffectVisualEffect(VFX_IMP_UNSUMMON); + effect eImpact = EffectVisualEffect(VFX_FNF_LOS_EVIL_30); + location lTarget = GetSpellTargetLocation(); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpact, lTarget); + int nSpellDC; + //Get the first object in the are of effect + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lTarget); + while(GetIsObjectValid(oTarget)) + { + //does the creature have a master. + oMaster = GetMaster(oTarget); + //Is that master valid and is he an enemy + if(GetIsObjectValid(oMaster) && spellsIsTarget(oMaster,SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF )) + { + //Is the creature a summoned associate + if(GetAssociate(ASSOCIATE_TYPE_SUMMONED, oMaster) == oTarget || + GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oMaster) == oTarget || + GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oMaster) == oTarget ) + { + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_DISMISSAL)); + //Determine correct save + nSpellDC = GetSpellSaveDC()+6; + //Make SR and will save checks + if (!MyResistSpell(OBJECT_SELF, oTarget) && !MySavingThrow(SAVING_THROW_WILL, oTarget, nSpellDC)) + { + //Apply the VFX and delay the destruction of the summoned monster so + //that the script and VFX can play. + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + DestroyObject(oTarget, 0.5); + } + } + } + //Get next creature in the shape. + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lTarget); + } +} + diff --git a/src/_removed/nw_s0_doom.nss b/src/_removed/nw_s0_doom.nss new file mode 100644 index 0000000..596ef86 --- /dev/null +++ b/src/_removed/nw_s0_doom.nss @@ -0,0 +1,79 @@ +//:://///////////////////////////////////////////// +//:: Doom +//:: NW_S0_Doom.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + If the target fails a save they recieve a -2 + penalty to all saves, attack rolls, damage and + skill checks for the duration of the spell. + + July 22 2002 (BK): Made it mind affecting. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Oct 22, 2001 +//::////////////////////////////////////////////// + + +#include "NW_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oTarget = GetSpellTargetObject(); + effect eVis = EffectVisualEffect(VFX_IMP_DOOM); + effect eLink = CreateDoomEffectsLink(); + + int nLevel = GetCasterLevel(OBJECT_SELF); + int nMetaMagic = GetMetaMagicFeat(); + //Meta-Magic checks + if(nMetaMagic == METAMAGIC_EXTEND) + { + nLevel *= 2; + } + if(!GetIsReactionTypeFriendly(oTarget)) + { + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_DOOM)); + //Spell Resistance and Saving throw + + //* GZ Engine fix for mind affecting spell + + int nResult = WillSave(oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_MIND_SPELLS); + if (nResult == 2) + { + if (GetIsPC(OBJECT_SELF)) // only display immune feedback for PCs + { + FloatingTextStrRefOnCreature(84525, OBJECT_SELF, FALSE); // * Target Immune + } + return; + } + + nResult = (nResult || MyResistSpell(OBJECT_SELF, oTarget)); + if (!nResult) + { + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink , oTarget, TurnsToSeconds(nLevel)); + } + } +} + diff --git a/src/_removed/nw_s0_eleswarm.nss b/src/_removed/nw_s0_eleswarm.nss new file mode 100644 index 0000000..420e837 --- /dev/null +++ b/src/_removed/nw_s0_eleswarm.nss @@ -0,0 +1,58 @@ +//:://///////////////////////////////////////////// +//:: Elemental Swarm +//:: NW_S0_EleSwarm.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + This spell creates a conduit from the caster + to the elemental planes. The first elemental + summoned is a 24 HD Air elemental. Whenever an + elemental dies it is replaced by the next + elemental in the chain Air, Earth, Water, Fire +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 12, 2001 +//::////////////////////////////////////////////// +//:: Update Pass By: Preston W, On: July 30, 2001 + +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + int nMetaMagic = GetMetaMagicFeat(); + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + int nDuration = GetCasterLevel(OBJECT_SELF); + nDuration = 24; + effect eSummon; + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_3); + //Check for metamagic duration + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration * 2; //Duration is +100% + } + //Set the summoning effect + eSummon = EffectSwarm(FALSE, "wog_s_airgreat2", "WoG_S_WATERGRT2","WoG_S_EARTHGRT2","WoG_S_FIREGREAT2"); + //Apply the summon effect + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eSummon, OBJECT_SELF, HoursToSeconds(nDuration)); +} + diff --git a/src/_removed/nw_s0_evardsa.nss b/src/_removed/nw_s0_evardsa.nss new file mode 100644 index 0000000..0d74e4e --- /dev/null +++ b/src/_removed/nw_s0_evardsa.nss @@ -0,0 +1,150 @@ +//:://///////////////////////////////////////////// +//:: Evards Black Tentacles: On Enter +//:: NW_S0_EvardsA +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Upon entering the mass of rubbery tentacles the + target is struck by 1d4 +1/lvl tentacles. Each + makes a grapple check. If it succeeds then + it does 1d6+4damage and the target must make + a Fortitude Save versus paralysis or be paralyzed + for 1 round. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Nov 23, 2001 +//::////////////////////////////////////////////// +//:: GZ: Removed SR, its not there by the book + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + + object oTarget = GetEnteringObject(); + effect eParal = EffectParalyze(); + effect eDur = EffectVisualEffect(VFX_DUR_PARALYZED); + effect eLink = EffectLinkEffects(eDur, eParal); + effect eDam; + + int nMetaMagic = GetMetaMagicFeat(); + int nDamage = 0; + int nHits; + float fDelay; + int nNumberTargets = 0; + int nMinimumTargets = 2; + int nDieDam; + int nTargetSize; + int nTentacleGrappleCheck; + int nOpposedGrappleCheck; + int nOppossedGrappleCheckModifiers; + int nTentaclesPerTarget; + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + + if ( GetCreatureSize(oTarget) < CREATURE_SIZE_MEDIUM ) + { + // Some visual feedback that the spell doesn't affect creatures of this type. + effect eFail = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); + fDelay = GetRandomDelay(0.75, 1.5); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eFail, oTarget,fDelay); + return; + } + + if ( nCasterLevel > 20 ) + { + nCasterLevel = 20; + } + + nTentaclesPerTarget = d4(); + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nTentaclesPerTarget = 4; + } + nTentaclesPerTarget = nTentaclesPerTarget + nCasterLevel; + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nTentaclesPerTarget = nTentaclesPerTarget + (nTentaclesPerTarget/2); //Number of variable tentacles is +50% + } + + oTarget = GetFirstInPersistentObject(); + while(GetIsObjectValid(oTarget)) + { + if ( GetCreatureSize(oTarget) >= CREATURE_SIZE_MEDIUM ) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, GetAreaOfEffectCreator())) + { + nNumberTargets++; + } + } + oTarget = GetNextInPersistentObject(); + } + + oTarget = GetEnteringObject(); + if ( nNumberTargets >= 0 ) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, GetAreaOfEffectCreator())) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_EVARDS_BLACK_TENTACLES)); + + // Distribute the tentacle between all valid targets. + if ( nNumberTargets < nMinimumTargets ) + { + // If there is only one target in the area, then only a portion of the tentacles should be able to reach them. + nTentaclesPerTarget = nTentaclesPerTarget/nMinimumTargets; + } + else + { + nTentaclesPerTarget = nTentaclesPerTarget/nNumberTargets; + } + + nOppossedGrappleCheckModifiers = GetBaseAttackBonus(oTarget) + GetAbilityModifier(ABILITY_STRENGTH,oTarget); + nTargetSize = GetCreatureSize(oTarget); + if (nTargetSize == CREATURE_SIZE_LARGE ) + { + nOppossedGrappleCheckModifiers = nOppossedGrappleCheckModifiers + 4; + } + else if ( nTargetSize == CREATURE_SIZE_HUGE ) + { + nOppossedGrappleCheckModifiers = nOppossedGrappleCheckModifiers + 8; + } + + for (nHits = nTentaclesPerTarget; nHits > 0; nHits--) + { + // Grapple Check. + nTentacleGrappleCheck = d20() + nCasterLevel + 8; // Str(4) + Large Tentacle(4) + nOpposedGrappleCheck = d20() + nOppossedGrappleCheckModifiers; + + if(nTentacleGrappleCheck >= nOpposedGrappleCheck) + { + nDieDam = d6() + 4; + //Enter Metamagic conditions + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDieDam = 10;//Damage is at max 6+4=10 + } + + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDieDam = nDieDam + (nDieDam/2); //Damage/Healing is +50% + } + nDamage = nDamage + nDieDam; + + fDelay = GetRandomDelay(1.0, 2.2); + eDam = EffectDamage(nDieDam, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_PLUS_TWO); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + } + } + + if(nDamage > 0) + { + if(!MySavingThrow(SAVING_THROW_FORT, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_NONE, OBJECT_SELF, fDelay)) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(1))); + } + } + } + } +} diff --git a/src/_removed/nw_s0_evardsc.nss b/src/_removed/nw_s0_evardsc.nss new file mode 100644 index 0000000..f9f9fcc --- /dev/null +++ b/src/_removed/nw_s0_evardsc.nss @@ -0,0 +1,158 @@ +//:://///////////////////////////////////////////// +//:: Evards Black Tentacles: Heartbeat +//:: NW_S0_EvardsB +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Upon remaining within the mass of rubbery tentacles the + target is struck by 1d4 + 1/lvl tentacles. Each + makes a grapple check. If it succeeds then + it does 1d6+4 damage and the target must make + a Fortitude Save versus paralysis or be paralyzed + for 1 round. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Nov 23, 2001 +//::////////////////////////////////////////////// +//:: GZ: Removed SR, its not there by the book + + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + + object oTarget; + effect eParal = EffectParalyze(); + effect eDur = EffectVisualEffect(VFX_DUR_PARALYZED); + effect eLink = EffectLinkEffects(eDur, eParal); + effect eDam; + effect eFail = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); + + int nMetaMagic = GetMetaMagicFeat(); + int nDamage; + int nDieDam; + float fDelay; + int nNumberTargets = 0; + int nTargetSize; + int nTentacleGrappleCheck; + int nOpposedGrappleCheck; + int nOppossedGrappleCheckModifiers; + int nHits; + int nMinimumTargets = 2; + int nTentaclesPerTarget; + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + + if ( nCasterLevel > 20 ) + { + nCasterLevel = 20; + } + + nTentaclesPerTarget = d4(); + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nTentaclesPerTarget = 4; + } + nTentaclesPerTarget = nTentaclesPerTarget + nCasterLevel; + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nTentaclesPerTarget = nTentaclesPerTarget + (nTentaclesPerTarget/2); //Number of variable tentacles is +50% + } + + oTarget = GetFirstInPersistentObject(); + while(GetIsObjectValid(oTarget)) + { + if ( GetCreatureSize(oTarget) >= CREATURE_SIZE_MEDIUM ) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, GetAreaOfEffectCreator())) + { + nNumberTargets++; + } + } + else + { + // Some visual feedback that the spell doesn't affect creatures of this type. + fDelay = GetRandomDelay(0.75, 1.5); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eFail, oTarget,fDelay); + } + oTarget = GetNextInPersistentObject(); + } + + if ( nNumberTargets > 0 ) + { + // Distribute the tentacle between all valid targets. + if ( nNumberTargets < nMinimumTargets ) + { + // If there is only one target in the area, then only a portion of the tentacles should be able to reach them. + nTentaclesPerTarget = nTentaclesPerTarget/nMinimumTargets; + } + else + { + nTentaclesPerTarget = nTentaclesPerTarget/nNumberTargets; + } + + oTarget = GetFirstInPersistentObject(); + while(GetIsObjectValid(oTarget)) + { + nDamage = 0; + nTargetSize = GetCreatureSize(oTarget); + if ( nTargetSize >= CREATURE_SIZE_MEDIUM ) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, GetAreaOfEffectCreator())) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_EVARDS_BLACK_TENTACLES)); + + nOppossedGrappleCheckModifiers = GetBaseAttackBonus(oTarget) + GetAbilityModifier(ABILITY_STRENGTH,oTarget); + if (nTargetSize == CREATURE_SIZE_LARGE ) + { + nOppossedGrappleCheckModifiers = nOppossedGrappleCheckModifiers + 4; + } + else if ( nTargetSize == CREATURE_SIZE_HUGE ) + { + nOppossedGrappleCheckModifiers = nOppossedGrappleCheckModifiers + 8; + } + + for (nHits = nTentaclesPerTarget; nHits > 0; nHits--) + { + // Grapple Check. + nTentacleGrappleCheck = d20() + nCasterLevel + 8; // Str(4) + Large Tentacle(4) + nOpposedGrappleCheck = d20() + nOppossedGrappleCheckModifiers; + + if(nTentacleGrappleCheck >= nOpposedGrappleCheck) + { + nDieDam = d6() + 4; + //Enter Metamagic conditions + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDieDam = 10;//Damage is at max 6+4=10 + } + + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDieDam = nDieDam + (nDieDam/2); //Damage/Healing is +50% + } + nDamage = nDamage + nDieDam; + + eDam = EffectDamage(nDieDam, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_PLUS_TWO); + fDelay = GetRandomDelay(0.75, 1.5); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + } + } + } + } + + if(nDamage > 0) + { + if(!MySavingThrow(SAVING_THROW_FORT, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_NONE, OBJECT_SELF, fDelay)) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(1))); + } + } + + oTarget = GetNextInPersistentObject(); + } + } +} diff --git a/src/_removed/nw_s0_feebmind.nss b/src/_removed/nw_s0_feebmind.nss new file mode 100644 index 0000000..bf223dd --- /dev/null +++ b/src/_removed/nw_s0_feebmind.nss @@ -0,0 +1,97 @@ +//:://///////////////////////////////////////////// +//:: Feeblemind +//:: [NW_S0_FeebMind.nss] +//:: Copyright (c) 2000 Bioware Corp. +//::////////////////////////////////////////////// +//:: Target must make a Will save or take ability +//:: damage to Intelligence equaling 1d4 per 4 levels. +//:: Duration of 1 rounds per 2 levels. +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Feb 2, 2001 +//::////////////////////////////////////////////// + +#include "NW_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oTarget = GetSpellTargetObject(); + int nDuration = GetCasterLevel(OBJECT_SELF)/2; + int nLoss = GetCasterLevel(OBJECT_SELF)/4; + //Check to make at least 1d4 damage is done + if (nLoss < 1) + { + nLoss = 1; + } + nLoss = d4(nLoss); + //Check to make sure the duration is 1 or greater + if (nDuration < 1) + { + nDuration == 1; + } + int nMetaMagic = GetMetaMagicFeat(); + effect eFeeb; + effect eVis = EffectVisualEffect(VFX_IMP_REDUCE_ABILITY_SCORE); + effect eRay = EffectBeam(VFX_BEAM_MIND, OBJECT_SELF, BODY_NODE_HAND); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); + + if(!GetIsReactionTypeFriendly(oTarget)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_FEEBLEMIND)); + //Make SR check + if (!MyResistSpell(OBJECT_SELF, oTarget)) + { + //Make an will save + + int nWillResult = WillSave(oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_MIND_SPELLS); + if (nWillResult == 0) + { + //Enter Metamagic conditions + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nLoss = nLoss * 4; + } + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nLoss = nLoss + (nLoss/2); + } + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration * 2; + } + //Set the ability damage + eFeeb = EffectAbilityDecrease(ABILITY_INTELLIGENCE, nLoss); + effect eLink = EffectLinkEffects(eFeeb, eDur); + + //Apply the VFX impact and ability damage effect. + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration)); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eRay, oTarget, 1.0); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + } else if (GetIsPC(OBJECT_SELF)) + { + FloatingTextStrRefOnCreature(84525, OBJECT_SELF, FALSE); // * Target Immune + } + } + } +} diff --git a/src/_removed/nw_s0_findtrap.nss b/src/_removed/nw_s0_findtrap.nss new file mode 100644 index 0000000..fd166ab --- /dev/null +++ b/src/_removed/nw_s0_findtrap.nss @@ -0,0 +1,101 @@ +//:://////////////////////////////////////////////////////////////////////////// +//:: Find Traps +//:: NW_S0_FindTrap +//:: Copyright (c) 2001 Bioware Corp. +//:://////////////////////////////////////////////////////////////////////////// +/* + - Finds and removes all traps within 30m. + - Caster level + d20 vs the trap disarm + + Fail - Trap detected + Success - Trap disabled +*/ +//:://////////////////////////////////////////////////////////////////////////// +//:: Created By : Preston Watamaniuk +//:: Created On : Oct 29, 2001 +//:: Modified By: Sir Elric +//:: Modified On: 15th April, 2006 +//:://////////////////////////////////////////////////////////////////////////// + +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + effect eVis = EffectVisualEffect(VFX_IMP_KNOCK); + int nCnt = 1; + object oTrap = GetNearestObject(OBJECT_TYPE_TRIGGER | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, OBJECT_SELF, nCnt); + while(GetIsObjectValid(oTrap) && GetDistanceToObject(oTrap) <= 30.0) + { + if(GetIsTrapped(oTrap)) + { + SetTrapDetectedBy(oTrap, OBJECT_SELF); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, GetLocation(oTrap)); + + object oCaster = OBJECT_SELF; + int nDC = GetTrapDisarmDC(oTrap); + int nLevel = GetCasterLevel(oCaster); + int nRandom = d20()+ nLevel; + string sTrap = GetName(oTrap); + + if(nRandom >= nDC) + { + if(GetObjectType(oTrap) == OBJECT_TYPE_TRIGGER) + SendMessageToPC(oCaster, "You have successfully disabled the " + sTrap + ""); + else + SendMessageToPC(oCaster, "You have successfully disabled the trap on the " + sTrap + ""); + + // For respawning trap code... + SetLocalInt(oTrap, "DISARMED_BY_SPELL", TRUE); + DelayCommand(2.0, SetTrapDisabled(oTrap)); + } + else + { + if(GetObjectType(oTrap) == OBJECT_TYPE_TRIGGER) + SendMessageToPC(oCaster, "You have detected " + sTrap + " but are unable to disable it"); + else + SendMessageToPC(oCaster, "You have detected the trap on the " + sTrap + " but are unable to disable it"); + } + } + nCnt++; + oTrap = GetNearestObject(OBJECT_TYPE_TRIGGER | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, OBJECT_SELF, nCnt); + } + //Declare major variables + object oTarget = GetSpellTargetObject(); + effect eVis2 = EffectVisualEffect(VFX_IMP_IMPROVE_ABILITY_SCORE); + int nMetaMagic = GetMetaMagicFeat(); + + effect eSearch = EffectSkillIncrease(SKILL_SEARCH, 10); + + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); + effect eLink = EffectLinkEffects(eSearch, eDur); + + int nDuration = (GetCasterLevel(OBJECT_SELF)/2); // * Duration 1 turn/level + if (nMetaMagic == METAMAGIC_EXTEND) //Duration is +100% + { + nDuration = nDuration * 2; + } + + //Fire spell cast at event for target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_AMPLIFY, FALSE)); + //Apply VFX impact and bonus effects + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis2, oTarget); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, TurnsToSeconds(nDuration)); +} diff --git a/src/_removed/nw_s0_gate.nss b/src/_removed/nw_s0_gate.nss new file mode 100644 index 0000000..3313267 --- /dev/null +++ b/src/_removed/nw_s0_gate.nss @@ -0,0 +1,69 @@ +//:://///////////////////////////////////////////// +//:: Gate +//:: NW_S0_Gate.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +//:: Summons a Balor to fight for the caster. +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 12, 2001 +//::////////////////////////////////////////////// +void CreateBalor(); +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + DelayCommand(3.0, CreateBalor()); +} + +void CreateBalor() +{ + //Declare major variables + int nMetaMagic = GetMetaMagicFeat(); + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + int nDuration = GetCasterLevel(OBJECT_SELF); + effect eSummon; + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_GATE); + //Make metamagic extend check + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + //Summon the Balor and apply the VFX impact + //ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, GetSpellTargetLocation()); + location lSpellTargetLOC = GetSpellTargetLocation(); + if(GetHasSpellEffect(SPELL_PROTECTION_FROM_EVIL) || + GetHasSpellEffect(SPELL_MAGIC_CIRCLE_AGAINST_EVIL) || + GetHasSpellEffect(SPELL_HOLY_AURA)) + { + eSummon = EffectSummonCreature("demon001",VFX_FNF_SUMMON_GATE,3.0); + float fSeconds = RoundsToSeconds(nDuration); + if(GetLocalInt(OBJECT_SELF, "DW_FLAG_PLANAR") == 0) + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, lSpellTargetLOC, fSeconds); + SetLocalInt(OBJECT_SELF, "DW_FLAG_PLANAR", 1); + DelayCommand(3.0, DeleteLocalInt(OBJECT_SELF, "DW_FLAG_PLANAR")); + } + else + { + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, lSpellTargetLOC); + CreateObject(OBJECT_TYPE_CREATURE, "NW_S_BALOR_EVIL", GetSpellTargetLocation()); + } +} + diff --git a/src/_removed/nw_s0_grdispel.nss b/src/_removed/nw_s0_grdispel.nss new file mode 100644 index 0000000..1e37092 --- /dev/null +++ b/src/_removed/nw_s0_grdispel.nss @@ -0,0 +1,79 @@ +//:://///////////////////////////////////////////// +//:: Greater Dispelling +//:: NW_S0_GrDispel.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Jan 7, 2002 +//:: Updated On: Oct 20, 2003, Georg Zoeller +//::////////////////////////////////////////////// +#include "x0_i0_spells" +#include "x2_inc_spellhook" + +void main() +{ + + //-------------------------------------------------------------------------- + /* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + */ + //-------------------------------------------------------------------------- + if (!X2PreSpellCastCode()) + { + return; + } + // End of Spell Cast Hook + + effect eVis = EffectVisualEffect( VFX_IMP_BREACH ); + effect eImpact = EffectVisualEffect( VFX_FNF_DISPEL_GREATER ); + int nCasterLevel = GetCasterLevel( OBJECT_SELF ); + object oTarget = GetSpellTargetObject(); + location lLocal = GetSpellTargetLocation(); + + //-------------------------------------------------------------------------- + // Dispel Magic is capped at caster level 10 + //-------------------------------------------------------------------------- + if(nCasterLevel >15 ) + { + nCasterLevel = 15; + } + + if (GetIsObjectValid(oTarget)) + { + //---------------------------------------------------------------------- + // Targeted Dispel - Dispel all + //---------------------------------------------------------------------- + spellsDispelMagic(oTarget, nCasterLevel, eVis, eImpact); + } + else + { + //---------------------------------------------------------------------- + // Area of Effect - Only dispel best effect + //---------------------------------------------------------------------- + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpact, GetSpellTargetLocation()); + oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, lLocal, FALSE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_AREA_OF_EFFECT | OBJECT_TYPE_PLACEABLE); + while (GetIsObjectValid(oTarget)) + { + if(GetObjectType(oTarget) == OBJECT_TYPE_AREA_OF_EFFECT) + { + //-------------------------------------------------------------- + // Handle Area of Effects + //-------------------------------------------------------------- + spellsDispelAoE(oTarget, OBJECT_SELF, nCasterLevel); + } + else if (GetObjectType(oTarget) == OBJECT_TYPE_PLACEABLE) + { + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + } + else + { + spellsDispelMagic(oTarget, nCasterLevel, eVis, eImpact, FALSE); + } + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE,lLocal, FALSE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_AREA_OF_EFFECT | OBJECT_TYPE_PLACEABLE); + } + } + +} diff --git a/src/_removed/nw_s0_grplanar.nss b/src/_removed/nw_s0_grplanar.nss new file mode 100644 index 0000000..b6e78a3 --- /dev/null +++ b/src/_removed/nw_s0_grplanar.nss @@ -0,0 +1,104 @@ +//:://///////////////////////////////////////////// +//:: Greater Planar Binding +//:: NW_S0_GrPlanar.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Summons an outsider dependant on alignment, or + holds an outsider if the creature fails a save. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 12, 2001 +//::////////////////////////////////////////////// +#include "NW_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + int nMetaMagic = GetMetaMagicFeat(); + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + int nDuration = GetCasterLevel(OBJECT_SELF); + effect eSummon; + effect eGate; + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); + effect eDur2 = EffectVisualEffect(VFX_DUR_PARALYZED); + effect eDur3 = EffectVisualEffect(VFX_DUR_PARALYZE_HOLD); + + effect eLink = EffectLinkEffects(eDur, EffectParalyze()); + eLink = EffectLinkEffects(eLink, eDur2); + eLink = EffectLinkEffects(eLink, eDur3); + + object oTarget = GetSpellTargetObject(); + int nRacial = GetRacialType(oTarget); + //Check for metamagic extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + //Check to see if a valid target has been chosen + if (GetIsObjectValid(oTarget)) + { + if(!GetIsReactionTypeFriendly(oTarget)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_GREATER_PLANAR_BINDING)); + //Check for racial type + if(nRacial == RACIAL_TYPE_OUTSIDER) + { + //Allow will save to negate hold effect + if(!MySavingThrow(SAVING_THROW_WILL, oTarget, GetSpellSaveDC()+5)) + { + //Apply the hold effect + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration/2)); + } + } + } + } + else if(GetLocalInt(OBJECT_SELF, "DW_FLAG_PLANAR") == 0) + { + //If the ground was clicked on summon an outsider based on alignment + int nAlign = GetAlignmentGoodEvil(OBJECT_SELF); + float fDelay = 3.0; + switch (nAlign) + { + case ALIGNMENT_EVIL: + eSummon = EffectSummonCreature("wogsumvrock001", VFX_FNF_SUMMON_GATE, 3.0); + //eGate = EffectVisualEffect(VFX_FNF_SUMMON_GATE); + break; + case ALIGNMENT_GOOD: + eSummon = EffectSummonCreature("ctrumpet001", VFX_FNF_SUMMON_CELESTIAL, 3.0); + //eGate = EffectVisualEffect(VFX_FNF_SUMMON_CELESTIAL); + break; + case ALIGNMENT_NEUTRAL: + eSummon = EffectSummonCreature("slaaddeth001", VFX_FNF_SUMMON_MONSTER_3, 1.0); + //eGate = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_3); + fDelay = 1.0; + break; + } + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), RoundsToSeconds(nDuration)); + SetLocalInt(OBJECT_SELF, "DW_FLAG_PLANAR", 1); + DelayCommand(3.0, DeleteLocalInt(OBJECT_SELF, "DW_FLAG_PLANAR")); + } +} + diff --git a/src/_removed/nw_s0_grrestore.nss b/src/_removed/nw_s0_grrestore.nss new file mode 100644 index 0000000..47994d1 --- /dev/null +++ b/src/_removed/nw_s0_grrestore.nss @@ -0,0 +1,104 @@ +//:://///////////////////////////////////////////// +//:: Greater Restoration +//:: NW_S0_GrRestore.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Removes all negative effects of a temporary nature + and all permanent effects of a supernatural nature + from the character. Does not remove the effects + relating to Mind-Affecting spells or movement alteration. + Heals target for 5d8 + 1 point per caster level. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Jan 7, 2002 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 20, 2001 + +#include "nw_i0_spells" +#include "x2_inc_spellhook" +#include "wog_horse_inc" + +// return TRUE if the effect created by a supernatural force and can't be dispelled by spells +int GetIsSupernaturalCurse(effect eEff); + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oTarget = GetSpellTargetObject(); + effect eVisual = EffectVisualEffect(VFX_IMP_RESTORATION_GREATER); + + effect eBad = GetFirstEffect(oTarget); + //Search for negative effects + while(GetIsEffectValid(eBad)) + { + if (GetEffectType(eBad) == EFFECT_TYPE_ABILITY_DECREASE || + GetEffectType(eBad) == EFFECT_TYPE_AC_DECREASE || + GetEffectType(eBad) == EFFECT_TYPE_ATTACK_DECREASE || + GetEffectType(eBad) == EFFECT_TYPE_DAMAGE_DECREASE || + GetEffectType(eBad) == EFFECT_TYPE_DAMAGE_IMMUNITY_DECREASE || + GetEffectType(eBad) == EFFECT_TYPE_SAVING_THROW_DECREASE || + GetEffectType(eBad) == EFFECT_TYPE_SPELL_RESISTANCE_DECREASE || + GetEffectType(eBad) == EFFECT_TYPE_SKILL_DECREASE || + GetEffectType(eBad) == EFFECT_TYPE_BLINDNESS || + GetEffectType(eBad) == EFFECT_TYPE_DEAF || + GetEffectType(eBad) == EFFECT_TYPE_CURSE || + GetEffectType(eBad) == EFFECT_TYPE_DISEASE || + GetEffectType(eBad) == EFFECT_TYPE_POISON || + GetEffectType(eBad) == EFFECT_TYPE_PARALYZE || + GetEffectType(eBad) == EFFECT_TYPE_CHARMED || + GetEffectType(eBad) == EFFECT_TYPE_DOMINATED || + GetEffectType(eBad) == EFFECT_TYPE_DAZED || + GetEffectType(eBad) == EFFECT_TYPE_CONFUSED || + GetEffectType(eBad) == EFFECT_TYPE_FRIGHTENED || + GetEffectType(eBad) == EFFECT_TYPE_NEGATIVELEVEL || + GetEffectType(eBad) == EFFECT_TYPE_PARALYZE || + GetEffectType(eBad) == EFFECT_TYPE_SLOW || + GetEffectType(eBad) == EFFECT_TYPE_STUNNED) + { + //Remove effect if it is negative. + if(!GetIsSupernaturalCurse(eBad)) + RemoveEffect(oTarget, eBad); + } + eBad = GetNextEffect(oTarget); + } + if(GetRacialType(oTarget) != RACIAL_TYPE_UNDEAD) + { + //Apply the VFX impact and effects + spellsCure(d8(10), 40, 80, VFX_IMP_SUNSTRIKE, VFX_NONE, GetSpellId()); + } + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_GREATER_RESTORATION, FALSE)); + + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVisual, oTarget); +} + +int GetIsSupernaturalCurse(effect eEff) +{ + object oCreator = GetEffectCreator(eEff); + if(GetTag(oCreator) == "q6e_ShaorisFellTemple") + return TRUE; + object horseEffects = GetEffectCreatorObject(WOG_HORSE_EFFECT); + if (oCreator == horseEffects) + return TRUE; + return FALSE; +} diff --git a/src/_removed/nw_s0_grspbrch.nss b/src/_removed/nw_s0_grspbrch.nss new file mode 100644 index 0000000..64124c9 --- /dev/null +++ b/src/_removed/nw_s0_grspbrch.nss @@ -0,0 +1,40 @@ +//:://///////////////////////////////////////////// +//:: Greater Spell Breach +//:: NW_S0_GrSpBrch.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Removes 4 spell defenses from an enemy mage. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Jan 7, 2002 +//::////////////////////////////////////////////// +#include "NW_I0_SPELLS" + +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + DoSpellBreach(GetSpellTargetObject(), 4, 5); +} + + diff --git a/src/_removed/nw_s0_harm.nss b/src/_removed/nw_s0_harm.nss new file mode 100644 index 0000000..2141aa2 --- /dev/null +++ b/src/_removed/nw_s0_harm.nss @@ -0,0 +1,90 @@ +//:://///////////////////////////////////////////// +//:: [Harm] +//:: [NW_S0_Harm.nss] +//:: Copyright (c) 2000 Bioware Corp. +//::////////////////////////////////////////////// +//:: Reduces target to 1d4 HP on successful touch +//:: attack. If the target is undead it is healed. +//::////////////////////////////////////////////// +//:: Created By: Keith Soleski +//:: Created On: Jan 18, 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 20, 2001 +//:: Update Pass By: Preston W, On: Aug 1, 2001 +//:: Last Update: Georg Zoeller On: Oct 10, 2004 +//::////////////////////////////////////////////// + +#include "NW_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oTarget = GetSpellTargetObject(); + int nDamage, nHeal; + int nMetaMagic = GetMetaMagicFeat(); + int nTouch = TouchAttackMelee(oTarget); + effect eVis = EffectVisualEffect(246); + effect eVis2 = EffectVisualEffect(VFX_IMP_HEALING_G); + effect eHeal, eDam; + //Check that the target is undead + if (GetRacialType(oTarget) == RACIAL_TYPE_UNDEAD) + { + //Figure out the amount of damage to heal + nHeal = GetMaxHitPoints(oTarget) - GetCurrentHitPoints(oTarget); + if (nHeal > 250) + { + nHeal = 250; + } + //Set the heal effect + eHeal = EffectHeal(nHeal); + //Apply heal effect and VFX impact + ApplyEffectToObject(DURATION_TYPE_INSTANT, eHeal, oTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis2, oTarget); + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_HARM, FALSE)); + } + else if (nTouch != FALSE) //GZ: Fixed boolean check to work in NWScript. 1 or 2 are valid return numbers from TouchAttackMelee + { + if(!GetIsReactionTypeFriendly(oTarget)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_HARM)); + if (!MyResistSpell(OBJECT_SELF, oTarget)) + { + nDamage = GetCurrentHitPoints(oTarget) - d4(1); + //Check for metamagic + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = GetCurrentHitPoints(oTarget) - 1; + } + if (nDamage > 250) + { + nDamage = 250; + } + eDam = EffectDamage(nDamage,DAMAGE_TYPE_NEGATIVE); + //Apply the VFX impact and effects + DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + } + } + } +} diff --git a/src/_removed/nw_s0_heal.nss b/src/_removed/nw_s0_heal.nss new file mode 100644 index 0000000..956a981 --- /dev/null +++ b/src/_removed/nw_s0_heal.nss @@ -0,0 +1,98 @@ +// HCR v3.2.0 - Removed Wild Magic. Added spell hook and HOTU code. +//:://////////////////////////////////////////////////////////////////////////// +//:: FileName: NW_S0_Heal +//:://////////////////////////////////////////////////////////////////////////// +/* + Heals the target to full unless they are undead. If undead, they are reduced + to 1d4 HP. +*/ +//:://////////////////////////////////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Jan 12, 2001 +//:: Updated On: Aug 1, 2001 - Preston W. +//:://////////////////////////////////////////////////////////////////////////// +#include "NW_I0_SPELLS" +#include "x2_inc_spellhook" +//:://////////////////////////////////////////////////////////////////////////// +void main() +{ + +if (GetRacialType(OBJECT_SELF) == RACIAL_TYPE_UNDEAD) +{ +return; +} + +/* + Spellcast Hook Code. Added 2003-06-23 by GeorgZ. If you want to make changes + to all spells, check x2_inc_spellhook.nss to find out more. +*/ + // If code within the PreSpellCastHook reports FALSE, do not run this spell. + if (!X2PreSpellCastCode()) { return; } + // End of Spell Cast Hook. + + // Check to see if the target is an undead. + object oTarget = GetSpellTargetObject(); + int nCHP = GetCurrentHitPoints(oTarget); + if (GetRacialType(oTarget) == RACIAL_TYPE_UNDEAD) + { + if (!GetIsReactionTypeFriendly(oTarget)) + { + // Fire cast spell at event for the specified target. + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_HEAL)); + + // Make a touch attack. + if (TouchAttackMelee(oTarget) > 0) + { + // Make SR check. + if (!MyResistSpell(OBJECT_SELF, oTarget)) + { + // Determine the amount of damage to inflict. + int nModify; + int nMetaMagic = GetMetaMagicFeat(); + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { nModify = 1; } + else + { nModify = d4(); } + int nDam = (nCHP - nModify); + if (nDam > 250) + { + nDam = 250; + } + // Set the damage visual and effect. + effect eVis1 = EffectVisualEffect(VFX_IMP_SUNSTRIKE); + effect eKill = EffectDamage(nDam, DAMAGE_TYPE_POSITIVE); + + // Apply the damage visual and effect. + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis1, oTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eKill, oTarget); + } + } + } + } + else + { + // Fire cast spell at event for the specified target. + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_HEAL, FALSE)); + + // Figure out how much to heal. + int nHeal; + int nMHP = GetMaxHitPoints(oTarget); + if (nCHP < 0) + { nHeal = (abs(nCHP) + nMHP); } + else + { nHeal = (nMHP - nCHP); } + if (nHeal > 250) + { + nHeal = 250; + } + + // Set the heal visual and effect. + effect eVis2 = EffectVisualEffect(VFX_IMP_HEALING_X); + effect eHeal = EffectHeal(nHeal); + + // Apply the heal visual and effect. + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis2, oTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eHeal, oTarget); + } +} +//:://////////////////////////////////////////////////////////////////////////// diff --git a/src/_removed/nw_s0_healcirc.nss b/src/_removed/nw_s0_healcirc.nss new file mode 100644 index 0000000..bb57496 --- /dev/null +++ b/src/_removed/nw_s0_healcirc.nss @@ -0,0 +1,116 @@ +// sr 5.5.1 +// took out unnecessary include script. +// sr 5.5 +// added stable heal code. + +//:://///////////////////////////////////////////// +//:: Healing Circle +//:: NW_S0_HealCirc +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* +// Positive energy spreads out in all directions +// from the point of origin, curing 1d8 points of +// damage plus 1 point per caster level (maximum +20) +// to nearby living allies. +// +// Like cure spells, healing circle damages undead in +// its area rather than curing them. +*/ +//::////////////////////////////////////////////// +//:: Created By: Noel Borstad +//:: Created On: Oct 18,2000 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 20, 2001 +//:: Update Pass By: Preston W, On: Aug 1, 2001 + +#include "hc_text_health" +#include "wm_include" +#include "NW_I0_SPELLS" +// 5.5 added heal include. + +void main() +{ + if (WildMagicOverride()) { return; } + //Declare major variables + object oTarget; + int nCasterLvl = GetCasterLevel(OBJECT_SELF); + int nDamagen, nModify, nHurt, nHP; + int nMetaMagic = GetMetaMagicFeat(); + effect eKill; + effect eHeal; + effect eVis = EffectVisualEffect(VFX_IMP_SUNSTRIKE); + effect eVis2 = EffectVisualEffect(VFX_IMP_HEALING_M); + effect eImpact = EffectVisualEffect(VFX_FNF_LOS_HOLY_20); + float fDelay; + //Limit caster level + if (nCasterLvl > 20) + { + nCasterLvl = 20; + } + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpact, GetSpellTargetLocation()); + //Get first target in shape + oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetSpellTargetLocation()); + while (GetIsObjectValid(oTarget)) + { + fDelay = GetRandomDelay(); + //Check if racial type is undead + if (GetRacialType(oTarget) == RACIAL_TYPE_UNDEAD ) + { + if(!GetIsReactionTypeFriendly(oTarget)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_HEALING_CIRCLE)); + //Make SR check + if (!MyResistSpell(OBJECT_SELF, oTarget, fDelay)) + { + nModify = d8() + nCasterLvl; + //Make metamagic check + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nModify = 8 + nCasterLvl; + } + //Make Fort save + if (MySavingThrow(SAVING_THROW_FORT, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_NONE, OBJECT_SELF, fDelay)) + { + nModify /= 2; + } + //Calculate damage + nHurt = nModify; + //Set damage effect + eKill = EffectDamage(nHurt, DAMAGE_TYPE_POSITIVE); + //Apply damage effect and VFX impact + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eKill, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + } + else + { + if(GetIsReactionTypeFriendly(oTarget) || GetFactionEqual(oTarget)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_HEALING_CIRCLE, FALSE)); + nHP = d8(); + //Enter Metamagic conditions + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nHP =8;//Damage is at max + } + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nHP = nHP + (nHP/2); //Damage/Healing is +50% + } + //Set healing effect + nHP = nHP + nCasterLvl; + // 5.5 heal code. + eHeal = EffectHeal(nHP); + //Apply heal effect and VFX impact + ApplyEffectToObject(DURATION_TYPE_INSTANT, eHeal, oTarget); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis2, oTarget)); + } + } + //Get next target in the shape + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetSpellTargetLocation()); + } +} diff --git a/src/_removed/nw_s0_lsdispel.nss b/src/_removed/nw_s0_lsdispel.nss new file mode 100644 index 0000000..1cd9a76 --- /dev/null +++ b/src/_removed/nw_s0_lsdispel.nss @@ -0,0 +1,84 @@ +//:://///////////////////////////////////////////// +//:: Lesser Dispel +//:: NW_S0_LsDispel.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Jan 7, 2002 +//:: Updated On: Oct 20, 2003, Georg Zoeller +//::////////////////////////////////////////////// +#include "x0_i0_spells" +#include "x2_inc_spellhook" + +void main() +{ + + //-------------------------------------------------------------------------- + /* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + */ + //-------------------------------------------------------------------------- + if (!X2PreSpellCastCode()) + { + return; + } + // End of Spell Cast Hook + + + //Declare major variables + effect eVis = EffectVisualEffect(VFX_IMP_HEAD_SONIC); + effect eImpact = EffectVisualEffect(VFX_FNF_LOS_NORMAL_20); + object oTarget = GetSpellTargetObject(); + location lLocal = GetSpellTargetLocation(); + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + + //-------------------------------------------------------------------------- + // Lesser Magic is capped at caster level 5 + //-------------------------------------------------------------------------- + if(nCasterLevel > 5) + { + nCasterLevel = 5; + } + + + if (GetIsObjectValid(oTarget)) + { + //---------------------------------------------------------------------- + // Targeted Dispel - Dispel all + //---------------------------------------------------------------------- + spellsDispelMagic(oTarget, nCasterLevel, eVis, eImpact); + } + else + { + //---------------------------------------------------------------------- + // Area of Effect - Only dispel best effect + //---------------------------------------------------------------------- + + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpact, GetSpellTargetLocation()); + oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, lLocal, FALSE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_AREA_OF_EFFECT | OBJECT_TYPE_PLACEABLE); + while (GetIsObjectValid(oTarget)) + { + if(GetObjectType(oTarget) == OBJECT_TYPE_AREA_OF_EFFECT) + { + //-------------------------------------------------------------- + // Handle Area of Effects + //-------------------------------------------------------------- + spellsDispelAoE(oTarget, OBJECT_SELF,nCasterLevel); + + } + else if (GetObjectType(oTarget) == OBJECT_TYPE_PLACEABLE) + { + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + } + else + { + spellsDispelMagic(oTarget, nCasterLevel, eVis, eImpact, FALSE); + } + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE,lLocal, FALSE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_AREA_OF_EFFECT | OBJECT_TYPE_PLACEABLE); + } + } + +} diff --git a/src/_removed/nw_s0_lsplanar.nss b/src/_removed/nw_s0_lsplanar.nss new file mode 100644 index 0000000..0dd155f --- /dev/null +++ b/src/_removed/nw_s0_lsplanar.nss @@ -0,0 +1,116 @@ +//:://///////////////////////////////////////////// +//:: Lesser Planar Binding +//:: NW_S0_LsPlanar.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Summons an outsider dependant on alignment, or + holds an outsider if the creature fails a save. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 12, 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 20, 2001 + +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + int nMetaMagic = GetMetaMagicFeat(); + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + int nDuration = GetCasterLevel(OBJECT_SELF); + effect eSummon; + effect eGate; + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); + effect eDur2 = EffectVisualEffect(VFX_DUR_PARALYZED); + effect eDur3 = EffectVisualEffect(VFX_DUR_PARALYZE_HOLD); + effect eLink = EffectLinkEffects(eDur, EffectParalyze()); + eLink = EffectLinkEffects(eLink, eDur2); + eLink = EffectLinkEffects(eLink, eDur3); + + object oTarget = GetSpellTargetObject(); + int nRacial = GetRacialType(oTarget); + if(nDuration == 0) + { + nDuration = 1; + } + + //Check for metamagic extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + //Check to see if the target is valid + if (GetIsObjectValid(oTarget)) + { + if(!GetIsReactionTypeFriendly(oTarget)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_LESSER_PLANAR_BINDING)); + //Check to make sure the target is an outsider + if(nRacial == RACIAL_TYPE_OUTSIDER) + { + //Make a will save + if(!WillSave(oTarget, GetSpellSaveDC())) + { + //Apply the linked effect + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration/2)); + } + } + } + } + else if(GetLocalInt(OBJECT_SELF, "DW_FLAG_PLANAR") == 0) + { + //Get the alignment of the caster + int nAlign = GetAlignmentGoodEvil(OBJECT_SELF); + float fDelay = 3.0; + switch (nAlign) + { + //Set the summon effect based on alignment + case ALIGNMENT_EVIL: + { + eSummon = EffectSummonCreature("wogsumimp",VFX_FNF_SUMMON_GATE , fDelay); + //eGate = EffectVisualEffect(VFX_FNF_SUMMON_GATE); + } + break; + case ALIGNMENT_GOOD: + { + eSummon = EffectSummonCreature("wogsumlanarc", 219 ,fDelay); + //eGate = EffectVisualEffect(219); + } + break; + case ALIGNMENT_NEUTRAL: + { + eSummon = EffectSummonCreature("wogsumredslaad", VFX_FNF_SUMMON_MONSTER_3); + //eGate = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_3, ,1.0); + } + break; + } + //Apply the summon effect and the VFX impact + //ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eGate, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), RoundsToSeconds(nDuration)); + SetLocalInt(OBJECT_SELF, "DW_FLAG_PLANAR", 1); + DelayCommand(3.0, DeleteLocalInt(OBJECT_SELF, "DW_FLAG_PLANAR")); + } +} + diff --git a/src/_removed/nw_s0_lsrestor.nss b/src/_removed/nw_s0_lsrestor.nss new file mode 100644 index 0000000..07db3f0 --- /dev/null +++ b/src/_removed/nw_s0_lsrestor.nss @@ -0,0 +1,79 @@ +//:://///////////////////////////////////////////// +//:: Lesser Restoration +//:: NW_S0_LsRestor.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Removes all supernatural effects related to ability + damage, as well as AC, Damage, +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Jan 7, 2002 +//::////////////////////////////////////////////// + +#include "x2_inc_spellhook" +#include "wog_horse_inc" + +// return TRUE if the effect created by a supernatural force and can't be dispelled by spells +int GetIsSupernaturalCurse(effect eEff); + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oTarget = GetSpellTargetObject(); + effect eVisual = EffectVisualEffect(VFX_IMP_RESTORATION_LESSER); + effect eBad = GetFirstEffect(oTarget); + //Search for negative effects + while(GetIsEffectValid(eBad)) + { + if (GetEffectType(eBad) == EFFECT_TYPE_ABILITY_DECREASE || + GetEffectType(eBad) == EFFECT_TYPE_AC_DECREASE || + GetEffectType(eBad) == EFFECT_TYPE_ATTACK_DECREASE || + GetEffectType(eBad) == EFFECT_TYPE_DAMAGE_DECREASE || + GetEffectType(eBad) == EFFECT_TYPE_DAMAGE_IMMUNITY_DECREASE || + GetEffectType(eBad) == EFFECT_TYPE_SAVING_THROW_DECREASE || + GetEffectType(eBad) == EFFECT_TYPE_SPELL_RESISTANCE_DECREASE || + GetEffectType(eBad) == EFFECT_TYPE_SKILL_DECREASE) + { + //Remove effect if it is negative. + if(!GetIsSupernaturalCurse(eBad)) + RemoveEffect(oTarget, eBad); + } + eBad = GetNextEffect(oTarget); + } + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_LESSER_RESTORATION, FALSE)); + + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVisual, oTarget); +} + +int GetIsSupernaturalCurse(effect eEff) +{ + object oCreator = GetEffectCreator(eEff); + if(GetTag(oCreator) == "q6e_ShaorisFellTemple") + return TRUE; + object horseEffects = GetEffectCreatorObject(WOG_HORSE_EFFECT); + if (oCreator == horseEffects) + return TRUE; + return FALSE; +} + diff --git a/src/_removed/nw_s0_lsspbrch.nss b/src/_removed/nw_s0_lsspbrch.nss new file mode 100644 index 0000000..6bcc995 --- /dev/null +++ b/src/_removed/nw_s0_lsspbrch.nss @@ -0,0 +1,38 @@ +//:://///////////////////////////////////////////// +//:: Lesser Spell Breach +//:: NW_S0_LsSpBrch.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Removes 2 spell protection from an enemy mage. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Jan 10, 2002 +//::////////////////////////////////////////////// +#include "NW_I0_SPELLS" + +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + DoSpellBreach(GetSpellTargetObject(), 2, 3, GetSpellId()); +} diff --git a/src/_removed/nw_s0_masheal.nss b/src/_removed/nw_s0_masheal.nss new file mode 100644 index 0000000..927d6b3 --- /dev/null +++ b/src/_removed/nw_s0_masheal.nss @@ -0,0 +1,113 @@ +// HCR v3.2.0 - Removed Wild Magic include and function. Added spell hook code. +//:://////////////////////////////////////////////////////////////////////////// +//:: FileName: NW_S0_MasHeal +//:://////////////////////////////////////////////////////////////////////////// +/* + Heals all friendly targets within 10ft to full unless they are undead. If + undead they are reduced to 1d4 HP. +*/ +//:://////////////////////////////////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 11, 2001 +//:://////////////////////////////////////////////////////////////////////////// +#include "NW_I0_SPELLS" +#include "x2_inc_spellhook" +//:://////////////////////////////////////////////////////////////////////////// +void main() +{ + // If code within the PreSpellCastHook reports FALSE, do not run this spell. + if (!X2PreSpellCastCode()) { return; } + + if (GetRacialType(OBJECT_SELF) == RACIAL_TYPE_UNDEAD) + { + return; + } + + // Declare major variables. + float fDelay; + effect eKill; + effect eHeal; + effect eVis1 = EffectVisualEffect(VFX_IMP_SUNSTRIKE); + effect eVis2 = EffectVisualEffect(VFX_IMP_HEALING_G); + int nMHP, nCHP, nHeal, nDam, nMod; + int nMetaMagic = GetMetaMagicFeat(); + + // Apply VFX area impact. + effect eStrike = EffectVisualEffect(VFX_FNF_LOS_HOLY_10); + location lLoc = GetSpellTargetLocation(); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eStrike, lLoc); + + // Get first target in spell area. + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, lLoc); + while (GetIsObjectValid(oTarget)) + { + fDelay = GetRandomDelay(); + nCHP = GetCurrentHitPoints(oTarget); + + // Check to see if the target is an undead. + if (GetRacialType(oTarget) == RACIAL_TYPE_UNDEAD && !GetIsReactionTypeFriendly(oTarget)) + { + // Fire cast spell at event for the specified target. + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_MASS_HEAL)); + + // Make a touch attack. + if (TouchAttackRanged(oTarget) > 0) + { + if (!GetIsReactionTypeFriendly(oTarget)) + { + // Make an SR check. + if (!MyResistSpell(OBJECT_SELF, oTarget, fDelay)) + { + // Detemine the damage to inflict to the undead. + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { nMod = 1; } + else + { nMod = d4(); } + nDam = (nCHP - nMod); + if (nDam > 250) + { + nDam = 250; + } + // Set the damage effect. + eKill = EffectDamage(nDam, DAMAGE_TYPE_POSITIVE); + + // Apply the damage visual and effect. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis1, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eKill, oTarget)); + } + } + } + } + else + { + // Make a faction check + if (GetIsFriend(oTarget) && GetRacialType(oTarget) != RACIAL_TYPE_UNDEAD) + { + // Fire cast spell at event for the specified target. + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_MASS_HEAL, FALSE)); + + // Figure out how much to heal. + nMHP = GetMaxHitPoints(oTarget); + if (nCHP < 0) + { nHeal = (abs(nCHP) + nMHP); } + else + { nHeal = (nMHP - nCHP); } + if (nHeal > 250) + { + nHeal = 250; + } + + // Set the heal effect. + eHeal = EffectHeal(nHeal); + + // Apply the heal visual and effect. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis2, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eHeal, oTarget)); + } + } + + // Get next target in the spell area. + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, lLoc); + } +} +//:://////////////////////////////////////////////////////////////////////////// diff --git a/src/_removed/nw_s0_morddisj.nss b/src/_removed/nw_s0_morddisj.nss new file mode 100644 index 0000000..96fc0ab --- /dev/null +++ b/src/_removed/nw_s0_morddisj.nss @@ -0,0 +1,96 @@ +//:://///////////////////////////////////////////// +//:: Mordenkainen's Disjunction +//:: NW_S0_MordDisj.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Massive Dispel Magic and Spell Breach rolled into one + If the target is a general area of effect they lose + 6 spell protections. If it is an area of effect everyone + in the area loses 2 spells protections. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Jan 7, 2002 +//:: Updated On: Oct 20, 2003, Georg Zoeller +//::////////////////////////////////////////////// +void StripEffects(int nNumber, object oTarget); +#include "X0_I0_SPELLS" + +#include "x2_inc_spellhook" + + +void main() +{ + + //-------------------------------------------------------------------------- + /* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + */ + //-------------------------------------------------------------------------- + if (!X2PreSpellCastCode()) + { + return; + } + // End of Spell Cast Hook + + effect eVis = EffectVisualEffect(VFX_IMP_HEAD_ODD); + effect eImpact = EffectVisualEffect(VFX_FNF_DISPEL_DISJUNCTION); + object oTarget = GetSpellTargetObject(); + location lLocal = GetSpellTargetLocation(); + int nCasterLevel= GetCasterLevel(OBJECT_SELF); + + + //-------------------------------------------------------------------------- + // Mord's is not capped anymore as we can go past level 20 now + //-------------------------------------------------------------------------- + /* + if(nCasterLevel > 20) + { + nCasterLevel = 20; + } + */ + + if (GetIsObjectValid(oTarget)) + { + //---------------------------------------------------------------------- + // Targeted Dispel - Dispel all + //---------------------------------------------------------------------- + spellsDispelMagic(oTarget, nCasterLevel, eVis, eImpact,TRUE,TRUE); + } + else + { + //---------------------------------------------------------------------- + // Area of Effect - Only dispel best effect + //---------------------------------------------------------------------- + + //Apply the VFX impact and effects + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpact, GetSpellTargetLocation()); + oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, lLocal, FALSE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_AREA_OF_EFFECT | OBJECT_TYPE_PLACEABLE ); + while (GetIsObjectValid(oTarget)) + { + if(GetObjectType(oTarget) == OBJECT_TYPE_AREA_OF_EFFECT) + { + //-------------------------------------------------------------- + // Handle Area of Effects + //-------------------------------------------------------------- + spellsDispelAoE(oTarget, OBJECT_SELF,nCasterLevel); + + } + else if (GetObjectType(oTarget) == OBJECT_TYPE_PLACEABLE) + { + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + } + else + { + spellsDispelMagic(oTarget, nCasterLevel, eVis, eImpact, FALSE,TRUE); + } + + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE,lLocal, FALSE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_AREA_OF_EFFECT | OBJECT_TYPE_PLACEABLE); + } + } +} + diff --git a/src/_removed/nw_s0_mordswrd.nss b/src/_removed/nw_s0_mordswrd.nss new file mode 100644 index 0000000..8ac405c --- /dev/null +++ b/src/_removed/nw_s0_mordswrd.nss @@ -0,0 +1,18 @@ +//:://///////////////////////////////////////////// +void main() + +{ + //Declare major variables + int nMetaMagic = GetMetaMagicFeat(); + int nDuration = GetCasterLevel(OBJECT_SELF); + effect eSummon = EffectSummonCreature("mordenkainensswo"); + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_3); + //Make metamagic check for extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2;//Duration is +100% + } + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), RoundsToSeconds(nDuration)); +} diff --git a/src/_removed/nw_s0_planar.nss b/src/_removed/nw_s0_planar.nss new file mode 100644 index 0000000..c628238 --- /dev/null +++ b/src/_removed/nw_s0_planar.nss @@ -0,0 +1,109 @@ +//:://///////////////////////////////////////////// +//:: Planar Binding +//:: NW_S0_Planar.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Summons an outsider dependant on alignment, or + holds an outsider if the creature fails a save. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 12, 2001 +//::////////////////////////////////////////////// +#include "NW_I0_SPELLS" + +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oTarget = GetSpellTargetObject(); + int nMetaMagic = GetMetaMagicFeat(); + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + int nDuration = GetCasterLevel(OBJECT_SELF); + effect eSummon; + effect eGate; + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); + effect eDur2 = EffectVisualEffect(VFX_DUR_PARALYZED); + effect eDur3 = EffectVisualEffect(VFX_DUR_PARALYZE_HOLD); + effect eLink = EffectLinkEffects(eDur, EffectParalyze()); + eLink = EffectLinkEffects(eLink, eDur2); + eLink = EffectLinkEffects(eLink, eDur3); + + int nRacial = GetRacialType(oTarget); + int nAlign = GetAlignmentGoodEvil(OBJECT_SELF); + if(nDuration == 0) + { + nDuration == 1; + } + //Check for metamagic extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + //Check to make sure a target was selected + if (GetIsObjectValid(oTarget)) + { + //Check the racial type of the target + if(nRacial == RACIAL_TYPE_OUTSIDER) + { + if(!GetIsReactionTypeFriendly(oTarget)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_PLANAR_BINDING)); + //Make a Will save + if(!MySavingThrow(SAVING_THROW_WILL, oTarget, GetSpellSaveDC()+2)) + { + //Apply the linked effect + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration/2)); + } + } + } + } + else if(GetLocalInt(OBJECT_SELF, "DW_FLAG_PLANAR") == 0) + { + //Set the summon effect based on the alignment of the caster + float fDelay = 3.0; + switch (nAlign) + { + case ALIGNMENT_EVIL: + eSummon = EffectSummonCreature("wogsumsucubusa01",VFX_FNF_SUMMON_GATE, fDelay); + //eGate = EffectVisualEffect(VFX_FNF_SUMMON_GATE); + break; + case ALIGNMENT_GOOD: + eSummon = EffectSummonCreature("chound002", VFX_FNF_SUMMON_CELESTIAL, fDelay); + //eGate = EffectVisualEffect(219); + break; + case ALIGNMENT_NEUTRAL: + eSummon = EffectSummonCreature("slaadgrn001",VFX_FNF_SUMMON_MONSTER_3, 1.0); + //eGate = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_3); + //fDelay = 1.0; + break; + } + //Apply the summon effect and VFX impact + //ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eGate, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), HoursToSeconds(nDuration)); + SetLocalInt(OBJECT_SELF, "DW_FLAG_PLANAR", 1); + DelayCommand(3.0, DeleteLocalInt(OBJECT_SELF, "DW_FLAG_PLANAR")); + } +} + diff --git a/src/_removed/nw_s0_premo.nss b/src/_removed/nw_s0_premo.nss new file mode 100644 index 0000000..f240475 --- /dev/null +++ b/src/_removed/nw_s0_premo.nss @@ -0,0 +1,61 @@ +//:://///////////////////////////////////////////// +//:: Premonition +//:: NW_S0_Premo +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Gives the gives the creature touched 30/+5 + damage reduction. This lasts for 1 hour per + caster level or until 10 * Caster Level + is dealt to the person. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: March 16 , 2001 +//::////////////////////////////////////////////// +//:: Last Updated By: Preston Watamaniuk, On: April 11, 2001 +#include "nw_i0_spells" + +#include "x2_inc_spellhook" + +void main() +{ + + /* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + + */ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + + // End of Spell Cast Hook + + object oTarget = GetSpellTargetObject(); + + //Declare major variables + int nDuration = GetCasterLevel(OBJECT_SELF); + int nLimit = nDuration * 10; + int nMetaMagic = GetMetaMagicFeat(); + effect eStone = EffectDamageReduction(30, DAMAGE_POWER_PLUS_SIX, nLimit); + effect eVis = EffectVisualEffect(VFX_DUR_PROT_PREMONITION); + //Link the visual and the damage reduction effect + effect eLink = EffectLinkEffects(eStone, eVis); + //Enter Metamagic conditions + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_PREMONITION, FALSE)); + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + + RemoveEffectsFromSpell(oTarget, SPELL_PREMONITION); + //Apply the linked effect + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, HoursToSeconds(nDuration)); +} diff --git a/src/_removed/nw_s0_raisdead.nss b/src/_removed/nw_s0_raisdead.nss new file mode 100644 index 0000000..d0745b0 --- /dev/null +++ b/src/_removed/nw_s0_raisdead.nss @@ -0,0 +1,320 @@ +// HCR 3.03 - 9th September, 2005 - SE +// ---------------------------------------------------------------------------- +// nw_s0_raisdead +// ---------------------------------------------------------------------------- +/* + Spell script to bring a PC or an NPC back to life with full health. + + In HCR, death has many variants: + ---------------------------------- + + - Death, Limbo: PC dies and is in due course transferred to limbo. In their + place a static Corpse NPC, an "invisible" DeathCorpse placeable and an PCT + (Player Corpse Token) item are created. A caster can use the DeathCorpse + to revive the PC. Currently if the caster tries to revive a PC before + they are transferred to limbo they will be informed that this is not + possible. The DeathCorpse can be used to revive a PC who is off-line. + + - Death, No Limbo: PC dies and remains where they fell. At their location + the same 3 components are created (Corpse, DeathCorpse and PCT). A caster + can use the DeathCorpse to revive the PC or cast directly onto the PC. The + DeathCorpse can be used to revive a PC who is off-line. + + - No Death, No Limbo: PC dies and remains where they fell. They have the + option to respawn however if they choose to wait for help a caster can + cast directly onto the PC to revive them. + + - NPC: NPC dies and remains where they fell (depending on other options). A + Caster can cast directly onto the NPC to revive them. + + + HCR 3.02.05 - Unresolved Issues + ------------------------------- + - NOTFUGUE is used to prevent a PC from being transfered to fugue while in + the process of being revived. The flag is checked by a delayed function + in hc_on_play_death which otherwise transfers the PC to fugue. However as + noted above MOVING pre-empts all attempts to revive a PC who has not yet + been transfered to Fugue. NOTFUGUE appears to have been rendered + redundant. + + + HCR 3.02.05 - TODO List + ----------------------- + - replace literals with DEATH and REVIVAL constants when available + + + Original BW Notes + ----------------- + When cast on placeables, you get a default error message. + * You can specify a different message in X2_L_RESURRECT_SPELL_MSG_RESREF + * You can turn off the message by setting the variable to -1 + +*/ +// ---------------------------------------------------------------------------- +/* + HCR 3.02 - 06 September 2005 - Sir Elric + - bug fix not checking target is dead + + HCR 3.02 - 05 August 2004 - Sunjammer + - modified for use with NPC Corpse system + + HCR 3.02 - 21 March 2004 - Sunjammer + - rewritten + + Credits: + - Georg Zeoller + - Preston Watamaniuk +*/ +// ---------------------------------------------------------------------------- +#include "hc_inc" +#include "hc_inc_dcorpse" +#include "hc_inc_npccorpse" +#include "hc_inc_rezpen" +#include "hc_text_activate" +#include "x2_inc_spellhook" + +#include "wog_speed_inc" + +// ---------------------------------------------------------------------------- +// MAIN +// ---------------------------------------------------------------------------- + +void main() +{ + // if code within the PreSpellCastHook reports FALSE, do not run this spell + if (X2PreSpellCastCode() == FALSE) + return; + + object oMod = GetModule(); + object oCaster = OBJECT_SELF; + object oTarget = GetSpellTargetObject(); + object oCreature; + + // get system being used + int bUsingDeath = GetLocalInt(oMod, "DEATHSYSTEM"); + int bUsingCorpses = GetLocalInt(oMod, "NPCCORPSE"); + int bUsingLimbo = GetLocalInt(oMod, "LIMBO"); + int bUsingRezPenalty = GetLocalInt(oMod, "REZPENALTY"); + + // cast at DeathCorpse flag + int bCastAtDC = FALSE; + + + // ------------------------------------------------------------------------- + // Part 1: find the creature to revive + // ------------------------------------------------------------------------- + + int nType = GetObjectType(oTarget); + string sTag = GetTag(oTarget); + + if(nType == OBJECT_TYPE_CREATURE && GetIsDead(oTarget)) + { + // target is a PC or an NPC and hence the creature to revive + oCreature = oTarget; + } + else if(nType == OBJECT_TYPE_PLACEABLE) + { + // target is a DeathCorpse (requires Death System) or other placeable + if(bUsingDeath && sTag == "DeathCorpse") + { + // valid: get creature to revive and raise cast at DC flag + oCreature = GetLocalObject(oTarget, "Owner"); + bCastAtDC = TRUE; + } + else if(bUsingCorpses && sTag == HC_TAG_NPCCORPSE_CORPSE) + { + // valid: get creature to revive + oCreature = GetLocalObject(oTarget, HC_VAR_NPCCORPSE_BODY); + } + else + { + // invalid: send "can't revive that" message to caster and abort + int nStrRef = GetLocalInt(oTarget, "X2_L_RESURRECT_SPELL_MSG_RESREF"); + if(nStrRef == 0) + { + nStrRef = 83861; + } + if(nStrRef != -1) + { + // inform caster that they cannot revive this object + FloatingTextStrRefOnCreature(nStrRef, oCaster); + } + return; + } + } + else + { + // target is invalid or an invalid type: abort + return; + } + + // pre-emptive abort if MOVING to LIMBO (see above) + if(bUsingLimbo && GetLocalInt(oCreature, "MOVING")) + { + SendMessageToPC(oCaster, NOTRAISE); + return; + } + + // ------------------------------------------------------------------------- + // Part 2: Revive the creature. + // ------------------------------------------------------------------------- + + int bIsPC = GetIsPC(oCreature); + + // raise/lower NOTFUGUE flag according to location (see above) + if(bUsingLimbo && GetTag(GetArea(oCreature)) == "FuguePlane") + DeleteLocalInt(oCreature, "NOTFUGUE"); + else + SetLocalInt(oCreature, "NOTFUGUE", TRUE); + + // visual revival + effect eVFX = EffectVisualEffect(VFX_IMP_RAISE_DEAD); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVFX, GetLocation(oTarget)); + + // actual revival + if(bCastAtDC && GetIsObjectValid(oCreature) == FALSE) + { + // --------------------------------------------------------------------- + // off-line revival can only occur when casting at a DeathCorpse + // --------------------------------------------------------------------- + string sID = GetLocalString(oTarget, "Pkey"); + + // inform caster, store revival location + SendMessageToPC(oCaster, NOTONLINE); + HCRSetPersistentLocation(oMod, "RESLOC" + sID, GetLocation(oCaster)); + + // revive the off-line PC + if(GetIsDM(oCaster)) + { + // DM provides a Raise Dead + // NOTE: this is left seperate to allow different state to be used + SPS(oCreature, PWS_PLAYER_STATE_RAISEDEAD); + } + else + { + // PC/NPC provides a Raise Dead + SPS(oCreature, PWS_PLAYER_STATE_RAISEDEAD); + } + + return; + } + else + { + // --------------------------------------------------------------------- + // on-line revival can occur when casting at a DeathCorpse or at a dead + // PC or NPC with various combinations of systems and targets + // --------------------------------------------------------------------- + // 1: PC, bUsingDeath, bUsingLimbo, bCastAtDC + // - PC in fugue (MOVING) + // - manually jump to DC + // - existing Heal, RemEff & Ress (hc_on_play_death) + // - existing kill body, DC & PCT (hc_fugue_exit) + // - existing player state change (hc_fugue_exit) + // 2: PC, bUsingDeath, bCastAtDC + // - PC is anywhere, DC is target + // - manually jump to DC + // - manually kill body, DC & PCT + // - manually player state change + // - manually Heal, RemEff & Ress + // 3: PC, bUsingDeath + // - PC (wait for help) is target + // - manually kill body, DC & PCT + // - manually player state change + // - manually Heal, RemEff & Ress + // 4: PC + // - PC (wait for help) is target + // - manually Heal, RemEff & Ress + // 5: NPC + // - NPC is target + // - manually Heal, RemEff & Ress + // --------------------------------------------------------------------- + string sID = GetPlayerID(oCreature); + + // fire cast spell at event for the specified creature + SignalEvent(oCreature, EventSpellCastAt(oCaster, SPELL_RESURRECTION, FALSE)); + + // start reviving + if(bIsPC && bUsingDeath && bUsingLimbo && bCastAtDC) + { + // 1: requires a jump to the DeathCorpse, everything else is done + AssignCommand(oCreature, JumpToObject(oTarget)); + } + else + { + // 2-3: require the body, DeathCorpse and PCT to be destoyed and for + // the PC's player state to be updated + if(bIsPC && bUsingDeath) + { + // 2: requires a jump to the DeathCorpse + if(bCastAtDC) + { + AssignCommand(oCreature, JumpToObject(oTarget)); + } + + // destroy the cloned NPC corpse + DelayCommand(0.5, DestroyCorpse(oCreature)); + + // destroy DeathCorpse + DelayCommand(0.6, DestroyObject(oTarget)); + + // destoy the PlayerCorpseToken + object oPCT = GetLocalObject(oMod, "PlayerCorpse" + sID); + DestroyObject(oPCT); + + // set PC's player state as alive + SPS(oCreature, PWS_PLAYER_STATE_ALIVE); + } + + // 2-5: require revival, healing and removal of effects + effect eRess = EffectResurrection(); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eRess, oCreature); + + HC_SetCurrentHitPoints(oCreature, 1); + + RemoveEffects(oCreature); + } + } + // added by Nocturne + if ( GetLocalInt(oMod, "SDEATHSYSTEM") ) + { + if (bIsPC ) + // set PC's player state as alive + SPS(oCreature, PWS_PLAYER_STATE_ALIVE); + } + + // ------------------------------------------------------------------------- + // Part 3: post-revival common stuff and clean up + // ------------------------------------------------------------------------- + + if(bIsPC) + { + if(bUsingRezPenalty && GetIsDM(oCaster) == FALSE) + { + // apply RezPenalty if appropriate + DelayCommand(3.0, hcRezPenalty(oCreature)); + } + + // force any nearby hostiles to attack + DelayCommand(5.0, ExecuteScript("hc_attackpc" , oCreature)); + + // lower NOTFUGUE flag + DeleteLocalInt(oCreature, "NOTFUGUE"); + + // Re-apply racial and armor encumbrance, if they are in effect. + if ( GetLocalInt(oMod, "RACIALMOVEMENT") ) + DelayCommand(1.0, HC_SetRacialMovementRate(oCreature)); + if ( GetLocalInt(oMod, "ARMORENCUMBER") ) + DelayCommand(1.1, HC_EffectArmorEncumbrance(oCreature)); + + // reapply boots of travel + DelayCommand(1.2, ApplyBootEffect(oCreature, FALSE)); + + DeleteLocalObject(oCreature, "ONDYING_MOUNT"); + } + else + { + // NPC Corpse clean up + HC_NPCCorpse_CleanUp(oTarget); + DeleteLocalInt(oTarget, "DEAD"); + } +} diff --git a/src/_removed/nw_s0_remeffect.nss b/src/_removed/nw_s0_remeffect.nss new file mode 100644 index 0000000..f253ca2 --- /dev/null +++ b/src/_removed/nw_s0_remeffect.nss @@ -0,0 +1,169 @@ +//:://///////////////////////////////////////////// +//:: Remove Effects +//:: NW_SO_RemEffect +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Takes the place of + Remove Disease + Neutralize Poison + Remove Paralysis + Remove Curse + Remove Blindness / Deafness +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Jan 8, 2002 +//::////////////////////////////////////////////// + +//#include "NW_I0_SPELLS" +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + + +// Allows equipped CURSED items to be unequipped. +// This is special handling for a custom flag supported by WoG's version of stopswap. +void DecurseItems(object oTarget); + + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + int nSpellID = GetSpellId(); + object oTarget = GetSpellTargetObject(); + int nEffect1; + int nEffect2; + int nEffect3; + int bAreaOfEffect = FALSE; + + effect eVis = EffectVisualEffect(VFX_IMP_REMOVE_CONDITION); + //Check for which removal spell is being cast. + if(nSpellID == SPELL_REMOVE_BLINDNESS_AND_DEAFNESS) + { + nEffect1 = EFFECT_TYPE_BLINDNESS; + nEffect2 = EFFECT_TYPE_DEAF; + bAreaOfEffect = TRUE; + } + else if(nSpellID == SPELL_REMOVE_CURSE) + { + nEffect1 = EFFECT_TYPE_CURSE; + } + else if(nSpellID == SPELL_REMOVE_DISEASE || nSpellID == SPELLABILITY_REMOVE_DISEASE) + { + nEffect1 = EFFECT_TYPE_DISEASE; + nEffect2 = EFFECT_TYPE_ABILITY_DECREASE; + } + else if(nSpellID == SPELL_NEUTRALIZE_POISON) + { + nEffect1 = EFFECT_TYPE_POISON; + nEffect2 = EFFECT_TYPE_DISEASE; + nEffect3 = EFFECT_TYPE_ABILITY_DECREASE; + } + + + // * March 2003. Remove blindness and deafness should be an area of effect spell + if (bAreaOfEffect == TRUE) + { + effect eImpact = EffectVisualEffect(VFX_FNF_LOS_HOLY_30); + effect eLink; + + spellsGenericAreaOfEffect(OBJECT_SELF, GetSpellTargetLocation(), SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, + SPELL_REMOVE_BLINDNESS_AND_DEAFNESS, eImpact, eLink, eVis, + DURATION_TYPE_INSTANT, 0.0, + SPELL_TARGET_ALLALLIES, FALSE, TRUE, nEffect1, nEffect2); + return; + } + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, nSpellID, FALSE)); + //Remove effects + RemoveSpecificEffect(nEffect1, oTarget); + if(nEffect2 != 0) + { + RemoveSpecificEffect(nEffect2, oTarget); + } + if(nEffect3 != 0) + { + RemoveSpecificEffect(nEffect3, oTarget); + } + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + + + // Support for CURSED items that cannot be unequipped (WoG & stopswap feature). + if ( nSpellID == SPELL_REMOVE_CURSE ) + DecurseItems(oTarget); +} + + +// Unequips oItem if it is flagged as unable to be unequipped and nLevel meets +// or exceeds the required level for breaking this curse. +// Returns nLevel minus the required level if oItem was unequipped. +// Otherwise, returns nLevel. +int DecurseItem(object oItem, object oPossessor, int nLevel); +int DecurseItem(object oItem, object oPossessor, int nLevel) +{ + int nRequired = GetLocalInt(oItem, "CURSED"); + + // See if this item gets unequipped. + // To be unequipped, the CURSED flag needs to be positive (negative indicates + // a curse that is not beaten by the remove curse spell), and nLevel must be + // at least the value of this flag. + if ( nRequired > 0 && nLevel >= nRequired ) + { + // Unequip. + SetLocalInt(oItem, "CURSED", 0); + AssignCommand(oPossessor, ActionUnequipItem(oItem)); + // Restore the flag. (The item is unequipped, but the curse is not broken.) + DelayCommand(2.0, SetLocalInt(oItem, "CURSED", nRequired)); + } + else + // Nothing going on with this item. + nRequired = 0; + + // Done. + return nLevel - nRequired; +} + + +// Allows equipped CURSED items to be unequipped. +// This is special handling for a custom flag supported by WoG's version of stopswap. +void DecurseItems(object oTarget) +{ + int nSlot; + int nLevel = GetCasterLevel(OBJECT_SELF); + + // Support casting on items as well as creatures. + switch ( GetObjectType(oTarget) ) + { + case OBJECT_TYPE_ITEM: + // Try to unequip the target item. + DecurseItem(oTarget, GetItemPossessor(oTarget), nLevel); + break; + + case OBJECT_TYPE_CREATURE: + // Loop through the target's inventory slots. + nSlot = NUM_INVENTORY_SLOTS - 4; // The number of non-creature inventory slots. + while ( nSlot-- > 0 && nLevel > 0 ) + // Try to unequip the item in this slot. + nLevel = DecurseItem(GetItemInSlot(nSlot, oTarget), oTarget, nLevel); + break; + } +} + diff --git a/src/_removed/nw_s0_resserec.nss b/src/_removed/nw_s0_resserec.nss new file mode 100644 index 0000000..421de97 --- /dev/null +++ b/src/_removed/nw_s0_resserec.nss @@ -0,0 +1,319 @@ +// HCR 3.03 - 9th September, 2005 - SE +// ---------------------------------------------------------------------------- +// nw_s0_ressurec +// ---------------------------------------------------------------------------- +/* + Spell script to bring a PC or an NPC back to life with full health. + + In HCR, death has many variants: + ---------------------------------- + + - Death, Limbo: PC dies and is in due course transferred to limbo. In their + place a static Corpse NPC, an "invisible" DeathCorpse placeable and an PCT + (Player Corpse Token) item are created. A caster can use the DeathCorpse + to revive the PC. Currently if the caster tries to revive a PC before + they are transferred to limbo they will be informed that this is not + possible. The DeathCorpse can be used to revive a PC who is off-line. + + - Death, No Limbo: PC dies and remains where they fell. At their location + the same 3 components are created (Corpse, DeathCorpse and PCT). A caster + can use the DeathCorpse to revive the PC or cast directly onto the PC. The + DeathCorpse can be used to revive a PC who is off-line. + + - No Death, No Limbo: PC dies and remains where they fell. They have the + option to respawn however if they choose to wait for help a caster can + cast directly onto the PC to revive them. + + - NPC: NPC dies and remains where they fell (depending on other options). A + Caster can cast directly onto the NPC to revive them. + + + HCR 3.02.05 - Unresolved Issues + ------------------------------- + - NOTFUGUE is used to prevent a PC from being transfered to fugue while in + the process of being revived. The flag is checked by a delayed function + in hc_on_play_death which otherwise transfers the PC to fugue. However as + noted above MOVING pre-empts all attempts to revive a PC who has not yet + been transfered to Fugue. NOTFUGUE appears to have been rendered + redundant. + + + HCR 3.02.05 - TODO List + ----------------------- + - replace literals with DEATH and REVIVAL constants when available + + + Original BW Notes + ----------------- + When cast on placeables, you get a default error message. + * You can specify a different message in X2_L_RESURRECT_SPELL_MSG_RESREF + * You can turn off the message by setting the variable to -1 + +*/ +// ---------------------------------------------------------------------------- +/* + HCR 3.02 - 06 September 2005 - Sir Elric + - bug fix not checking target is dead + + HCR 3.02 - 05 August 2004 - Sunjammer + - modified for use with NPC Corpse system + + HCR 3.02 - 21 March 2004 - Sunjammer + - rewritten + + Credits: + - Georg Zeoller + - Preston Watamaniuk +*/ +// ---------------------------------------------------------------------------- +#include "hc_inc" +#include "hc_inc_dcorpse" +#include "hc_inc_npccorpse" +#include "hc_inc_rezpen" +#include "hc_text_activate" +#include "x2_inc_spellhook" + +#include "wog_speed_inc" + +// ---------------------------------------------------------------------------- +// MAIN +// ---------------------------------------------------------------------------- + +void main() +{ + // if code within the PreSpellCastHook reports FALSE, do not run this spell + if (X2PreSpellCastCode() == FALSE) + return; + + object oMod = GetModule(); + object oCaster = OBJECT_SELF; + object oTarget = GetSpellTargetObject(); + object oCreature; + + // get system being used + int bUsingDeath = GetLocalInt(oMod, "DEATHSYSTEM"); + int bUsingCorpses = GetLocalInt(oMod, "NPCCORPSE"); + int bUsingLimbo = GetLocalInt(oMod, "LIMBO"); + int bUsingRezPenalty = GetLocalInt(oMod, "REZPENALTY"); + + // cast at DeathCorpse flag + int bCastAtDC = FALSE; + + + // ------------------------------------------------------------------------- + // Part 1: find the creature to revive + // ------------------------------------------------------------------------- + + int nType = GetObjectType(oTarget); + string sTag = GetTag(oTarget); + + if(nType == OBJECT_TYPE_CREATURE && GetIsDead(oTarget)) + { + // target is a PC or an NPC and hence the creature to revive + oCreature = oTarget; + } + else if(nType == OBJECT_TYPE_PLACEABLE) + { + // target is a DeathCorpse (requires Death System) or other placeable + if(bUsingDeath && sTag == "DeathCorpse") + { + // valid: get creature to revive and raise cast at DC flag + oCreature = GetLocalObject(oTarget, "Owner"); + bCastAtDC = TRUE; + } + else if(bUsingCorpses && sTag == HC_TAG_NPCCORPSE_CORPSE) + { + // valid: get creature to revive + oCreature = GetLocalObject(oTarget, HC_VAR_NPCCORPSE_BODY); + } + else + { + // invalid: send "can't revive that" message to caster and abort + int nStrRef = GetLocalInt(oTarget, "X2_L_RESURRECT_SPELL_MSG_RESREF"); + if(nStrRef == 0) + { + nStrRef = 83861; + } + if(nStrRef != -1) + { + // inform caster that they cannot revive this object + FloatingTextStrRefOnCreature(nStrRef, oCaster); + } + return; + } + } + else + { + // target is invalid or an invalid type: abort + return; + } + + // pre-emptive abort if MOVING to LIMBO (see above) + if(bUsingLimbo && GetLocalInt(oCreature, "MOVING")) + { + SendMessageToPC(oCaster, NOTRAISE); + return; + } + + // ------------------------------------------------------------------------- + // Part 2: Revive the creature. + // ------------------------------------------------------------------------- + + int bIsPC = GetIsPC(oCreature); + + // raise/lower NOTFUGUE flag according to location (see above) + if(bUsingLimbo && GetTag(GetArea(oCreature)) == "FuguePlane") + DeleteLocalInt(oCreature, "NOTFUGUE"); + else + SetLocalInt(oCreature, "NOTFUGUE", TRUE); + + // visual revival + effect eVFX = EffectVisualEffect(VFX_IMP_RAISE_DEAD); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVFX, GetLocation(oTarget)); + + // actual revival + if(bCastAtDC && GetIsObjectValid(oCreature) == FALSE) + { + // --------------------------------------------------------------------- + // off-line revival can only occur when casting at a DeathCorpse + // --------------------------------------------------------------------- + string sID = GetLocalString(oTarget, "Pkey"); + + // inform caster, store revival location + SendMessageToPC(oCaster, NOTONLINE); + HCRSetPersistentLocation(oMod, "RESLOC" + sID, GetLocation(oCaster)); + + // revive the off-line PC + if(GetIsDM(oCaster)) + { + // DM provides a True Resserection + SPS(oCreature, PWS_PLAYER_STATE_RESTRUE); + } + else + { + // PC/NPC provides a Resserection + SPS(oCreature, PWS_PLAYER_STATE_RESURRECTED); + } + + return; + } + else + { + // --------------------------------------------------------------------- + // on-line revival can occur when casting at a DeathCorpse or at a dead + // PC or NPC with various combinations of systems and targets + // --------------------------------------------------------------------- + // 1: PC, bUsingDeath, bUsingLimbo, bCastAtDC + // - PC in fugue (MOVING) + // - manually jump to DC + // - existing Heal, RemEff & Ress (hc_on_play_death) + // - existing kill body, DC & PCT (hc_fugue_exit) + // - existing player state change (hc_fugue_exit) + // 2: PC, bUsingDeath, bCastAtDC + // - PC is anywhere, DC is target + // - manually jump to DC + // - manually kill body, DC & PCT + // - manually player state change + // - manually Heal, RemEff & Ress + // 3: PC, bUsingDeath + // - PC (wait for help) is target + // - manually kill body, DC & PCT + // - manually player state change + // - manually Heal, RemEff & Ress + // 4: PC + // - PC (wait for help) is target + // - manually Heal, RemEff & Ress + // 5: NPC + // - NPC is target + // - manually Heal, RemEff & Ress + // --------------------------------------------------------------------- + string sID = GetPlayerID(oCreature); + + // fire cast spell at event for the specified creature + SignalEvent(oCreature, EventSpellCastAt(oCaster, SPELL_RESURRECTION, FALSE)); + + // start reviving + if(bIsPC && bUsingDeath && bUsingLimbo && bCastAtDC) + { + // 1: requires a jump to the DeathCorpse, everything else is done + AssignCommand(oCreature, JumpToObject(oTarget)); + } + else + { + // 2-3: require the body, DeathCorpse and PCT to be destoyed + // and for the PC's player state to be updated + if(bIsPC && bUsingDeath) + { + // 2: requires a jump to the DeathCorpse + if(bCastAtDC) + { + AssignCommand(oCreature, JumpToObject(oTarget)); + } + + // destroy the cloned NPC corpse + DelayCommand(0.5, DestroyCorpse(oCreature)); + + // destroy DeathCorpse + DelayCommand(0.6, DestroyObject(oTarget)); + + // destoy the PlayerCorpseToken + object oPCT = GetLocalObject(oMod, "PlayerCorpse" + sID); + DestroyObject(oPCT); + + // set PC's player state as alive + SPS(oCreature, PWS_PLAYER_STATE_ALIVE); + } + + // 2-5: require revival, healing and removal of effects + effect eRess = EffectResurrection(); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eRess, oCreature); + + HC_SetCurrentHitPoints(oCreature, GetMaxHitPoints(oCreature)); + + RemoveEffects(oCreature); + } + } + // added by Nocturne + if ( GetLocalInt(oMod, "SDEATHSYSTEM") ) + { + if (bIsPC ) + // set PC's player state as alive + SPS(oCreature, PWS_PLAYER_STATE_ALIVE); + } + + // ------------------------------------------------------------------------- + // Part 3: post-revival common stuff and clean up + // ------------------------------------------------------------------------- + + if(bIsPC) + { + if(bUsingRezPenalty && GetIsDM(oCaster) == FALSE) + { + // apply RezPenalty if appropriate + DelayCommand(3.0, hcRezPenalty(oCreature)); + } + + // force any nearby hostiles to attack + DelayCommand(5.0, ExecuteScript("hc_attackpc" , oCreature)); + + // lower NOTFUGUE flag + DeleteLocalInt(oCreature, "NOTFUGUE"); + + // Re-apply racial and armor encumbrance, if they are in effect. + if ( GetLocalInt(oMod, "RACIALMOVEMENT") ) + DelayCommand(1.0, HC_SetRacialMovementRate(oCreature)); + if ( GetLocalInt(oMod, "ARMORENCUMBER") ) + DelayCommand(1.1, HC_EffectArmorEncumbrance(oCreature)); + + // reapply boots of travel + DelayCommand(1.2, ApplyBootEffect(oCreature, FALSE)); + + DeleteLocalObject(oCreature, "ONDYING_MOUNT"); + } + else + { + // NPC Corpse clean up + HC_NPCCorpse_CleanUp(oTarget); + DeleteLocalInt(oTarget, "DEAD"); + } +} diff --git a/src/_removed/nw_s0_restore.nss b/src/_removed/nw_s0_restore.nss new file mode 100644 index 0000000..d58cfc3 --- /dev/null +++ b/src/_removed/nw_s0_restore.nss @@ -0,0 +1,85 @@ +//:://///////////////////////////////////////////// +//:: Restoration +//:: NW_S0_Restore.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Removes all negative effects unless they come + from Poison, Disease or Curses. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Jan 7, 2002 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 22, 2001 + +#include "x2_inc_spellhook" +#include "wog_horse_inc" + +// return TRUE if the effect created by a supernatural force and can't be dispelled by spells +int GetIsSupernaturalCurse(effect eEff); + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oTarget = GetSpellTargetObject(); + effect eVisual = EffectVisualEffect(VFX_IMP_RESTORATION); + int bValid; + + effect eBad = GetFirstEffect(oTarget); + //Search for negative effects + while(GetIsEffectValid(eBad)) + { + if (GetEffectType(eBad) == EFFECT_TYPE_ABILITY_DECREASE || + GetEffectType(eBad) == EFFECT_TYPE_AC_DECREASE || + GetEffectType(eBad) == EFFECT_TYPE_ATTACK_DECREASE || + GetEffectType(eBad) == EFFECT_TYPE_DAMAGE_DECREASE || + GetEffectType(eBad) == EFFECT_TYPE_DAMAGE_IMMUNITY_DECREASE || + GetEffectType(eBad) == EFFECT_TYPE_SAVING_THROW_DECREASE || + GetEffectType(eBad) == EFFECT_TYPE_SPELL_RESISTANCE_DECREASE || + GetEffectType(eBad) == EFFECT_TYPE_SKILL_DECREASE || + GetEffectType(eBad) == EFFECT_TYPE_BLINDNESS || + GetEffectType(eBad) == EFFECT_TYPE_DEAF || + GetEffectType(eBad) == EFFECT_TYPE_PARALYZE || + GetEffectType(eBad) == EFFECT_TYPE_NEGATIVELEVEL) + { + //Remove effect if it is negative. + if(!GetIsSupernaturalCurse(eBad)) + RemoveEffect(oTarget, eBad); + } + eBad = GetNextEffect(oTarget); + } + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_RESTORATION, FALSE)); + + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVisual, oTarget); +} + +int GetIsSupernaturalCurse(effect eEff) +{ + object oCreator = GetEffectCreator(eEff); + if(GetTag(oCreator) == "q6e_ShaorisFellTemple") + return TRUE; + object horseEffects = GetEffectCreatorObject(WOG_HORSE_EFFECT); + if (oCreator == horseEffects) + return TRUE; + return FALSE; +} diff --git a/src/_removed/nw_s0_summon.nss b/src/_removed/nw_s0_summon.nss new file mode 100644 index 0000000..f074e15 --- /dev/null +++ b/src/_removed/nw_s0_summon.nss @@ -0,0 +1,153 @@ +//:://///////////////////////////////////////////// +//:: Summon Creature Series +//:: NW_S0_Summon +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Carries out the summoning of the appropriate + creature for the Summon Monster Series of spells + 1 to 9 +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Jan 8, 2002 +//::////////////////////////////////////////////// + +#include "x2_inc_spellhook" +//:://////////////////////////////////////////////////////////////////////////// + +effect GetSummonEffect(int nSpellID); + +//:://////////////////////////////////////////////////////////////////////////// +void main() +{ + // If code within the PreSpellCastHook reports FALSE, do not run this spell. + if (!X2PreSpellCastCode()) { return; } + + // Determine base duration. + object oMod = GetModule(); + int nLevel = GetCasterLevel(OBJECT_SELF); + int nSummon = GetLocalInt(oMod, "SUMMONTIME"); + int nDuration; + if (nSummon > 0) + { nDuration = (((nLevel * nSummon) + 2)+10); } + else + { nDuration = 24; } + + // Check for Meta-Magic extend. + int nMetaMagic = GetMetaMagicFeat(); + if (nMetaMagic == METAMAGIC_EXTEND) + { nDuration = (nDuration*2); } + + // Apply the VFX impact and summon effect. + int nSpellID = GetSpellId(); + effect eSummon = GetSummonEffect(nSpellID); + location lLoc = GetSpellTargetLocation(); + float fDuration; + if (nSummon > 0) + { fDuration = RoundsToSeconds(nDuration); } + else + { fDuration = HoursToSeconds(nDuration); } + + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, lLoc, fDuration); +} +//:://////////////////////////////////////////////////////////////////////////// +effect GetSummonEffect(int nSpellID) +{ + // Set the visual effect constant based on the spell being cast. + int nFNF_Effect; + switch ( nSpellID ) + { + case SPELL_SUMMON_CREATURE_I: + case SPELL_SUMMON_CREATURE_II: + case SPELL_SUMMON_CREATURE_III: + nFNF_Effect = VFX_FNF_SUMMON_MONSTER_1; + break; + + case SPELL_SUMMON_CREATURE_IV: + case SPELL_SUMMON_CREATURE_V: + case SPELL_SUMMON_CREATURE_VI: + nFNF_Effect = VFX_FNF_SUMMON_MONSTER_2; + break; + + case SPELL_SUMMON_CREATURE_VII: + case SPELL_SUMMON_CREATURE_VIII: + case SPELL_SUMMON_CREATURE_IX: + nFNF_Effect = VFX_FNF_SUMMON_MONSTER_3; + break; + } + + + // Set the power level based on the spell ID. + int nPowerLevel; + switch ( nSpellID ) + { + case SPELL_SUMMON_CREATURE_I: nPowerLevel = 1; break; + case SPELL_SUMMON_CREATURE_II: nPowerLevel = 2; break; + case SPELL_SUMMON_CREATURE_III: nPowerLevel = 3; break; + case SPELL_SUMMON_CREATURE_IV: nPowerLevel = 4; break; + case SPELL_SUMMON_CREATURE_V: nPowerLevel = 5; break; + case SPELL_SUMMON_CREATURE_VI: nPowerLevel = 6; break; + case SPELL_SUMMON_CREATURE_VII: nPowerLevel = 7; break; + case SPELL_SUMMON_CREATURE_VIII: nPowerLevel = 8; break; + case SPELL_SUMMON_CREATURE_IX: nPowerLevel = 9; break; + } + // Power level is increased for those with the animal domain. + if( GetHasFeat(FEAT_ANIMAL_DOMAIN_POWER)||GetHasFeat(FEAT_NATURE_SENSE)) + nPowerLevel++; + + + // Set the ResRef of the creature to summon based on the power level. + string sResRef = ""; + object oBook = GetItemPossessedBy(OBJECT_SELF, "bookofsummons"); + + // Try to get the resref from the Book of Summons. + if ( oBook != OBJECT_INVALID ) + sResRef = GetLocalString(oBook, "summons" + IntToString(nPowerLevel)); + + if ( sResRef == "" ) + // Either no Book of Summons, or variable not set. + switch ( nPowerLevel ) + { + case 1: sResRef = "NW_S_BADGERDIRE"; break; + case 2: sResRef = "NW_S_BOARDIRE"; break; + case 3: sResRef = "NW_S_WOLFDIRE"; break; + case 4: sResRef = "wog_spidswrd001"; break; + case 5: sResRef = "wog_beardire001"; break; + case 6: sResRef = "WoG_DIRETIGER001"; break; + case 7: switch ( d4() ) + { + case 1: sResRef = "wog_s_airhuge001"; break; + case 2: sResRef = "WoG_S_WATERHUGE"; break; + case 3: sResRef = "WoG_S_FIREHUGE"; break; + case 4: sResRef = "WoG_S_EARTHHUGE"; break; + } + break; + case 8: switch ( d4() ) + { + case 1: sResRef = "wog_airgreat001"; break; + case 2: sResRef = "wog_watergreat"; break; + case 3: sResRef = "wog_firegreat001"; break; + case 4: sResRef = "wog_earthgreat"; break; + } + break; + case 9: switch ( d4() ) + { + case 1: sResRef = "WoG_S_AIRELDER"; break; + case 2: sResRef = "WoG_S_WATELDER"; break; + case 3: sResRef = "WoG_S_FIREELDER"; break; + case 4: sResRef = "WoG_S_EARTHELD"; break; + } + break; + case 10: switch ( d4() ) + { + case 1: sResRef = "wog_s_airelder01"; break; + case 2: sResRef = "wog_s_waterpr001"; break; + case 3: sResRef = "wog_s_fireprn001"; break; + case 4: sResRef = "WoG_S_EARTHPRINCE"; break; + } + } + return EffectSummonCreature(sResRef, nFNF_Effect); +} +//:://////////////////////////////////////////////////////////////////////////// +//:://////////////////////////////////////////////////////////////////////////// diff --git a/src/_removed/nw_s0_summon1.nss b/src/_removed/nw_s0_summon1.nss new file mode 100644 index 0000000..cd48dde --- /dev/null +++ b/src/_removed/nw_s0_summon1.nss @@ -0,0 +1,50 @@ +#include "wm_include" +#include "x2_inc_spellhook" +void main() +{ + if (WildMagicOverride()) { return; } + //Declare major variables + int nMetaMagic = GetMetaMagicFeat(); + object oMod = GetModule(); + int nLevel = GetCasterLevel(OBJECT_SELF); + int nSummon = GetLocalInt(oMod, "SUMMONTIME"); + int nDuration; + if (nSummon > 0) + { nDuration = ((nLevel * nSummon) + 10); } + else + { nDuration = 24; } + string sResRef = ""; // ResRef of the creature to summon. + //Make metamagic check for extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + // Check for a Book of Summons + object oBook = GetItemPossessedBy(OBJECT_SELF, "bookofsummons"); + if ( oBook != OBJECT_INVALID ) + { + sResRef = GetLocalString(oBook, "summons1"); + } + + if ( sResRef == "" ) + { + // Either no Book of Summons, or variable not set. + // Go with the defaults. + if ( GetHasFeat(FEAT_ANIMAL_DOMAIN_POWER) ) + sResRef = "NW_S_BOARDIRE"; + else + sResRef = "NW_S_badgerdire"; + } + + float fDuration; + if (nSummon > 0) + { fDuration = RoundsToSeconds(nDuration); } + else + { fDuration = HoursToSeconds(nDuration); } + + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_1); + effect eSummon = EffectSummonCreature(sResRef); + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), fDuration); +} diff --git a/src/_removed/nw_s0_summon2.nss b/src/_removed/nw_s0_summon2.nss new file mode 100644 index 0000000..68927b9 --- /dev/null +++ b/src/_removed/nw_s0_summon2.nss @@ -0,0 +1,53 @@ +//:://///////////////////////////////////////////// +//:: Summon Monster II +//:: NW_S0_Summon2 +#include "wm_include" +#include "x2_inc_spellhook" +void main() +{ + if (WildMagicOverride()) { return; } + //Declare major variables + int nMetaMagic = GetMetaMagicFeat(); + object oMod = GetModule(); + int nLevel = GetCasterLevel(OBJECT_SELF); + int nSummon = GetLocalInt(oMod, "SUMMONTIME"); + int nDuration; + if (nSummon > 0) + { nDuration = ((nLevel * nSummon) + 10); } + else + { nDuration = 24; } + string sResRef = ""; // ResRef of the creature to summon. + //Make metamagic check for extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + // Check for a Book of Summons + object oBook = GetItemPossessedBy(OBJECT_SELF, "bookofsummons"); + if ( oBook != OBJECT_INVALID ) + { + sResRef = GetLocalString(oBook, "summons2"); + } + + if ( sResRef == "" ) + { + // Either no Book of Summons, or variable not set. + // Go with the defaults. + if ( GetHasFeat(FEAT_ANIMAL_DOMAIN_POWER) ) + sResRef = "NW_S_WOLFDIRE"; + else + sResRef = "NW_S_BOARDIRE"; + } + + float fDuration; + if (nSummon > 0) + { fDuration = RoundsToSeconds(nDuration); } + else + { fDuration = HoursToSeconds(nDuration); } + + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_1); + effect eSummon = EffectSummonCreature(sResRef); + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), fDuration); +} diff --git a/src/_removed/nw_s0_summon3.nss b/src/_removed/nw_s0_summon3.nss new file mode 100644 index 0000000..b9881f8 --- /dev/null +++ b/src/_removed/nw_s0_summon3.nss @@ -0,0 +1,66 @@ +//:://///////////////////////////////////////////// +//:: Summon Monster III +//:: NW_S0_Summon3 +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Summons a dire wolf to fight for the character +*/ +//::////////////////////////////////////////////// +//:: Created By: Brenon Holmes +//:: Created On: Dec 10 , 2000 +//::////////////////////////////////////////////// +//:: Last Updated By: Preston Watamaniuk, On: April 12, 2001 +//:: VFX Pass By: Preston W, On: June 25, 2001 + +#include "wm_include" +#include "x2_inc_spellhook" +void main() +{ + if (WildMagicOverride()) { return; } + //Declare major variables + int nMetaMagic = GetMetaMagicFeat(); + object oMod = GetModule(); + int nLevel = GetCasterLevel(OBJECT_SELF); + int nSummon = GetLocalInt(oMod, "SUMMONTIME"); + int nDuration; + if (nSummon > 0) + { nDuration = ((nLevel * nSummon) + 10); } + else + { nDuration = 24; } + string sResRef = ""; // ResRef of the creature to summon. + //Make metamagic check for extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + // Check for a Book of Summons + object oBook = GetItemPossessedBy(OBJECT_SELF, "bookofsummons"); + if ( oBook != OBJECT_INVALID ) + { + sResRef = GetLocalString(oBook, "summons3"); + } + + if ( sResRef == "" ) + { + // Either no Book of Summons, or variable not set. + // Go with the defaults. + if ( GetHasFeat(FEAT_ANIMAL_DOMAIN_POWER) ) + sResRef = "wog_spidswrd001"; + else + sResRef = "NW_S_WOLFDIRE"; + } + + float fDuration; + if (nSummon > 0) + { fDuration = RoundsToSeconds(nDuration); } + else + { fDuration = HoursToSeconds(nDuration); } + + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_1); + effect eSummon = EffectSummonCreature(sResRef); + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), fDuration); +} + diff --git a/src/_removed/nw_s0_summon4.nss b/src/_removed/nw_s0_summon4.nss new file mode 100644 index 0000000..3b4c4ad --- /dev/null +++ b/src/_removed/nw_s0_summon4.nss @@ -0,0 +1,65 @@ +//:://///////////////////////////////////////////// +//:: Summon Monster IV +//:: NW_S0_Summon4 +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Summons a Sword Spider to fight for the character +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 12, 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 25, 2001 + +#include "wm_include" +#include "x2_inc_spellhook" +void main() +{ + if (WildMagicOverride()) { return; } + //Declare major variables + int nMetaMagic = GetMetaMagicFeat(); + object oMod = GetModule(); + int nLevel = GetCasterLevel(OBJECT_SELF); + int nSummon = GetLocalInt(oMod, "SUMMONTIME"); + int nDuration; + if (nSummon > 0) + { nDuration = ((nLevel * nSummon) + 10); } + else + { nDuration = 24; } + string sResRef = ""; // ResRef of the creature to summon. + //Make metamagic check for extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + // Check for a Book of Summons + object oBook = GetItemPossessedBy(OBJECT_SELF, "bookofsummons"); + if ( oBook != OBJECT_INVALID ) + { + sResRef = GetLocalString(oBook, "summons4"); + } + + if ( sResRef == "" ) + { + // Either no Book of Summons, or variable not set. + // Go with the defaults. + if ( GetHasFeat(FEAT_ANIMAL_DOMAIN_POWER) ) + sResRef = "wog_beardire001"; + else + sResRef = "wog_spidswrd001"; + } + + float fDuration; + if (nSummon > 0) + { fDuration = RoundsToSeconds(nDuration); } + else + { fDuration = HoursToSeconds(nDuration); } + + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_1); + effect eSummon = EffectSummonCreature(sResRef); + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), fDuration); +} + diff --git a/src/_removed/nw_s0_summon5.nss b/src/_removed/nw_s0_summon5.nss new file mode 100644 index 0000000..95fb296 --- /dev/null +++ b/src/_removed/nw_s0_summon5.nss @@ -0,0 +1,65 @@ +//:://///////////////////////////////////////////// +//:: Summon Monster V +//:: NW_S0_Summon5 +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Summons a dire bear to fight for the character +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 12 , 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 25, 2001 + +#include "wm_include" +#include "x2_inc_spellhook" +void main() +{ + if (WildMagicOverride()) { return; } + //Declare major variables + int nMetaMagic = GetMetaMagicFeat(); + object oMod = GetModule(); + int nLevel = GetCasterLevel(OBJECT_SELF); + int nSummon = GetLocalInt(oMod, "SUMMONTIME"); + int nDuration; + if (nSummon > 0) + { nDuration = ((nLevel * nSummon) + 10); } + else + { nDuration = 24; } + string sResRef = ""; // ResRef of the creature to summon. + //Make metamagic check for extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + // Check for a Book of Summons + object oBook = GetItemPossessedBy(OBJECT_SELF, "bookofsummons"); + if ( oBook != OBJECT_INVALID ) + { + sResRef = GetLocalString(oBook, "summons5"); + } + + if ( sResRef == "" ) + { + // Either no Book of Summons, or variable not set. + // Go with the defaults. + if ( GetHasFeat(FEAT_ANIMAL_DOMAIN_POWER) ) + sResRef = "WoG_DIRETIGER001"; + else + sResRef = "wog_beardire001"; + } + + float fDuration; + if (nSummon > 0) + { fDuration = RoundsToSeconds(nDuration); } + else + { fDuration = HoursToSeconds(nDuration); } + + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_1); + effect eSummon = EffectSummonCreature(sResRef); + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), fDuration); +} + diff --git a/src/_removed/nw_s0_summon6.nss b/src/_removed/nw_s0_summon6.nss new file mode 100644 index 0000000..63fc418 --- /dev/null +++ b/src/_removed/nw_s0_summon6.nss @@ -0,0 +1,77 @@ +//:://///////////////////////////////////////////// +//:: Summon Monster VI +//:: NW_S0_Summon6 +//::////////////////////////////////////////////// + +#include "wm_include" +#include "x2_inc_spellhook" +void main() +{ + if (WildMagicOverride()) { return; } + //Declare major variables + int nMetaMagic = GetMetaMagicFeat(); + object oMod = GetModule(); + int nLevel = GetCasterLevel(OBJECT_SELF); + int nSummon = GetLocalInt(oMod, "SUMMONTIME"); + int nDuration; + if (nSummon > 0) + { nDuration = ((nLevel * nSummon) + 10); } + else + { nDuration = 24; } + string sResRef = ""; // ResRef of the creature to summon. + //Make metamagic check for extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + // Check for a Book of Summons + object oBook = GetItemPossessedBy(OBJECT_SELF, "bookofsummons"); + if ( oBook != OBJECT_INVALID ) + { + sResRef = GetLocalString(oBook, "summons6"); + } + + if ( sResRef == "" ) + { + // Either no Book of Summons, or variable not set. + // Go with the defaults. + if (GetHasFeat(FEAT_ANIMAL_DOMAIN_POWER)) + { + int nRoll = d4(); + switch (nRoll) + { + case 1: + sResRef = "wog_s_airhuge001"; + break; + + case 2: + sResRef = "WoG_S_WATERHUGE"; + break; + + case 3: + sResRef = "WoG_S_EARTHHUGE"; + break; + + case 4: + sResRef = "WoG_S_FIREHUGE"; + break; + } + } + else + sResRef = "WoG_DIRETIGER001"; + } + + float fDuration; + if (nSummon > 0) + { fDuration = RoundsToSeconds(nDuration); } + else + { fDuration = HoursToSeconds(nDuration); } + + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_1); + effect eSummon = EffectSummonCreature(sResRef); + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), fDuration); +} + + diff --git a/src/_removed/nw_s0_summon7.nss b/src/_removed/nw_s0_summon7.nss new file mode 100644 index 0000000..3947b6e --- /dev/null +++ b/src/_removed/nw_s0_summon7.nss @@ -0,0 +1,94 @@ +//:://///////////////////////////////////////////// +//:: Summon Monster VII +//:: NW_S0_Summon7 +//::////////////////////////////////////////////// +#include "wm_include" +#include "x2_inc_spellhook" +void main() +{ + if (WildMagicOverride()) { return; } + //Declare major variables + int nMetaMagic = GetMetaMagicFeat(); + object oMod = GetModule(); + int nLevel = GetCasterLevel(OBJECT_SELF); + int nSummon = GetLocalInt(oMod, "SUMMONTIME"); + int nDuration; + if (nSummon > 0) + { nDuration = ((nLevel * nSummon) + 10); } + else + { nDuration = 24; } + string sResRef = ""; // ResRef of the creature to summon. + //Make metamagic check for extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + // Check for a Book of Summons + object oBook = GetItemPossessedBy(OBJECT_SELF, "bookofsummons"); + if ( oBook != OBJECT_INVALID ) + { + sResRef = GetLocalString(oBook, "summons7"); + } + + if ( sResRef == "" ) + { + // Either no Book of Summons, or variable not set. + // Go with the defaults. + int nRoll = d4(); + if(GetHasFeat(FEAT_ANIMAL_DOMAIN_POWER)) + { + switch (nRoll) + { + case 1: + sResRef = "wog_airgreat001"; + break; + + case 2: + sResRef = "wog_watergreat"; + break; + + case 3: + sResRef = "wog_earthgreat"; + break; + + case 4: + sResRef = "wog_firegreat001"; + break; + } + } + else + { + switch (nRoll) + { + case 1: + sResRef = "wog_s_airhuge001"; + break; + + case 2: + sResRef = "WoG_S_WATERHUGE"; + break; + + case 3: + sResRef = "WoG_S_EARTHHUGE"; + break; + + case 4: + sResRef = "WoG_S_FIREHUGE"; + break; + } + } + } + + float fDuration; + if (nSummon > 0) + { fDuration = RoundsToSeconds(nDuration); } + else + { fDuration = HoursToSeconds(nDuration); } + + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_1); + effect eSummon = EffectSummonCreature(sResRef); + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), fDuration); +} + diff --git a/src/_removed/nw_s0_summon8.nss b/src/_removed/nw_s0_summon8.nss new file mode 100644 index 0000000..086e7d8 --- /dev/null +++ b/src/_removed/nw_s0_summon8.nss @@ -0,0 +1,94 @@ +//:://///////////////////////////////////////////// +//:: Summon Monster VIII +//:: NW_S0_Summon8 +//::////////////////////////////////////////////// + +#include "wm_include" +#include "x2_inc_spellhook" +void main() +{ + if (WildMagicOverride()) { return; } + //Declare major variables + int nMetaMagic = GetMetaMagicFeat(); + object oMod = GetModule(); + int nLevel = GetCasterLevel(OBJECT_SELF); + int nSummon = GetLocalInt(oMod, "SUMMONTIME"); + int nDuration; + if (nSummon > 0) + { nDuration = ((nLevel * nSummon) + 10); } + else + { nDuration = 24; } + string sResRef = ""; // ResRef of the creature to summon. + //Make metamagic check for extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + // Check for a Book of Summons + object oBook = GetItemPossessedBy(OBJECT_SELF, "bookofsummons"); + if ( oBook != OBJECT_INVALID ) + { + sResRef = GetLocalString(oBook, "summons8"); + } + + if ( sResRef == "" ) + { + // Either no Book of Summons, or variable not set. + // Go with the defaults. + int nRoll = d4(); + if(GetHasFeat(FEAT_ANIMAL_DOMAIN_POWER)) + { + switch (nRoll) + { + case 1: + sResRef == "WoG_S_AIRELDER"; + break; + + case 2: + sResRef == "WoG_S_WATELDER"; + break; + + case 3: + sResRef == "WoG_S_EARTHELD"; + break; + + case 4: + sResRef == "WoG_S_FIREELDER"; + break; + + } + } + else + { + switch (nRoll) + { + case 1: + sResRef = "wog_airgreat001"; + break; + + case 2: + sResRef = "wog_watergreat"; + break; + + case 3: + sResRef = "wog_earthgreat"; + break; + + case 4: + sResRef = "wog_firegreat001"; + break; + } + } + } + float fDuration; + if (nSummon > 0) + { fDuration = RoundsToSeconds(nDuration); } + else + { fDuration = HoursToSeconds(nDuration); } + + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_1); + effect eSummon = EffectSummonCreature(sResRef); + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), fDuration); +} diff --git a/src/_removed/nw_s0_summon9.nss b/src/_removed/nw_s0_summon9.nss new file mode 100644 index 0000000..71e8d8b --- /dev/null +++ b/src/_removed/nw_s0_summon9.nss @@ -0,0 +1,95 @@ +//:://///////////////////////////////////////////// +//:: Summon Monster IX +//:: NW_S0_Summon9 +//::////////////////////////////////////////////// + +#include "wm_include" +#include "x2_inc_spellhook" +void main() +{ + if (WildMagicOverride()) { return; } + //Declare major variables + int nMetaMagic = GetMetaMagicFeat(); + object oMod = GetModule(); + int nLevel = GetCasterLevel(OBJECT_SELF); + int nSummon = GetLocalInt(oMod, "SUMMONTIME"); + int nDuration; + if (nSummon > 0) + { nDuration = ((nLevel * nSummon) + 10); } + else + { nDuration = 24; } + string sResRef = ""; // ResRef of the creature to summon. + //Make metamagic check for extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + // Check for a Book of Summons + object oBook = GetItemPossessedBy(OBJECT_SELF, "bookofsummons"); + if ( oBook != OBJECT_INVALID ) + { + sResRef = GetLocalString(oBook, "summons9"); + } + + if ( sResRef == "" ) + { + // Either no Book of Summons, or variable not set. + // Go with the defaults. + int nRoll = d4(); + if(GetHasFeat(FEAT_ANIMAL_DOMAIN_POWER)) + { + switch (nRoll) + { + case 1: + sResRef == "wog_s_airelder01"; + break; + + case 2: + sResRef == "wog_s_waterpr001"; + break; + + case 3: + sResRef == "WoG_S_EARTHPRINCE"; + break; + + case 4: + sResRef == "wog_s_fireprn001"; + break; + } + } + else + { + switch (nRoll) + { + case 1: + sResRef == "WoG_S_AIRELDER"; + break; + + case 2: + sResRef == "WoG_S_WATELDER"; + break; + + case 3: + sResRef == "WoG_S_EARTHELD"; + break; + + case 4: + sResRef == "WoG_S_FIREELDER"; + break; + + } + } + float fDuration; + if (nSummon > 0) + { fDuration = RoundsToSeconds(nDuration); } + else + { fDuration = HoursToSeconds(nDuration); } + + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_1); + effect eSummon = EffectSummonCreature(sResRef); + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), fDuration); + } +} + diff --git a/src/_removed/nw_s0_summshad.nss b/src/_removed/nw_s0_summshad.nss new file mode 100644 index 0000000..2a0687f --- /dev/null +++ b/src/_removed/nw_s0_summshad.nss @@ -0,0 +1,82 @@ +// HCR v3.2.0 - +//:://////////////////////////////////////////////////////////////////////////// +//:: FileName: NW_S0_SummShad +//:://////////////////////////////////////////////////////////////////////////// +/* + Spell calls a powerful ally from the shadow plane to battle for the wizard. +*/ +//:://////////////////////////////////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Oct 26, 2001 +//:://////////////////////////////////////////////////////////////////////////// +#include "x2_inc_spellhook" +//:://////////////////////////////////////////////////////////////////////////// +void HCR_RemoveSummonMonster(object oAC) +{ + DestroyObject(oAC); + string sMsg = "The shadow returns to its home plane, it's "; + sMsg += "far too powerful for you to retain control."; + SendMessageToPC(OBJECT_SELF, sMsg); +} +//:://////////////////////////////////////////////////////////////////////////// +void HCR_CheckSummonStrength() +{ + object oAC = GetAssociate(ASSOCIATE_TYPE_SUMMONED); + if (GetIsObjectValid(oAC)) + { + int nAHD = GetHitDice(oAC); + int nMCL = GetCasterLevel(OBJECT_SELF); + if ((nAHD > (nMCL+4))) + { HCR_RemoveSummonMonster(oAC); } + else if (nAHD > nMCL) + { + float fDelay = IntToFloat(240-((nAHD-nMCL)*60)); + DelayCommand(fDelay, HCR_RemoveSummonMonster(oAC)); + } + } +} +//:://////////////////////////////////////////////////////////////////////////// +void main() +{ + // If code within the PreSpellCastHook reports FALSE, do not run this spell. + if (!X2PreSpellCastCode()) { return; } + + // Declare major variables. + int nMetaMagic = GetMetaMagicFeat(); + int nLvl = GetCasterLevel(OBJECT_SELF); + int nDur = nLvl; + + // Check for Meta-Magic extend. + if (nMetaMagic == METAMAGIC_EXTEND) + { nDur = (nDur*2); } + + // Set the summoned undead to the appropriate template based on the caster level. + effect eSum; + if (nLvl <= 7) + { eSum = EffectSummonCreature("wogsumshadow002", VFX_FNF_SUMMON_UNDEAD); } + else if ((nLvl >= 8) && (nLvl <= 10)) + { eSum = EffectSummonCreature("wogsumshmast001", VFX_FNF_SUMMON_UNDEAD); } + else if ((nLvl >= 11) && (nLvl <= 14)) + { eSum = EffectSummonCreature("wogsumshfiend001", VFX_FNF_SUMMON_UNDEAD); } + else if ((nLvl >= 15)) + { eSum = EffectSummonCreature("wogsumshlord007", VFX_FNF_SUMMON_UNDEAD); } + + // Apply VFX impact and summon effect. + //effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); + location lLoc = GetSpellTargetLocation(); + float fDur = HoursToSeconds(nDur); + //ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, lLoc); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSum, lLoc, fDur); + + // If real familiars are used, compare the hitdice of the summoned creature to + // the caster of this spell. If the hitdie is too high, remove the summoned + // creature from service. Note: This only effects PC's, not NPC's or DM's. + if (GetLocalInt(GetModule(), "REALFAM") == TRUE) + { + if (GetIsPC(OBJECT_SELF) && + !GetIsDM(OBJECT_SELF) && + !GetIsDMPossessed(OBJECT_SELF)) + { HCR_CheckSummonStrength(); } + } +} +//:://////////////////////////////////////////////////////////////////////////// diff --git a/src/_removed/nw_s0_summshad02.nss b/src/_removed/nw_s0_summshad02.nss new file mode 100644 index 0000000..2410a76 --- /dev/null +++ b/src/_removed/nw_s0_summshad02.nss @@ -0,0 +1,72 @@ +// HCR v3.2.0 - +//:://////////////////////////////////////////////////////////////////////////// +//:: FileName: NW_S0_SummShad02 +//:://////////////////////////////////////////////////////////////////////////// +/* + Spell calls a powerful ally from the shadow plane to battle for the wizard. +*/ +//:://////////////////////////////////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Oct 26, 2001 +//:://////////////////////////////////////////////////////////////////////////// +#include "x2_inc_spellhook" +//:://////////////////////////////////////////////////////////////////////////// +void HCR_RemoveSummonMonster(object oAC) +{ + DestroyObject(oAC); + string sMsg = "The shadow returns to its home plane, it's "; + sMsg += "far too powerful for you to retain control."; + SendMessageToPC(OBJECT_SELF, sMsg); +} +//:://////////////////////////////////////////////////////////////////////////// +void HCR_CheckSummonStrength() +{ + object oAC = GetAssociate(ASSOCIATE_TYPE_SUMMONED); + if (GetIsObjectValid(oAC)) + { + int nAHD = GetHitDice(oAC); + int nMCL = GetCasterLevel(OBJECT_SELF); + if ((nAHD > (nMCL+4))) + { HCR_RemoveSummonMonster(oAC); } + else if (nAHD > nMCL) + { + float fDelay = IntToFloat(240-((nAHD-nMCL)*60)); + DelayCommand(fDelay, HCR_RemoveSummonMonster(oAC)); + } + } +} +//:://////////////////////////////////////////////////////////////////////////// +void main() +{ + // If code within the PreSpellCastHook reports FALSE, do not run this spell. + if (!X2PreSpellCastCode()) { return; } + + // Set the summoned undead to the appropriate template based on the caster level. + effect eSum; + int nLvl = GetLevelByClass(CLASS_TYPE_CLERIC); + if (nLvl <= 7) + { eSum = EffectSummonCreature("wogsumshadow002", VFX_FNF_SUMMON_UNDEAD); } + else if ((nLvl >= 8) && (nLvl <= 10)) + { eSum = EffectSummonCreature("wogsumshmast001", VFX_FNF_SUMMON_UNDEAD); } + else if ((nLvl >= 11) && (nLvl <= 14)) + { eSum = EffectSummonCreature("wogsumshfiend001", VFX_FNF_SUMMON_UNDEAD); } + else if ((nLvl >= 15)) + { eSum = EffectSummonCreature("wogsumshlord007", VFX_FNF_SUMMON_UNDEAD); } + + // Apply VFX impact and summon effect. + location lLoc = GetSpellTargetLocation(); + float fDur = HoursToSeconds(24); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSum, lLoc, fDur); + + // If real familiars are used, compare the hitdice of the summoned creature to + // the caster of this spell. If the hitdie is too high, remove the summoned + // creature from service. Note: This only effects PC's, not NPC's or DM's. + if (GetLocalInt(GetModule(), "REALFAM") == TRUE) + { + if (GetIsPC(OBJECT_SELF) && + !GetIsDM(OBJECT_SELF) && + !GetIsDMPossessed(OBJECT_SELF)) + { HCR_CheckSummonStrength(); } + } +} +//:://////////////////////////////////////////////////////////////////////////// diff --git a/src/_removed/nw_s0_sunbeam.nss b/src/_removed/nw_s0_sunbeam.nss new file mode 100644 index 0000000..b1d77e6 --- /dev/null +++ b/src/_removed/nw_s0_sunbeam.nss @@ -0,0 +1,123 @@ + +//:://///////////////////////////////////////////// +//:: Sunbeam +//:: s_Sunbeam.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +//:: All creatures in the beam are struck blind and suffer 3d6 points of damage. +//:: (A successful Reflex save negates the blindness and reduces the damage by +//:: half.) +//:: Creatures to whom sunlight is harmful or unnatural should suffer double +//:: damage, but there is no standard way to flag a creature as such. +//:: +//:: Undead creatures caught within the ray are dealt 1d6 points of damage per +//:: caster level (maximum 20d6), or half damage if a Reflex save is successful. +//:: In addition, the ray should result in the total destruction of undead +//:: creatures specifically affected by sunlight if they fail their saves, but +//:: this was never implemented not mentioned in the in-game description. +//::////////////////////////////////////////////// +//:: Created By: Keith Soleski +//:: Created On: Feb 22, 2001 +//::////////////////////////////////////////////// +//:: Modified By: Keith Soleski, On: March 21, 2001 +//:: VFX Pass By: Preston W, On: June 25, 2001 +//::////////////////////////////////////////////// +//:: Modified By: The Krit +//:: Modified On: September 1, 2008 +//::////////////////////////////////////////////// + + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + + +void main() +{ + // Spellcast hook code + // Added 2003-06-20 by Georg + // If you want to make changes to all spells, + // check x2_inc_spellhook.nss to find out more. + if ( !X2PreSpellCastCode() ) + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell. + return; + // End of spellcast hook. + + // Effect-related variables + effect eCreatureVFX = EffectVisualEffect(VFX_IMP_SUNSTRIKE); + effect eAreaVFX = EffectVisualEffect(VFX_FNF_SUNBEAM); + effect eDamage; // Set for each target. + effect eBlind = EffectLinkEffects(EffectBlindness(), + EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE)); + float fBlindDuration = RoundsToSeconds(3); + float fDelay; // Set for each target. + + // Casting-related variables. + location lTarget = GetSpellTargetLocation(); + int nDice; + int nDamage; + int nOrigDamage; + int nMetaMagic = GetMetaMagicFeat(); + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + // Caster level is capped at 20. + if ( nCasterLevel > 20 ) + nCasterLevel = 20; + // Just in case... undead should never take less damage than others. --TK + else if ( nCasterLevel < 3 ) + nCasterLevel = 3; + + // Apply the grand visual effect. + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eAreaVFX, lTarget); + + // Cycle through the targets in the spell area. + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lTarget); + while ( GetIsObjectValid(oTarget) ) + { + // Make a faction check + if ( spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF) ) + { + fDelay = GetRandomDelay(1.0, 2.0); + // Fire the "spell cast at" event for the target. + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_SUNBEAM)); + // Make a SR check. + if ( !MyResistSpell(OBJECT_SELF, oTarget, 1.0) ) + { + // Check if the target is undead. + if ( GetRacialType(oTarget) == RACIAL_TYPE_UNDEAD ) + // Full damage. + nDice = nCasterLevel; + else + // Limited damage. + nDice = 3; + + // Roll the damage (with metamagic checks). + if ( nMetaMagic & METAMAGIC_MAXIMIZE ) + nOrigDamage = 6 * nDice; + else + nOrigDamage = d6(nDice); + // Empower for +50%? + if ( nMetaMagic & METAMAGIC_EMPOWER ) + nOrigDamage += nOrigDamage / 2; + + // Get the adjusted damage due to reflex save and (improved) evasion. + nDamage = GetReflexAdjustedDamage(nOrigDamage, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_DIVINE); + + // If the reflex save failed... + if ( nDamage == nOrigDamage || + ( nDamage > 0 && GetHasFeat(FEAT_IMPROVED_EVASION, oTarget) ) ) + // ...apply blindness. + DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBlind, oTarget, fBlindDuration)); + + // Apply the damage. + if( nDamage > 0 ) + { + eDamage = EffectDamage(nDamage, DAMAGE_TYPE_DIVINE); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eCreatureVFX, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget)); + } + }//if ( not resist spell ) + }//if ( is target ) + + // Get the next target in the spell area. + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lTarget); + }//while +} diff --git a/src/_removed/nw_s0_tenstrans.nss b/src/_removed/nw_s0_tenstrans.nss new file mode 100644 index 0000000..23d95e9 --- /dev/null +++ b/src/_removed/nw_s0_tenstrans.nss @@ -0,0 +1,169 @@ +//:://///////////////////////////////////////////// +//:: Tensor's Transformation +//:: NW_S0_TensTrans.nss +//:: Originally hacked all to hell by: BitRaiser +//:: Additional refinements by: Alex Moskwa +//::////////////////////////////////////////////// +/* +PnP description: +Transmutation +Level: Sor/Wiz 6 +Components: V, S, M +Casting Time: 1 action +Range: Personal +Target: The character +Duration: 1 round/level +The character gains 1d6 temporary hit points per caster level, +a +4 natural armor bonus to AC, a +2d4 Strength enhancement bonus, +a +2d4 Dexterity enhancement bonus, +a +1 base attack bonus per two caster levels +(which may give the character an extra attack), +a +5 competence bonus on Fortitude saves, +and proficiency with all simple and martial weapons. +The character attacks opponents with melee or ranged weapons if the character +can, even resorting to unarmed attacks if that’s all the character can do. +The character can’t cast spells, even from magic items. +Material Component: A potion of Strength, +which the character drinks (and whose effects are subsumed by the spell effects). +*/ + +#include "x2_inc_spellhook" +#include "x2_inc_itemprop" +#include "x2_inc_shifter" + +//The following function tells you how many attacks you have given a Base Attack Bonus Value. +int Attacks (int BAB) +{ + if (BAB%5) + { + return BAB/5 + 1; + + } + else { + return BAB/5;; + } +} + + +void main() +{ + + + //---------------------------------------------------------------------------- + // GZ, Nov 3, 2003 + // There is a serious problems with creatures turning into unstoppable killer + // machines when affected by tensors transformation. NPC AI can't handle that + // spell anyway, so I added this code to disable the use of Tensors by any + // NPC. + //---------------------------------------------------------------------------- + if (!GetIsPC(OBJECT_SELF)) + { + WriteTimestampedLogEntry(GetName(OBJECT_SELF) + "[" + GetTag (OBJECT_SELF) +"] tried to cast Tensors Transformation. Bad! Remove that spell from the creature"); + return; + } + + /* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + */ + + if (!X2PreSpellCastCode()) + { + return; + } + + // End of Spell Cast Hook + + + //Declare major variables + int nLevel = GetCasterLevel(OBJECT_SELF); + int nHP, nCnt, nDuration, nSTR, nDEX; + nDuration = GetCasterLevel(OBJECT_SELF); + nSTR = d4(2); + nDEX = d4(2); + //Determine bonus HP + nHP = d6(nLevel); + int nMeta = GetMetaMagicFeat(); + //Metamagic + if(nMeta == METAMAGIC_MAXIMIZE) + { + nHP = nLevel * 6; + nSTR = 8; + nDEX = 8; + } + else if(nMeta == METAMAGIC_EMPOWER) + { + nHP = nHP + (nHP/2); + nSTR += nSTR/2; + nDEX += nDEX/2; + } + else if(nMeta == METAMAGIC_EXTEND) + { + nDuration *= 2; + } + + //Add temporary proficiency feats to the currently equipped armor for Transformation + itemproperty ipAdd1 = ItemPropertyBonusFeat(IP_CONST_FEAT_WEAPON_PROF_SIMPLE); + itemproperty ipAdd2 = ItemPropertyBonusFeat(IP_CONST_FEAT_WEAPON_PROF_MARTIAL); + object oItem = GetItemInSlot(INVENTORY_SLOT_CHEST, OBJECT_SELF); + if (GetIsObjectValid(oItem)) { + IPSafeAddItemProperty(oItem, ipAdd1, RoundsToSeconds(nDuration)); + IPSafeAddItemProperty(oItem, ipAdd2, RoundsToSeconds(nDuration)); + } + + //The following is the unfortunately rather involved logic it takes to add the proper number of attacks for the spell. + int oBAB, nBAB, AddAttacks, n, cLevel; + oBAB = GetBaseAttackBonus(OBJECT_SELF); + cLevel=0; + //Determine if the character is epic and adjust oBAB accordingly to determine # of attacks. + for (n = 1;n <= 3; n++) { + cLevel += GetLevelByPosition(n,OBJECT_SELF); + } + if (cLevel > 20) { + oBAB -= ((cLevel - 19)/2); + } + //Figure out your new spell modified BAB and derive how many extra attacks it should give you. + nBAB = oBAB + (nLevel/2); + if (nBAB>20) + AddAttacks = 4 - Attacks(oBAB); + else + AddAttacks = Attacks(nBAB) - Attacks(oBAB); + if (Attacks(oBAB)>=4) { + AddAttacks=0; + } + + + + //Declare effects + effect eSpellFail = EffectSpellFailure(100, SPELL_SCHOOL_GENERAL); + effect eAttack = EffectAttackIncrease(nLevel/2); + effect eSave = EffectSavingThrowIncrease(SAVING_THROW_FORT, 5); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); + effect eSwing = EffectModifyAttacks(AddAttacks); + effect eStr = EffectAbilityIncrease(ABILITY_STRENGTH, nSTR); + effect eDex = EffectAbilityIncrease(ABILITY_DEXTERITY, nDEX); + effect eAC = EffectACIncrease(4,AC_NATURAL_BONUS); + effect eDis = EffectSkillIncrease(SKILL_DISCIPLINE, (nLevel + 2)); + //effect ePoly = EffectPolymorph(POLYMORPH_TYPE_HEURODIS); + //Link effects + effect eLink = EffectLinkEffects(eAttack, eSave); + eLink = EffectLinkEffects(eLink, eDis); + eLink = EffectLinkEffects(eLink, eDex); + eLink = EffectLinkEffects(eLink, eAC); + eLink = EffectLinkEffects(eLink, eStr); + eLink = EffectLinkEffects(eLink, eDur); + if (AddAttacks > 0) + eLink = EffectLinkEffects(eLink, eSwing); + eLink = EffectLinkEffects(eLink, eSpellFail); + //eLink = EffectLinkEffects(eLink, ePoly); + effect eHP = EffectTemporaryHitpoints(nHP); + effect eVis = EffectVisualEffect(VFX_IMP_SUPER_HEROISM); + //Signal Spell Event + SignalEvent(OBJECT_SELF, EventSpellCastAt(OBJECT_SELF, SPELL_TENSERS_TRANSFORMATION, FALSE)); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, OBJECT_SELF); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eHP, OBJECT_SELF, RoundsToSeconds(nDuration)); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, OBJECT_SELF, RoundsToSeconds(nDuration)); + +} diff --git a/src/_removed/nw_s0_timestop.nss b/src/_removed/nw_s0_timestop.nss new file mode 100644 index 0000000..d8b0956 --- /dev/null +++ b/src/_removed/nw_s0_timestop.nss @@ -0,0 +1,83 @@ +//:://///////////////////////////////////////////// +//:: Time Stop +//:: NW_S0_TimeStop.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + All persons in the Area are frozen in time + except the caster. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Jan 7, 2002 +//::////////////////////////////////////////////// + +//#include "wm_include" +//void main() +//{ +// if (WildMagicOverride()) { return; } + //Declare major variables +// location lTarget = GetSpellTargetLocation(); +// effect eVis = EffectVisualEffect(VFX_FNF_TIME_STOP); +// effect eTime = EffectTimeStop(); +// int nRoll = 1 + d4(); + + //Fire cast spell at event for the specified target +// SignalEvent(OBJECT_SELF, EventSpellCastAt(OBJECT_SELF, SPELL_TIME_STOP, FALSE)); + + //Apply the VFX impact and effects +// DelayCommand(0.75, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eTime, OBJECT_SELF, 9.0)); +// ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, lTarget); +//} + +//GhostNWN - AoE Timestop script +#include "x2_inc_spellhook" + +void main() +{ +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run + //this spell + return; + } +// End of Spell Cast Hook + + //Declare major variables + object oArea = GetArea(OBJECT_SELF); + object oLoop = GetFirstObjectInArea(oArea); + location lTarget = GetLocation(OBJECT_SELF); + effect eVis = EffectVisualEffect(VFX_FNF_TIME_STOP); + effect eVis2 = +SupernaturalEffect(EffectVisualEffect(VFX_DUR_FREEZE_ANIMATION)); + effect eHold = SupernaturalEffect(EffectCutsceneParalyze()); + eHold = EffectLinkEffects(eVis2, eHold); + + while (GetIsObjectValid(oLoop)) + { + if (oLoop != OBJECT_SELF) + { + if (GetObjectType(oLoop) == OBJECT_TYPE_CREATURE) + { + DelayCommand(0.75, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, +eHold, oLoop, 12.0)); + } + } + oLoop = GetNextObjectInArea(oArea); + } + + //Fire cast spell at event for the specified target + SignalEvent(OBJECT_SELF, EventSpellCastAt(OBJECT_SELF, SPELL_TIME_STOP, +FALSE)); + //Apply the VFX impact and effects + DelayCommand(0.75, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, +lTarget)); +} + diff --git a/src/_removed/nw_s0_truesee.nss b/src/_removed/nw_s0_truesee.nss new file mode 100644 index 0000000..100636b --- /dev/null +++ b/src/_removed/nw_s0_truesee.nss @@ -0,0 +1,72 @@ +//:://///////////////////////////////////////////// +//:: True Seeing +//:: NW_S0_TrueSee.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + The creature can seen all invisible, sanctuared, + or hidden opponents. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: [date] +//::////////////////////////////////////////////// + +#include "x2_inc_spellhook" + +// modifed by DM Nocturne to not be 100% reliable against stealth: +// - see invisibility +// - ultravision +// - spot skill bonus +20 + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + int casterLevel = GetCasterLevel(OBJECT_SELF); + + object oTarget = GetSpellTargetObject(); + effect eVis = EffectVisualEffect(VFX_DUR_MAGICAL_SIGHT); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); + + //effect eSight = EffectTrueSeeing(); + //effect eLink = EffectLinkEffects(eVis, eSight); + effect seeInvis = EffectSeeInvisible(); + effect ultraVis = EffectUltravision(); + effect spotBonus = EffectSkillIncrease(SKILL_SPOT, 20); + effect eLink = EffectLinkEffects(eVis, seeInvis); + eLink = EffectLinkEffects(eLink, ultraVis); + eLink = EffectLinkEffects(eLink, spotBonus); + + eLink = EffectLinkEffects(eLink, eDur); + + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_TRUE_SEEING, FALSE)); + int nDuration = GetCasterLevel(OBJECT_SELF); + int nMetaMagic = GetMetaMagicFeat(); + //Enter Metamagic conditions + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + //Apply the VFX impact and effects + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, TurnsToSeconds(nDuration)); +} + diff --git a/src/_removed/nw_s0_weird.nss b/src/_removed/nw_s0_weird.nss new file mode 100644 index 0000000..302b978 --- /dev/null +++ b/src/_removed/nw_s0_weird.nss @@ -0,0 +1,129 @@ +//:://///////////////////////////////////////////// +//:: Weird +//:: NW_S0_Weird +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + All enemies in LOS of the spell must make 2 saves or die. + Even IF the fortitude save is succesful, they will still take + 3d6 damage. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: DEc 14 , 2001 +//::////////////////////////////////////////////// +//:: Last Updated By: Preston Watamaniuk, On: April 10, 2001 +//:: VFX Pass By: Preston W, On: June 27, 2001 + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oTarget; + effect eDam; + effect eVis = EffectVisualEffect(VFX_IMP_SONIC); + effect eVis2 = EffectVisualEffect(VFX_IMP_DEATH); + effect eWeird = EffectVisualEffect(VFX_FNF_WEIRD); + effect eAbyss = EffectVisualEffect(VFX_DUR_ANTI_LIGHT_10); + int nCasterLvl = GetCasterLevel(OBJECT_SELF); + int nMetaMagic = GetMetaMagicFeat(); + int nDamage; + float fDelay; + + //Apply the FNF VFX impact + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eWeird, GetSpellTargetLocation()); + //Get the first target in the spell area + oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetSpellTargetLocation(), TRUE); + while (GetIsObjectValid(oTarget)) + { + //Make a faction check + if (spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, OBJECT_SELF)) + { + fDelay = GetRandomDelay(3.0, 4.0); + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_WEIRD)); + //Make an SR Check + if(!MyResistSpell(OBJECT_SELF, oTarget, fDelay)) + { + if ( !GetIsImmune(oTarget, IMMUNITY_TYPE_MIND_SPELLS,OBJECT_SELF) && + !GetIsImmune(oTarget, IMMUNITY_TYPE_FEAR,OBJECT_SELF)) + { + if(GetHitDice(oTarget) >= 4) + { + //Make a Will save against mind-affecting + if(!MySavingThrow(SAVING_THROW_WILL, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_MIND_SPELLS, OBJECT_SELF, fDelay)) + { + //Make a fortitude save against death + if(MySavingThrow(SAVING_THROW_FORT, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_DEATH, OBJECT_SELF, fDelay)) + { + // * I made my saving throw but I still have to take the 3d6 damage + + //Roll damage + nDamage = d6(10); + //Make metamagic check + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 60; + } + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = FloatToInt( IntToFloat(nDamage) * 1.5 ); + } + //Set damage effect + eDam = EffectDamage(nDamage, DAMAGE_TYPE_MAGICAL); + //Apply VFX Impact and damage effect + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + } + else + { + // * I failed BOTH saving throws. Now I die. + + + //Apply VFX impact and death effect + //DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis2, oTarget)); + effect eDeath = EffectDeath(); + // Need to make this supernatural, so that it ignores death immunity. + eDeath = SupernaturalEffect( eDeath ); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDeath, oTarget)); + } + } // Will save + } + else + { + // * I have less than 4HD, I die. + + //Apply VFX impact and death effect + //DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis2, oTarget)); + effect eDeath = EffectDeath(); + // Need to make this supernatural, so that it ignores death immunity. + eDeath = SupernaturalEffect( eDeath ); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDeath, oTarget)); + } + } + } + } + //Get next target in spell area + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetSpellTargetLocation(), TRUE); + } +} diff --git a/src/_removed/nw_s2_bardsong.nss b/src/_removed/nw_s2_bardsong.nss new file mode 100644 index 0000000..2fb4eee --- /dev/null +++ b/src/_removed/nw_s2_bardsong.nss @@ -0,0 +1,427 @@ +//:://///////////////////////////////////////////// +//:: Bard Song +//:: NW_S2_BardSong +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + This spells applies bonuses to all of the + bard's allies within 30ft for a set duration of + 10 rounds. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Feb 25, 2002 +//::////////////////////////////////////////////// +//:: Last Updated By: Georg Zoeller Oct 1, 2003 +/* +bugfix by Kovi 2002.07.30 +- loosing temporary hp resulted in loosing the other bonuses +*/ + +#include "tk_song_inc" // -- TK +#include "x0_i0_spells" + +void main() +{ + if (GetHasEffect(EFFECT_TYPE_SILENCE,OBJECT_SELF)) + { + FloatingTextStrRefOnCreature(85764,OBJECT_SELF); // not useable when silenced + return; + } + string sTag = GetTag(OBJECT_SELF); + + if (sTag == "x0_hen_dee" || sTag == "x2_hen_deekin") + { + // * Deekin has a chance of singing a doom song + // * same effect, better tune + if (Random(100) + 1 > 80) + { + // the Xp2 Deekin knows more than one doom song + if (d3() ==1 && sTag == "x2_hen_deekin") + { + DelayCommand(0.0, PlaySound("vs_nx2deekM_050")); + } + else + { + DelayCommand(0.0, PlaySound("vs_nx0deekM_074")); + DelayCommand(5.0, PlaySound("vs_nx0deekM_074")); + } + } + } + + + //Declare major variables + int nLevel = GetLevelByClass(CLASS_TYPE_BARD); + int nRanks = GetSkillRank(SKILL_PERFORM); + int nChr = GetAbilityModifier(ABILITY_CHARISMA); + int nPerform = nRanks; + int nDuration = 10; //+ nChr; + + effect eAttack; + effect eDamage; + effect eWill; + effect eFort; + effect eReflex; + effect eHP; + effect eAC; + effect eSkill; + + int nAttack; + int nDamage; + int nWill; + int nFort; + int nReflex; + int nHP; + int nAC; + int nSkill; + //Check to see if the caster has Lasting Impression and increase duration. + if(GetHasFeat(870)) + { + nDuration *= 10; + } + + // lingering song + if(GetHasFeat(424)) // lingering song + { + nDuration += 5; + } + + //SpeakString("Level: " + IntToString(nLevel) + " Ranks: " + IntToString(nRanks)); + + if(nPerform >= 100 && nLevel >= 30) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 48; + nAC = 7; + nSkill = 19; + } + else if(nPerform >= 95 && nLevel >= 29) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 46; + nAC = 6; + nSkill = 18; + } + else if(nPerform >= 90 && nLevel >= 28) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 44; + nAC = 6; + nSkill = 17; + } + else if(nPerform >= 85 && nLevel >= 27) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 42; + nAC = 6; + nSkill = 16; + } + else if(nPerform >= 80 && nLevel >= 26) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 40; + nAC = 6; + nSkill = 15; + } + else if(nPerform >= 75 && nLevel >= 25) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 38; + nAC = 6; + nSkill = 14; + } + else if(nPerform >= 70 && nLevel >= 24) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 36; + nAC = 5; + nSkill = 13; + } + else if(nPerform >= 65 && nLevel >= 23) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 34; + nAC = 5; + nSkill = 12; + } + else if(nPerform >= 60 && nLevel >= 22) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 32; + nAC = 5; + nSkill = 11; + } + else if(nPerform >= 55 && nLevel >= 21) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 30; + nAC = 5; + nSkill = 9; + } + else if(nPerform >= 50 && nLevel >= 20) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 28; + nAC = 5; + nSkill = 8; + } + else if(nPerform >= 45 && nLevel >= 19) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 26; + nAC = 5; + nSkill = 7; + } + else if(nPerform >= 40 && nLevel >= 18) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 24; + nAC = 5; + nSkill = 6; + } + else if(nPerform >= 35 && nLevel >= 17) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 22; + nAC = 5; + nSkill = 5; + } + else if(nPerform >= 30 && nLevel >= 16) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 20; + nAC = 5; + nSkill = 4; + } + else if(nPerform >= 24 && nLevel >= 15) + { + nAttack = 2; + nDamage = 3; + nWill = 2; + nFort = 2; + nReflex = 2; + nHP = 16; + nAC = 4; + nSkill = 3; + } + else if(nPerform >= 21 && nLevel >= 14) + { + nAttack = 2; + nDamage = 3; + nWill = 1; + nFort = 1; + nReflex = 1; + nHP = 16; + nAC = 3; + nSkill = 2; + } + else if(nPerform >= 18 && nLevel >= 11) + { + nAttack = 2; + nDamage = 2; + nWill = 1; + nFort = 1; + nReflex = 1; + nHP = 8; + nAC = 2; + nSkill = 2; + } + else if(nPerform >= 15 && nLevel >= 8) + { + nAttack = 2; + nDamage = 2; + nWill = 1; + nFort = 1; + nReflex = 1; + nHP = 8; + nAC = 0; + nSkill = 1; + } + else if(nPerform >= 12 && nLevel >= 6) + { + nAttack = 1; + nDamage = 2; + nWill = 1; + nFort = 1; + nReflex = 1; + nHP = 0; + nAC = 0; + nSkill = 1; + } + else if(nPerform >= 9 && nLevel >= 3) + { + nAttack = 1; + nDamage = 2; + nWill = 1; + nFort = 1; + nReflex = 0; + nHP = 0; + nAC = 0; + nSkill = 0; + } + else if(nPerform >= 6 && nLevel >= 2) + { + nAttack = 1; + nDamage = 1; + nWill = 1; + nFort = 0; + nReflex = 0; + nHP = 0; + nAC = 0; + nSkill = 0; + } + else if(nPerform >= 3 && nLevel >= 1) + { + nAttack = 1; + nDamage = 1; + nWill = 0; + nFort = 0; + nReflex = 0; + nHP = 0; + nAC = 0; + nSkill = 0; + } + effect eVis = EffectVisualEffect(VFX_DUR_BARD_SONG); + + eAttack = EffectAttackIncrease(nAttack); + eDamage = EffectDamageIncrease(nDamage, DAMAGE_TYPE_BLUDGEONING); + effect eLink = EffectLinkEffects(eAttack, eDamage); + + if(nWill > 0) + { + eWill = EffectSavingThrowIncrease(SAVING_THROW_WILL, nWill); + eLink = EffectLinkEffects(eLink, eWill); + } + if(nFort > 0) + { + eFort = EffectSavingThrowIncrease(SAVING_THROW_FORT, nFort); + eLink = EffectLinkEffects(eLink, eFort); + } + if(nReflex > 0) + { + eReflex = EffectSavingThrowIncrease(SAVING_THROW_REFLEX, nReflex); + eLink = EffectLinkEffects(eLink, eReflex); + } + if(nHP > 0) + { + //SpeakString("HP Bonus " + IntToString(nHP)); + eHP = EffectTemporaryHitpoints(nHP); +// eLink = EffectLinkEffects(eLink, eHP); + } + if(nAC > 0) + { + eAC = EffectACIncrease(nAC, AC_DODGE_BONUS); + eLink = EffectLinkEffects(eLink, eAC); + } + if(nSkill > 0) + { + eSkill = EffectSkillIncrease(SKILL_ALL_SKILLS, nSkill); + eLink = EffectLinkEffects(eLink, eSkill); + } + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); + eLink = EffectLinkEffects(eLink, eDur); + + effect eImpact = EffectVisualEffect(VFX_IMP_HEAD_SONIC); + effect eFNF = EffectVisualEffect(VFX_FNF_LOS_NORMAL_30); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eFNF, GetLocation(OBJECT_SELF)); + + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(OBJECT_SELF)); + + eHP = ExtraordinaryEffect(eHP); + eLink = ExtraordinaryEffect(eLink); + + while(GetIsObjectValid(oTarget)) + { + if(!GetHasFeatEffect(FEAT_BARD_SONGS, oTarget) && !GetHasSpellEffect(GetSpellId(),oTarget)) + { + // * GZ Oct 2003: If we are silenced, we can not benefit from bard song + if (!GetHasEffect(EFFECT_TYPE_SILENCE,oTarget) && !GetHasEffect(EFFECT_TYPE_DEAF,oTarget)) + { + if(oTarget == OBJECT_SELF) + { + effect eLinkBard = EffectLinkEffects(eLink, eVis); + eLinkBard = ExtraordinaryEffect(eLinkBard); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLinkBard, oTarget, RoundsToSeconds(nDuration)); + if (nHP > 0) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eHP, oTarget, RoundsToSeconds(nDuration)); + } + } + else if(GetIsFriend(oTarget)) + { + ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oTarget); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration)); + if (nHP > 0) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eHP, oTarget, RoundsToSeconds(nDuration)); + } + } + } + } + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(OBJECT_SELF)); + } + + // Sing lyrics, if any. -- TK + StartLyrics(nDuration); +} + diff --git a/src/_removed/nw_s2_familiar.nss b/src/_removed/nw_s2_familiar.nss new file mode 100644 index 0000000..4c27e12 --- /dev/null +++ b/src/_removed/nw_s2_familiar.nss @@ -0,0 +1,39 @@ +// HCR v3.2.0 - Re-Added REALFAM code. +//:://////////////////////////////////////////////////////////////////////////// +//:: FileName: NW_S2_Familiar +//:://////////////////////////////////////////////////////////////////////////// +/* + This spell summons an Arcane caster's Familiar. +*/ +//:://////////////////////////////////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Sept 27, 2001 +//:://////////////////////////////////////////////////////////////////////////// +#include "HC_Inc" +//:://////////////////////////////////////////////////////////////////////////// +void main() +{ + object oMod = GetModule(); + if (GetLocalInt(oMod, "REALFAM")) + { + if (GetIsPC(OBJECT_SELF) && + !GetIsDM(OBJECT_SELF) && + !GetIsDMPossessed(OBJECT_SELF)) + { + string sID = GetPlayerID(OBJECT_SELF); + if (GetLocalInt(oMod, "FAMDIED" + sID)) + { + if (GetGold(OBJECT_SELF) < 100) + { + string sMsg = "You need 100 gp's to pay for the materials."; + SendMessageToPC(OBJECT_SELF, sMsg); + return; + } + TakeGoldFromCreature(100, OBJECT_SELF, TRUE); + DeleteLocalInt(oMod, "FAMDIED" + sID); + } + } + } + SummonFamiliar(); +} +//:://////////////////////////////////////////////////////////////////////////// diff --git a/src/_removed/nw_s2_turndead.nss b/src/_removed/nw_s2_turndead.nss new file mode 100644 index 0000000..6e43c5e --- /dev/null +++ b/src/_removed/nw_s2_turndead.nss @@ -0,0 +1,949 @@ + //:://///////////////////////////////////////////// +//:: Turn Undead +//:: NW_S2_TurnDead +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Checks domain powers and class to determine + the proper turning abilities of the casting + character. + + Changelog: + Note: The first section contains a summary of changes made. The second + section explains in greater detail about the changes. + + Modified by : Slynderdale + on : April 15 , 2005 + Changes: + - Added Rebuke Undead + - Turning is now a Supernatural effect + - Turning now skips creatures that were already turned/rebuked + - Turn undead checks both the creatures racial type and class + - Turned creatures have their movement speed decreased by half + - Cleric, Paladin, Blackguard and Champion of Torm levels now stack + - Turn undead Knocks over valid creatures + + Modified by : Slynderdale + on : April 21 , 2005 + Changes: + - Added function HasTurnedEffect + - Added function GetTurnModifier + - Added function GetIsAssociate + - Magical beasts are now turnable/rebukable + + Modified by : Slynderdale + on : April 26 , 2005 + Changes: + - Added more to the Turn Modifier function and Fixed it up a bit + - Fixed some errors and bugs in the code and made some code improvments + + Modified by : Slynderdale + on : May 1 , 2005 + Changes: + - Added support for the War Domain, Turned/Rebuked creatures will take divine damage. + - Added support for the Travel domain which adds to the turning range. + - Added more to the Trickery domain, Added rolling a lucky 7 or unlucky 13. + - Construct turn damage was changed from d3(nTurnLevel+nHDModifier) to d3(nTurnLevel)+nHDModifier + - Fixed some errors and bugs in the code and made some code improvments + + Modified by : Slynderdale + on : June 3 , 2005 + Changes: + - Added support for local integers on creatures + - Added function GetRacialCheck which now handles the racial checkings + - Fixed some errors and bugs in the code and made some code improvments + + ---------------------------------------------------------------------------------------- + + More Info: + - Added Rebuke Undead + Evil aligned players or those with the REBUKE_UNDEAD local int can + now rebuke undead. When you rebuke undead, instead of turning a creature, + you paralyze them. If your rebuking level is high enough, you have a chance + of dominating them and having them under your control for a duration. + + - Turning is now a Supernatural effect + Made turning a Supernatural effect so the turning effects can not be dispelled. + + - Turning now skips creatures that were already turned/rebuked + Turned creatures will not count against your turning count. + + - Turn undead checks both the creatures racial type and class + If a creature was created and have an incorrectly set race but + have levels like Undead, it will be considered undead. + + - Turned creatures have their movement speed decreased by half + If you're attacking something with a fear effect in NWN, the game + tends to move you close to the target, then stop you, then move the creature away, + so you never actually get to ATTACK it even if you're hasted and it's a zombie. + Even worse is that creatures that are knocked down magically spring up and run away, + and it's just SO annoying. + + - Cleric, Paladin, Blackguard and Champion of Torm levels now stack + The turning level isn't decided on the class with the highest level. + Cleric levels now stack with Blackguard and Paladin levels but Paladin + and Blackguard levels don't stack with each other. + + - Turn undead Knocks over valid creatures + This fixes a bug where sometimes turned/Rebuked undead still attack. + The other reason behind this is when you rebuke/turn undead. You + release a tremendous amount of (un)holy energy. This energy causing those + affected to be knocked off their feet. + + - Added checks to see if a creature is turnable + HasTurnedEffect is called to check if the creature can be turned. + It checks to see if the creature is already turned, paralized, + petrified, frightened, stunned or dominated. This way creatures + who can't or shouldn't be turned won't use up HD turn counts. + + - Added Associate Checking + I added a check so rebuke undead will not try to add associates + under your command, instead they will be paralized. Also when turning + a summoned creature, it will show an unsummon special effect. + + - Magical beasts are now turnable/rebukable + If you have the magic domain, you can turn/rebuke magical beasts now. + + - Several domains and feats affect your turn modifier + GetTurnModifier is used to get the modifier for the current target. The bigger the + modifier the better the chance you will turn the target and the longer the effects will last. + The modifier also effects the damage you do to constructs if you have the destruction domain. + This modifier take into account several domains that don't really get much use and also + focuses in necromancy adds to the modifier against undead. Also various domains and things + may subtract from your modifier. + *Evil Domain: If you try to turn a creature with an good alignment and you + have the evil domain power, you gain a +1 modifier. Unless you also have the + good domain, -1 is subtracted from the modifier versus evil. + *Good Domain: If you try to turn a creature with a evil alignment and you + have the good domain power, you gain a +1 modifier. Unless you also have the + good domain, -1 is subtracted from the modifier versus good. + *Sun Domain: You gain a +1 modifier to all checks. + *Knowledge Domain: You gain a modifier that is dependant on your wisdom bonus. + You gain one third of your wisdom bonus as a modifier. If your wisdom bonus is + equal to or smaller then 0, then the current wisdom bonus - 2 is subtracted + from the modifier. + *Strength Domain: Checks your strength bonus versus the targets strength bonus. + If your strength bonus is 2 or more times higher, then you gain +1 to the modifier. + If your strength is higher, then you gain +1 to the modifer. + If the targets strength is 2 or more times higher, then you lose -1 from the modifier. + If the targets strength is higher, then you lose -1 from the modifer. + These stack for a total of +2 or -2 to your modifier. + *Water/Fire/Air/Earth Domain: You gain +1 to your modifier versus the corresponding + elemental of the domain you have. + *Trickery Domain: The trickery can have a negative and positive effect to our modifier, + Theres a 50% chance it will have a positive effect and a 50% it will have a negative effect. + If you also have the luck domain, it becomes 80% for a positive effect and 20% for a negative + effect. If its positive, you gain 1-3 to your modifier. If its negative, you lose 1-3 from + your modifier. Also if it rolls a lucky 7 or a unluck 13, the results of the modifier are + doubled. So if you had a negative effect of -3 and roll an unlucky 13, it will become -6. + The same goes for the positive modifier with rolling a 7, + *Death Domain: You gain a +1 modifier versus undead. + Focuses in necromancy will add to your modifier against those considered undead. + *Spell Focus Necromancy: +2 + *Greater Spell Focus Necromancy: +2 + *Epic Spell Focus Necromancy: +2 + The bonuses from the focuses stack for a total of +6 if you have all three. + The higher the modifier the easier it is to turn the creature. Also the + higher the modifier, the longer the rebuke/turn effects will last on the target. + The current duration is (nClassLevel + 5)*nTimeModifier rounds. + nClassLevel is the number of levels of cleric, paladin/blackguard and CoT you have. + nTimeModifier defaults to 1, so the duration is normal, but if your modifier is greater + then 1, the nTimeModifier is set to the current modifier. + The modifier is added to the dice roll when damaging constructs if you have the destruction + domain, so the damage is now d3(nTurnLevel)+nHDModifier. + + - War Domain damages Turned/Rebuked creatures + If you have the War Domain and successfuly turn or rebuke a creature, they will take a small + ammount of Divine damage. This doesn't stack with the magic damage that is already done to + constructs. The damage done is d6(3)+nHDModifier. + + - Travel Domain Extends Turning Range + Originally the turning range is 20m (65ft) but if you have the Travel Doamin this changes to + 25m (80ft), adding another 5m tot he original distance. This way you can turn creatures which + are farther away then usual. + + - Added support for local integers on creatures + Added support for several local integers on the creatures so builders have greater control how a + creature is turned or if they are immune to turning. + TurnImmunity: If TurnImmunity is set to True, the creature can not be turned. + IsTurnable: Is IsTurnable is set to true, the creatue can be turned no matter what it might be. + IsUndead: If IsUndead is set, the creature will be treated as an undead when turned. + IsVermin: If IsVermin is set, the creature will be treated as a vermin when turned. + IsElemental: If IsElemental is set, the creature will be treated as an elemenal when turned. + IsConstruct: If IsConstruct is set, the creature will be treated as a construct when turned. + IsOutsider: If IsOutsider is set, the creature will be treated as an outsider when turned. + IsMagicalBeast: If IsMagicalBeast is set, the creature will be treated as a magical beast when turned. + TurnHDOverride: If TurnHDOverride is set to anything greater then 0, the value set for TurnHDOverride + will override the creatures current HD and be used instead of their default one. + The new value will still be affected by the turn modifier as well. + You can specify is a creature can be turned with IsTurnable, if so, the creature can be turned like everything + else but it won't have a race type like undead or so on unless it has thatr ace already. The creature will have HD + equal to their HitDice plus their turn resistance. Also anyone with Turn Undead will be able to turn them without + any special feats or skills. + If you want to make a creature be set as turnable but give it a race or use a race check, use the more precise ones + such as IsOutsider. The creature will then be considered an outsider while being turned, using the outsider HD + calculations and also check if the player can turn outsiders. + **Note: IsTurnable overrides the other settings except for TurnImmunity. So if you have IsTurnable and IsOutsider, the + creature can still be turned even if the player can't turn outsiders. + + - Added function GetRacialCheck which now handles the racial checkings + This function compares the given race against the targets race. This checks against the targets + racial type, if they have the racial class or if they have the racial local interget override set. + If true, it returns True, if False, it returns false. The first parameter is the race to check for + such as RACIAL_TYPE_UNDEAD. The second parameter is optional and specifies the target. The default + is OBJECT_SELF which is the PC using the script. +*/ +//::////////////////////////////////////////////// +//:: Created By: Nov 2, 2001 +//:: Created On: Preston Watamaniuk +//::////////////////////////////////////////////// +//:: MODIFIED MARCH 5 2003 for Blackguards +//::////////////////////////////////////////////// +#include "NW_I0_GENERIC" + +//This function is used to do a racial check against the target. +//This checks the creatures race, classes and also local integers that specify the race +int GetRacialCheck(int nRace, object oTarget = OBJECT_SELF) +{ + if (!GetIsObjectValid(oTarget)) + return FALSE; + + int nRacial; + int nClassUndead, nClassVermin, nClassElemental, nClassConstruct, nClassOutsider, nClassMagicalBeast; + int nIsUndead, nIsVermin, nIsElemental, nIsConstruct, nIsOutsider, nIsMagicalBeast; + + nRacial = GetRacialType(oTarget); + nClassUndead = GetLevelByClass(CLASS_TYPE_UNDEAD,oTarget); + nClassVermin = GetLevelByClass(CLASS_TYPE_VERMIN,oTarget); + nClassElemental = GetLevelByClass(CLASS_TYPE_ELEMENTAL,oTarget); + nClassConstruct = GetLevelByClass(CLASS_TYPE_CONSTRUCT,oTarget); + nClassOutsider = GetLevelByClass(CLASS_TYPE_OUTSIDER,oTarget); + nClassMagicalBeast = GetLevelByClass(CLASS_TYPE_MAGICAL_BEAST,oTarget); + + nIsUndead=FALSE; nIsVermin=FALSE; nIsElemental=FALSE; nIsConstruct=FALSE; nIsOutsider=FALSE; nIsMagicalBeast=FALSE; + if(nRacial == RACIAL_TYPE_UNDEAD || nClassUndead > 0 || GetLocalInt(oTarget,"IsUndead")) nIsUndead = TRUE; + if(nRacial == RACIAL_TYPE_VERMIN || nClassVermin > 0 || GetLocalInt(oTarget,"IsVermin")) nIsVermin = TRUE; + if(nRacial == RACIAL_TYPE_ELEMENTAL || nClassElemental > 0 || GetLocalInt(oTarget,"IsElemental")) nIsElemental = TRUE; + if(nRacial == RACIAL_TYPE_CONSTRUCT || nClassConstruct > 0 || GetLocalInt(oTarget,"IsConstruct")) nIsConstruct = TRUE; + if(nRacial == RACIAL_TYPE_OUTSIDER || nClassOutsider > 0 || GetLocalInt(oTarget,"IsOutsider")) nIsOutsider = TRUE; + if(nRacial == RACIAL_TYPE_MAGICAL_BEAST || nClassMagicalBeast > 0 || GetLocalInt(oTarget,"IsMagicalBeast")) nIsMagicalBeast = TRUE; + + if (nRace == RACIAL_TYPE_UNDEAD && nIsUndead || + nRace == RACIAL_TYPE_VERMIN && nIsVermin || + nRace == RACIAL_TYPE_ELEMENTAL && nIsElemental || + nRace == RACIAL_TYPE_CONSTRUCT && nIsConstruct || + nRace == RACIAL_TYPE_OUTSIDER && nIsOutsider || + nRace == RACIAL_TYPE_MAGICAL_BEAST && nIsMagicalBeast) + return TRUE; + + if (nRacial == nRace) + return TRUE; + + return FALSE; +} + +//Get the modifer for Turn Undead. This effects how long the turn effects last and how well +//it will go against a creature. +int GetTurnModifier(object oTarget) +{ + //Declare major variables + int nHDModifier = 0; + int nWisMod; + int nWisdomBonus = GetAbilityModifier(ABILITY_WISDOM); + int nStrengthBonus = GetAbilityModifier(ABILITY_STRENGTH); + int nAppearance = GetAppearanceType(oTarget); + int nAlign = GetAlignmentGoodEvil(oTarget); + int nRacial = GetRacialType(oTarget); + int nClassUndead = GetLevelByClass(CLASS_TYPE_UNDEAD,oTarget); + + //Check to see if they have any focuses in Necromancy or the death domain + //If so, add them to the modifier which makes it easier to turn the undead + if(GetRacialCheck(RACIAL_TYPE_UNDEAD, oTarget)) + { + if(GetHasFeat(FEAT_DEATH_DOMAIN_POWER)) + nHDModifier = nHDModifier + 1; + if(GetHasFeat(FEAT_SPELL_FOCUS_NECROMANCY)) + nHDModifier = nHDModifier + 2; + if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_NECROMANCY)) + nHDModifier = nHDModifier + 2; + if(GetHasFeat(FEAT_EPIC_SPELL_FOCUS_NECROMANCY)) + nHDModifier = nHDModifier + 2; + } + + //Check to see if the player has the Good or Evil domain + //If they do, check to see if the creature's alignment is good or evil + //If the alignment opposite the domain, add to the turning modifier if the + //alignment is the same, subtract from the modifier + if (GetHasFeat(FEAT_EVIL_DOMAIN_POWER)) + { + if (nAlign == ALIGNMENT_GOOD) + nHDModifier = nHDModifier + 1; + if (nAlign == ALIGNMENT_EVIL && !GetHasFeat(FEAT_GOOD_DOMAIN_POWER)) + nHDModifier = nHDModifier - 1; + } + if (GetHasFeat(FEAT_GOOD_DOMAIN_POWER)) + { + if (nAlign == ALIGNMENT_EVIL) + nHDModifier = nHDModifier + 1; + if (nAlign == ALIGNMENT_GOOD && !GetHasFeat(FEAT_EVIL_DOMAIN_POWER)) + nHDModifier = nHDModifier - 1; + } + + //Check to see if the player has the knoledge domain power + //If so, add 1/3rd if their wisdom bonus to the modifier + //If their wisdom bonus is 0 or lower, then the modifier is + //their wisdom bonus minus 2. + if (GetHasFeat(FEAT_KNOWLEDGE_DOMAIN_POWER)) + { + if (nWisdomBonus > 0) + { + nWisMod = nWisdomBonus / 3; + if (nWisMod > 0) + nHDModifier = nHDModifier + nWisMod; + } + else + { + nWisMod = nWisdomBonus - 2; + nHDModifier = nHDModifier + nWisMod; + } + } + + //Check your strength bonus versus the targets + //If your strength bonus is 2 or more times higher, then you gain +1 to the modifier + //If your strength is higher, then you gain +1 to the modifer + //If the targets strength is 2 or more times higher, then you lose -1 from the modifier + //If the targets strength is higher, then you lose -1 from the modifer + //These stack for a total of +2 or -2 + if (GetHasFeat(FEAT_STRENGTH_DOMAIN_POWER)) + { + int nTarStrengthBonus = GetAbilityModifier(ABILITY_STRENGTH,oTarget); + if ((nStrengthBonus*2) < nTarStrengthBonus) + nHDModifier = nHDModifier - 1; + if (nStrengthBonus < nTarStrengthBonus) + nHDModifier = nHDModifier - 1; + if (nStrengthBonus > (nTarStrengthBonus*2)) + nHDModifier = nHDModifier + 1; + if (nStrengthBonus > nTarStrengthBonus) + nHDModifier = nHDModifier + 1; + } + + //If you have the air domain, make it easier to turn air elementals + if (GetHasFeat(FEAT_AIR_DOMAIN_POWER) && + (nAppearance == APPEARANCE_TYPE_ELEMENTAL_AIR || + nAppearance == APPEARANCE_TYPE_ELEMENTAL_AIR_ELDER)) + { + nHDModifier = nHDModifier + 1; + } + + //If you have the earth domain, make it easier to turn earth elementals + if (GetHasFeat(FEAT_EARTH_DOMAIN_POWER) && + (nAppearance == APPEARANCE_TYPE_ELEMENTAL_EARTH || + nAppearance == APPEARANCE_TYPE_ELEMENTAL_EARTH_ELDER)) + { + nHDModifier = nHDModifier + 1; + } + + //If you have the fire domain, make it easier to turn fire elementals + if (GetHasFeat(FEAT_FIRE_DOMAIN_POWER) && + (nAppearance == APPEARANCE_TYPE_ELEMENTAL_FIRE || + nAppearance == APPEARANCE_TYPE_ELEMENTAL_FIRE_ELDER)) + { + nHDModifier = nHDModifier + 1; + } + + //If you have the water domain, make it easier to turn water elementals + if (GetHasFeat(FEAT_WATER_DOMAIN_POWER) && + (nAppearance == APPEARANCE_TYPE_ELEMENTAL_WATER || + nAppearance == APPEARANCE_TYPE_ELEMENTAL_WATER_ELDER)) + { + nHDModifier = nHDModifier + 1; + } + + //Checks to see if you have the Trickery domain and calculate the effects + //Theres a 50% chance for a positive effect and a 50% for a negative effect + //unless you have the luck domain feat, then theres only a 20% chance for a + //negative effect. Lucky 7 and Unlucky 13 doubles the results. + if (GetHasFeat(FEAT_TRICKERY_DOMAIN_POWER)) + { + int nTrickMod; + int nTrick = d20(); + if (GetHasFeat(FEAT_LUCK_DOMAIN_POWER)) + nTrick = nTrick - 6; + if (nTrick <= 10) + { + nTrickMod = d3(); + if (nTrick == 7) //Lucky 7 + nTrickMod = nTrickMod * 2; + } + else + { + nTrickMod = d3()*-1; + if (nTrick == 13) //UnLucky 13 + nTrickMod = nTrickMod * 2; + } + nHDModifier = nHDModifier + nTrickMod; + } + + //The sun domain improves your turning modifier + if (GetHasFeat(FEAT_SUN_DOMAIN_POWER)) + { + nHDModifier = nHDModifier + 1; + } + + if (GetTag(GetItemInSlot(INVENTORY_SLOT_LEFTHAND)) == "HolySymbol") + { + nHDModifier = nHDModifier + 2; + } + + return nHDModifier; +} + +//This function checks to see if the turned creature is an associate to another creature +//This way it won't try to rebuke associates of another player and also unsummon summons +int GetIsAssociate(object oTarget, int nCheckAll = FALSE) +{ + if (GetIsObjectValid(oTarget)) + { + object oMaster = GetMaster(oTarget); + if (GetIsObjectValid(oMaster)) + { + int nAssociate = GetAssociateType(oTarget); + if(nAssociate == ASSOCIATE_TYPE_SUMMONED || + nAssociate == ASSOCIATE_TYPE_FAMILIAR || + nAssociate == ASSOCIATE_TYPE_ANIMALCOMPANION) + { + return TRUE; + } + if (nCheckAll && + (nAssociate == ASSOCIATE_TYPE_DOMINATED || + nAssociate == ASSOCIATE_TYPE_HENCHMAN)) + { + return TRUE; + } + } + } + return FALSE; +} + +//Check to see if the target is already turned, paralized, +//petrified, frightened, stunned and dominated. If so, return true. +int HasTurnedEffect(object oTarget) +{ + return + GetHasEffect(EFFECT_TYPE_TURNED, oTarget) || + GetHasEffect(EFFECT_TYPE_FRIGHTENED, oTarget) || + GetHasEffect(EFFECT_TYPE_PARALYZE, oTarget) || + GetHasEffect(EFFECT_TYPE_CUTSCENE_PARALYZE, oTarget) || + GetHasEffect(EFFECT_TYPE_PETRIFY, oTarget) || + GetHasEffect(EFFECT_TYPE_STUNNED, oTarget) || + GetHasEffect(EFFECT_TYPE_DOMINATED, oTarget); +} + +//Checks to see if the player is able to command the creature depending +//On how many slots you have left and the target HD. +int CanCommand(int nClassLevel, int nTargetHD) +{ + int nSlots = GetLocalInt(OBJECT_SELF, "wb_clr_comm_slots"); + int nNew = nSlots + nTargetHD; + if(nClassLevel >= nNew) + { + return TRUE; + } + return FALSE; +} + +//Add the creature under the player's command +void AddCommand(int nTargetHD) +{ + int nSlots = GetLocalInt(OBJECT_SELF, "wb_clr_comm_slots"); + SetLocalInt(OBJECT_SELF, "wb_clr_comm_slots", nSlots + nTargetHD); +} + +//Remove the creature from the players command +void SubCommand(int nTargetHD) +{ + int nSlots = GetLocalInt(OBJECT_SELF, "wb_clr_comm_slots"); + SetLocalInt(OBJECT_SELF, "wb_clr_comm_slots", nSlots - nTargetHD); +} + +//Gets all creatures in a 20m radius around the caster and rebukes them or not. If the creatures +//HD are 1/2 or less of the nClassLevel then the creature is commanded (dominated) or dismissed. +void RebukeUndead(int nTurnLevel, int nTurnHD, int nVermin, int nElemental, int nConstructs, int nGoodOrEvilDomain, int nPlanar, int nMagicDomain, int nClassLevel) +{ + //Declare major variables + int nCnt = 1; + int nHDModifier = 0; + int nTimeModifier = 1; + int nIsUndead, nIsVermin, nIsElemental, nIsConstruct, nIsOutsider, nIsMagicalBeast; + int nHD, nHDCount, bValid, nDamage, nDuration; + nHDCount = 0; + effect eVis = EffectVisualEffect(VFX_IMP_PULSE_NEGATIVE); + effect eVisTurn = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DOMINATED); + effect eUnsummonVis = EffectVisualEffect(VFX_IMP_UNSUMMON); + effect eDamage; + effect eKnockdown = EffectKnockdown(); + //Yes I know its rebuke undead, but turn then anyways so they don't count towards the HD score + effect eTurned = EffectTurned(); + //Cutscene Paralyze sometimes fail if the target is immune to paralyzation. + //If thats the case, then immobilze them so they can't move. + //They won't attack because they are turned with EffectTurned. Hence another reason why I left it in. + effect eParalyze = EffectCutsceneParalyze(); + effect eImmobilize = EffectCutsceneImmobilize(); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); + effect eRebukeLink = EffectLinkEffects(eVisTurn, eTurned); + eRebukeLink = EffectLinkEffects(eRebukeLink, eParalyze); + eRebukeLink = EffectLinkEffects(eRebukeLink, eImmobilize); + eRebukeLink = EffectLinkEffects(eRebukeLink, eDur); + //Made it a supernatural effect so it can't be dispelled. + eRebukeLink = SupernaturalEffect(eRebukeLink); + + effect eDeath = SupernaturalEffect(EffectDeath(TRUE)); + + effect eDominate = SupernaturalEffect(EffectCutsceneDominated()); + effect eDominVis = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_NEGATIVE); + effect eDominateLink = EffectLinkEffects(eDominate, eDominVis); + + effect eImpactVis = EffectVisualEffect(VFX_FNF_LOS_EVIL_30); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpactVis, GetLocation(OBJECT_SELF)); + + //Get nearest enemy within 20m (60ft) + //If you have the Travel domain get the nearest enemy within 25m (80ft) + float fDistance = 20.0; + if (GetHasFeat(FEAT_TRAVEL_DOMAIN_POWER)) + fDistance = 25.0; + object oTarget = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE , OBJECT_SELF, nCnt,CREATURE_TYPE_PERCEPTION , PERCEPTION_SEEN); + while(GetIsObjectValid(oTarget) && nHDCount < nTurnHD && GetDistanceToObject(oTarget) <= fDistance) + { + //Check to see if the creature is can be turned or is friendly + //This will prevent creatures thata re already turned from using up HD slots + if(!GetIsFriend(oTarget) && !GetFactionEqual(oTarget) && !HasTurnedEffect(oTarget) && !GetLocalInt(oTarget,"TurnImmunity")) + { + //Check the racial type of the creature. This checks both the race and the classes they have + //So if a creature has an improperly set race but took undead levels, consider them undead + nIsUndead=FALSE; nIsVermin=FALSE; nIsElemental=FALSE; nIsConstruct=FALSE; nIsOutsider=FALSE; nIsMagicalBeast=FALSE; + if(GetRacialCheck(RACIAL_TYPE_UNDEAD, oTarget)) nIsUndead = TRUE; + if(GetRacialCheck(RACIAL_TYPE_VERMIN, oTarget)) nIsVermin = TRUE; + if(GetRacialCheck(RACIAL_TYPE_ELEMENTAL, oTarget)) nIsElemental = TRUE; + if(GetRacialCheck(RACIAL_TYPE_CONSTRUCT, oTarget)) nIsConstruct = TRUE; + if(GetRacialCheck(RACIAL_TYPE_OUTSIDER, oTarget)) nIsOutsider = TRUE; + if(GetRacialCheck(RACIAL_TYPE_MAGICAL_BEAST, oTarget)) nIsMagicalBeast = TRUE; + + if (nIsOutsider) + { + if (nPlanar) + { + //Planar turning decreases spell resistance against turning by 1/2 + nHD = GetHitDice(oTarget) + (GetSpellResistance(oTarget) /2) + GetTurnResistanceHD(oTarget); + } + else + { + nHD = GetHitDice(oTarget) + (GetSpellResistance(oTarget) + GetTurnResistanceHD(oTarget)); + } + } + else //(full turn resistance) + { + nHD = GetHitDice(oTarget) + GetTurnResistanceHD(oTarget); + } + + if (GetLocalInt(oTarget,"TurnHDOverride") > 0) + { + nHD = GetLocalInt(oTarget,"TurnHDOverride"); + } + + nHDModifier = GetTurnModifier(oTarget); + nHD = nHD - nHDModifier; + if(nHD < 1) + nHD = 1; + if(nHDModifier > 1) + nTimeModifier = nHDModifier; + + if(nHD <= nTurnLevel && nHD <= (nTurnHD - nHDCount)) + { + //Check the various domain turning types + if(nIsUndead) + { + bValid = TRUE; + } + else if (nIsVermin && nVermin > 0) + { + bValid = TRUE; + } + else if (nIsElemental && nElemental > 0) + { + bValid = TRUE; + } + else if (nIsConstruct && nConstructs > 0) + { + //The construct handling code below to prevent redundant code. + bValid = TRUE; + } + else if (nIsOutsider && (nGoodOrEvilDomain+nPlanar) > 0) + { + bValid = TRUE; + } + else if (nIsMagicalBeast && nMagicDomain > 0) + { + bValid = TRUE; + } + else if (GetLocalInt(oTarget,"IsTurnable")) + { + bValid = TRUE; + } + // * if wearing gauntlets of the lich,then can be turned + else if (GetIsObjectValid(GetItemPossessedBy(oTarget, "x2_gauntletlich")) == TRUE) + { + if (GetTag(GetItemInSlot(INVENTORY_SLOT_ARMS)) == "x2_gauntletlich") + { + bValid = TRUE; + } + } + + //Apply results of the turn + if(bValid == TRUE) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELLABILITY_TURN_UNDEAD)); + + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + //Added Knockdown to the target. The reason behind this is simple, when a cleric + //Paladin, ect uses Turn undead, they release a powerful blast of (un)holy energy that + //Knocks the creatures off their feet. Also fixes the bug were sometimes the creatures + //Still attacked when turned. + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eKnockdown, oTarget, 3.0); + + //The duration for the turning effect in Rounds + nDuration = (nClassLevel + 5)*nTimeModifier; + if (nIsConstruct) + { + //Handle the construct damage here + nDamage = d3(nTurnLevel)+nHDModifier; + if (nDamage < 1) nDamage = 1; + eDamage = EffectDamage(nDamage, DAMAGE_TYPE_MAGICAL); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget); + } + else if((nClassLevel/2) >= nHD && !GetIsPC(oTarget) && !GetIsAssociate(oTarget, TRUE) && CanCommand(nClassLevel, nHD)) + { + //Dominate the target + DelayCommand(0.1f, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDominateLink, oTarget, RoundsToSeconds(nDuration))); + AssignCommand(oTarget, ClearAllActions()); + SetIsTemporaryFriend(oTarget, OBJECT_SELF, TRUE, RoundsToSeconds(nDuration)); + AddCommand(nHD); + DelayCommand(RoundsToSeconds(nDuration), SubCommand(nHD)); + } + else + { + //Damage the target if player has the War Domain + if (GetHasFeat(FEAT_WAR_DOMAIN_POWER)) + { + nDamage = d6(3)+nHDModifier; + if (nDamage < 1) nDamage = 1; + ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDamage, DAMAGE_TYPE_DIVINE), oTarget); + } + //Rebuke the target + AssignCommand(oTarget, ClearAllActions()); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eRebukeLink, oTarget, RoundsToSeconds(nDuration)); + } + nHDCount = nHDCount + nHD; + } + } + bValid = FALSE; + } + nCnt++; + oTarget = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE , OBJECT_SELF, nCnt,CREATURE_TYPE_PERCEPTION , PERCEPTION_SEEN); + } +} + +//Gets all creatures in a 20m radius around the caster and turns them or not. If the creatures +//HD are 1/2 or less of the nClassLevel then the creature is destroyed. +void TurnUndead(int nTurnLevel, int nTurnHD, int nVermin, int nElemental, int nConstructs, int nGoodOrEvilDomain, int nPlanar, int nMagicDomain, int nClassLevel) +{ + //Declare major variables + int nCnt = 1; + int nHDModifier = 0; + int nTimeModifier = 1; + int nIsUndead, nIsVermin, nIsElemental, nIsConstruct, nIsOutsider, nIsMagicalBeast; + int nHD, nHDCount, bValid, nDamage, nDuration; + nHDCount = 0; + effect eVis = EffectVisualEffect(VFX_IMP_SUNSTRIKE); + effect eVisTurn = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_FEAR); + effect eUnsummonVis = EffectVisualEffect(VFX_IMP_UNSUMMON); + effect eDamage; + effect eKnockdown = EffectKnockdown(); + effect eTurned = EffectTurned(); + //Decrease the creatures speed to fix an annoying bug. If you're attacking something with a fear effect in NWN, + //the game tends to move you close to the target, then stop you, then move the creature away, + //so you never actually get to ATTACK it even if you're hasted and it's a zombie. + //Even worse is that creatures that are knocked down magically spring up and run away, and it's just SO annoying. + effect eSlowDown = EffectMovementSpeedDecrease(50); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); + effect eTurnLink = EffectLinkEffects(eVisTurn, eTurned); + eTurnLink = EffectLinkEffects(eTurnLink, eSlowDown); + eTurnLink = EffectLinkEffects(eTurnLink, eDur); + //Made it a supernatural effect so it cant't be dispelled. + eTurnLink = SupernaturalEffect(eTurnLink); + + effect eDeath = SupernaturalEffect(EffectDeath(TRUE)); + + effect eImpactVis = EffectVisualEffect(VFX_FNF_LOS_HOLY_30); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpactVis, GetLocation(OBJECT_SELF)); + + //Get nearest enemy within 20m (65ft) + //If you have the Travel domain get the nearest enemy within 25m (80ft) + float fDistance = 20.0; + if (GetHasFeat(FEAT_TRAVEL_DOMAIN_POWER)) + fDistance = 25.0; + object oTarget = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE , OBJECT_SELF, nCnt,CREATURE_TYPE_PERCEPTION , PERCEPTION_SEEN); + while(GetIsObjectValid(oTarget) && nHDCount < nTurnHD && GetDistanceToObject(oTarget) <= fDistance) + { + //Check to see if the creature is can be turned or is friendly + //This will prevent creatures thata re already turned from using up HD slots + if(!GetIsFriend(oTarget) && !GetFactionEqual(oTarget) && !HasTurnedEffect(oTarget) && !GetLocalInt(oTarget,"TurnImmunity")) + { + //Check the racial type of the creature. This checks both the race and the classes they have + //So if a creature has an improperly set race but took undead levels, consider them undead + nIsUndead=FALSE; nIsVermin=FALSE; nIsElemental=FALSE; nIsConstruct=FALSE; nIsOutsider=FALSE; nIsMagicalBeast=FALSE; + if(GetRacialCheck(RACIAL_TYPE_UNDEAD, oTarget)) nIsUndead = TRUE; + if(GetRacialCheck(RACIAL_TYPE_VERMIN, oTarget)) nIsVermin = TRUE; + if(GetRacialCheck(RACIAL_TYPE_ELEMENTAL, oTarget)) nIsElemental = TRUE; + if(GetRacialCheck(RACIAL_TYPE_CONSTRUCT, oTarget)) nIsConstruct = TRUE; + if(GetRacialCheck(RACIAL_TYPE_OUTSIDER, oTarget)) nIsOutsider = TRUE; + if(GetRacialCheck(RACIAL_TYPE_MAGICAL_BEAST, oTarget)) nIsMagicalBeast = TRUE; + + if (nIsOutsider) + { + if (nPlanar) + { + //Planar turning decreases spell resistance against turning by 1/2 + nHD = GetHitDice(oTarget) + (GetSpellResistance(oTarget) /2) + GetTurnResistanceHD(oTarget); + } + else + { + nHD = GetHitDice(oTarget) + (GetSpellResistance(oTarget) + GetTurnResistanceHD(oTarget)); + } + } + else //(full turn resistance) + { + nHD = GetHitDice(oTarget) + GetTurnResistanceHD(oTarget); + } + + if (GetLocalInt(oTarget,"TurnHDOverride") > 0) + { + nHD = GetLocalInt(oTarget,"TurnHDOverride"); + } + + nHDModifier = GetTurnModifier(oTarget); + nHD = nHD - nHDModifier; + if(nHD < 1) + nHD = 1; + if(nHDModifier > 1) + nTimeModifier = nHDModifier; + + if(nHD <= nTurnLevel && nHD <= (nTurnHD - nHDCount)) + { + //Check the various domain turning types + if(nIsUndead) + { + bValid = TRUE; + } + else if (nIsVermin && nVermin > 0) + { + bValid = TRUE; + } + else if (nIsElemental && nElemental > 0) + { + bValid = TRUE; + } + else if (nIsConstruct && nConstructs > 0) + { + //The construct handling code below to prevent redundant code. + bValid = TRUE; + } + else if (nIsOutsider && (nGoodOrEvilDomain+nPlanar) > 0) + { + bValid = TRUE; + } + else if (nIsMagicalBeast && nMagicDomain > 0) + { + bValid = TRUE; + } + else if (GetLocalInt(oTarget,"IsTurnable")) + { + bValid = TRUE; + } + // * if wearing gauntlets of the lich,then can be turned + else if (GetIsObjectValid(GetItemPossessedBy(oTarget, "x2_gauntletlich")) == TRUE) + { + if (GetTag(GetItemInSlot(INVENTORY_SLOT_ARMS)) == "x2_gauntletlich") + { + bValid = TRUE; + } + } + + //Apply results of the turn + if(bValid == TRUE) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELLABILITY_TURN_UNDEAD)); + + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + //Added Knockdown to the target. The reason behind this is simple, when a cleric + //Paladin, ect uses Turn undead, they release a powerful blast of (un)holy energy that + //Knocks the creatures off their feet. Also fixes the bug were sometimes the creatures + //Still attacked when turned. + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eKnockdown, oTarget, 3.0); + + //The duration for the turning effect in Rounds + nDuration = (nClassLevel + 5)*nTimeModifier; + if (nIsConstruct) + { + //Handle the construct damage here + nDamage = d3(nTurnLevel)+nHDModifier; + if (nDamage < 1) nDamage = 1; + eDamage = EffectDamage(nDamage, DAMAGE_TYPE_MAGICAL); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget); + } + else if((nClassLevel/2) >= nHD) + { + if (nIsOutsider && (nGoodOrEvilDomain+nPlanar) > 0 || GetIsAssociate(oTarget)) + { + ApplyEffectToObject(DURATION_TYPE_INSTANT, eUnsummonVis, oTarget); + } + + //Destroy the target + DelayCommand(0.1f, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDeath, oTarget)); + } + else + { + //Damage the target if player has the War Domain + if (GetHasFeat(FEAT_WAR_DOMAIN_POWER)) + { + nDamage = d6(3)+nHDModifier; + if (nDamage < 1) nDamage = 1; + ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDamage, DAMAGE_TYPE_DIVINE), oTarget); + } + //Turn the target + AssignCommand(oTarget, ClearAllActions()); + AssignCommand(oTarget, ActionMoveAwayFromObject(OBJECT_SELF, TRUE)); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eTurnLink, oTarget, RoundsToSeconds(nDuration)); + } + nHDCount = nHDCount + nHD; + } + } + bValid = FALSE; + } + nCnt++; + oTarget = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE , OBJECT_SELF, nCnt,CREATURE_TYPE_PERCEPTION , PERCEPTION_SEEN); + } +} + +void main() +{ + int nClericLevel = GetLevelByClass(CLASS_TYPE_CLERIC); + int nPaladinLevel = GetLevelByClass(CLASS_TYPE_PALADIN); + int nBlackguardlevel = GetLevelByClass(CLASS_TYPE_BLACKGUARD); + int nDivineChampionLevel = GetLevelByClass(CLASS_TYPE_DIVINECHAMPION); + int nTotalLevel = GetHitDice(OBJECT_SELF); + + int nTurnLevel = nClericLevel; + int nClassLevel = nClericLevel; + + // GZ: Since paladin levels stack when turning, blackguard levels should stack as well + // GZ: but not with the paladin levels (thus else if). + if((nBlackguardlevel - 2) > 0 && (nBlackguardlevel > nPaladinLevel)) + { + nClassLevel += (nBlackguardlevel - 2); + nTurnLevel += (nBlackguardlevel - 2); + } + else if((nPaladinLevel - 2) > 0) + { + nClassLevel += (nPaladinLevel -2); + nTurnLevel += (nPaladinLevel - 2); + } + + //Added Divine Champion/Champion of Torm to the turning levels since they are similar to paladins. + if(nDivineChampionLevel > 0) + { + nClassLevel += nDivineChampionLevel; + nTurnLevel += nDivineChampionLevel; + } + + //Flags for bonus turning types + int nElemental = GetHasFeat(FEAT_AIR_DOMAIN_POWER) + GetHasFeat(FEAT_EARTH_DOMAIN_POWER) + GetHasFeat(FEAT_FIRE_DOMAIN_POWER) + GetHasFeat(FEAT_WATER_DOMAIN_POWER); + int nVermin = GetHasFeat(FEAT_PLANT_DOMAIN_POWER) + GetHasFeat(FEAT_ANIMAL_DOMAIN_POWER) + GetHasFeat(FEAT_ANIMAL_COMPANION); + int nConstructs = GetHasFeat(FEAT_DESTRUCTION_DOMAIN_POWER); + int nGoodOrEvilDomain = GetHasFeat(FEAT_GOOD_DOMAIN_POWER) + GetHasFeat(FEAT_EVIL_DOMAIN_POWER); + int nMagicDomain = GetHasFeat(FEAT_MAGIC_DOMAIN_POWER); + int nPlanar = GetHasFeat(854); //FEAT_EPIC_PLANAR_TURNING + + //Flag for improved turning ability + int nSun = GetHasFeat(FEAT_SUN_DOMAIN_POWER); + + //Make a turning check roll, modify if have the Sun Domain + int nChrMod = GetAbilityModifier(ABILITY_CHARISMA); + int nTurnCheck = d20() + nChrMod; //The roll to apply to the max HD of undead that can be turned --> nTurnLevel + int nTurnHD = d6(2) + nChrMod + nClassLevel; //The number of HD of undead that can be turned. + + if(nSun == TRUE) + { + nTurnCheck += d4(); + nTurnHD += d6(); + } + + //Determine the maximum HD of the undead that can be turned. + if(nTurnCheck <= 0) + { + nTurnLevel -= 4; + } + else if(nTurnCheck >= 1 && nTurnCheck <= 3) + { + nTurnLevel -= 3; + } + else if(nTurnCheck >= 4 && nTurnCheck <= 6) + { + nTurnLevel -= 2; + } + else if(nTurnCheck >= 7 && nTurnCheck <= 9) + { + nTurnLevel -= 1; + } + else if(nTurnCheck >= 10 && nTurnCheck <= 12) + { + //Stays the same + } + else if(nTurnCheck >= 13 && nTurnCheck <= 15) + { + nTurnLevel += 1; + } + else if(nTurnCheck >= 16 && nTurnCheck <= 18) + { + nTurnLevel += 2; + } + else if(nTurnCheck >= 19 && nTurnCheck <= 21) + { + nTurnLevel += 3; + } + else if(nTurnCheck >= 22) + { + nTurnLevel += 4; + } + + //Make sure the character's Turning Level is never less than 1. + if (nTurnLevel < 1) + { + nTurnLevel = 1; + } + + //Check to see if they are an Evil aligned Cleric or have the REBUKE_UNDEAD local int set to true. + //If so, use rebuke undead instead of turn undead. + int nAlign = GetAlignmentGoodEvil(OBJECT_SELF); + if(nAlign == ALIGNMENT_EVIL || GetLocalInt(OBJECT_SELF, "REBUKE_UNDEAD") == TRUE) + { + RebukeUndead(nTurnLevel, nTurnHD, nVermin, nElemental, nConstructs, nGoodOrEvilDomain, nPlanar, nMagicDomain, nClassLevel); + } + else + { + TurnUndead(nTurnLevel, nTurnHD, nVermin, nElemental, nConstructs, nGoodOrEvilDomain, nPlanar, nMagicDomain, nClassLevel); + } +} diff --git a/src/_removed/sei_at_setsubr02.nss b/src/_removed/sei_at_setsubr02.nss new file mode 100644 index 0000000..8257c65 --- /dev/null +++ b/src/_removed/sei_at_setsubr02.nss @@ -0,0 +1,17 @@ +// +// NWSetSubrace02 +// +// Set the subrace of the conversing object to 'gold dwarf' +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + + +void main() +{ + SEI_SetSubraceVar( OBJECT_SELF, SUBRACE_DWARF_GOLD ); +} + diff --git a/src/_removed/sei_at_setsubr03.nss b/src/_removed/sei_at_setsubr03.nss new file mode 100644 index 0000000..2a14874 --- /dev/null +++ b/src/_removed/sei_at_setsubr03.nss @@ -0,0 +1,17 @@ +// +// NWSetSubrace03 +// +// Set the subrace of the conversing object to 'gray dwarf' +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + + +void main() +{ + SEI_SetSubraceVar( OBJECT_SELF, SUBRACE_DWARF_GRAY ); +} + diff --git a/src/_removed/sei_at_setsubr04.nss b/src/_removed/sei_at_setsubr04.nss new file mode 100644 index 0000000..15ed9c1 --- /dev/null +++ b/src/_removed/sei_at_setsubr04.nss @@ -0,0 +1,17 @@ +// +// NWSetSubrace04 +// +// Set the subrace of the conversing object to 'shield dwarf' +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + + +void main() +{ + SEI_SetSubraceVar( OBJECT_SELF, SUBRACE_DWARF_SHIELD ); +} + diff --git a/src/_removed/sei_at_setsubr05.nss b/src/_removed/sei_at_setsubr05.nss new file mode 100644 index 0000000..36e8169 --- /dev/null +++ b/src/_removed/sei_at_setsubr05.nss @@ -0,0 +1,17 @@ +// +// NWSetSubrace05 +// +// Set the subrace of the conversing object to 'dark elf' +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + + +void main() +{ + SEI_SetSubraceVar( OBJECT_SELF, SUBRACE_ELF_DARK ); +} + diff --git a/src/_removed/sei_at_setsubr06.nss b/src/_removed/sei_at_setsubr06.nss new file mode 100644 index 0000000..41842e6 --- /dev/null +++ b/src/_removed/sei_at_setsubr06.nss @@ -0,0 +1,17 @@ +// +// NWSetSubrace06 +// +// Set the subrace of the conversing object to 'moon elf' +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + + +void main() +{ + SEI_SetSubraceVar( OBJECT_SELF, SUBRACE_ELF_MOON ); +} + diff --git a/src/_removed/sei_at_setsubr07.nss b/src/_removed/sei_at_setsubr07.nss new file mode 100644 index 0000000..3cfff4a --- /dev/null +++ b/src/_removed/sei_at_setsubr07.nss @@ -0,0 +1,17 @@ +// +// NWSetSubrace07 +// +// Set the subrace of the conversing object to 'sun elf' +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + + +void main() +{ + SEI_SetSubraceVar( OBJECT_SELF, SUBRACE_ELF_SUN ); +} + diff --git a/src/_removed/sei_at_setsubr08.nss b/src/_removed/sei_at_setsubr08.nss new file mode 100644 index 0000000..814ac82 --- /dev/null +++ b/src/_removed/sei_at_setsubr08.nss @@ -0,0 +1,17 @@ +// +// NWSetSubrace08 +// +// Set the subrace of the conversing object to 'wild elf' +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + + +void main() +{ + SEI_SetSubraceVar( OBJECT_SELF, SUBRACE_ELF_WILD ); +} + diff --git a/src/_removed/sei_at_setsubr09.nss b/src/_removed/sei_at_setsubr09.nss new file mode 100644 index 0000000..455ecf7 --- /dev/null +++ b/src/_removed/sei_at_setsubr09.nss @@ -0,0 +1,17 @@ +// +// NWSetSubrace09 +// +// Set the subrace of the conversing object to 'wood elf' +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + + +void main() +{ + SEI_SetSubraceVar( OBJECT_SELF, SUBRACE_ELF_WOOD ); +} + diff --git a/src/_removed/sei_at_setsubr10.nss b/src/_removed/sei_at_setsubr10.nss new file mode 100644 index 0000000..4d56f63 --- /dev/null +++ b/src/_removed/sei_at_setsubr10.nss @@ -0,0 +1,17 @@ +// +// NWSetSubrace10 +// +// Set the subrace of the conversing object to 'deep gnome' +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + + +void main() +{ + SEI_SetSubraceVar( OBJECT_SELF, SUBRACE_GNOME_DEEP ); +} + diff --git a/src/_removed/sei_at_setsubr11.nss b/src/_removed/sei_at_setsubr11.nss new file mode 100644 index 0000000..35870ed --- /dev/null +++ b/src/_removed/sei_at_setsubr11.nss @@ -0,0 +1,17 @@ +// +// NWSetSubrace11 +// +// Set the subrace of the conversing object to 'rock gnome' +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + + +void main() +{ + SEI_SetSubraceVar( OBJECT_SELF, SUBRACE_GNOME_ROCK ); +} + diff --git a/src/_removed/sei_at_setsubr12.nss b/src/_removed/sei_at_setsubr12.nss new file mode 100644 index 0000000..7c30b76 --- /dev/null +++ b/src/_removed/sei_at_setsubr12.nss @@ -0,0 +1,17 @@ +// +// NWSetSubrace12 +// +// Set the subrace of the conversing object to 'half-elf' +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + + +void main() +{ + SEI_SetSubraceVar( OBJECT_SELF, SUBRACE_HALFELF ); +} + diff --git a/src/_removed/sei_at_setsubr13.nss b/src/_removed/sei_at_setsubr13.nss new file mode 100644 index 0000000..13461e6 --- /dev/null +++ b/src/_removed/sei_at_setsubr13.nss @@ -0,0 +1,17 @@ +// +// NWSetSubrace13 +// +// Set the subrace of the conversing object to 'half-orc' +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + + +void main() +{ + SEI_SetSubraceVar( OBJECT_SELF, SUBRACE_HALFORC ); +} + diff --git a/src/_removed/sei_at_setsubr14.nss b/src/_removed/sei_at_setsubr14.nss new file mode 100644 index 0000000..c40e416 --- /dev/null +++ b/src/_removed/sei_at_setsubr14.nss @@ -0,0 +1,17 @@ +// +// NWSetSubrace14 +// +// Set the subrace of the conversing object to 'ghostwise halfling' +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + + +void main() +{ + SEI_SetSubraceVar( OBJECT_SELF, SUBRACE_HALFLING_GHOSTWISE ); +} + diff --git a/src/_removed/sei_at_setsubr15.nss b/src/_removed/sei_at_setsubr15.nss new file mode 100644 index 0000000..a0e8c15 --- /dev/null +++ b/src/_removed/sei_at_setsubr15.nss @@ -0,0 +1,17 @@ +// +// NWSetSubrace15 +// +// Set the subrace of the conversing object to 'lightfoot halfling' +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + + +void main() +{ + SEI_SetSubraceVar( OBJECT_SELF, SUBRACE_HALFLING_LIGHTFOOT ); +} + diff --git a/src/_removed/sei_at_setsubr16.nss b/src/_removed/sei_at_setsubr16.nss new file mode 100644 index 0000000..c55db4d --- /dev/null +++ b/src/_removed/sei_at_setsubr16.nss @@ -0,0 +1,17 @@ +// +// NWSetSubrace16 +// +// Set the subrace of the conversing object to 'strongheart halfling' +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + + +void main() +{ + SEI_SetSubraceVar( OBJECT_SELF, SUBRACE_HALFLING_STRONGHEART ); +} + diff --git a/src/_removed/sei_at_setsubr17.nss b/src/_removed/sei_at_setsubr17.nss new file mode 100644 index 0000000..e4933fb --- /dev/null +++ b/src/_removed/sei_at_setsubr17.nss @@ -0,0 +1,17 @@ +// +// NWSetSubrace17 +// +// Set the subrace of the conversing object to 'human' +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + + +void main() +{ + SEI_SetSubraceVar( OBJECT_SELF, SUBRACE_HUMAN ); +} + diff --git a/src/_removed/sei_at_setsubr18.nss b/src/_removed/sei_at_setsubr18.nss new file mode 100644 index 0000000..d0bc51f --- /dev/null +++ b/src/_removed/sei_at_setsubr18.nss @@ -0,0 +1,17 @@ +// +// NWSetSubrace18 +// +// Set the subrace of the conversing object to 'half-drow' +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + + +void main() +{ + SEI_SetSubraceVar( OBJECT_SELF, SUBRACE_HALFDROW ); +} + diff --git a/src/_removed/sei_endsubrdial.nss b/src/_removed/sei_endsubrdial.nss new file mode 100644 index 0000000..9d92483 --- /dev/null +++ b/src/_removed/sei_endsubrdial.nss @@ -0,0 +1,16 @@ +// +// NWEndSubraceDialog +// +// End the subrace dialog and complete initialization of the subrace. +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + +void main() +{ + SEI_FinishSubraceDialog( OBJECT_SELF ); +} + diff --git a/src/_removed/sei_onpcrested.nss b/src/_removed/sei_onpcrested.nss new file mode 100644 index 0000000..e772db6 --- /dev/null +++ b/src/_removed/sei_onpcrested.nss @@ -0,0 +1,37 @@ +// +// NWOnPCRested +// +// When a PC finishes resting give them back the subrace items +// (if they've lost it). +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + + +void main() +{ + + object oPC = GetLastPCRested(); + + switch( GetLastRestEventType() ) + { + + case REST_EVENTTYPE_REST_FINISHED: + { + SEI_KeepSubraceItem( oPC ); + } + break; + + case REST_EVENTTYPE_REST_STARTED: + case REST_EVENTTYPE_REST_CANCELLED: + case REST_EVENTTYPE_REST_INVALID: + default: + break; + + } // End switch-case + +} // End main + diff --git a/src/_removed/sei_subracedrop.nss b/src/_removed/sei_subracedrop.nss new file mode 100644 index 0000000..86ad3e6 --- /dev/null +++ b/src/_removed/sei_subracedrop.nss @@ -0,0 +1,42 @@ +// +// NWSubraceDrop +// +// Script for when a character drops a subrace item. +// Place in the OnUnAcquireItem module event. +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + + +void main() +{ + + // Get te item that was lost. + object oItem = GetModuleItemLost(); + + // Get the character who lost the item. + object oChar = GetModuleItemLostBy(); + + // SEI_Note: There seems to be a bug in GetModuleItemLostBy(), which + // returns the lost object, not the lost character holding the + // object. But strangely enough GetEnteringObject does return the + // character. Done like this for backwards compatibility if + // BioWare ever fixes the bug. + if( oChar == oItem ) + { + oChar = GetEnteringObject(); + } + + // Check if the item being dropped is a spell-like abilities item. + if( ! SEI_DropSubraceItem( oItem ) ) + { + + // SEI_NOTE: Here one could test for other items. + + } + +} // End main + diff --git a/src/_removed/sei_subraceinit.nss b/src/_removed/sei_subraceinit.nss new file mode 100644 index 0000000..3f60be5 --- /dev/null +++ b/src/_removed/sei_subraceinit.nss @@ -0,0 +1,16 @@ +// +// NWSubraceInit +// +// Subrace initialization script. +// To be placed in the OnClientEnter event of the module. +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + +void main() +{ + Subraces_InitSubrace( GetEnteringObject() ); +} diff --git a/src/_removed/sei_subracelvlup.nss b/src/_removed/sei_subracelvlup.nss new file mode 100644 index 0000000..0bbbcb9 --- /dev/null +++ b/src/_removed/sei_subracelvlup.nss @@ -0,0 +1,16 @@ +// +// NWSubraceLevelUp +// +// Subrace level up script. +// To be placed in the OnPlayerLevelUp event of the module. +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + +void main() +{ + Subraces_LevelUpSubrace( GetPCLevellingUp() ); +} diff --git a/src/_removed/sei_subraces.dlg b/src/_removed/sei_subraces.dlg new file mode 100644 index 0000000..b166028 Binary files /dev/null and b/src/_removed/sei_subraces.dlg differ diff --git a/src/_removed/sei_subraces.nss b/src/_removed/sei_subraces.nss new file mode 100644 index 0000000..122066b --- /dev/null +++ b/src/_removed/sei_subraces.nss @@ -0,0 +1,1464 @@ +// HCR 5.5 change by Lorinton +// Modified to reduce (hopefully eliminate) subrace effects being stripped by the game +// and other effects such as level drain being stripped by the subrace system. +// +// NWSubraces +// +// Basic subrace functionality - private stuff +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// +// ************************************************************** +// ** Constants +// ********************** +// Constant to note if we are currently debugging. Should be FALSE in release version. +int SUBRACE_DEBUG = FALSE; +// Constant to note if we're using the subrace hide or the subrace effects. +int USE_SUBRACE_HIDE = FALSE; +// Lorinton change +// Use a constant to indicate a mix of subrace hide and effects. +int USE_SUBRACE_MIX = TRUE; +// Name of the subrace field on the characters. +string SUBRACE_FIELD = "SUBRACE_CHARACTER"; +// Base field name used to save subrace information. +string SUBRACE_STRUCT_TAG = "SUBRACE"; +// Field name for the number of stored subraces. +string SUBRACE_COUNT = "SUBRACE_COUNT"; +// Base field name for the mapping of subrace ID to index. +string SUBRACE_IDMAP = "SUBRACE_IDMAP"; +// Base field name for the mapping of subrace ID to description. +string SUBRACE_DESCMAP = "SUBRACE_DESCMAP"; +// The field name for the area settings. +string AREA_SETTING = "AREA_SETTING"; +// The Field name for the light setting on the character. +string LIGHT_SETTING = "LIGHT_SETTING"; +// The Field name for the ground setting on the character. +string GROUND_SETTING = "GROUND_SETTING"; +// ************************************************************** +// ** Forward declarations +// ********************** +// Private function for the subraces script. Do not use. +effect SEI_ParseTrait( object a_oCharacter, string a_sTrait ); +// Private function for the subraces script. Do not use. +void SEI_DefineSubraces(); +// Lorinton change +void SEI_InitSubrace( object a_oCharacter ); +// ************************************************************** +// ** Feedback functions +// ********************** +// Write an entry for subraces in the log. +// +void SEI_WriteSubraceLogEntry( string a_sLogEntry, int a_bIsDebug = FALSE ) +{ + // If this is a normal log entry or if we are debugging. + if( !a_bIsDebug || SUBRACE_DEBUG ) + { + // Write entry to log file. + WriteTimestampedLogEntry( "SEI Subraces: " + a_sLogEntry ); + } +} +// Send a subraces message to a PC. +// +void SEI_SendSubraceMessageToPC( object a_oPC, string a_sMessage ) +{ + // First make sure we actually have a valid PC + if( GetIsPC( a_oPC ) ) + { + SEI_WriteSubraceLogEntry( a_sMessage, TRUE ); + SendMessageToPC( a_oPC, "[Subraces] " + a_sMessage ); + } +} +// Translates the subrace enum to a readable string. +// +string SEI_SubraceEnumToString( int a_nSubrace ) +{ + if( a_nSubrace == SUBRACE_NONE ) + { + return "subrace not initialized"; + } + else if( a_nSubrace == SUBRACE_MONSTER ) + { + return "Monster"; + } + else + { + return GetLocalString( GetModule(), SUBRACE_DESCMAP + IntToString( a_nSubrace ) ); + } +} // End SEI_SubraceEnumToString +// Send a message to the character that the subrace has been initialized. +// +void SEI_SendSubraceInitMsg( object a_oCharacter, int a_nSubrace ) +{ + // Send a message to the PC that the subrace was successfully initialized. + if( GetIsPC( a_oCharacter ) ) + { + // Get the textual description of the subrace. + string sSubraceDesc = SEI_SubraceEnumToString( a_nSubrace ); + // Write a debug message to the log. + SEI_WriteSubraceLogEntry( + "Subrace field of character '" + GetName( a_oCharacter ) + + "' (played by '" + GetPCPlayerName( a_oCharacter ) + + "') is '" + GetSubRace( a_oCharacter ) + + "', which has been interpreted as [" + IntToString( a_nSubrace ) + + "] '" + sSubraceDesc + "' and set accordingly." ); + // Tell the player that the subrace was initialized. + SEI_SendSubraceMessageToPC( a_oCharacter, + "Your subrace field has been interpreted as '" + sSubraceDesc + + "' and your abilities have been set accordingly." ); + } // End if +} // End SEI_SendSubraceInitMsg +// ************************************************************** +// ** Subrace data functions +// ********************** +// Returns a new subrace structure and saves it to the global object. +// +struct Subrace SEI_CreateSubrace( int a_nSubrace, int a_nBaseRace, string a_sDescription ) +{ + // The struct we're creating. + struct Subrace stSubrace; + // Global object to store the values on. + object oModule = GetModule(); + // Number of subraces already added (highest index is nSubraceCount-1) + int nSubraceCount = GetLocalInt( oModule, SUBRACE_COUNT ); + // Store the values in the new struct. + stSubrace.m_nID = a_nSubrace; + stSubrace.m_nBaseRace = a_nBaseRace; + stSubrace.m_nNumFieldValues = 0; + stSubrace.m_nNumTraits = 0; + stSubrace.m_bSpellResistance = 0; + stSubrace.m_nLightSensitivity = 0; + stSubrace.m_fLightBlindness = 0.0; + stSubrace.m_nStonecunning = 0; + stSubrace.m_nSpellLikeAbility = 0; + stSubrace.m_nECLAdd = 0; + stSubrace.m_nFavoredClassF = -1; + stSubrace.m_nFavoredClassM = -1; + stSubrace.m_bIsDefault = FALSE; + // Save the mapping of subrace ID to index. + SetLocalInt( oModule, SUBRACE_IDMAP + IntToString(a_nSubrace), nSubraceCount ); + // Save the textual description of this subrace + // SEI_NOTE: Storing strings in structs doesn't seem to work. Hence done this way. + SetLocalString( GetModule(), SUBRACE_DESCMAP + IntToString( a_nSubrace ), a_sDescription ); + // Increase the number of added subraces. + SetLocalInt( oModule, SUBRACE_COUNT, ++nSubraceCount ); + return stSubrace; +} // End SEI_CreateSubrace +// Adds a new field text for the subrace. +// These field texts translate to matches in the subrace field on the character +// sheet; if the field contains one of these texts the subrace will match. +// +struct Subrace SEI_AddFieldText( struct Subrace a_stSubrace, string a_sText ) +{ + // Global object to store the values on. + object oModule = GetModule(); + // The field name to store the new text under. + string sTag = SUBRACE_STRUCT_TAG + IntToString(a_stSubrace.m_nID) + + "_FIELD" + IntToString(a_stSubrace.m_nNumFieldValues); + // Store the text. + SetLocalString( oModule, sTag, a_sText ); + // Increase the number of stored texts. + ++(a_stSubrace.m_nNumFieldValues); + return a_stSubrace; +} // End SEI_AddFieldText +// Adds a trait for the subrace. +// These trait strings are parsed into the effects applied to the character. +// +struct Subrace SEI_AddTrait( struct Subrace a_stSubrace, string a_sTrait ) +{ + // Global object to store the values on. + object oModule = GetModule(); + // The field name to store the new trait under. + string sTag = SUBRACE_STRUCT_TAG + IntToString(a_stSubrace.m_nID) + + "_TRAIT" + IntToString(a_stSubrace.m_nNumTraits); + // Store the text. + SetLocalString( oModule, sTag, a_sTrait ); + // Increase the number of stored traits. + ++(a_stSubrace.m_nNumTraits); + return a_stSubrace; +} // End SEI_AddTrait +// Returns the mapping of the subrace to the index where the subrace is stored. +// +int SEI_SubraceIDToIdx( int a_nSubrace ) +{ + return GetLocalInt( GetModule(), SUBRACE_IDMAP + IntToString(a_nSubrace) ); +} +// Saves the subrace struct to the module for later retrieval to a specific index. +// +void SEI_SaveSubraceIdx( struct Subrace a_stSubrace, int a_nSubraceIdx ) +{ + // Global object to store the values on. + object oModule = GetModule(); + // The base field name to store the values under. + string sTag = SUBRACE_STRUCT_TAG + IntToString(a_nSubraceIdx) + "_"; + // Save the values from the struct. + SetLocalInt( oModule, sTag + "ID", a_stSubrace.m_nID ); + SetLocalInt( oModule, sTag + "RACE", a_stSubrace.m_nBaseRace ); + SetLocalInt( oModule, sTag + "NFLD", a_stSubrace.m_nNumFieldValues ); + SetLocalInt( oModule, sTag + "NTRT", a_stSubrace.m_nNumTraits ); + SetLocalInt( oModule, sTag + "SRES", a_stSubrace.m_bSpellResistance ); + SetLocalInt( oModule, sTag + "LSEN", a_stSubrace.m_nLightSensitivity ); + SetLocalFloat( oModule, sTag + "LBLI", a_stSubrace.m_fLightBlindness ); + SetLocalInt( oModule, sTag + "STON", a_stSubrace.m_nStonecunning ); + SetLocalInt( oModule, sTag + "SLA", a_stSubrace.m_nSpellLikeAbility ); + SetLocalInt( oModule, sTag + "ECL", a_stSubrace.m_nECLAdd ); + SetLocalInt( oModule, sTag + "FAVF", a_stSubrace.m_nFavoredClassF ); + SetLocalInt( oModule, sTag + "FAVM", a_stSubrace.m_nFavoredClassM ); + SetLocalInt( oModule, sTag + "DEF", a_stSubrace.m_bIsDefault ); +} // End SEI_SaveSubraceIdx +// Loads the subrace struct from the module at a specific index. +// +struct Subrace SEI_LoadSubraceIdx( int a_nSubraceIdx ) +{ + // The structure that the data will be loaded into. + struct Subrace stSubrace; + // Global object where the values are stored. + object oModule = GetModule(); + // The base field name the values are stored under. + string sTag = SUBRACE_STRUCT_TAG + IntToString(a_nSubraceIdx) + "_"; + // Load the values into the struct. + stSubrace.m_nID = GetLocalInt( oModule, sTag + "ID" ); + stSubrace.m_nBaseRace = GetLocalInt( oModule, sTag + "RACE" ); + stSubrace.m_nNumFieldValues = GetLocalInt( oModule, sTag + "NFLD" ); + stSubrace.m_nNumTraits = GetLocalInt( oModule, sTag + "NTRT" ); + stSubrace.m_bSpellResistance = GetLocalInt( oModule, sTag + "SRES" ); + stSubrace.m_nLightSensitivity = GetLocalInt( oModule, sTag + "LSEN" ); + stSubrace.m_fLightBlindness = GetLocalFloat( oModule, sTag + "LBLI" ); + stSubrace.m_nStonecunning = GetLocalInt( oModule, sTag + "STON" ); + stSubrace.m_nSpellLikeAbility = GetLocalInt( oModule, sTag + "SLA" ); + stSubrace.m_nECLAdd = GetLocalInt( oModule, sTag + "ECL" ); + stSubrace.m_nFavoredClassF = GetLocalInt( oModule, sTag + "FAVF" ); + stSubrace.m_nFavoredClassM = GetLocalInt( oModule, sTag + "FAVM" ); + stSubrace.m_bIsDefault = GetLocalInt( oModule, sTag + "DEF" ); + return stSubrace; +} // End SEI_LoadSubraceIdx +// Saves the subrace struct to the module for later retrieval. +// +void SEI_SaveSubrace( struct Subrace a_stSubrace ) +{ + SEI_SaveSubraceIdx( a_stSubrace, SEI_SubraceIDToIdx( a_stSubrace.m_nID ) ); +} +// Loads the subrace struct from the module. +// +struct Subrace SEI_LoadSubrace( int a_nSubrace ) +{ + return SEI_LoadSubraceIdx( SEI_SubraceIDToIdx( a_nSubrace ) ); +} +// Returns the ECL modification for the character. +// +int SEI_GetECLAdd( object a_oCharacter ) +{ + int nECLAdd = 0; + // Read the local variable off the character. + int nSubrace = GetLocalInt( a_oCharacter, SUBRACE_FIELD ); + // Make sure we actually have a subrace. + if( nSubrace != SUBRACE_NONE ) + { + // Load the information on the character's subrace. + struct Subrace stSubrace = SEI_LoadSubrace( nSubrace ); + // Get the ECL modification from the subrace information. + nECLAdd = stSubrace.m_nECLAdd; + } // End if + return nECLAdd; +} // End SEI_GetECLAdd +// ************************************************************** +// ** Subrace trait parser functions +// ********************** +// Parse the trait string to get the effect it describes. +// This function recognises traits with three arguments. +// +effect SEI_ParseTrait3( object a_oCharacter, string a_sTrait, string a_sArg1, string a_sArg2, string a_sArg3 ) +{ + effect eResult; + if( a_sTrait == "save_inc" ) + { + eResult = EffectSavingThrowIncrease( StringToInt(a_sArg1), StringToInt(a_sArg2), StringToInt(a_sArg3) ); + } + else if( a_sTrait == "save_dec" ) + { + eResult = EffectSavingThrowDecrease( StringToInt(a_sArg1), StringToInt(a_sArg2), StringToInt(a_sArg3) ); + } +//////////////////////// +// Lorinton change +// Add damage resistance + else if( a_sTrait == "dam_resist" ) + { + eResult = EffectDamageResistance( StringToInt( a_sArg1 ), StringToInt( a_sArg2 ), StringToInt( a_sArg3 )); + } +// end Lorinton change +//////////////////////// + else + { + SEI_WriteSubraceLogEntry( "Unable to parse trait: '" + + a_sTrait + " " + a_sArg1 + " " + a_sArg2 + " " + a_sArg3 + "'" ); + } + return eResult; +} // End SEI_ParseTrait3 +// Parse the trait string to get the effect it describes. +// This function recognises traits with two arguments. +// +effect SEI_ParseTrait2( object a_oCharacter, string a_sTrait, string a_sArg1, string a_sArg2 ) +{ + effect eResult; + if( a_sTrait == "ability_inc" ) + { + eResult = EffectAbilityIncrease( StringToInt(a_sArg1), StringToInt(a_sArg2) ); + } + else if( a_sTrait == "ability_dec" ) + { + eResult = EffectAbilityDecrease( StringToInt(a_sArg1), StringToInt(a_sArg2) ); + } + else if( a_sTrait == "skill_inc" ) + { + eResult = EffectSkillIncrease( StringToInt(a_sArg1), StringToInt(a_sArg2) ); + } + else if( a_sTrait == "skill_dec" ) + { + eResult = EffectSkillDecrease( StringToInt(a_sArg1), StringToInt(a_sArg2) ); + } + else if( a_sTrait == "vs" ) + { + effect eEffect = SEI_ParseTrait( a_oCharacter, a_sArg2 ); + eResult = VersusRacialTypeEffect( eEffect, StringToInt( a_sArg1 ) ); + } + else + { + int nSplit = FindSubString( a_sArg2, " " ); + if( nSplit >= 0 ) + { + string sHead = GetStringLeft( a_sArg2, nSplit ); + string sTail = GetStringRight( a_sArg2, GetStringLength(a_sArg2) - ( nSplit + 1 ) ); + eResult = SEI_ParseTrait3( a_oCharacter, a_sTrait, a_sArg1, sHead, sTail ); + } + else + { + SEI_WriteSubraceLogEntry( "Unable to parse trait: '" + + a_sTrait + " " + a_sArg1 + " " + a_sArg2 + "'" ); + } + } // End if-elseif-else + return eResult; +} // End SEI_ParseTrait2 +// Parse the trait string to get the effect it describes. +// This function recognises traits with one argument. +// +effect SEI_ParseTrait1( object a_oCharacter, string a_sTrait, string a_sArg1 ) +{ + effect eResult; + if( a_sTrait == "ac_inc" ) + { + eResult = EffectACIncrease( StringToInt(a_sArg1) ); + } + else if( a_sTrait == "ac_dec" ) + { + eResult = EffectACDecrease( StringToInt(a_sArg1) ); + } + else if( a_sTrait == "attack_inc" ) + { + eResult = EffectAttackIncrease( StringToInt(a_sArg1) ); + } + else if( a_sTrait == "attack_dec" ) + { + eResult = EffectAttackDecrease( StringToInt(a_sArg1) ); + } + else if( a_sTrait == "immune" ) + { + eResult = EffectImmunity( StringToInt(a_sArg1) ); + } + else if( a_sTrait == "ex" ) + { + effect eEffect = SEI_ParseTrait( a_oCharacter, a_sArg1 ); + eResult = ExtraordinaryEffect( eEffect ); + } + else if( a_sTrait == "su" ) + { + effect eEffect = SEI_ParseTrait( a_oCharacter, a_sArg1 ); + eResult = SupernaturalEffect( eEffect ); + } + else if( a_sTrait == "m" ) + { + if( GetGender( a_oCharacter ) == GENDER_MALE ) + { + eResult = SEI_ParseTrait( a_oCharacter, a_sArg1 ); + } + } + else if( a_sTrait == "f" ) + { + if( GetGender( a_oCharacter ) == GENDER_FEMALE ) + { + eResult = SEI_ParseTrait( a_oCharacter, a_sArg1 ); + } + } + else + { + int nSplit = FindSubString( a_sArg1, " " ); + if( nSplit >= 0 ) + { + string sHead = GetStringLeft( a_sArg1, nSplit ); + string sTail = GetStringRight( a_sArg1, GetStringLength(a_sArg1) - ( nSplit + 1 ) ); + eResult = SEI_ParseTrait2( a_oCharacter, a_sTrait, sHead, sTail ); + } + else + { + SEI_WriteSubraceLogEntry( "Unable to parse trait: '" + + a_sTrait + " " + a_sArg1 + "'" ); + } + } // End if-elseif-else + return eResult; +} // End SEI_ParseTrait1 +// Parse the trait string to get the effect it describes. +// This function recognises traits without arguments. +// +effect SEI_ParseTrait( object a_oCharacter, string a_sTrait ) +{ + effect eResult; + if( a_sTrait == "darkvision" ) + { + eResult = EffectVisualEffect( VFX_DUR_DARKVISION ); + } + else + { + int nSplit = FindSubString( a_sTrait, " " ); + if( nSplit >= 0 ) + { + string sHead = GetStringLeft( a_sTrait, nSplit ); + string sTail = GetStringRight( a_sTrait, GetStringLength(a_sTrait) - ( nSplit + 1 ) ); + eResult = SEI_ParseTrait1( a_oCharacter, sHead, sTail ); + } + else + { + SEI_WriteSubraceLogEntry( "Unable to parse trait: '" + a_sTrait + "'" ); + } + } // End if-else + return eResult; +} // End SEI_ParseTrait +// ************************************************************** +// ** Subrace initialization functions +// ********************** +// Initializes the available subraces and everything that is needed to properly +// run this script. +// +void SEI_InitSubraces() +{ + struct Subrace stSubrace; + // First define an invalid subrace. + stSubrace = SEI_CreateSubrace( SUBRACE_NONE, RACIAL_TYPE_INVALID, "Invalid subrace" ); + stSubrace.m_bIsDefault = TRUE; + SEI_SaveSubrace( stSubrace ); + // Then define all the other subraces. + SEI_DefineSubraces(); +} // End SEI_InitSubraces +// Sets the subrace field on a_oCharacter to a_nSubrace. +// +void SEI_SetSubraceVar( object a_oCharacter, int a_nSubrace, int a_bPrintToLog = TRUE ) +{ + if( a_oCharacter != OBJECT_INVALID ) + { + SEI_WriteSubraceLogEntry( + "Setting subrace variable of character '" + GetName(a_oCharacter) + + "' (played by '" + GetPCPlayerName(a_oCharacter) + + "') to [" + IntToString(a_nSubrace) + + "] '" + SEI_SubraceEnumToString(a_nSubrace) + "'.", !a_bPrintToLog ); + // Store the subrace on the character for easy reference later. + SetLocalInt( a_oCharacter, SUBRACE_FIELD, a_nSubrace ); + } // End if +} // End SEI_SetSubraceVar +// Test to see if the subrace field (and base race) match to this subrace. +// +int SEI_TestSubraceField( struct Subrace a_stSubrace, int a_nRace, string a_sSubraceField ) +{ + int nSubrace = SUBRACE_NONE; + // If subrace's base race matches the to be tested race. + if( a_stSubrace.m_nBaseRace == a_nRace ) + { + // Global object whre the values are stored. + object oModule = GetModule(); + // Basic field name of the stored field texts. + string sTag = SUBRACE_STRUCT_TAG + IntToString(a_stSubrace.m_nID) + "_FIELD"; + // If this subrace is a default and no subrace was specified then use this subrace. + if( a_stSubrace.m_bIsDefault && ( GetStringLength( a_sSubraceField ) == 0 ) ) + { + nSubrace = a_stSubrace.m_nID; + } + else + { + // For each text stored (and so long as we haven't found a match). + int nField; + for( nField = 0 ; + ( nField < a_stSubrace.m_nNumFieldValues ) && ( nSubrace == SUBRACE_NONE ) ; + ++nField ) + { + // Get the field text and test for a match. + string sFieldText = GetLocalString( oModule, sTag + IntToString(nField) ); + if( FindSubString( a_sSubraceField, sFieldText ) != -1 ) + { + nSubrace = a_stSubrace.m_nID; + } + } + } // End if-else + } // End if + return nSubrace; +} // End SEI_TestSubraceField +// Interpret the subrace string and return the subrace enum. +// +int SEI_ReadSubraceField( int a_nRace, string a_sSubraceField ) +{ + int nSubrace = SUBRACE_NONE; + // Get the total number of added subraces. + int nNrSubraces = GetLocalInt( GetModule(), SUBRACE_COUNT ); + // For each subrace stored (and so long as we haven't found a match). + int nIdx; + for( nIdx = 0 ; ( nIdx < nNrSubraces ) && ( nSubrace == SUBRACE_NONE ) ; ++nIdx ) + { + // Load the subrace information and check to see if there's a match. + struct Subrace stSubrace = SEI_LoadSubraceIdx( nIdx ); + nSubrace = SEI_TestSubraceField( stSubrace, a_nRace, a_sSubraceField ); + } + return nSubrace; +} // End SEI_ReadSubraceField +// Start the subrace dialog for character a_oCharacter. +// +void SEI_StartSubraceDialog( object a_oCharacter ) +{ + if( a_oCharacter != OBJECT_INVALID ) + { + AssignCommand( a_oCharacter, SetCommandable( TRUE, a_oCharacter ) ); + AssignCommand( a_oCharacter, ClearAllActions() ); + AssignCommand( a_oCharacter, ActionStartConversation( a_oCharacter, "sei_subraces", TRUE ) ); + AssignCommand( a_oCharacter, ActionDoCommand( SetCommandable( FALSE, a_oCharacter ) ) ); + } +} +// Reads the character's subrace field and sets the corresponding variable +// on the character. To do this it tries to interpret the subrace field on +// the character sheet. +// +int SEI_InitSubraceVar( object a_oCharacter ) +{ + // Read the local variable off the character. + int nSubrace = GetLocalInt( a_oCharacter, SUBRACE_FIELD ); + // Only initialize the subrace variable if we haven't done so already. + if( nSubrace == SUBRACE_NONE ) + { + string sSubraceField = GetStringLowerCase( GetSubRace( a_oCharacter ) ); + SEI_WriteSubraceLogEntry( "Subrace field of " + GetName( a_oCharacter ) + + " is '" + sSubraceField + "'", TRUE ); + nSubrace = SEI_ReadSubraceField( GetRacialType( a_oCharacter ), sSubraceField ); + SEI_WriteSubraceLogEntry( "Subrace of player " + GetName( a_oCharacter ) + + " interpreted as " + IntToString( nSubrace ) + + " (" + SEI_SubraceEnumToString( nSubrace ) + ")", TRUE ); + // See if we have recognized the subrace or not. + if( nSubrace == SUBRACE_NONE ) + { +//////////////////////////// +// Lorinton change +// Don't bring up the dialog. If the subrace field is wrong just assume there is no subrace. +/* + if( GetIsPC( a_oCharacter ) ) + { + // Ask the player for a subrace we understand. + SEI_StartSubraceDialog( a_oCharacter ); + } + else + { + // Assume the character is a monster. + nSubrace = SUBRACE_MONSTER; + } +*/ + nSubrace = SUBRACE_NONE; +// End Lorinton change +/////////////////////////////// + } + // Store the subrace on the character for easy reference later. + SEI_SetSubraceVar( a_oCharacter, nSubrace, FALSE ); + } // End if + return nSubrace; +} // End SEI_InitSubraceVar +// Remove the subrace hide item of the character. +// +void SEI_RemoveSubraceHide( object a_oCharacter ) +{ + // Get the item stored in the creature hide slot. + object oHide = GetItemInSlot( INVENTORY_SLOT_CARMOUR, a_oCharacter ); + if( GetIsObjectValid( oHide ) && + ( GetStringLeft( GetTag( oHide ), 11 ) == "sei_subrace" ) ) + { + //DestroyObject( oHide ); + } +} // End SEI_RemoveSubraceHide +// Create the subrace hide item on the character. +// +void SEI_CreateSubraceHide( object a_oCharacter, string a_sHide ) +{ + object oHide = CreateItemOnObject( a_sHide, a_oCharacter ); + if( oHide != OBJECT_INVALID ) + { + //AssignCommand( a_oCharacter, ActionEquipItem( oHide, INVENTORY_SLOT_CARMOUR ) ); + //ActionEquipItem( oHide, INVENTORY_SLOT_CARMOUR ); + } +} // End SEI_CreateSubraceHide +// Set the subrace hide item of the character to a_sHide. +// +void SEI_GiveSubraceHide( object a_oCharacter, string a_sHide ) +{ + //object oHide = GetItemInSlot( INVENTORY_SLOT_CARMOUR, a_oCharacter ); + string sHideTag = GetTag( oHide ); + // If this item isn't already equiped. + if( sHideTag != a_sHide ) + { + // Let the character stop doing whatever it is doing. + AssignCommand( a_oCharacter, ClearAllActions() ); + // First remove whatever hide item is already set on the character. + AssignCommand( a_oCharacter, ActionDoCommand( SEI_RemoveSubraceHide( a_oCharacter ) ) ); + // Create the subrace hide and equip it. + // SEI_NOTE: Assigned as an action to correctly follow the removal of the item. + AssignCommand( a_oCharacter, ActionDoCommand( SEI_CreateSubraceHide( a_oCharacter, a_sHide ) ) ); + } // End if +} // End SEI_GiveSubraceHide +// ************************************************************** +// ** Subrace area functions +// ********************** +// Read a specific setting of the settings. +// +int SEI_ReadAreaSetting( int a_nSettings, int a_nUnit ) +{ + if( a_nUnit == 0 ) + { + return AREA_NONE; + } + else + { + // SEI_NOTE: Making use of the integer-division rounding here. + return ( ( ( a_nSettings % ( 10 * a_nUnit ) ) / a_nUnit ) * a_nUnit ); + } +} +// Get an area setting. +// +int SEI_GetAreaSetting( object a_oArea, int a_nSettings, int a_nUnit ) +{ + // Read the passed settings to get the specific setting. + int nResult = SEI_ReadAreaSetting( a_nSettings, a_nUnit ); + // If we want to use the default for the area... + if( nResult <= a_nUnit ) + { + // Read the area settings from the area. + int nAreaSetting = GetLocalInt( a_oArea, AREA_SETTING ); + // Get the area setting. + nResult = SEI_ReadAreaSetting( nAreaSetting, a_nUnit ); + // If the area uses the module default... + if( nResult <= a_nUnit ) + { + // Get the module. + object oModule = GetModule(); + // Read the default settings from the module. + nAreaSetting = GetLocalInt( oModule, AREA_SETTING ); + // Get the default setting. + nResult = SEI_ReadAreaSetting( nAreaSetting, a_nUnit ); + // We're already at the default, so if it's default again then nothing is set. + if( nResult <= a_nUnit ) + { + nResult = AREA_NONE; + } + } // End if + } // End if + return nResult; +} // End SEI_GetAreaSetting +// Sets the area settings for the area. +// SEI_NOTE: I'd much rather use the toolset area settings, but I can't +// access them from script. +// +void SEI_SetAreaSettings( object a_oArea, int a_nSettings ) +{ + // If we have a valid object. + if( GetIsObjectValid( a_oArea ) ) + { + // Get the current default settings. + int nDefaultSettings = GetLocalInt( a_oArea, AREA_SETTING ); + // Make sure we're not going to set the same settings again. + if( nDefaultSettings != a_nSettings ) + { + // Get the current default light setting. + int nDefaultLight =( nDefaultSettings % 10 ); + // Get the current default underground setting. + int nDefaultGround = ( ( nDefaultSettings % 100 ) / 10 ) * 10; + // Get the rest of the current default settings. + int nDefaultRest =( nDefaultSettings / 100 ) * 100; + // Get the light setting. + int nSettingLight = ( a_nSettings % 10 ); + // Get the underground setting. + int nSettingGround = ( ( a_nSettings % 100 ) / 10 ) * 10; + // If we're trying to set the light setting, then change it. + if( nSettingLight > 0 ) + { + nDefaultLight = nSettingLight; + } + // If we're trying to set the underground setting, then change it. + if( nSettingGround > 0 ) + { + nDefaultGround = nSettingGround; + } + // Combine the new settings to get the new default setting. + int nNewDefaultSettings = nDefaultRest + nDefaultGround + nDefaultLight; + // Set the new settings if they have changed. + if( nNewDefaultSettings != nDefaultSettings ) + { + SetLocalInt( a_oArea, AREA_SETTING, nNewDefaultSettings ); + } + } // End if + } // End if +} // End SEI_SetAreaSettings +// Sets the default area settings for the module. +// +void SEI_SetDefaultAreaSettings( int a_nSettings ) +{ + // Get the module to store the defaults on. + object oModule = GetModule(); + // Set the default settings on the module object. + // SEI_NOTE: This is a bit of a sneaky way of doing this, but since the + // SEI_SetAreaSettings functions doesn't use the fact that it is + // an area being passed to it, it works. + SEI_SetAreaSettings( oModule, a_nSettings ); +} // End SEI_SetDefaultAreaSettings +// Remove the effects from the character if it isn't a subrace effect. +// +void SEI_RemoveEffect( object a_oCharacter, effect a_eEffect ) +{ + // Only remove effects not applied by the module. + if(( GetEffectCreator( a_eEffect ) != GetModule() ) && + ( GetEffectSubType( a_eEffect ) != SUBTYPE_EXTRAORDINARY ) ) // Lorinton change, was supernatural + { + RemoveEffect( a_oCharacter, a_eEffect ); + // Lorinton change, the RemoveEffect function appears to be very buggy, redo the subrace afterwards + SEI_InitSubrace( a_oCharacter ); + } +} // End SEI_RemoveEffect + +// Remove the effects from the character if it isn't a subrace effect. +// +void SEI_RemoveEffects( object a_oCharacter ) +{ + effect a_eEffect; + // Go through all effects on the character. + effect eEffect = GetFirstEffect( a_oCharacter ); + while( GetIsEffectValid( eEffect ) ) + { + // Lorinton change + // Added the check for extraordinary effect + if(( GetEffectCreator( a_eEffect ) != GetModule() ) && + ( GetEffectSubType( eEffect ) != SUBTYPE_EXTRAORDINARY ) ) + { + RemoveEffect( a_oCharacter, eEffect ); + } + eEffect = GetNextEffect( a_oCharacter ); + } // End while + // Lorinton change, the RemoveEffect function appears to be very buggy, redo the subrace afterwards + SEI_InitSubrace( a_oCharacter ); +} // End SEI_RemoveEffects +// Remove the subrace effects from the character. +// +void SEI_RemoveSubraceEffects( object a_oCharacter, int a_bIncludePermanent = TRUE, + int a_iEffectType = EFFECT_TYPE_INVALIDEFFECT ) +{ + // Go through all effects on the character. + effect eEffect = GetFirstEffect( a_oCharacter ); + while( GetIsEffectValid( eEffect ) ) + { + // Only remove subrace effects. + // Lorinton change + // Switch from supernatural to extraordinary + if( ( GetEffectSubType( eEffect ) == SUBTYPE_EXTRAORDINARY ) && + ( ( a_iEffectType == EFFECT_TYPE_INVALIDEFFECT ) || + ( GetEffectType( eEffect ) == a_iEffectType ) ) && + ( ( a_bIncludePermanent ) || + ( GetEffectCreator( eEffect ) != GetModule() ) ) ) + { + RemoveEffect( a_oCharacter, eEffect ); + } + eEffect = GetNextEffect( a_oCharacter ); + } // End while +} // End SEI_RemoveSubraceEffects +void SEI_ApplyEffectToObject( int a_nDurationType, effect a_eEffect, object a_oTarget, float a_fDuration = 0.0, int a_bPermanent = FALSE ) +{ + // Make the effect supernatural so that it persists through resting. + // Lorinton change + // Switch to extraordinary from supernatural + AssignCommand( ( a_bPermanent ? GetModule() : GetArea( a_oTarget ) ), + ApplyEffectToObject( a_nDurationType, ExtraordinaryEffect( a_eEffect ), a_oTarget, a_fDuration )); +} // End SEI_ApplyEffectToObject +// Create the effect simulating stonecunning. +// +effect SEI_EffectStonecunning() +{ + // Stonecunning gives +2 on search checks while underground. + effect eResult = EffectSkillIncrease( SKILL_SEARCH, 2 ); + // +2 to Hide checks while underground. + // SEI_NOTE: Included in Stonecunning to safe from adding yet another attribute. + eResult = EffectLinkEffects( eResult, + EffectSkillIncrease( SKILL_HIDE, 2 ) ); + return eResult; +} // End SEI_EffectStonecunning +// Create the effect simulating light sensitivity. +// +effect SEI_EffectLightSensitivity( int a_nSeverity ) +{ + // Decrease attack rolls. + effect eResult = EffectAttackDecrease( a_nSeverity ); + // Decrease all saving throws. + eResult = EffectLinkEffects( eResult, + EffectSavingThrowDecrease( SAVING_THROW_ALL, a_nSeverity, SAVING_THROW_TYPE_ALL ) ); + // Decrease all skill checks. + eResult = EffectLinkEffects( eResult, + EffectSkillDecrease( SKILL_ALL_SKILLS, a_nSeverity ) ); + return eResult; +} // End SEI_EffectLightSensitivity +// Apply the area settings to the character. +// +void SEI_ApplyAreaSettings( object a_oCharacter, int a_nSettings ) +{ + // If we have something to work with. + if( GetIsObjectValid( a_oCharacter ) ) + { + // Read the local variable off the character. + int nSubrace = GetLocalInt( a_oCharacter, SUBRACE_FIELD ); + // Make sure we actually have a subrace. + if( nSubrace != SUBRACE_NONE ) + { + // Load the information on the character's subrace. + struct Subrace stSubrace = SEI_LoadSubrace( nSubrace ); + // Get the area the character is in. + object oArea = GetArea( a_oCharacter ); + // If this subrace has stonecunning... + if( stSubrace.m_nStonecunning ) + { + // Get the ground setting (underground/above ground). + int nGroundSetting = SEI_GetAreaSetting( oArea, a_nSettings, 10 ); + // Get if the character thinks it's above or underground. + int nCharGround = GetLocalInt( a_oCharacter, GROUND_SETTING ); + // If this area is underground... + if( nGroundSetting == AREA_UNDERGROUND ) + { + // If the character just went underground. + if( nCharGround != AREA_UNDERGROUND ) + { + // Apply the stonecunning effect to the character. + SEI_ApplyEffectToObject( + DURATION_TYPE_PERMANENT, + SEI_EffectStonecunning(), + a_oCharacter ); + // Remember that the character is underground. + SetLocalInt( a_oCharacter, GROUND_SETTING, AREA_UNDERGROUND ); + } // End if + } + else + { + // If the character just came above ground. + if( nCharGround != AREA_ABOVEGROUND ) + { + // Remove the stonecunning effect. + SEI_RemoveSubraceEffects( a_oCharacter, FALSE, EFFECT_TYPE_SKILL_INCREASE ); + // Remember that the character is above ground. + SetLocalInt( a_oCharacter, GROUND_SETTING, AREA_ABOVEGROUND ); + } // End if + } // End if-else + } // End if (Stonecunning) + // If this subrace is sensitive to light... + if( stSubrace.m_nLightSensitivity > 0 ) + { + // Get the light setting. + int nLightSetting = SEI_GetAreaSetting( oArea, a_nSettings, 1 ); + // Get the amount of light the character is in. + int nCharLight = GetLocalInt( a_oCharacter, LIGHT_SETTING ); + // If the character is in a light area... + if( ( nLightSetting == AREA_LIGHT ) || + ( ( nLightSetting == AREA_SUN ) && ( GetIsDay() || GetIsDawn() ) ) ) + { + // If the character just entered a light area. + if( nCharLight != AREA_LIGHT ) + { + // Apply the light sensitivity effect to the character. + SEI_ApplyEffectToObject( + DURATION_TYPE_PERMANENT, + SEI_EffectLightSensitivity( stSubrace.m_nLightSensitivity ), + a_oCharacter ); + // If the character is blinded by bright light... + if( stSubrace.m_fLightBlindness > 0.0 ) + { + // Blind the character for the time specified. + SEI_ApplyEffectToObject( + DURATION_TYPE_TEMPORARY, + EffectBlindness(), + a_oCharacter, + stSubrace.m_fLightBlindness ); + } // End if + // Remember that the character is in a light area. + SetLocalInt( a_oCharacter, LIGHT_SETTING, AREA_LIGHT ); + } // End if + } + else + { + // If the character just entered a dark area. + if( nCharLight != AREA_DARK ) + { + // Remove the light sensitivity effect. + SEI_RemoveSubraceEffects( a_oCharacter, FALSE, EFFECT_TYPE_SKILL_DECREASE ); + // Remember that the character is in a dark area. + SetLocalInt( a_oCharacter, LIGHT_SETTING, AREA_DARK ); + } // End if + } // End if-else + } // End if (Light sensitivity) + } // End if + } // End if +} // End SEI_ApplyAreaSettings +// Set spacial traits to a character when the characters enters an area. +// +void SEI_EnterArea( object a_oCharacter, int a_nSettings ) +{ + // If we have something to work with. + if( GetIsObjectValid( a_oCharacter ) ) + { + // Get the area the character is in. + object oArea = GetArea( a_oCharacter ); + // Save the settings as the area settings. + SEI_SetAreaSettings( oArea, a_nSettings ); + // Apply the settings to the character. + SEI_ApplyAreaSettings( a_oCharacter, a_nSettings ); + } // End if +} // End SEI_EnterArea +void SEI_AreaHeartbeat( object a_oArea ) +{ + // Get the area's light setting setting. + int nAreaLightSetting = SEI_ReadAreaSetting( GetLocalInt( a_oArea, AREA_SETTING ), 1 ); + if( nAreaLightSetting == AREA_SUN ) + { + // Is it currently light or dark? + int bIsLight = ( GetIsDay() || GetIsDawn() ); + // What does the area think it is? + int nAreaLight = GetLocalInt( a_oArea, LIGHT_SETTING ); + // Variable of whether the characters in the area need updating. + int bMustUpdate = FALSE; + // If it is light, but the area still thinks it's dark... + if( bIsLight && ( nAreaLight != AREA_LIGHT ) ) + { + // We must update the characters in the area. + bMustUpdate = TRUE; + // Update the light setting of the area. + SetLocalInt( a_oArea, LIGHT_SETTING, AREA_LIGHT ); + } + // If it is dark, but the area still thinks it's light... + else if( !bIsLight && ( nAreaLight != AREA_DARK ) ) + { + // We must update the characters in the area. + bMustUpdate = TRUE; + // Update the light setting of the area. + SetLocalInt( a_oArea, LIGHT_SETTING, AREA_DARK ); + } // End if-elseif + // If the characters in the area must be updated. + if( bMustUpdate ) + { + // Go through all the PCs. + object oPC = GetFirstPC(); + while( GetIsObjectValid( oPC ) ) + { + // If the PC is in this area then update the character. + if( GetArea( oPC ) == a_oArea ) + { + SEI_ApplyAreaSettings( oPC, 0 ); + } + oPC = GetNextPC(); + } // End while + } // End if + } // End if +} // End SEI_AreaHeartbeat +// ************************************************************** +// ** Subrace initialization functions (cont.) +// ********************** +// Set the character's correct hide item based on the subrace. +// +void SEI_SetSubraceHide( struct Subrace a_stSubrace, object a_oCharacter ) +{ + // If we're using the subrace hide instead of the subrace effects.... + if( USE_SUBRACE_HIDE ) + { + // Default subraces don't have any traits (past the default). + if( a_stSubrace.m_bIsDefault ) + { + // Give the subrace hide item without any attributes. + SEI_GiveSubraceHide( a_oCharacter, "sei_subrace0" ); + } + else + { + // Give the subrace hide item with the traits. + SEI_GiveSubraceHide( a_oCharacter, "sei_subrace_" + IntToString( a_stSubrace.m_nID ) ); + } + } + else + { + SEI_RemoveSubraceHide( a_oCharacter ); + } // End if-else +} // End SEI_SetSubraceHide +// Give the spell-like abilities to the character depending on the subrace. +// +void SEI_GiveSpellLikeAbilities( struct Subrace a_stSubrace, object a_oCharacter ) +{ + // If this subrace has a spell-like ability then give it to them. + if( a_stSubrace.m_nSpellLikeAbility > 0 ) + { + // Create the tag for the item. + string sItemTag = "sei_sla_" + IntToString( a_stSubrace.m_nSpellLikeAbility ); + // Get an item with the tag (if the character has one). + object oSpellItem = GetItemPossessedBy( a_oCharacter, sItemTag ); + // If the character doesn't have the item yet... + if( ! GetIsObjectValid( oSpellItem ) ) + { + // Create a new spell-like abilities item on the character. + CreateItemOnObject( sItemTag, a_oCharacter ); + } + } // End if +} // End SEI_GiveSpellLikeAbilities +// Apply the subrace traits for this subrace to the character. +// +void SEI_ApplySubraceTraits( struct Subrace a_stSubrace, object a_oCharacter ) +{ + effect eSubraceEffect; + int bFirstValidInited = FALSE; + // Only do this if we're not using the subrace hide item for this. + // Lorinton change + // Using a mix of hide and effects to do this as the effects are disappearing at times. + // The subraces must be defined so that all attributes which can be placed on a hide are. + // The remaining attributes will be handled here. + if( !USE_SUBRACE_HIDE || USE_SUBRACE_MIX ) + { + // Global object where the values are stored. + object oModule = GetModule(); + // Basic field name of the stored traits. + string sTag = SUBRACE_STRUCT_TAG + IntToString(a_stSubrace.m_nID) + "_TRAIT"; + // For each trait stored... + int nTrait; + for( nTrait = 0 ; nTrait < a_stSubrace.m_nNumTraits ; ++nTrait ) + { + // Get the string describing this trait. + string sTraitString = GetLocalString( oModule, sTag + IntToString( nTrait ) ); + if( bFirstValidInited ) + { + // Add the effect to the chain of effects we already have. + eSubraceEffect = SEI_ParseTrait( a_oCharacter, sTraitString ); + eSubraceEffect = EffectLinkEffects( eSubraceEffect, + SEI_ParseTrait( a_oCharacter, sTraitString ) ); + } + else + { + // This may be the first trait, so just parse the trait string. + eSubraceEffect = SEI_ParseTrait( a_oCharacter, sTraitString ); + // If this is the first valid effect then note that so. + if( GetEffectType( eSubraceEffect ) != EFFECT_TYPE_INVALIDEFFECT ) + { + bFirstValidInited = TRUE; + } + } // End if-else + } // End for + } // End if + // If this subrace has spell resistance, apply it based on character level. + if( a_stSubrace.m_bSpellResistance ) + { + // Create the spell resistance effect. + effect eSREffect = EffectSpellResistanceIncrease( 11 + GetHitDice( a_oCharacter ) ); + // Link it if we haven't linked anything yet. + if( bFirstValidInited ) + { + eSubraceEffect = EffectLinkEffects( eSubraceEffect, eSREffect ); + } + else + { + // This is the first valid effect. + eSubraceEffect = eSREffect; + bFirstValidInited = TRUE; + } + } // End if + // If we have something to apply, then apply it to the character. + if( bFirstValidInited ) + { + SEI_ApplyEffectToObject( DURATION_TYPE_PERMANENT, + eSubraceEffect, a_oCharacter, 0.0, TRUE ); + } +} // End SEI_ApplySubraceTraits +// Reads the character's subrace field and sets the corresponding traits +// on the character. +// +void SEI_InitSubraceTraits( object a_oCharacter, int a_bIncludeItems = TRUE ) +{ + // Read the local variable off the character. + int nSubrace = GetLocalInt( a_oCharacter, SUBRACE_FIELD ); + // Make sure we actually have a subrace. + if( nSubrace != SUBRACE_NONE ) + { +// SendMessageToPC( a_oCharacter, "Loading subrace..." ); + // Load the information on the character's subrace. + struct Subrace stSubrace = SEI_LoadSubrace( nSubrace ); + // If we also want to include the items + if( a_bIncludeItems ) + { + // Set the subrace hide item to te character. + SEI_SetSubraceHide( stSubrace, a_oCharacter ); + // Give the spell-like abilities item. + SEI_GiveSpellLikeAbilities( stSubrace, a_oCharacter ); + } // End if +// SendMessageToPC( a_oCharacter, "Applying subrace..." ); + // Apply the subrace's racial traits to the character. + SEI_ApplySubraceTraits( stSubrace, a_oCharacter ); + // Apply effects based on the area settings if needed. + SEI_ApplyAreaSettings( a_oCharacter, 0 ); + } // End if +} // End SEI_InitSubraceTraits +// Remove all possible subrace stuff from the character. +// +void SEI_RemoveSubrace( object a_oCharacter, int a_bRemoveItems = TRUE ) +{ + if( GetIsObjectValid( a_oCharacter ) ) + { + if( a_bRemoveItems ) + { + // Remove the subrace hide. + SEI_RemoveSubraceHide( a_oCharacter ); + int nSpellItem; + for( nSpellItem = 1 ; nSpellItem <= 4 ; ++nSpellItem ) + { + // Get the spell-like ability item. + object oSpellItem = GetItemPossessedBy( a_oCharacter, "sei_sla_" + IntToString( nSpellItem ) ); + // If the character has the object, then destroy it. + if( GetIsObjectValid( oSpellItem ) ) + { + DestroyObject( oSpellItem ); + } + } // End for + } // End if + SEI_RemoveSubraceEffects( a_oCharacter ); + } // End if +} // End SEI_RemoveSubrace +// Initializes the subrace for character a_oCharacter. +// +void SEI_InitSubrace( object a_oCharacter ) +{ + // Sanity check, make sure we have something to work with. + if( GetIsObjectValid( a_oCharacter ) ) + { +// SendMessageToPC( a_oCharacter, "Respawning subrace..." ); + // Get the character's subrace. + int nSubrace = GetLocalInt( a_oCharacter, SUBRACE_FIELD ); + SEI_RemoveSubrace( a_oCharacter, FALSE ); +// SendMessageToPC( a_oCharacter, "Removing subrace..." ); + // See if this character's subrace has been initialized before. + if( nSubrace == SUBRACE_NONE ) + { +// SendMessageToPC( a_oCharacter, "Initializing empty subrace..." ); + // Initialize the subrace variable on the character. + nSubrace = SEI_InitSubraceVar( a_oCharacter ); + // See if we successfully initialized the character's subrace. + if( nSubrace != SUBRACE_NONE ) + { + // Initialize the subrace traits on the character. + SEI_InitSubraceTraits( a_oCharacter ); + // Send a message that the subrace has been inited. + SEI_SendSubraceInitMsg( a_oCharacter, nSubrace ); + } // End if + } + else + { +// SendMessageToPC( a_oCharacter, "Initializing subrace..." ); + // Initialize the subrace traits on the character. + SEI_InitSubraceTraits( a_oCharacter ); + } // End if + } // End if +} // End SEI_InitSubrace +// Finishes the subrace dialog for the character, initializing the subrace. +// +void SEI_FinishSubraceDialog( object a_oCharacter ) +{ + SetCommandable( TRUE, a_oCharacter ); + // Sanity check, make sure we have something to work with. + if( GetIsObjectValid( a_oCharacter ) ) + { + // Initialize the subrace for the effects, etc. + SEI_InitSubraceTraits( a_oCharacter ); + SEI_SendSubraceInitMsg( a_oCharacter, GetLocalInt( a_oCharacter, SUBRACE_FIELD ) ); + } +} // End SEI_FinishSubraceDialog +// ************************************************************** +// ** Subrace active functions +// ********************** +// Modifies the character's subrace attributes on a character's level up. +// +void SEI_LevelUpSubrace( object a_oCharacter ) +{ + // Read the local variable off the character. + int nSubrace = GetLocalInt( a_oCharacter, SUBRACE_FIELD ); + // Make sure that we actually have a subrace. + if( nSubrace != SUBRACE_NONE ) + { + // Load the information on the character's subrace. + struct Subrace stSubrace = SEI_LoadSubrace( nSubrace ); + // If this subrace has spell resistance then increase it. + if( stSubrace.m_bSpellResistance ) + { + // Create the spell resistance effect (for being higher it overrides the old values). + effect eSREffect = EffectSpellResistanceIncrease( 11 + GetHitDice( a_oCharacter ) ); + // Apply the effect to the character. + SEI_ApplyEffectToObject( DURATION_TYPE_INSTANT, eSREffect, a_oCharacter, 0.0, TRUE ); + } // End if + } // End if +} // End SEI_LevelUpSubrace +// Returns the subrace (enum) for the target. +// +int SEI_GetCharacterSubrace( object a_oCharacter ) +{ + int nSubrace = SUBRACE_NONE; + // Sanity check, make sure we have something to work with. + if( a_oCharacter != OBJECT_INVALID ) + { + // Read the local variable off the character. + nSubrace = GetLocalInt( a_oCharacter, SUBRACE_FIELD ); + // Write the findings into the log. + SEI_WriteSubraceLogEntry( "Subrace of player " + GetName( a_oCharacter ) + + " is " + IntToString( nSubrace ) + + " (" + SEI_SubraceEnumToString( nSubrace ) + ")", TRUE ); + // If subrace not initialized yet. + if( nSubrace == SUBRACE_NONE ) + { + SEI_InitSubrace( a_oCharacter ); + nSubrace = GetLocalInt( a_oCharacter, SUBRACE_FIELD ); + } // End if + } // End if + // Return the character's subrace. + return nSubrace; +} // End SEI_GetCharacterSubrace +// Returns whether the character is of subrace a_nSubrace. +// +int SEI_IsCharacterOfSubrace( object a_oCharacter, int a_nSubrace ) +{ + return SEI_GetCharacterSubrace( a_oCharacter ) == a_nSubrace; +} +// Returns the effective character level of the character. +// +int SEI_GetEffectiveCharacterLevel( object a_oCharacter ) +{ + return GetHitDice( a_oCharacter ) + SEI_GetECLAdd( a_oCharacter ); +} +// Make sure that the character has the subrace items they're supposed to have. +// +void SEI_KeepSubraceItem( object a_oCharacter ) +{ + // Have we been given a valid character? + if( GetIsObjectValid( a_oCharacter ) ) + { + // Read the local variable off the character. + int nSubrace = GetLocalInt( a_oCharacter, SUBRACE_FIELD ); + // Make sure we actually have a subrace. + if( nSubrace != SUBRACE_NONE ) + { + // Load the information on the character's subrace. + struct Subrace stSubrace = SEI_LoadSubrace( nSubrace ); + // Give the spell-like abilities item. + SEI_GiveSpellLikeAbilities( stSubrace, a_oCharacter ); + } // End if + } // End if +} // End SEI_KeepSubraceItem +// Make sure that the subrace item is removed when someone loses it. +// +int SEI_DropSubraceItem( object a_oItem ) +{ + // If this is a spell-like ability item... + if( GetStringLeft( GetTag( a_oItem ), 8 ) == "sei_sla_" ) + { + // Destroy the item. + DestroyObject( a_oItem ); + // Return the we've recognized the item. + return TRUE; + } + else + { + // This is not a spell-like ability item, + // so return we haven't recognized it. + return FALSE; + } // End if-else +} // End SEI_DropSubraceItem +// ************************************************************** +// ** Subrace experience functions +// ********************** +// Finds the default subrace for the race. +// +int SEI_FindDefaultSubrace( int a_nRace ) +{ + // Global object where the values are stored. + object oModule = GetModule(); + // Get the total number of added subraces. + int nNrSubraces = GetLocalInt( oModule, SUBRACE_COUNT ); + // For all stored subraces... + int nIdx; + for( nIdx = 0 ; nIdx < nNrSubraces ; ++nIdx ) + { + // The base field name the values are stored under. + string sTag = SUBRACE_STRUCT_TAG + IntToString( nIdx ) + "_"; + // If this is the default subrace for the race... + if( ( GetLocalInt( oModule, sTag + "RACE" ) == a_nRace ) && + GetLocalInt( oModule, sTag + "DEF" ) ) + { + // Return the ID of the subrace. + return GetLocalInt( oModule, sTag + "ID" ); + } + } // End for + // There is no default race for this subrace. + return SUBRACE_NONE; +} // End SEI_FindDefaultSubrace +// Returns the favored class for the subrace. +// +int SEI_GetFavoredClass( object a_oCharacter, struct Subrace a_stSubrace, int n_aHighestClass ) +{ + int nResult = CLASS_TYPE_INVALID; + int nClass = -1; + // Get te favored class depending on the gender of the character. + if( GetGender( a_oCharacter ) == GENDER_FEMALE ) + { + nClass = a_stSubrace.m_nFavoredClassF; + } + else if( GetGender( a_oCharacter ) == GENDER_MALE ) + { + nClass = a_stSubrace.m_nFavoredClassM; + } + // If we have a favored class... + if( nClass >= 0 ) + { + // If no specific class is specified then take the highest class. + if( nClass == CLASS_TYPE_INVALID ) + { + nResult = n_aHighestClass; + } + else + { + nResult = nClass; + } + } // End if + return nResult; +} // End SEI_GetFavoredClass +// Find the favored class for the subrace. +// +int SEI_FindFavoredClass( object a_oCharacter, struct Subrace a_stSubrace, int n_aHighestClass ) +{ + // Get the favored class for the subrace. + int nResult = SEI_GetFavoredClass( a_oCharacter, a_stSubrace, n_aHighestClass ); + // If no favored class was specified... + if( nResult == CLASS_TYPE_INVALID ) + { + // Get the favored class for the subrace's base race. + nResult = SEI_GetFavoredClass( + a_oCharacter, + SEI_LoadSubrace( SEI_FindDefaultSubrace( a_stSubrace.m_nBaseRace ) ), + n_aHighestClass ); + } // End if + return nResult; +} // End SEI_FindFavoredClass +// Calculate the amount of experience the character of would get with these two classes. +// It is assumed that a_nHigh is the highest level in a class. +// It is assumed that the favored class is already dropped. +// +float SEI_CalcXPPenaltyForClasses( int a_nHigh, int a_nLow ) +{ + // Start without a penalty. + float fPenalty = 0.0; + // If the difference between the highest class and the other class is too + // high then increase the penalty. + if( ( a_nLow != 0 ) && ( ( a_nHigh - a_nLow ) > 1 ) ) + { + fPenalty += 0.2; + } + return fPenalty; +} // End SEI_CalcXPPenaltyForClasses +// Calculate the amount of experience penalty the character will get. +// Sorts level according to highest level and drops the favored class. +// +float SEI_DropForFavoredClass( object a_oCharacter, struct Subrace a_stSubrace, int a_nClass1, int a_nLevel1, int a_nClass2, int a_nLevel2, int a_nClass3, int a_nLevel3 ) +{ + // Get the class with the most levels. + int nHighestClass = CLASS_TYPE_INVALID; + if( a_nLevel2 > a_nLevel1 ) + { + nHighestClass = ( ( a_nLevel3 > a_nLevel2 ) ? a_nClass3 : a_nClass2 ); + } + else + { + nHighestClass = ( ( a_nLevel3 > a_nLevel1 ) ? a_nClass3 : a_nClass1 ); + } + // Find the favored class for this subrace. + int nFavoredClass = SEI_FindFavoredClass( a_oCharacter, a_stSubrace, nHighestClass ); + // Ignore the level in the favored class. + int nLevel1 = ( ( a_nClass1 == nFavoredClass ) ? 0 : a_nLevel1 ); + int nLevel2 = ( ( a_nClass2 == nFavoredClass ) ? 0 : a_nLevel2 ); + int nLevel3 = ( ( a_nClass3 == nFavoredClass ) ? 0 : a_nLevel3 ); + // Sort the first and the second level to highest. + int nTempHigh = ( ( nLevel1 > nLevel2 ) ? nLevel1 : nLevel2 ); + int nLow1 = ( ( nLevel1 > nLevel2 ) ? nLevel2 : nLevel1 ); + // Sort the third level and the current highest. + int nHigh = ( ( nLevel3 > nTempHigh ) ? nLevel3 : nTempHigh ); + int nLow2 = ( ( nLevel3 > nTempHigh ) ? nTempHigh : nLevel3 ); + // Start without a penalty. + float fPenalty = 0.0; + // Calculate the penalty for the two lower classes in relation to the higher one. + fPenalty += SEI_CalcXPPenaltyForClasses( nHigh, nLow1 ); + fPenalty += SEI_CalcXPPenaltyForClasses( nHigh, nLow2 ); + // Return the calculated penalty. + return fPenalty; +} // End SEI_DropForFavoredClass +// Modify the amount of experience for the character's favored class. +// +int SEI_ModifyXPForFavoredClass( object a_oCharacter, int a_nXP ) +{ + int nXP = a_nXP; + // Get the three classes the character has. + int nClass1 = GetClassByPosition( 1, a_oCharacter ); + int nClass2 = GetClassByPosition( 2, a_oCharacter ); + int nClass3 = GetClassByPosition( 3, a_oCharacter ); + // If character only has one class then this isn't an issue. + if( nClass2 != CLASS_TYPE_INVALID ) + { + // Get the number of levels in the character's classes. + int nLevel1 = GetLevelByClass( nClass1, a_oCharacter ); + int nLevel2 = GetLevelByClass( nClass2, a_oCharacter ); + int nLevel3 = 0; + // If this character has three classes get the level in the third class. + if( nClass3 != CLASS_TYPE_INVALID ) + { + nLevel3 = GetLevelByClass( nClass3, a_oCharacter ); + } + // Load the character's subrace. + struct Subrace stSubrace = SEI_LoadSubrace( SEI_GetCharacterSubrace( a_oCharacter ) ); + // Get the normal XP modification. + float fNormalMod = 1.0 - SEI_DropForFavoredClass( + a_oCharacter, SEI_LoadSubrace( SEI_FindDefaultSubrace( stSubrace.m_nBaseRace ) ), + nClass1, nLevel1, nClass2, nLevel2, nClass3, nLevel3 ); + // Get the XP modification for subrace. + float fSubraceMod = 1.0 - SEI_DropForFavoredClass( + a_oCharacter, stSubrace, nClass1, nLevel1, nClass2, nLevel2, nClass3, nLevel3 ); + // Undo the normal penalty and set the new one. + // SEI_NOTE: No danger of div-0 as the max penalty is 40%. + nXP = FloatToInt( IntToFloat( nXP ) * ( fSubraceMod / fNormalMod ) ); + } // End if + return nXP; +} // End SEI_ModifyXPForFavoredClass +// Modify the experience to take into acount any ECL modification. +// +int SEI_ModifyXPForECL( object a_oCharacter, int a_nXP ) +{ + // Get the level without ECL modification. + float fBaseLevel = IntToFloat( GetHitDice( a_oCharacter ) ); + // Get the amount of ECL modification. + int nECLAdd = SEI_GetECLAdd( a_oCharacter ); + // Calculate how much to modify the experience. + float fModify = ( fBaseLevel / ( fBaseLevel + nECLAdd ) ); + // Modify the experience and return. + return FloatToInt( fModify * a_nXP ); +} // End SEI_ModifyXPForECL +// Modify the experience the character would get to correct for subrace. +// +int SEI_ModifyXPForSubrace( object a_oCharacter, int a_nXP ) +{ + int nXP = a_nXP; + nXP = SEI_ModifyXPForFavoredClass( a_oCharacter, nXP ); + nXP = SEI_ModifyXPForECL( a_oCharacter, nXP ); + return nXP; +} // End SEI_ModifyXPForSubrace diff --git a/src/_removed/sei_subracesinit.nss b/src/_removed/sei_subracesinit.nss new file mode 100644 index 0000000..b835eb6 --- /dev/null +++ b/src/_removed/sei_subracesinit.nss @@ -0,0 +1,19 @@ +// +// NWSubracesInit +// +// Initializes the subraces script. +// To be placed in the OnModuleLoad event of the module. +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + + +void main() +{ + Subraces_InitSubraces(); + Subraces_SetDefaultAreaSettings( AREA_DARK + AREA_UNDERGROUND ); +} + diff --git a/src/_removed/sei_subraceslst.nss b/src/_removed/sei_subraceslst.nss new file mode 100644 index 0000000..ace536a --- /dev/null +++ b/src/_removed/sei_subraceslst.nss @@ -0,0 +1,542 @@ +// HCR 5.5 update by Lorinton +// Modified to reduce (hopefully eliminate) subrace effects being stripped by the game +// and other effects such as level drain being stripped by the subrace system. +// +// NWSubracesList +// +// Function that creates a list defining all available subraces. +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// +// This file contains the data defining the subraces. In this way it is very +// easy to change existing subraces or add new ones. Below follows an +// explanation of the functions and fields available to set the subrace data. +// +// +// SEI_CreateSubrace( Subrace, Base race, Description ) +// +// This function creates a new subrace. The first parameter must be a unique +// ID number to define the subrace (best would be to add to the SUBRACE_ enum +// list). The second parameter is the base race on which the subrace is based +// and the third parameter is a textual descriptive name for the subrace. +// +// +// SEI_AddFieldText( subrace struct, Text ) +// +// This function adds a text that the subrace will recognize. When a character +// of the subrace's base race has this text somewhere in their "Subrace" field +// (on their character sheet) the character will be seen as a character of this +// subrace. Multiple texts can be added to allow for maximum compatibility. +// +// +// SEI_AddTrait( subrace struct, "" ) +// +// This function adds a subrace trait (as represented by an effect) to the +// character. Each trait consists of a string that the script will interpret +// and translate to the correct effect. For this a strict syntax must be +// followed. Below is a list of all the texts it recognizes. Everything between +// angular brackets "<>" has it's own section with tokens to put there. Thus a +// trait can be 'constructed'. +// +// trait: +// - "ac_inc " = AC Increase by amount +// - "ac_dec " = AC decrease by amount +// - "attack_inc " = Attack increase by amount +// - "attack_dec " = Attack decrease by amount +// - "immune " = Immunity to immunity-type +// - "ex " = Make trait extraordinary +// - "su " = Make trait supernatural +// - "m " = Only males characters get this trait +// - "f " = Only females characters get this trait +// - "ability_inc " = Increase ability by amount +// - "ability_dec " = Decrease ability by amount +// - "skill_inc " = Increase skill by amount +// - "skill_dec " = Decrease skill by amount +// - "vs " = Make trait against race +// - "save_inc " = Increase saving throws of save and save-type by amount +// - "save_dec " = Decrease saving throws of save and save-type by amount +// +/////////////////////// +// Lorinton change +// Add damage resist +// +// - "dam_resist " = Provide damage resistance (uses EffectDamageResistance arguments) +// +// ability: +// - "0" = ABILITY_STRENGTH +// - "1" = ABILITY_DEXTERITY +// - "2" = ABILITY_CONSTITUTION +// - "3" = ABILITY_INTELLIGENCE +// - "4" = ABILITY_WISDOM +// - "5" = ABILITY_CHARISMA +// +// immunity-type: +// - "0" = IMMUNITY_TYPE_NONE +// - "1" = IMMUNITY_TYPE_MIND_SPELLS +// - "2" = IMMUNITY_TYPE_POISON +// - "3" = IMMUNITY_TYPE_DISEASE +// - "4" = IMMUNITY_TYPE_FEAR +// - "5" = IMMUNITY_TYPE_TRAP +// - "6" = IMMUNITY_TYPE_PARALYSIS +// - "7" = IMMUNITY_TYPE_BLINDNESS +// - "8" = IMMUNITY_TYPE_DEAFNESS +// - "9" = IMMUNITY_TYPE_SLOW +// - "10" = IMMUNITY_TYPE_ENTANGLE +// - "11" = IMMUNITY_TYPE_SILENCE +// - "12" = IMMUNITY_TYPE_STUN +// - "13" = IMMUNITY_TYPE_SLEEP +// - "14" = IMMUNITY_TYPE_CHARM +// - "15" = IMMUNITY_TYPE_DOMINATE +// - "16" = IMMUNITY_TYPE_CONFUSED +// - "17" = IMMUNITY_TYPE_CURSED +// - "18" = IMMUNITY_TYPE_DAZED +// - "19" = IMMUNITY_TYPE_ABILITY_DECREASE +// - "20" = IMMUNITY_TYPE_ATTACK_DECREASE +// - "21" = IMMUNITY_TYPE_DAMAGE_DECREASE +// - "22" = IMMUNITY_TYPE_DAMAGE_IMMUNITY_DECREASE +// - "23" = IMMUNITY_TYPE_AC_DECREASE +// - "24" = IMMUNITY_TYPE_MOVEMENT_SPEED_DECREASE +// - "25" = IMMUNITY_TYPE_SAVING_THROW_DECREASE +// - "26" = IMMUNITY_TYPE_SPELL_RESISTANCE_DECREASE +// - "27" = IMMUNITY_TYPE_SKILL_DECREASE +// - "28" = IMMUNITY_TYPE_KNOCKDOWN +// - "29" = IMMUNITY_TYPE_NEGATIVE_LEVEL +// - "30" = IMMUNITY_TYPE_SNEAK_ATTACK +// - "31" = IMMUNITY_TYPE_CRITICAL_HIT +// - "32" = IMMUNITY_TYPE_DEATH +// +// race: +// - "0" = RACIAL_TYPE_DWARF +// - "1" = RACIAL_TYPE_ELF +// - "2" = RACIAL_TYPE_GNOME +// - "3" = RACIAL_TYPE_HALFLING +// - "4" = RACIAL_TYPE_HALFELF +// - "5" = RACIAL_TYPE_HALFORC +// - "6" = RACIAL_TYPE_HUMAN +// - "7" = RACIAL_TYPE_ABERRATION +// - "8" = RACIAL_TYPE_ANIMAL +// - "9" = RACIAL_TYPE_BEAST +// - "10" = RACIAL_TYPE_CONSTRUCT +// - "11" = RACIAL_TYPE_DRAGON +// - "12" = RACIAL_TYPE_HUMANOID_GOBLINOID +// - "13" = RACIAL_TYPE_HUMANOID_MONSTROUS +// - "14" = RACIAL_TYPE_HUMANOID_ORC +// - "15" = RACIAL_TYPE_HUMANOID_REPTILIAN +// - "16" = RACIAL_TYPE_ELEMENTAL +// - "17" = RACIAL_TYPE_FEY +// - "18" = RACIAL_TYPE_GIANT +// - "19" = RACIAL_TYPE_MAGICAL_BEAST +// - "20" = RACIAL_TYPE_OUTSIDER +// - "23" = RACIAL_TYPE_SHAPECHANGER +// - "24" = RACIAL_TYPE_UNDEAD +// - "25" = RACIAL_TYPE_VERMIN +// - "28" = RACIAL_TYPE_ALL +// - "29" = RACIAL_TYPE_INVALID +// +// save: +// - "0" = SAVING_THROW_ALL +// - "1" = SAVING_THROW_FORT +// - "2" = SAVING_THROW_REFLEX +// - "3" = SAVING_THROW_WILL +// +// save-type: +// - "0" = SAVING_THROW_TYPE_ALL +// - "1" = SAVING_THROW_TYPE_MIND_SPELLS +// - "2" = SAVING_THROW_TYPE_POISON +// - "3" = SAVING_THROW_TYPE_DISEASE +// - "4" = SAVING_THROW_TYPE_FEAR +// - "5" = SAVING_THROW_TYPE_SONIC +// - "6" = SAVING_THROW_TYPE_ACID +// - "7" = SAVING_THROW_TYPE_FIRE +// - "8" = SAVING_THROW_TYPE_ELECTRICITY +// - "9" = SAVING_THROW_TYPE_POSITIVE +// - "10" = SAVING_THROW_TYPE_NEGATIVE +// - "11" = SAVING_THROW_TYPE_DEATH +// - "12" = SAVING_THROW_TYPE_COLD +// - "13" = SAVING_THROW_TYPE_DIVINE +// - "14" = SAVING_THROW_TYPE_TRAP +// - "15" = SAVING_THROW_TYPE_SPELL +// - "16" = SAVING_THROW_TYPE_GOOD +// - "17" = SAVING_THROW_TYPE_EVIL +// - "18" = SAVING_THROW_TYPE_LAW +// - "19" = SAVING_THROW_TYPE_CHAOS +// +// skill: +// - "0" = SKILL_ANIMAL_EMPATHY +// - "1" = SKILL_CONCENTRATION +// - "2" = SKILL_DISABLE_TRAP +// - "3" = SKILL_DISCIPLINE +// - "4" = SKILL_HEAL +// - "5" = SKILL_HIDE +// - "6" = SKILL_LISTEN +// - "7" = SKILL_LORE +// - "8" = SKILL_MOVE_SILENTLY +// - "9" = SKILL_OPEN_LOCK +// - "10" = SKILL_PARRY +// - "11" = SKILL_PERFORM +// - "12" = SKILL_PERSUADE +// - "13" = SKILL_PICK_POCKET +// - "14" = SKILL_SEARCH +// - "15" = SKILL_SET_TRAP +// - "16" = SKILL_SPELLCRAFT +// - "17" = SKILL_SPOT +// - "18" = SKILL_TAUNT +// - "19" = SKILL_USE_MAGIC_DEVICE +// - "255" = SKILL_ALL_SKILLS +// +/////////////////////////// +// Lorinton change +// Add damage reduction +// +// - "32" = DAMAGE_TYPE_COLD +// - "128" = DAMAGE_TYPE_ELECTRICAL +// - "256" = DAMAGE_TYPE_FIRE +// +// stSubrace.m_nLightSensitivity = ; +// +// This field sets the subrace's light sensitivity. Characters sensitive to +// bright light get a penalty based on the light sensitivity. Note that while +// light blindness isn't included in the light sensitivity, a subrace must have +// a light sensitivity of at least 1 to have light blindness. +// +// sensitivity level: +// 0 = Not sensitive to bright light. +// 1 = Exposure to bright light give a -1 penalty. +// 2 = Exposure to bright light give a -2 penalty. +// +// +// stSubrace.m_nStonecunning = ; +// +// This field describes if the subrace gives stonecunning. Characters with +// stonecunning will have a higher search and hide skill while underground. +// +// +// stSubrace.m_nSpellLikeAbility = ; +// +// This field describes which spell-like ability the subrace gives. Currently +// there are three spell-like abilities supported (based on spells available +// in NWN): Blindness/deafness, darkness and invisibility. A subrace can only +// have one spell-like ability. +// +// spell-like ability: +// 0 = No spell-like ability. +// 1 = Blindness/deafness +// 2 = Darkness +// 3 = Invisibility +// +// +// stSubrace.m_bSpellResistance = ; +// +// This field describes if the subrace grants spell resistance. If granted the +// spell resistance will be 11 + character level. +// +// +// stSubrace.m_nFavoredClassF = ; +// stSubrace.m_nFavoredClassM = ; +// +// These fields set the favored class for the subrace (for females and males +// respectively). If no favored class is specified then the base race's favored +// class will be used. Use "CLASS_TYPE_INVALID" to have a character's highest +// class be their favored class. +// +// favored class: +// CLASS_TYPE_BARBARIAN +// CLASS_TYPE_BARD +// CLASS_TYPE_CLERIC +// CLASS_TYPE_DRUID +// CLASS_TYPE_FIGHTER +// CLASS_TYPE_MONK +// CLASS_TYPE_PALADIN +// CLASS_TYPE_RANGER +// CLASS_TYPE_ROGUE +// CLASS_TYPE_SORCERER +// CLASS_TYPE_WIZARD +// CLASS_TYPE_INVALID +// +// +// stSubrace.m_nECLAdd = ; +// +// These fields set how much must be added to the subrace's level to get to +// the effective character level. This is used to define the powerful races. +// +// +// stSubrace.m_bIsDefault = ; +// +// This field sets if the subrace is the default race for the base race. Only +// use it if you know what you're doing. +// +// +// SEI_SaveSubrace( subrace struct ) +// +// Once the subrace is completely defined this function saves the data so +// that characters can become this subrace when they enter. +// +// Lorinton change +// Creature skins may be used in place of or mixed with effects to create +// subrace attributes. Not all subrace attributes may be assigned to the skin. +// To use only creature skins set USE_SUBRACE_HIDE = TRUE +// and USE_SUBRACE_MIX = FALSE in sei_subraces. +// To use creature skins with effects set USE_SUBRACE_HIDE = TRUE +// and USE_SUBRACE_MIX = TRUE in sei_subraces. +// To use only effects set USE_SUBRACE_HIDE = FALSE in sei_subraces. +// +#include "sei_subraces" +// ************************************************************** +// ** Forward declarations +// ********************** +// Private function for the subraces script. Do not use. +struct Subrace SEI_CreateSubrace( int a_nSubrace, int a_nBaseRace, string a_sDescription ); +// Private function for the subraces script. Do not use. +struct Subrace SEI_AddFieldText( struct Subrace a_stSubrace, string a_sText ); +// Private function for the subraces script. Do not use. +struct Subrace SEI_AddTrait( struct Subrace a_stSubrace, string a_sTrait ); +// Private function for the subraces script. Do not use. +void SEI_SaveSubrace( struct Subrace a_stSubrace ); +// Define all available subraces. +// +void SEI_DefineSubraces() +{ + struct Subrace stSubrace; + //////////////////////////////////////////////////////////////////////////// + // Default subraces + //////////////////////////////////////////////////////////////////////////// + // SEI_NOTE: The favored classes for the default subraces need to be the + // same as the favored classes for the base races in NWN. + // Only change the default subraces if you know what you're doing. + // Define the "Shield Dwarf" subrace (dwarf default). + stSubrace = SEI_CreateSubrace( SUBRACE_DWARF_SHIELD, RACIAL_TYPE_DWARF, "Shield Dwarf" ); + stSubrace = SEI_AddFieldText( stSubrace, "shield" ); // "shield dwarf" + // The favored class for dwarves is fighter. + stSubrace.m_nFavoredClassF = CLASS_TYPE_FIGHTER; + stSubrace.m_nFavoredClassM = CLASS_TYPE_FIGHTER; + stSubrace.m_bIsDefault = TRUE; + SEI_SaveSubrace( stSubrace ); + // Define the "Moon Elf" subrace (elf default). + stSubrace = SEI_CreateSubrace( SUBRACE_ELF_MOON, RACIAL_TYPE_ELF, "Moon Elf" ); + stSubrace = SEI_AddFieldText( stSubrace, "moon" ); // "moon elf" + stSubrace = SEI_AddFieldText( stSubrace, "silver" ); // "silver elf" + stSubrace = SEI_AddFieldText( stSubrace, "gray" ); // "gray elf" + stSubrace = SEI_AddFieldText( stSubrace, "grey" ); // "grey elf" + stSubrace = SEI_AddFieldText( stSubrace, "teu-tel" ); // "Teu-Tel'Quessir" + // The favored class for elves is wizard. + stSubrace.m_nFavoredClassF = CLASS_TYPE_WIZARD; + stSubrace.m_nFavoredClassM = CLASS_TYPE_WIZARD; + stSubrace.m_bIsDefault = TRUE; + SEI_SaveSubrace( stSubrace ); + // Define the "Rock Gnome" subrace (gnome default). + stSubrace = SEI_CreateSubrace( SUBRACE_GNOME_ROCK, RACIAL_TYPE_GNOME, "Rock Gnome" ); + stSubrace = SEI_AddFieldText( stSubrace, "rock" ); + // The favored class for gnomes is illusionist (wizard in NWN). + stSubrace.m_nFavoredClassF = CLASS_TYPE_WIZARD; + stSubrace.m_nFavoredClassM = CLASS_TYPE_WIZARD; + stSubrace.m_bIsDefault = TRUE; + SEI_SaveSubrace( stSubrace ); + // Define the "Half-elf" subrace (half-elf default). + stSubrace = SEI_CreateSubrace( SUBRACE_HALFELF, RACIAL_TYPE_HALFELF, "Half-elf" ); + // The favored class for half-elves is any. + stSubrace.m_nFavoredClassF = CLASS_TYPE_INVALID; + stSubrace.m_nFavoredClassM = CLASS_TYPE_INVALID; + stSubrace.m_bIsDefault = TRUE; + SEI_SaveSubrace( stSubrace ); + // Define the "Half-orc" subrace (half-orc). + stSubrace = SEI_CreateSubrace( SUBRACE_HALFORC, RACIAL_TYPE_HALFORC, "Half-orc" ); + // The favored class for half-orcs is barbarian. + stSubrace.m_nFavoredClassF = CLASS_TYPE_BARBARIAN; + stSubrace.m_nFavoredClassM = CLASS_TYPE_BARBARIAN; + stSubrace.m_bIsDefault = TRUE; + SEI_SaveSubrace( stSubrace ); + // Define the "Lightfoot Halfling" subrace (halfling default). + stSubrace = SEI_CreateSubrace( SUBRACE_HALFLING_LIGHTFOOT, RACIAL_TYPE_HALFLING, "Lightfoot Halfling" ); + stSubrace = SEI_AddFieldText( stSubrace, "light" ); + // The favored class for halflings is rogue. + stSubrace.m_nFavoredClassF = CLASS_TYPE_ROGUE; + stSubrace.m_nFavoredClassM = CLASS_TYPE_ROGUE; + stSubrace.m_bIsDefault = TRUE; + SEI_SaveSubrace( stSubrace ); + // Define the "Human" subrace (human default). + stSubrace = SEI_CreateSubrace( SUBRACE_HUMAN, RACIAL_TYPE_HUMAN, "Human" ); + // The favored class for elves is any. + stSubrace.m_nFavoredClassF = CLASS_TYPE_INVALID; + stSubrace.m_nFavoredClassM = CLASS_TYPE_INVALID; + stSubrace.m_bIsDefault = TRUE; + SEI_SaveSubrace( stSubrace ); + //////////////////////////////////////////////////////////////////////////// + // Additional subraces + //////////////////////////////////////////////////////////////////////////// + // Define the "Gold Dwarf" subrace. + stSubrace = SEI_CreateSubrace( SUBRACE_DWARF_GOLD, RACIAL_TYPE_DWARF, "Gold Dwarf" ); + stSubrace = SEI_AddFieldText( stSubrace, "gold" ); // "gold dwarf" + // Gold dwarves get +2 Con, -2 Dex instead of the standard +2 Con, -2 Cha. + if( !USE_SUBRACE_HIDE ) + { + stSubrace = SEI_AddTrait( stSubrace, "ex ability_inc 5 2" ); // +2 Cha + stSubrace = SEI_AddTrait( stSubrace, "ex ability_dec 1 2" ); // -2 Dex + } + // Gold dwarves get +1 attack against aberrations instead of against orcs and goblinoids. + stSubrace = SEI_AddTrait( stSubrace, "ex vs 14 attack_dec 1" ); // -1 attack vs orcs + stSubrace = SEI_AddTrait( stSubrace, "ex vs 12 attack_dec 1" ); // -1 attack vs goblinoids + stSubrace = SEI_AddTrait( stSubrace, "ex vs 7 attack_inc 1" ); // +1 attack vs aberrations + SEI_SaveSubrace( stSubrace ); + // Define the "Gray Dwarf" subrace. + stSubrace = SEI_CreateSubrace( SUBRACE_DWARF_GRAY, RACIAL_TYPE_DWARF, "Gray Dwarf (Duergar)" ); + stSubrace = SEI_AddFieldText( stSubrace, "gray" ); // "gray dwarf" + stSubrace = SEI_AddFieldText( stSubrace, "grey" ); // "grey dwarf" + stSubrace = SEI_AddFieldText( stSubrace, "deep" ); // "deep dwarf" + stSubrace = SEI_AddFieldText( stSubrace, "duergar" ); // "duergar" + // Gray dwarves get +2 Con, -4 Cha instead of the standard +2 Con, -2 Cha. + if( !USE_SUBRACE_HIDE) + { + stSubrace = SEI_AddTrait( stSubrace, "ex ability_dec 5 2" ); // -2 Cha + // Gray dwarves get immunity to paralysis, phantasms, and magic or alchemical poisons (but not normal poisons). + // SEI_NOTE: Removed the phantasms one and replaced it with immunity to all poisons. + stSubrace = SEI_AddTrait( stSubrace, "ex immune 6" ); // Immune to paralysis + stSubrace = SEI_AddTrait( stSubrace, "ex immune 2" ); // Immune to poison + // Gray dwarves get +4 racial bonus on Move Silently checks. + stSubrace = SEI_AddTrait( stSubrace, "ex skill_inc 8 4" ); // +4 to Move Silently + // Gray dwarves get +1 racial bonus on Listen and Spot checks. + stSubrace = SEI_AddTrait( stSubrace, "ex skill_inc 6 1" ); // +1 to Listen + stSubrace = SEI_AddTrait( stSubrace, "ex skill_inc 17 1" ); // +1 to Spot + } + // Gray dwarves are sensitive to bright light. + stSubrace.m_nLightSensitivity = 2; // Light sensitivity level 2 + // Gray dwarves get the invisibility spell-like ability. + stSubrace.m_nSpellLikeAbility = 3; // Invisibility + // Gray dwarves get a +2 level adjustment for being a powerful race + stSubrace.m_nECLAdd = 2; // ECL + 2 + SEI_SaveSubrace( stSubrace ); + // Define the "Dark Elf" subrace. + stSubrace = SEI_CreateSubrace( SUBRACE_ELF_DARK, RACIAL_TYPE_ELF, "Dark Elf (Drow)" ); + stSubrace = SEI_AddFieldText( stSubrace, "drow" ); // "drow" + stSubrace = SEI_AddFieldText( stSubrace, "dark" ); // "dark elf" + stSubrace = SEI_AddFieldText( stSubrace, "black" ); // "black elf" + stSubrace = SEI_AddFieldText( stSubrace, "ilythiiri" ); // "Ilythiiri" + stSubrace = SEI_AddFieldText( stSubrace, "dhaeraow" ); // "Dhaerow" + stSubrace = SEI_AddFieldText( stSubrace, "mori" ); // "Mori'Quessir" + stSubrace = SEI_AddFieldText( stSubrace, "ssri-tel" ); // "Ssri-Tel'Quessir" + stSubrace = SEI_AddFieldText( stSubrace, "gothrim" ); // "Tel'gothrim" + // Drow get +2 Dex, -2 Con, +2 Int, +2 Cha instead of the standard +2 Dex, -2 Con. + if( !USE_SUBRACE_HIDE ) + { + stSubrace = SEI_AddTrait( stSubrace, "ex ability_inc 3 2" ); // +2 Int + stSubrace = SEI_AddTrait( stSubrace, "ex ability_inc 5 2" ); // +2 Cha + // Drow get a +2 racial bonus on Will saves against spells and spell-like abilities. + stSubrace = SEI_AddTrait( stSubrace, "ex save_inc 3 2 15" ); // +2 Will save against spells + stSubrace = SEI_AddTrait( stSubrace, "ex save_inc 3 2 1" ); // +2 Will save against mind-spells + // Drow get darkvision. + stSubrace = SEI_AddTrait( stSubrace, "ex darkvision" ); // Darkvision + } + // Drow are sensitive to bright light. + stSubrace.m_nLightSensitivity = 1; // Light sensitivity level 1 + // Drow are blinded when coming into bright light. + stSubrace.m_fLightBlindness = 6.0; // Blinded for 6 seconds + // Drow get spell resistance. + stSubrace.m_bSpellResistance = TRUE; // Spell resistance + // Drow get the darkness spell-like ability. + stSubrace.m_nSpellLikeAbility = 2; // Darkness + // Drow get a +2 level adjustment for being a powerful race + stSubrace.m_nECLAdd = 2; // ECL + 2 + // Drow females have cleric as their favored class. + stSubrace.m_nFavoredClassF = CLASS_TYPE_CLERIC; // Favored class: Cleric + SEI_SaveSubrace( stSubrace ); + // Define the "Sun Elf" subrace. + stSubrace = SEI_CreateSubrace( SUBRACE_ELF_SUN, RACIAL_TYPE_ELF, "Sun Elf" ); + stSubrace = SEI_AddFieldText( stSubrace, "sun" ); // "sun elf" + stSubrace = SEI_AddFieldText( stSubrace, "gold" ); // "gold elf" + stSubrace = SEI_AddFieldText( stSubrace, "ar-tel" ); // "Ar-Tel'Quessir" + // Sun elves get +2 Int, -2 Con instead of the standard +2 Dex, -2 Con. + if (!USE_SUBRACE_HIDE ) + { + stSubrace = SEI_AddTrait( stSubrace, "ex ability_inc 3 2" ); // +2 Int + stSubrace = SEI_AddTrait( stSubrace, "ex ability_dec 1 2" ); // -2 Dex + } + SEI_SaveSubrace( stSubrace ); + // Define the "Wild Elf" subrace. + stSubrace = SEI_CreateSubrace( SUBRACE_ELF_WILD, RACIAL_TYPE_ELF, "Wild Elf" ); + stSubrace = SEI_AddFieldText( stSubrace, "wild" ); // "wild elf" + stSubrace = SEI_AddFieldText( stSubrace, "savage" ); // "savage elf" + stSubrace = SEI_AddFieldText( stSubrace, "sy-tel" ); // "Sy-Tel'Quessir" + // Wild elves get +2 Dex, -2 Int instead of the standard +2 Dex, -2 Con. + if( !USE_SUBRACE_HIDE ) + { + stSubrace = SEI_AddTrait( stSubrace, "ex ability_inc 2 2" ); // +2 Con + stSubrace = SEI_AddTrait( stSubrace, "ex ability_dec 3 2" ); // -2 Int + } + // [Errata] Wild elves have sorcerer as their favored class. + stSubrace.m_nFavoredClassF = CLASS_TYPE_SORCERER; // Favored class: Sorcerer + stSubrace.m_nFavoredClassM = CLASS_TYPE_SORCERER; // Favored class: Sorcerer + SEI_SaveSubrace( stSubrace ); + // Define the "Wood Elf" subrace. + stSubrace = SEI_CreateSubrace( SUBRACE_ELF_WOOD, RACIAL_TYPE_ELF, "Wood Elf" ); + stSubrace = SEI_AddFieldText( stSubrace, "wood" ); // "wood elf" + stSubrace = SEI_AddFieldText( stSubrace, "green" ); // "green elf" + stSubrace = SEI_AddFieldText( stSubrace, "forest" ); // "forest elf" + // Wood elves get +2 Str, +2 Dex, -2 Con, -2 Int, -2 Cha instead of the standard +2 Dex, -2 Con. + if( !USE_SUBRACE_HIDE ) + { + stSubrace = SEI_AddTrait( stSubrace, "ex ability_inc 0 2" ); // +2 Str + stSubrace = SEI_AddTrait( stSubrace, "ex ability_dec 3 2" ); // -2 Int + stSubrace = SEI_AddTrait( stSubrace, "ex ability_dec 5 2" ); // -2 Cha + } + // [Errata] Wood elves have ranger as their favored class. + stSubrace.m_nFavoredClassF = CLASS_TYPE_RANGER; // Favored class: Ranger + stSubrace.m_nFavoredClassM = CLASS_TYPE_RANGER; // Favored class: Ranger + SEI_SaveSubrace( stSubrace ); + // Define the "Deep Gnome" subrace. + stSubrace = SEI_CreateSubrace( SUBRACE_GNOME_DEEP, RACIAL_TYPE_GNOME, "Deep Gnome (Svirfneblin)" ); + stSubrace = SEI_AddFieldText( stSubrace, "deep" ); + stSubrace = SEI_AddFieldText( stSubrace, "svirfneblin" ); + // Deep gnomes get -2 Str, +2 Dex, +2 Wis, -4 Cha instead of the standard +2 Con, -2 Str. + if( !USE_SUBRACE_HIDE ) + { + stSubrace = SEI_AddTrait( stSubrace, "ex ability_inc 1 2" ); // +2 Dex + stSubrace = SEI_AddTrait( stSubrace, "ex ability_inc 4 2" ); // +2 Wis + stSubrace = SEI_AddTrait( stSubrace, "ex ability_dec 2 2" ); // -2 Con + stSubrace = SEI_AddTrait( stSubrace, "ex ability_dec 5 4" ); // -4 Cha + // Deep gnomes get a +4 dodge bonus against all creatures (and no special bonus against giants). + stSubrace = SEI_AddTrait( stSubrace, "ex ac_inc 4" ); // +4 AC + // Deep gnomes get a +2 racial bonus on all saving throws. + stSubrace = SEI_AddTrait( stSubrace, "ex save_inc 0 2 0" ); // +2 save bonus + // Deep gnomes get a +2 racial bonus on Hide checks. + stSubrace = SEI_AddTrait( stSubrace, "ex skill_inc 5 2" ); // +2 to Hide + // Deep gnomes get darkvision. + stSubrace = SEI_AddTrait( stSubrace, "ex darkvision" ); // Darkvision + } + // Deep gnomes get a +4 dodge bonus against all creatures (and no special bonus against giants). + stSubrace = SEI_AddTrait( stSubrace, "ex vs 18 ac_dec 4" ); // -4 AC vs giants + // Deep gnomes get spell resistance. + stSubrace.m_bSpellResistance = TRUE; // Spell resistance + // Deep gnomes get stonecunning. + stSubrace.m_nStonecunning = TRUE; // Stonecunning + // Deep gnomes get the blindness spell-like ability. + stSubrace.m_nSpellLikeAbility = 1; // Blindness/deafness + // Drow get a +3 level adjustment for being a powerful race + stSubrace.m_nECLAdd = 3; // ECL + 3 + SEI_SaveSubrace( stSubrace ); + // Define the "Ghostwise Halfling" subrace. + stSubrace = SEI_CreateSubrace( SUBRACE_HALFLING_GHOSTWISE, RACIAL_TYPE_HALFLING, "Ghostwise Halfling" ); + stSubrace = SEI_AddFieldText( stSubrace, "ghost" ); + // Ghostwise halflings do not receive the standard Halfling +1 racial bonus on all saving throws. + if( !USE_SUBRACE_HIDE ) + stSubrace = SEI_AddTrait( stSubrace, "ex save_dec 0 1 0" ); // -1 save penalty + SEI_SaveSubrace( stSubrace ); + // Define the "Strongheart Halfling" subrace. + stSubrace = SEI_CreateSubrace( SUBRACE_HALFLING_STRONGHEART, RACIAL_TYPE_HALFLING, "Strongheart Halfling" ); + stSubrace = SEI_AddFieldText( stSubrace, "strong" ); + // Strongheart halflings do not receive the standard Halfling +1 racial bonus on all saving throws. + if( !USE_SUBRACE_HIDE ) + stSubrace = SEI_AddTrait( stSubrace, "ex save_dec 0 1 0" ); // -1 save penalty + SEI_SaveSubrace( stSubrace ); + // Define the "Half-drow" subrace. + stSubrace = SEI_CreateSubrace( SUBRACE_HALFDROW, RACIAL_TYPE_HALFELF, "Half-drow" ); + stSubrace = SEI_AddFieldText( stSubrace, "drow" ); // "drow" + stSubrace = SEI_AddFieldText( stSubrace, "dark" ); // "dark elf" + // Half-drow get darkvision. + if( !USE_SUBRACE_HIDE ) + stSubrace = SEI_AddTrait( stSubrace, "ex darkvision" ); // Darkvision + // The favored class for half-drow is any. + stSubrace.m_nFavoredClassF = CLASS_TYPE_INVALID; + stSubrace.m_nFavoredClassM = CLASS_TYPE_INVALID; + SEI_SaveSubrace( stSubrace ); + // SEI_NOTE: New subraces can be added here. +} // End SEI_DefineSubraces diff --git a/src/_removed/sei_subrconv.nss b/src/_removed/sei_subrconv.nss new file mode 100644 index 0000000..6ff65ed --- /dev/null +++ b/src/_removed/sei_subrconv.nss @@ -0,0 +1,17 @@ +// +// NWSubraceConversation +// +// Re-start the interrupted subrace selection conversation +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// + +#include "subraces" + +void main() +{ + // Conversation interrupted, start again. + SEI_StartSubraceDialog( OBJECT_SELF ); +} + diff --git a/src/_removed/subraces.nss b/src/_removed/subraces.nss new file mode 100644 index 0000000..d24a724 --- /dev/null +++ b/src/_removed/subraces.nss @@ -0,0 +1,290 @@ +// HCR 5.5 change by Lorinton +// Modified to reduce (hopefully eliminate) subrace effects being stripped by the game +// and other effects such as level drain being stripped by the subrace system. +// +// NWSubraces +// +// Basic subrace functionality +// +// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) +// +//////////////////////////////////////////////////////// +// Include the subrace definitions and the subraces code. +// Lorinton change +//#include "sei_subraces" +#include "sei_subraceslst" +#include "sei_xp" +// ************************************************************** +// ** Constants +// ********************** +// Enum of the supported subraces +int SUBRACE_NONE = 0; // No Subrace set yet +int SUBRACE_MONSTER = 1; // For monsters, etc. without subrace +int SUBRACE_DWARF_GOLD = 2; +int SUBRACE_DWARF_GRAY = 3; +int SUBRACE_DWARF_SHIELD = 4; +int SUBRACE_ELF_DARK = 5; +int SUBRACE_ELF_MOON = 6; +int SUBRACE_ELF_SUN = 7; +int SUBRACE_ELF_WILD = 8; +int SUBRACE_ELF_WOOD = 9; +int SUBRACE_GNOME_DEEP = 10; +int SUBRACE_GNOME_ROCK = 11; +int SUBRACE_HALFELF = 12; +int SUBRACE_HALFORC = 13; +int SUBRACE_HALFLING_GHOSTWISE = 14; +int SUBRACE_HALFLING_LIGHTFOOT = 15; +int SUBRACE_HALFLING_STRONGHEART = 16; +int SUBRACE_HUMAN = 17; +int SUBRACE_HALFDROW = 18; +int AREA_NONE = 0; +int AREA_DEFAULT_LIGHT = 1; +int AREA_DARK = 2; +int AREA_LIGHT = 3; +int AREA_SUN = 4; +int AREA_DEFAULT_GROUND = 10; +int AREA_LEXINGTON = 20; +int AREA_KENTUCKY = 30; + +// ************************************************************** +// ** Structures +// ********************** +// Structure used to pass information on a certain subrace. +struct Subrace +{ + int m_nID; + int m_nBaseRace; + int m_nNumFieldValues; + int m_nNumTraits; + int m_bSpellResistance; + int m_nLightSensitivity; + float m_fLightBlindness; + int m_nStonecunning; + int m_nSpellLikeAbility; + int m_nECLAdd; + int m_nFavoredClassF; + int m_nFavoredClassM; + int m_bIsDefault; +}; +// ************************************************************** +// ** Event functions +// ********************** +// Initializes the available subraces and everything that is needed to properly +// run this script. +// Call this function in the OnModuleLoad event of the module. +// +void Subraces_InitSubraces(); +// Sets the default area settings. This is so you don't have to do it for every area. +// Call this function in the OnModuleLoad event of the module. +// ARGUMENTS: +// a_nSettings = What the default settings for the area are. +// There is light-level: +// AREA_DARK - The area is considered dark. +// AREA_LIGHT - The area is considered daylight. +// AREA_SUN - The light level depends on the sun (day/night). +// And there is the 'ground' setting: +// AREA_UNDERGROUND - The area is underground. +// AREA_ABOVEGROUND - The area is above ground. +// Add the setting for lightness to that of ground for the +// final setting, i.e.: +// Subraces_SetDefaultAreaSettings( AREA_DARK + AREA_UNDERGROUND ); +// for if most of the areas in the module are dark and underground. +// +void Subraces_SetDefaultAreaSettings( int a_nSettings ); +// Initializes the subrace for character a_oCharacter. +// Call this function in the OnClientEnter event of the module. +// ARGUMENTS: +// a_oCharacter = The character to initialize the subrace for +// +void Subraces_InitSubrace( object a_oCharacter ); +// Modifies the character's subrace attributes on a character's level up. +// Call this function in the OnPlayerLevelUp event of the module. +// ARGUMENTS: +// a_oCharacter = The character to level up. +// +void Subraces_LevelUpSubrace( object a_oCharacter ); +// Makes sure that the subrace is set correctly again when the character respawns. +// ARGUMENTS: +// a_oCharacter = The character respawning. +// +void Subraces_RespawnSubrace( object a_oCharacter ); +// Does some subrace specific things when a character enters a new area. +// Call this function in the OnEnter event of every area. +// ARGUMENTS: +// a_oCharacter = The character to enter the new area. +// a_nSettings = The light and (under)ground settings of the area. +// Don't specify this argument to use module defaults. +// +void Subraces_OnEnterArea( object a_oCharacter, int a_nSettings = 0 ); +// ************************************************************** +// ** Useage functions +// ********************** +// Returns the subrace (enum) for the target. +// ARGUMENTS: +// a_oCharacter = The character to get the subrace from (assumed valid) +// RESULT: +// The subrace of a_oCharacter (see te "SUBRACE_" variables) +// +int Subraces_GetCharacterSubrace( object a_oCharacter ); +// Returns whether the character is of subrace a_nSubrace. +// ARGUMENTS: +// a_oCharacter = The character to get the subrace from (assumed valid) +// a_nSubrace = The subrace to check against +// RESULT: +// Whether a_oCharacter is of subrace a_nSubrace +// +int Subraces_IsCharacterOfSubrace( object a_oCharacter, int a_nSubrace ); +// Returns the effective character level of the character. +// ARGUMENTS: +// a_oCharacter = The character to get the ECL from (assumed valid) +// +int Subraces_GetEffectiveCharacterLevel( object a_oCharacter ); +// Remove subrace related items before starting a new module. +// If the new module supports subraces it should re-initialize them. +// ARGUMENTS: +// a_sModuleName = The name of the module to start. +// +void Subraces_StartNewModule( string a_sModuleName ); +// Remove subrace related items before sending PC through protal. +// If the new server supports subraces it should re-initialize them. +// ARGUMENTS: +// a_oTarget = The character to send through the portal. +// a_sIPaddress = This can be numerical "192.168.0.84" or alphanumeric +// "www.bioware.com". It can also contain a port +// "192.168.0.84:5121" or "www.bioware.com:5121"; if the +// port is not specified, it will default to 5121. +// a_sPassword = Login password for the destination server. +// a_sWaypointTag = If this is set, after portalling the character will be +// moved to this waypoint if it exists. +// a_bSeamless = If this is set, the client wil not be prompted with +// the information window telling them about the server, +// and they will not be allowed to save a copy of their +// character if they are using a local vault character. +// +void Subraces_ActivatePortal( object a_oTarget, string a_sIPaddress="", string a_sPassword="", string a_sWaypointTag="", int a_bSeemless=FALSE ); +// Change the area settings dependent traits for the character. +// This function can for instance be called in the OnEnter and OnExit scripts +// of a trigger to create an area where the settings differ from the rest of the +// area. (Like a room of sunlight in an otherwise lightless dungeon). +// ARGUMENTS: +// a_oCharacter = The character the settings affect. +// a_nSettings = What these differing settings are. Leave away to reset +// to the area defaults. +// +void Subraces_ChangeAreaSettings( object a_oCharacter, int a_nSettings = 0 ); +// A subrace safe version of BioWare's RemoveEffect function. Removes effect +// in such a way as not to touch te subraces (i.e. te subraces are safe). +// ARGUMENTS: +// a_oCreature = The creature to remove the effect from. +// a_eEffect = The effect to remove from the creature. +// +void Subraces_SafeRemoveEffect( object a_oCreature, effect a_eEffect ); +// A subrace safe version that removes all non-subrace effects from the char. +// ARGUMENTS: +// a_oCreature = The creature to remove the effect from. +// +void Subraces_SafeRemoveEffects( object a_oCreature ); +// ************************************************************** +// ** Function definitions +// ********************** +// Initializes the available subraces and everything that is needed to properly +// run this script. +// +void Subraces_InitSubraces() +{ + SEI_InitSubraces(); +} +// Sets the default area settings. This is so you don't have to do it for every area. +// +void Subraces_SetDefaultAreaSettings( int a_nSettings ) +{ + SEI_SetDefaultAreaSettings( a_nSettings ); +} +// Initializes the subrace for character a_oCharacter. +// +void Subraces_InitSubrace( object a_oCharacter ) +{ + AssignCommand( GetModule(), SEI_InitSubrace( a_oCharacter ) ); +} +// Modifies the character's subrace attributes on a character's level up. +// +void Subraces_LevelUpSubrace( object a_oCharacter ) +{ + SEI_LevelUpSubrace( a_oCharacter ); +} +// Makes sure that the subrace is set correctly again when the character respawns. +// +void Subraces_RespawnSubrace( object a_oCharacter ) +{ + SEI_InitSubrace( a_oCharacter ); +} +// Does some subrace specific things when a character enters a new area. +// +void Subraces_OnEnterArea( object a_oCharacter, int a_nSettings = 0 ) +{ + SEI_EnterArea( a_oCharacter, a_nSettings ); +} +// Returns the subrace (enum) for the target. +// +int Subraces_GetCharacterSubrace( object a_oCharacter ) +{ + return SEI_GetCharacterSubrace( a_oCharacter ); +} +// Returns whether the character is of subrace a_nSubrace. +// +int Subraces_IsCharacterOfSubrace( object a_oCharacter, int a_nSubrace ) +{ + return SEI_IsCharacterOfSubrace( a_oCharacter, a_nSubrace ); +} +// Returns the effective character level of the character. +// +int Subraces_GetEffectiveCharacterLevel( object a_oCharacter ) +{ + return SEI_GetEffectiveCharacterLevel( a_oCharacter ); +} +// Remove subrace related items before starting a new module. +// +void Subraces_StartNewModule( string a_sModuleName ) +{ + object oPC = GetFirstPC(); + while( GetIsObjectValid( oPC ) ) + { + SEI_RemoveSubrace( oPC ); + oPC = GetNextPC(); + } + StartNewModule( a_sModuleName ); +} +// Remove subrace related items before sending PC through protal. +// +void Subraces_ActivatePortal( object a_oTarget, string a_sIPaddress="", string a_sPassword="", string a_sWaypointTag="", int a_bSeemless=FALSE ) +{ + SEI_RemoveSubrace( a_oTarget ); + ActivatePortal( a_oTarget, a_sIPaddress, a_sPassword, a_sWaypointTag, a_bSeemless ); +} +// Change the area settings dependent traits for the character. +// +void Subraces_ChangeAreaSettings( object a_oCharacter, int a_nSettings = 0 ) +{ + SEI_ApplyAreaSettings( a_oCharacter, a_nSettings ); +} +// A subrace safe version of BioWare's RemoveEffect function. +// +void Subraces_SafeRemoveEffect( object a_oCreature, effect a_eEffect ) +{ + SEI_RemoveEffect( a_oCreature, a_eEffect ); +} +// A subrace safe version that removes all non-subrace effects from the char. +// +void Subraces_SafeRemoveEffects( object a_oCreature ) +{ + SEI_RemoveEffects( a_oCreature ); + // Lorinton change, the subrace is now reinitialized after removing effects. + // This call is not needed. + //SEI_InitSubraceTraits( a_oCreature, FALSE ); +} +// SEI_TODO: Added for development. Remove! +/* +void main () +{ +} +//*/ diff --git a/src/_removed/x0_i0_spells.nss b/src/_removed/x0_i0_spells.nss new file mode 100644 index 0000000..6e1845e --- /dev/null +++ b/src/_removed/x0_i0_spells.nss @@ -0,0 +1,2273 @@ +//:://///////////////////////////////////////////// +//:: x0_i0_spells +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Expansion 1 and above include file for spells +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 2002 +//:: Updated On: August 2003, Georg Zoeller: +//:: Arcane Archer special ability fix, +//:: New creatures added to Flying/Petrification check +//:: Several Fixes toMDispelagic +//:: Added spellsGetHighestSpellcastingClassLevel +//:: Added code to spellsIsTarget to make NPCs hurt their allies with AoE spells if ModuleSwitch MODULE_SWITCH_ENABLE_NPC_AOE_HURT_ALLIES is set +//:: Creatures with Plot or DM Flag set will no longer be affected by petrify. DMs used to get a GUI panel, even if unaffected. +//:: Updated On: September 2003, Georg Zoeller: +//:: spellsIsTarget was not using oSource in source checks. +//:: Creatures with Plot or DM Flag set will no longer be affected by petrify. DMs used to get a GUI panel, even if unaffected. +//:: Updated On: October 2003, Georg Zoeller: +//:: Missile storm's no longer do a SR check for each missile, but only one per target +//:: ... and there was much rejoicing +//:: Added code to handleldispeling of AoE spells better +//:: Henchmen are booted from the party when petrified +//:: Dispel Magic delay until VFX hit has been set down to 0.3 +//::////////////////////////////////////////////// + +#include "NW_I0_SPELLS" +#include "x0_i0_match" +#include "x2_inc_switches" +#include "prc_x2_itemprop" +#include "x0_i0_henchman" +// Include for item properties getting dispelled: +#include "tk_dispel" +#include "prc_inc_spells" + +// * Constants +// * see spellsIsTarget for a definition of these constants +const int SPELL_TARGET_ALLALLIES = 1; +const int SPELL_TARGET_STANDARDHOSTILE = 2; +const int SPELL_TARGET_SELECTIVEHOSTILE = 3; +const int SAVING_THROW_NONE = 4; + + +//* get the hightest spellcasting class level of oCreature) +int GZGetHighestSpellcastingClassLevel(object oCreature); + +// * dispel magic on one or multiple targets. +// * if bAll is set to TRUE, all effects are dispelled from a creature +// * else it will only dispel the best effect from each creature (used for AoE) +// * Specify bBreachSpells to add Mord's Disjunction to the dispel +void spellsDispelMagic(object oTarget, int nCasterLevel, effect eVis, effect eImpac, int bAll = TRUE, int bBreachSpells = FALSE); + +// * returns true if oCreature does not have a mind +int spellsIsMindless(object oCreature); + +// * Returns true or false depending on whether the creature is flying +// * or not +int spellsIsFlying(object oCreature); + +// * returns true if the creature has flesh +int spellsIsImmuneToPetrification(object oCreature); + +// * Generic apply area of effect Wrapper +// * lTargetLoc = where spell was targeted +// * fRadius = RADIUS_SIZE_ constant +// * nSpellID +// * eImpact = ring impact +// * eLink = Linked effects to apply to targets in area +// * eVis +void spellsGenericAreaOfEffect( + object oCaster, location lTargetLoc, + int nShape, float fRadiusSize, int nSpellID, + effect eImpact, effect eLink, effect eVis, + int nDurationType=DURATION_TYPE_INSTANT, float fDuration = 0.0, + int nTargetType=SPELL_TARGET_ALLALLIES, int bHarmful = FALSE, + int nRemoveEffectSpell=FALSE, int nRemoveEffect1=0, int nRemoveEffect2=0, int nRemoveEffect3=0, + int bLineOfSight=FALSE, int nObjectFilter=OBJECT_TYPE_CREATURE, + int bPersistentObject=FALSE, int bResistCheck=FALSE, int nSavingThrowType=SAVING_THROW_NONE, + int nSavingThrowSubType=SAVING_THROW_TYPE_ALL + ); + +// * Generic reputation wrapper +// * definition of constants: +// * SPELL_TARGET_ALLALLIES = Will affect all allies, even those in my faction who don't like me +// * SPELL_TARGET_STANDARDHOSTILE: 90% of offensive area spells will work +// this way. They will never hurt NEUTRAL or FRIENDLY NPCs. +// They will never hurt FRIENDLY PCs +// They WILL hurt NEUTRAL PCs +// * SPELL_TARGET_SELECTIVEHOSTILE: Will only ever hurt enemies +int spellsIsTarget(object oTarget, int nTargetType, object oSource); + + +// * how much should special archer arrows do for damage +int ArcaneArcherDamageDoneByBow(int bCrit = FALSE, object oUser = OBJECT_SELF); + +// * simulating enchant arrow +int ArcaneArcherCalculateBonus(); + +// * returns the size modifier for bullrush in spells +int GetSizeModifier(object oCreature); + +// * Returns the modifier from the ability score that matters for this caster +int GetCasterAbilityModifier(object oCaster); + +// * Checks the appropriate metamagic to see +// * how the damage should be scaled. +int MaximizeOrEmpower(int nDice, int nNumberOfDice, int nMeta, int nBonus = 0); + +// * can the creature be destroyed without breaking a plot +int CanCreatureBeDestroyed(object oTarget); + +// * Does a stinking cloud. If oTarget is Invalid, then does area effect, otherwise +// * just attempts on otarget +void spellsStinkingCloud(object oTarget = OBJECT_INVALID); + +// * caltrops do 25 points of damage (1 pnt per target per round) and then are gone +void DoCaltropEffect(object oTarget); + +// * apply effects of spike trap on entering object +void DoTrapSpike(int nDamage); + +//* fires a storm of nCap missiles at targets in area +void DoMissileStorm(int nD6Dice, int nCap, int nSpell, int nMIRV = VFX_IMP_MIRV, int nVIS = VFX_IMP_MAGBLUE, int nDAMAGETYPE = DAMAGE_TYPE_MAGICAL, int nONEHIT = FALSE, int nReflexSave = FALSE); + +// * Applies ability score damage +void DoDirgeEffect(object oTarget); + +void spellsInflictTouchAttack(int nDamage, int nMaxExtraDamage, int nMaximized, int vfx_impactHurt, int vfx_impactHeal, int nSpellID); + +// * improves an animal companion or summoned creature's attack and damage and the ability to hit +// * magically protected creatures +void DoMagicFang(int nPower, int nDamagePower); + +// * for spike growth area of effect object +// * applies damage and slow effect +void DoSpikeGrowthEffect(object oTarget); + +// * Applies the 'camoflage' magical effect to the target +void DoCamoflage(object oTarget); + +// * Does a damage type grenade (direct or splash on miss) +void DoGrenade(int nDirectDamage, int nSplashDamage, int vSmallHit, int vRingHit, int nDamageType, float fExplosionRadius , int nObjectFilter, int nRacialType=RACIAL_TYPE_ALL); + +// * This is a wrapper for how Petrify will work in Expansion Pack 1 +// * Scripts affected: flesh to stone, breath petrification, gaze petrification, touch petrification +// * nPower : This is the Hit Dice of a Monster using Gaze, Breath or Touch OR it is the Caster Spell of +// * a spellcaster +// * nFortSaveDC: pass in this number from the spell script +void DoPetrification(int nPower, object oSource, object oTarget, int nSpellID, int nFortSaveDC); + +// * removed mind effects and provide mind protection +void spellApplyMindBlank(object oTarget, int nSpellId, float fDelay=0.0); + +// * Handle dispel magic of AoEs +void spellsDispelAoE(object oTargetAoE, object oCaster, int nCasterLevel); + + + +//:://///////////////////////////////////////////// +//:: DoTrapSpike +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Does a spike trap. Reflex save allowed. +*/ +//::////////////////////////////////////////////// +//:: Created By: +//:: Created On: +//::////////////////////////////////////////////// +// apply effects of spike trap on entering object +void DoTrapSpike(int nDamage) +{ + //Declare major variables + object oTarget = GetEnteringObject(); + + int nRealDamage = GetReflexAdjustedDamage(nDamage, oTarget, 15, SAVING_THROW_TYPE_TRAP, OBJECT_SELF); + if (nDamage > 0) + { + effect eDam = EffectDamage(nRealDamage, DAMAGE_TYPE_PIERCING); + effect eVis = EffectVisualEffect(253); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, GetLocation(oTarget)); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); + } +} +//:://///////////////////////////////////////////// +//:: MaximizeOrEmpower +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Checks the appropriate metamagic to see + how the damage should be scaled. +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: September 2002 +//::////////////////////////////////////////////// + +int MaximizeOrEmpower(int nDice, int nNumberOfDice, int nMeta, int nBonus = 0) +{ + int i = 0; + int nDamage = 0; + for (i=1; i<=nNumberOfDice; i++) + { + nDamage = nDamage + Random(nDice) + 1; + } + //Resolve metamagic + if (nMeta == METAMAGIC_MAXIMIZE) + { + nDamage = nDice * nNumberOfDice; + } + else if (nMeta == METAMAGIC_EMPOWER) + { + nDamage = nDamage + nDamage / 2; + } + return nDamage + nBonus; +} + +//:://///////////////////////////////////////////// +//:: DoGrenade +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Does a damage type grenade (direct or splash on miss) +*/ +//::////////////////////////////////////////////// +//:: Created By: +//:: Created On: +//::////////////////////////////////////////////// +void DoGrenade(int nDirectDamage, int nSplashDamage, int vSmallHit, int vRingHit, int nDamageType, float fExplosionRadius , int nObjectFilter, int nRacialType=RACIAL_TYPE_ALL) +{ + //Declare major variables ( fDist / (3.0f * log( fDist ) + 2.0f) ) + object oTarget = GetSpellTargetObject(); + int nCasterLvl = GetCasterLevel(OBJECT_SELF); + int nDamage = 0; + int nMetaMagic = GetMetaMagicFeat(); + int nCnt; + effect eMissile; + effect eVis = EffectVisualEffect(vSmallHit); + location lTarget = GetSpellTargetLocation(); + + + float fDist = GetDistanceBetween(OBJECT_SELF, oTarget); + int nTouch; + + + if (GetIsObjectValid(oTarget) == TRUE) + { +/* // * BK September 27 2002 + // * if the object is 'far' from the original impact it + // * will be an automatic miss too + location lObject = GetLocation(oTarget); + float fDistance = GetDistanceBetweenLocations(lTarget, lObject); +// SpawnScriptDebugger(); + if (fDistance > 1.0) + { + nTouch = -1; + } + else + This did not work. The location and object location are the same. + For now we'll have to live with the possiblity of the 'explosion' + happening away from where the grenade hits. + We could convert everything to splash... + */ + nTouch = TouchAttackRanged(oTarget); + + } + else + { + nTouch = -1; // * this means that target was the ground, so the user + // * intended to splash + } + if (nTouch >= 1) + { + //Roll damage + int nDam = nDirectDamage; + + if(nTouch == 2) + { + nDam *= 2; + } + + //Set damage effect + effect eDam = EffectDamage(nDam, nDamageType); + //Apply the MIRV and damage effect + + // * only damage enemies + if(spellsIsTarget(oTarget,SPELL_TARGET_STANDARDHOSTILE,OBJECT_SELF) ) + { + // * must be the correct racial type (only used with Holy Water) + if ((nRacialType != RACIAL_TYPE_ALL) && (nRacialType == GetRacialType(oTarget))) + { + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + //ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eVis, oTarget); VISUALS outrace the grenade, looks bad + } + else + if ((nRacialType == RACIAL_TYPE_ALL) ) + { + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + //ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eVis, oTarget); VISUALS outrace the grenade, looks bad + } + + } + + // ApplyEffectToObject(DURATION_TYPE_INSTANT, eMissile, oTarget); + } + +// * +// * Splash damage always happens as well now +// * + { + effect eExplode = EffectVisualEffect(vRingHit); + //Apply the fireball explosion at the location captured above. + +/* float fFace = GetFacingFromLocation(lTarget); + vector vPos = GetPositionFromLocation(lTarget); + object oArea = GetAreaFromLocation(lTarget); + vPos.x = vPos.x - 1.0; + vPos.y = vPos.y - 1.0; + lTarget = Location(oArea, vPos, fFace); + missing code looks bad because it does not jive with visual +*/ + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, lTarget); + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, fExplosionRadius, lTarget, TRUE, nObjectFilter); + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget)) + { + if(spellsIsTarget(oTarget,SPELL_TARGET_STANDARDHOSTILE,OBJECT_SELF) ) + { + float fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oTarget))/20; + //Roll damage for each target + nDamage = nSplashDamage; + + //Set the damage effect + effect eDam = EffectDamage(nDamage, nDamageType); + if(nDamage > 0) + { + // * must be the correct racial type (only used with Holy Water) + if ((nRacialType != RACIAL_TYPE_ALL) && (nRacialType == GetRacialType(oTarget))) + { + // Apply effects to the currently selected target. + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + //This visual effect is applied to the target object not the location as above. This visual effect + //represents the flame that erupts on the target not on the ground. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + else + if ((nRacialType == RACIAL_TYPE_ALL) ) + { + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + + } + } + //Select the next target within the spell shape. + oTarget = GetNextObjectInShape(SHAPE_SPHERE, fExplosionRadius, lTarget, TRUE, nObjectFilter); + } + } +} + +//:://///////////////////////////////////////////// +//:: GetCasterAbilityModifier +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Returns the modifier from the ability + score that matters for this caster +*/ +//::////////////////////////////////////////////// +//:: Created By: +//:: Created On: +//::////////////////////////////////////////////// +int GetCasterAbilityModifier(object oCaster) +{ + int nClass = GetLevelByClass(CLASS_TYPE_WIZARD, oCaster); + int nAbility; + if (nClass > 0) + { + nAbility = ABILITY_INTELLIGENCE; + } + else + nAbility = ABILITY_CHARISMA; + + return GetAbilityModifier(nAbility, oCaster); +} +//:://///////////////////////////////////////////// +//:: GetSizeModifier +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Gets the creature's applicable size modifier. + Used in Bigby's Forceful hand for the 'bullrush' + attack. +*/ +//::////////////////////////////////////////////// +//:: Created By: +//:: Created On: +//::////////////////////////////////////////////// +int GetSizeModifier(object oCreature) +{ + int nSize = GetCreatureSize(oCreature); + int nModifier = 0; + switch (nSize) + { + case CREATURE_SIZE_TINY: nModifier = -8; break; + case CREATURE_SIZE_SMALL: nModifier = -4; break; + case CREATURE_SIZE_MEDIUM: nModifier = 0; break; + case CREATURE_SIZE_LARGE: nModifier = 4; break; + case CREATURE_SIZE_HUGE: nModifier = 8; break; + } + return nModifier; +} + +//:://///////////////////////////////////////////// +//:: +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Applies the ability score damage of the dirge effect. + + March 2003 + Because ability score penalties do not stack, I need + to store the ability score damage done + and increment each round. + To that effect I am going to update the description and + remove the dirge effects if the player leaves the area of effect. + +*/ +//::////////////////////////////////////////////// +//:: Created By: +//:: Created On: +//::////////////////////////////////////////////// + +void DoDirgeEffect(object oTarget) +{ //Declare major variables +// int nMetaMagic = GetMetaMagicFeat(); + + // SpawnScriptDebugger(); + + if (spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, GetAreaOfEffectCreator())) + { + //Fire cast spell at event for the target + SignalEvent(oTarget, EventSpellCastAt(GetAreaOfEffectCreator(), GetSpellId())); + //Spell resistance check + if(!MyResistSpell(GetAreaOfEffectCreator(), oTarget)) + { + + //Make a Fortitude Save to avoid the effects of the movement hit. + if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, GetSpellSaveDC(), SAVING_THROW_ALL, GetAreaOfEffectCreator())) + { + int nGetLastPenalty = GetLocalInt(oTarget, "X0_L_LASTPENALTY"); + // * increase penalty by 2 + nGetLastPenalty = nGetLastPenalty + 2; + + effect eStr = EffectAbilityDecrease(ABILITY_STRENGTH, nGetLastPenalty); + effect eDex = EffectAbilityDecrease(ABILITY_DEXTERITY, nGetLastPenalty); + //change from sonic effect to bard song... + effect eVis = EffectVisualEffect(VFX_FNF_SOUND_BURST); + effect eLink = EffectLinkEffects(eDex, eStr); + + //Apply damage and visuals + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oTarget); + SetLocalInt(oTarget, "X0_L_LASTPENALTY", nGetLastPenalty); + } + + } + } +} +//:://///////////////////////////////////////////// +//:: DoCamoflage +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Applies the 'camoflage' magical effect + to the target +*/ +//::////////////////////////////////////////////// +//:: Created By: +//:: Created On: +//::////////////////////////////////////////////// + +void DoCamoflage(object oTarget) +{ + //Declare major variables + effect eVis = EffectVisualEffect(VFX_IMP_IMPROVE_ABILITY_SCORE); + int nMetaMagic = GetMetaMagicFeat(); + + effect eHide = EffectSkillIncrease(SKILL_HIDE, 10); + + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); + effect eLink = EffectLinkEffects(eHide, eDur); + + int nDuration = GetCasterLevel(OBJECT_SELF); + nDuration = 10 * nDuration; // * Duration 10 turn/level + if (nMetaMagic == METAMAGIC_EXTEND) //Duration is +100% + { + nDuration = nDuration * 2; + } + + //Fire spell cast at event for target + SignalEvent(oTarget, EventSpellCastAt(oTarget, GetSpellId(), FALSE)); + //Apply VFX impact and bonus effects + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, TurnsToSeconds(nDuration)); +} +//:://///////////////////////////////////////////// +//:: DoSpikeGrowthEffect +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + 1d4 damage, plus a 24 hr slow if take damage. +*/ +//::////////////////////////////////////////////// +//:: Created By: +//:: Created On: +//::////////////////////////////////////////////// + +void DoSpikeGrowthEffect(object oTarget) +{ + float fDelay = GetRandomDelay(1.0, 2.2); + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, GetAreaOfEffectCreator())) + { + //Fire cast spell at event for the target + SignalEvent(oTarget, EventSpellCastAt(GetAreaOfEffectCreator(), SPELL_SPIKE_GROWTH)); + //Spell resistance check + if(!MyResistSpell(GetAreaOfEffectCreator(), oTarget, fDelay)) + { + int nMetaMagic = GetMetaMagicFeat(); + int nDam = MaximizeOrEmpower(4, 1, nMetaMagic); + + effect eDam = EffectDamage(nDam, DAMAGE_TYPE_PIERCING); + effect eVis = EffectVisualEffect(VFX_IMP_ACID_S); + //effect eLink = eDam; + //Apply damage and visuals + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam/*eLink*/, oTarget)); + + // * only apply a slow effect from this spell once + if (GetHasSpellEffect(SPELL_SPIKE_GROWTH, oTarget) == FALSE) + { + //Make a Reflex Save to avoid the effects of the movement hit. + if(!PRCMySavingThrow(SAVING_THROW_REFLEX, oTarget, GetSpellSaveDC(), SAVING_THROW_ALL, GetAreaOfEffectCreator(), fDelay)) + { + effect eSpeed = EffectMovementSpeedDecrease(30); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eSpeed, oTarget, HoursToSeconds(24)); + } + } + } + } +} +//:://///////////////////////////////////////////// +//:: spellsInflictTouchAttack +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + nDamage: Amount of damage to do + nMaxExtraDamage: Max amount of +1 per level damage + nMaximized: Amount of damage to do if maximized + vfx_impactHurt: Impact to play if hurt by spell + vfx_impactHeal: Impact to play if healed by spell + nSpellID: SpellID to broactcast in the signal event +*/ +//::////////////////////////////////////////////// +//:: Created By: +//:: Created On: +//::////////////////////////////////////////////// + +void spellsInflictTouchAttack(int nDamage, int nMaxExtraDamage, int nMaximized, int vfx_impactHurt, int vfx_impactHeal, int nSpellID) +{ + //Declare major variables + object oTarget = GetSpellTargetObject(); + int nMetaMagic = GetMetaMagicFeat(); + int nTouch = TouchAttackMelee(oTarget); + + int nExtraDamage = GetCasterLevel(OBJECT_SELF); // * figure out the bonus damage + if (nExtraDamage > nMaxExtraDamage) + { + nExtraDamage = nMaxExtraDamage; + } + + //Check for metamagic + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = nMaximized; + } + else + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + (nDamage / 2); + } + + + //Check that the target is undead + if (GetRacialType(oTarget) == RACIAL_TYPE_UNDEAD) + { + effect eVis2 = EffectVisualEffect(vfx_impactHeal); + //Figure out the amount of damage to heal + //nHeal = nDamage; + //Set the heal effect + effect eHeal = EffectHeal(nDamage + nExtraDamage); + //Apply heal effect and VFX impact + ApplyEffectToObject(DURATION_TYPE_INSTANT, eHeal, oTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis2, oTarget); + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, nSpellID, FALSE)); + } + else if (nTouch >0 ) + { + if(!GetIsReactionTypeFriendly(oTarget)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, nSpellID)); + if (!MyResistSpell(OBJECT_SELF, oTarget)) + { + int nDamageTotal = nDamage + nExtraDamage; + // A succesful will save halves the damage + if(PRCMySavingThrow(SAVING_THROW_WILL, oTarget, GetSpellSaveDC(), SAVING_THROW_ALL,OBJECT_SELF)) + { + nDamageTotal = nDamageTotal / 2; + } + effect eVis = EffectVisualEffect(vfx_impactHurt); + effect eDam = EffectDamage(nDamageTotal,DAMAGE_TYPE_NEGATIVE); + //Apply the VFX impact and effects + DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + + } + } + } +} + +//:://///////////////////////////////////////////// +//:: DoMissileStorm +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* + Fires a volley of missiles around the area + of the object selected. + + Each missiles (nD6Dice)d6 damage. + There are casterlevel missiles (to a cap as specified) +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 31, 2002 +//::////////////////////////////////////////////// +//:: Modified March 14 2003: Removed the option to hurt chests/doors +//:: was potentially causing bugs when no creature targets available. +void DoMissileStorm(int nD6Dice, int nCap, int nSpell, int nMIRV = VFX_IMP_MIRV, int nVIS = VFX_IMP_MAGBLUE, int nDAMAGETYPE = DAMAGE_TYPE_MAGICAL, int nONEHIT = FALSE, int nReflexSave = FALSE) +{ + object oTarget = OBJECT_INVALID; + int nCasterLvl = GetCasterLevel(OBJECT_SELF); +// int nDamage = 0; + int nMetaMagic = GetMetaMagicFeat(); + int nCnt = 1; + effect eMissile = EffectVisualEffect(nMIRV); + effect eVis = EffectVisualEffect(nVIS); + float fDist = 0.0; + float fDelay = 0.0; + float fDelay2, fTime; + location lTarget = GetSpellTargetLocation(); // missile spread centered around caster + int nMissiles = nCasterLvl; + + if (nMissiles > nCap) + { + nMissiles = nCap; + } + + /* New Algorithm + 1. Count # of targets + 2. Determine number of missiles + 3. First target gets a missile and all Excess missiles + 4. Rest of targets (max nMissiles) get one missile + */ + int nEnemies = 0; + + oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_GARGANTUAN, lTarget, TRUE, OBJECT_TYPE_CREATURE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget) ) + { + // * caster cannot be harmed by this spell + if (spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, OBJECT_SELF) && (oTarget != OBJECT_SELF)) + { + // GZ: You can only fire missiles on visible targets + // If the firing object is a placeable (such as a projectile trap), + // we skip the line of sight check as placeables can't "see" things. + if ( ( GetObjectType(OBJECT_SELF) == OBJECT_TYPE_PLACEABLE ) || + GetObjectSeen(oTarget,OBJECT_SELF)) + { + nEnemies++; + } + } + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_GARGANTUAN, lTarget, TRUE, OBJECT_TYPE_CREATURE); + } + + if (nEnemies == 0) return; // * Exit if no enemies to hit + int nExtraMissiles = nMissiles / nEnemies; + + // April 2003 + // * if more enemies than missiles, need to make sure that at least + // * one missile will hit each of the enemies + if (nExtraMissiles <= 0) + { + nExtraMissiles = 1; + } + + // by default the Remainder will be 0 (if more than enough enemies for all the missiles) + int nRemainder = 0; + + if (nExtraMissiles >0) + nRemainder = nMissiles % nEnemies; + + if (nEnemies > nMissiles) + nEnemies = nMissiles; + + oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_GARGANTUAN, lTarget, TRUE, OBJECT_TYPE_CREATURE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget) && nCnt <= nEnemies) + { + // * caster cannot be harmed by this spell + if (spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, OBJECT_SELF) && + (oTarget != OBJECT_SELF) && + (( GetObjectType(OBJECT_SELF) == OBJECT_TYPE_PLACEABLE ) || + (GetObjectSeen(oTarget,OBJECT_SELF)))) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, nSpell)); + + // * recalculate appropriate distances + fDist = GetDistanceBetween(OBJECT_SELF, oTarget); + fDelay = fDist/(3.0 * log(fDist) + 2.0); + + // Firebrand. + // It means that once the target has taken damage this round from the + // spell it won't take subsequent damage + if (nONEHIT == TRUE) + { + nExtraMissiles = 1; + nRemainder = 0; + } + + int i = 0; + //-------------------------------------------------------------- + // GZ: Moved SR check out of loop to have 1 check per target + // not one check per missile, which would rip spell mantels + // apart + //-------------------------------------------------------------- + if (!MyResistSpell(OBJECT_SELF, oTarget, fDelay)) + { + for (i=1; i <= nExtraMissiles + nRemainder; i++) + { + //Roll damage + int nDam = d6(nD6Dice); + //Enter Metamagic conditions + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDam = nD6Dice*6;//Damage is at max + } + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDam = nDam + nDam/2; //Damage/Healing is +50% + } + // Jan. 29, 2004 - Jonathan Epp + // Reflex save was not being calculated for Firebrand + if(nReflexSave) + { + if ( nDAMAGETYPE == DAMAGE_TYPE_ELECTRICAL ) + { + nDam = GetReflexAdjustedDamage(nDam, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_ELECTRICITY); + } + else if ( nDAMAGETYPE == DAMAGE_TYPE_FIRE ) + { + nDam = GetReflexAdjustedDamage(nDam, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_FIRE); + } + } + + fTime = fDelay; + fDelay2 += 0.1; + fTime += fDelay2; + + //Set damage effect + effect eDam = EffectDamage(nDam, nDAMAGETYPE); + //Apply the MIRV and damage effect + DelayCommand(fTime, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eVis, oTarget)); + DelayCommand(fDelay2, ApplyEffectToObject(DURATION_TYPE_INSTANT, eMissile, oTarget)); + DelayCommand(fTime, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + } + } // for + else + { // * apply a dummy visual effect + ApplyEffectToObject(DURATION_TYPE_INSTANT, eMissile, oTarget); + } + nCnt++;// * increment count of missiles fired + nRemainder = 0; + } + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_GARGANTUAN, lTarget, TRUE, OBJECT_TYPE_CREATURE); + } + +} +//:://///////////////////////////////////////////// +//:: DoMagicFang +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + +1 enhancement bonus to attack and damage rolls. + Also applys damage reduction +1; this allows the creature + to strike creatures with +1 damage reduction. + + Checks to see if a valid summoned monster or animal companion + exists to apply the effects to. If none exists, then + the spell is wasted. + +FEB 19: Made it so only Animal Companions get these bonuses +*/ +//::////////////////////////////////////////////// +//:: Created By: +//:: Created On: +//::////////////////////////////////////////////// + +void DoMagicFang(int nPower, int nDamagePower) +{ + + + //Declare major variables + object oTarget = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION); + + if (GetIsObjectValid(oTarget) == FALSE) + { + FloatingTextStrRefOnCreature(8962, OBJECT_SELF, FALSE); + return; // has neither an animal companion + } + + //Remove effects of anyother fang spells + RemoveSpellEffects(452, GetMaster(oTarget), oTarget); + RemoveSpellEffects(453, GetMaster(oTarget), oTarget); + + effect eVis = EffectVisualEffect(VFX_IMP_HOLY_AID); + int nMetaMagic = GetMetaMagicFeat(); + + effect eAttack = EffectAttackIncrease(nPower); + effect eDamage = EffectDamageIncrease(nPower); + effect eReduction = EffectDamageReduction(nPower, nDamagePower); // * doing this because + // * it creates a true + // * enhancement bonus + + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); + effect eLink = EffectLinkEffects(eAttack, eDur); + eLink = EffectLinkEffects(eLink, eDamage); + eLink = EffectLinkEffects(eLink, eReduction); + + int nDuration = GetCasterLevel(OBJECT_SELF); // * Duration 1 turn/level + if (nMetaMagic == METAMAGIC_EXTEND) //Duration is +100% + { + nDuration = nDuration * 2; + } + + //Fire spell cast at event for target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId(), FALSE)); + //Apply VFX impact and bonus effects + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, TurnsToSeconds(nDuration)); + +} + +//:://///////////////////////////////////////////// +//:: DoCaltropEffect +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + The area effect will only do a total of + 25 points of damage and then destroy itself. +*/ +//::////////////////////////////////////////////// +//:: Created By: +//:: Created On: +//::////////////////////////////////////////////// + +void DoCaltropEffect(object oTarget) +{ + + //int nDam = 1; + + // effect eVis = EffectVisualEffect(VFX_IMP_SPIKE_TRAP); + //effect eLink = eDam; + + if(spellsIsTarget(oTarget,SPELL_TARGET_STANDARDHOSTILE, GetAreaOfEffectCreator()) + && spellsIsFlying(oTarget) == FALSE) + { + //Fire cast spell at event for the target + SignalEvent(oTarget, EventSpellCastAt(GetAreaOfEffectCreator(), 471)); + { + effect eDam = EffectDamage(1, DAMAGE_TYPE_PIERCING); + float fDelay = GetRandomDelay(1.0, 2.2); + //Apply damage and visuals + //DelayCommand(fDelay, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, GetLocation(oTarget))); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + int nDamageDone = GetLocalInt(OBJECT_SELF, "NW_L_TOTAL_DAMAGE"); + nDamageDone++; + + // * storing variable on area of effect object + SetLocalInt(OBJECT_SELF, "NW_L_TOTAL_DAMAGE", nDamageDone); + if (nDamageDone == 25) + { + DestroyObject(OBJECT_SELF); + object oImpactNode = GetLocalObject(OBJECT_SELF, "X0_L_IMPACT"); + if (GetIsObjectValid(oImpactNode) == TRUE) + { + DestroyObject(oImpactNode); + } + } + + } + } +} + +//:://///////////////////////////////////////////// +//:: CanCreatureBeDestroyed +//:: Copyright (c) 2003 Bioware Corp. +//::////////////////////////////////////////////// +/* + Returns true if the creature is allowed + to die (i.e., not plot) +*/ +//::////////////////////////////////////////////// +//:: Created By: +//:: Created On: +//::////////////////////////////////////////////// + +int CanCreatureBeDestroyed(object oTarget) +{ + if (GetPlotFlag(oTarget) == FALSE && GetImmortal(oTarget) == FALSE) + { + return TRUE; + } + return FALSE; +} + +//*GZ: 2003-07-23. honor critical and weapon spec +// Updated: 02/14/2008 CraigW - Added support for Epic Weapon Specialization. +// nCrit - + +int ArcaneArcherDamageDoneByBow(int bCrit = FALSE, object oUser = OBJECT_SELF) +{ + object oItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND); + int nDamage; + int bSpec = FALSE; + int bEpicSpecialization = FALSE; + + if (GetIsObjectValid(oItem) == TRUE) + { + if (GetBaseItemType(oItem) == BASE_ITEM_LONGBOW ) + { + nDamage = d8(); + if (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_LONGBOW,oUser)) + { + bSpec = TRUE; + } + if (GetHasFeat(FEAT_EPIC_WEAPON_SPECIALIZATION_LONGBOW,oUser)) + { + bEpicSpecialization = TRUE; + } + } + else + if (GetBaseItemType(oItem) == BASE_ITEM_SHORTBOW) + { + nDamage = d6(); + if (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_SHORTBOW,oUser)) + { + bSpec = TRUE; + } + if (GetHasFeat(FEAT_EPIC_WEAPON_SPECIALIZATION_SHORTBOW,oUser)) + { + bEpicSpecialization = TRUE; + } + } + else + return 0; + } + else + { + return 0; + } + + // add strength bonus + int nStrength = GetAbilityModifier(ABILITY_STRENGTH,oUser); + nDamage += nStrength; + + if (bSpec == TRUE) + { + nDamage +=2; + } + if ( bEpicSpecialization == TRUE ) + { + nDamage +=4; + } + if (bCrit == TRUE) + { + nDamage *=3; + } + + return nDamage; +} + +//*GZ: 2003-07-23. Properly calculated enhancement bonus +int ArcaneArcherCalculateBonus() +{ + int nLevel = GetLevelByClass(CLASS_TYPE_ARCANE_ARCHER, OBJECT_SELF); + + if (nLevel == 0) //not an arcane archer? + { + return 0; + } + int nBonus = ((nLevel+1)/2); // every odd level after 1 get +1 + return nBonus; +} + + +// * This is a wrapper for how Petrify will work in Expansion Pack 1 +// * Scripts affected: flesh to stone, breath petrification, gaze petrification, touch petrification +// * nPower : This is the Hit Dice of a Monster using Gaze, Breath or Touch OR it is the Caster Spell of +// * a spellcaster +// * nFortSaveDC: pass in this number from the spell script +void DoPetrification(int nPower, object oSource, object oTarget, int nSpellID, int nFortSaveDC) +{ + if (!GetIsReactionTypeFriendly(oTarget)) + { + // * exit if creature is immune to petrification. + if (spellsIsImmuneToPetrification(oTarget)) + return; + + float fDifficulty = 0.0; + int bIsPC = GetIsPC(oTarget); + int bShowPopup = FALSE; + + // * calculate Duration based on difficulty settings. + int nGameDiff = GetGameDifficulty(); + switch (nGameDiff) + { + case GAME_DIFFICULTY_VERY_EASY: + case GAME_DIFFICULTY_EASY: + case GAME_DIFFICULTY_NORMAL: + fDifficulty = RoundsToSeconds(nPower);// One Round per hit-die or caster level. + break; + case GAME_DIFFICULTY_CORE_RULES: + case GAME_DIFFICULTY_DIFFICULT: + bShowPopup = TRUE; + break; + } + + int nSaveDC = nFortSaveDC; + effect ePetrify = EffectPetrify(); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); + effect eLink = EffectLinkEffects(eDur, ePetrify); + + // Let target know the negative spell has been cast. + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, nSpellID)); + //SpeakString(IntToString(nSpellID)); + + // Do a fortitude save check. + if (!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nSaveDC)) + { + // Save failed; apply paralyze effect and VFX impact + // * The duration is permanent against NPCs but only temporary against PC's. + if (bIsPC) + { + if (bShowPopup) + { + // * under hardcore rules or higher, this is an instant death. + ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oTarget); + + // Check for the PC not being a member of a party. + object oParty = GetFirstFactionMember(oTarget, TRUE); + // The test for being a member of a party is not being the + // first member of the party or having at least two PCs in + // the party. The following negates this. + // (Why not just test for two party members? Think about a + // possessed familiar as oTarget.) + if ( oParty == oTarget && !GetIsObjectValid(GetNextFactionMember(oTarget, TRUE)) ) + // Not a member of a party, so display the death panel. + DelayCommand(2.75, PopUpDeathGUIPanel(oTarget, TRUE , TRUE, 40579)); + + // if in hardcore, treat the player as an NPC. + bIsPC = FALSE; + //fDifficulty = TurnsToSeconds(nPower);// One turn per hit-die. + } + else + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, fDifficulty); + } + else + { + ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oTarget); + + //---------------------------------------------------------- + // GZ: Fix for henchmen statues haunting you when changing + // areas. Henchmen are now kicked from the party if + // petrified. + //---------------------------------------------------------- + if (GetAssociateType(oTarget) == ASSOCIATE_TYPE_HENCHMAN) + { + FireHenchman(GetMaster(oTarget), oTarget); + } + } + + // April 2003: Clearing actions to kick them out of conversation when petrified + AssignCommand(oTarget, ClearAllActions(TRUE)); + } + } +} + +//:://///////////////////////////////////////////// +//:: spellsIsTarget +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + This is the reputation wrapper. + It performs the check to see if, based on the + constant provided + it is okay to target this target with the + spell effect. + + + MODIFIED APRIL 2003 + - Other player's associates will now be harmed in + Standard Hostile mode + - Will ignore dead people in all target attempts + + MODIFIED AUG 2003 - GZ + - Multiple henchmen support: made sure that + AoE spells cast by one henchmen do not + affect other henchmen in the party + + MODIFIED JUL 2012 -- TK + - General logic cleanup. + - Target nothing if oSource is not valid (e.g. logged out PC). + - Allow associates to use beneficial spells on each other in all cases. + - Exclude bloodstains. +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: March 6 2003 +//::////////////////////////////////////////////// + +int spellsIsTarget(object oTarget, int nTargetType, object oSource) +{ + // If oSource no longer exists, do not target anything since we cannot + // determine reaction types. + // (Not in BioWare's version, but it could help when a PC logs out.) + if ( !GetIsObjectValid(oSource) ) + return FALSE; + + // If dead, not a valid target + if ( GetIsDead(oTarget) || GetTag(oTarget) == "Bloodstain" ) + return FALSE; + + + // Quickly deal with the beneficial targeting. + if ( nTargetType == SPELL_TARGET_ALLALLIES ) + { + // This kind of spell will affect all friendlies and anyone in my + // party, even if we are upset with each other currently. + return GetFactionEqual(oTarget, oSource) || + GetIsReactionTypeFriendly(oTarget, oSource); + } + + + // At this point, the targeting is "hostile" (either "standard" or "selective"). + // Apply the override that could block associates from hurting each other. + object oTargetMaster = GetMaster(oTarget); + if ( oTargetMaster != OBJECT_INVALID && oTargetMaster == GetMaster(oSource) ) + { + if ( GetModuleSwitchValue(MODULE_SWITCH_ENABLE_MULTI_HENCH_AOE_DAMAGE) == 0 ) + return FALSE; + } + + switch ( nTargetType ) + { + // Standard targeting targets hostiles and neutral PCs, and sometimes + // neutral NPCs, depending on difficulty and module settings. + case SPELL_TARGET_STANDARDHOSTILE: + { + int bHardcore = GetGameDifficulty() > GAME_DIFFICULTY_NORMAL; + + // April 9 2003: Also hurt the associates of non-friendly players. + int bIsPC = GetIsPC(oTarget) || GetIsPC(oTargetMaster); + // Local override is just an out for end users who want the area + // effect spells to hurt 'neutrals' (treat NPC targets like PCs). + if ( GetLocalInt(GetModule(), "X0_G_ALLOWSPELLSTOHURT") == 10 ) + bIsPC = TRUE; + + int bIsFriendly = GetIsReactionTypeFriendly(oTarget, oSource); + if ( bIsFriendly && oTargetMaster != OBJECT_INVALID ) + // Think of this as the previous assignment AND (&&) this: + bIsFriendly = GetIsReactionTypeFriendly(oTargetMaster, oSource); + + int bIsHostile = GetIsReactionTypeHostile(oTarget, oSource) || + GetIsReactionTypeHostile(oTargetMaster, oSource); + + // March 25 2003. The player itself (and associates) can be harmed + // by their own area of effect spells if in hardcore mode. + int bSelfTarget = oTarget == oSource || oTargetMaster == oSource; + + + // Now that we know what we are dealing with, is oTarget a target? + if ( bIsHostile ) + return TRUE; // Hostile creatures are always a target. + + else if ( bHardcore && bSelfTarget ) + return TRUE; // We can hurt ourselves. + + else if ( bIsFriendly ) + return FALSE; // Friends are spared (could be a no-PvP area). + + else if ( bIsPC ) + return TRUE; // Neutral PCs are targets. + + else if ( !bHardcore ) + return FALSE; // At normal and easier, neutral NPCs are not targets. + + else + // At hardcore and higher, a module switch controls targeting neutral NPCs. + return GetModuleSwitchValue(MODULE_SWITCH_ENABLE_NPC_AOE_HURT_ALLIES); + break; + } + + // Selective targeting only harms enemies. + // Examples: call lightning, Isaac's storms, firebrand, chain lightning, + // dirge, nature's balance, word of faith + case SPELL_TARGET_SELECTIVEHOSTILE: + { + return GetIsEnemy(oTarget, oSource); + } + } + + // If we make it this far, the target type is unrecognized. + // Assume no targeting, since that is more likely to generate bug reports. + return FALSE; +} + + +// * generic area of effect constructor +void spellsGenericAreaOfEffect( + object oCaster, location lTargetLoc, + int nShape, float fRadiusSize, int nSpellID, + effect eImpact, effect eLink, effect eVis, + int nDurationType=DURATION_TYPE_INSTANT, float fDuration = 0.0, + int nTargetType=SPELL_TARGET_ALLALLIES, int bHarmful = FALSE, + int nRemoveEffectSpell=FALSE, int nRemoveEffect1=0, int nRemoveEffect2=0, int nRemoveEffect3=0, + int bLineOfSight=FALSE, int nObjectFilter=OBJECT_TYPE_CREATURE, + int bPersistentObject=FALSE, int bResistCheck=FALSE, int nSavingThrowType=SAVING_THROW_NONE, + int nSavingThrowSubType=SAVING_THROW_TYPE_ALL + ) +{ + //Apply Impact + if (GetEffectType(eImpact) != 0) + { + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpact, lTargetLoc); + } + + object oTarget = OBJECT_INVALID; + float fDelay = 0.0; + + //Get the first target in the radius around the caster + if (bPersistentObject == TRUE) + oTarget = GetFirstInPersistentObject(); + else + oTarget = GetFirstObjectInShape(nShape, fRadiusSize, lTargetLoc, bLineOfSight, nObjectFilter); + + while(GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, nTargetType, oCaster) == TRUE) + { + //Fire spell cast at event for target + SignalEvent(oTarget, EventSpellCastAt(oCaster, nSpellID, bHarmful)); + int nResistSpellSuccess = FALSE; + // * actually perform the resist check + if (bResistCheck == TRUE) + { + nResistSpellSuccess = MyResistSpell(oCaster, oTarget); + } + if(!nResistSpellSuccess) + { + int nSavingThrowSuccess = FALSE; + // * actually roll saving throw if told to + if (nSavingThrowType != SAVING_THROW_NONE) + { + nSavingThrowSuccess = PRCMySavingThrow(nSavingThrowType, oTarget, GetSpellSaveDC(), nSavingThrowSubType); + } + if (!nSavingThrowSuccess) + { + fDelay = GetRandomDelay(0.4, 1.1); + + + + //Apply VFX impact + if (GetEffectType(eVis) != 0) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + + // * Apply effects + // if (GetEffectType(eLink) != 0) + // * Had to remove this test because LINKED effects have no valid type. + { + + DelayCommand(fDelay, ApplyEffectToObject(nDurationType, eLink, oTarget, fDuration)); + } + + // * If this is a removal spell then perform the appropriate removals + if (nRemoveEffectSpell == TRUE) + { + //Remove effects + RemoveSpecificEffect(nRemoveEffect1, oTarget); + if(nRemoveEffect2 != 0) + { + RemoveSpecificEffect(nRemoveEffect2, oTarget); + } + if(nRemoveEffect3 != 0) + { + RemoveSpecificEffect(nRemoveEffect3, oTarget); + } + + } + }// saving throw + } // resist spell check + } + //Get the next target in the specified area around the caster + if (bPersistentObject == TRUE) + oTarget = GetNextInPersistentObject(); + else + oTarget = GetNextObjectInShape(nShape, fRadiusSize, lTargetLoc, bLineOfSight, nObjectFilter); + + } +} + + +//:://///////////////////////////////////////////// +//:: ApplyMindBlank +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Applies Mind blank to the target +*/ +//::////////////////////////////////////////////// +//:: Created By: +//:: Created On: +//::////////////////////////////////////////////// +void spellApplyMindBlank(object oTarget, int nSpellId, float fDelay=0.0) +{ + effect eImm1 = EffectImmunity(IMMUNITY_TYPE_MIND_SPELLS); + effect eVis = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_POSITIVE); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); + + effect eLink = EffectLinkEffects(eImm1, eVis); + eLink = EffectLinkEffects(eLink, eDur); + effect eSearch = GetFirstEffect(oTarget); + int bValid; + int nDuration = GetCasterLevel(OBJECT_SELF); + int nMetaMagic = GetMetaMagicFeat(); + //Enter Metamagic conditions + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, nSpellId, FALSE)); + //Search through effects + while(GetIsEffectValid(eSearch)) + { + bValid = FALSE; + //Check to see if the effect matches a particular type defined below + if (GetEffectType(eSearch) == EFFECT_TYPE_DAZED) + { + bValid = TRUE; + } + else if(GetEffectType(eSearch) == EFFECT_TYPE_CHARMED) + { + bValid = TRUE; + } + else if(GetEffectType(eSearch) == EFFECT_TYPE_SLEEP) + { + bValid = TRUE; + } + else if(GetEffectType(eSearch) == EFFECT_TYPE_CONFUSED) + { + bValid = TRUE; + } + else if(GetEffectType(eSearch) == EFFECT_TYPE_STUNNED) + { + bValid = TRUE; + } + else if(GetEffectType(eSearch) == EFFECT_TYPE_DOMINATED) + { + bValid = TRUE; + } + // * Additional March 2003 + // * Remove any feeblemind originating effects + else if (GetEffectSpellId(eSearch) == SPELL_FEEBLEMIND) + { + bValid = TRUE; + } + else if (GetEffectSpellId(eSearch) == SPELL_BANE) + { + bValid = TRUE; + } + + //Apply damage and remove effect if the effect is a match + if (bValid == TRUE) + { + RemoveEffect(oTarget, eSearch); + } + eSearch = GetNextEffect(oTarget); + } + + //After effects are removed we apply the immunity to mind spells to the target + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, TurnsToSeconds(nDuration))); + +} +//:://///////////////////////////////////////////// +//:: doAura +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Used in the Alignment aura - unholy and holy + aura scripts fromthe original campaign + spells. Cleaned them up to be consistent. +*/ +//::////////////////////////////////////////////// +//:: Created By: +//:: Created On: +//::////////////////////////////////////////////// + +void doAura(int nAlign, int nVis1, int nVis2, int nDamageType) +{ + //Declare major variables + object oTarget = GetSpellTargetObject(); + int nDuration = GetCasterLevel(OBJECT_SELF); + int nMetaMagic = GetMetaMagicFeat(); + + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration * 2; //Duration is +100% + } + + effect eVis = EffectVisualEffect(nVis1); + effect eAC = EffectACIncrease(4, AC_DEFLECTION_BONUS); + effect eSave = EffectSavingThrowIncrease(SAVING_THROW_ALL, 4); + //Change the effects so that it only applies when the target is evil + effect eImmune = EffectImmunity(IMMUNITY_TYPE_MIND_SPELLS); + effect eSR = EffectSpellResistanceIncrease(25); //Check if this is a bonus or a setting. + effect eDur = EffectVisualEffect(nVis2); + effect eDur2 = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); + effect eEvil = EffectDamageShield(6, DAMAGE_BONUS_1d8, nDamageType); + + + // * make them versus the alignment + + eImmune = VersusAlignmentEffect(eImmune, ALIGNMENT_ALL, nAlign); + eSR = VersusAlignmentEffect(eSR,ALIGNMENT_ALL, nAlign); + eAC = VersusAlignmentEffect(eAC,ALIGNMENT_ALL, nAlign); + eSave = VersusAlignmentEffect(eSave,ALIGNMENT_ALL, nAlign); + eEvil = VersusAlignmentEffect(eEvil,ALIGNMENT_ALL, nAlign); + + + //Link effects + effect eLink = EffectLinkEffects(eImmune, eSave); + eLink = EffectLinkEffects(eLink, eAC); + eLink = EffectLinkEffects(eLink, eSR); + eLink = EffectLinkEffects(eLink, eDur); + eLink = EffectLinkEffects(eLink, eDur2); + eLink = EffectLinkEffects(eLink, eEvil); + + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId(), FALSE)); + + //Apply the VFX impact and effects + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration)); +} + +// * Does a stinking cloud. If oTarget is Invalid, then does area effect, otherwise +// * just attempts on otarget +void spellsStinkingCloud(object oTarget = OBJECT_INVALID) +{ + effect eStink = EffectDazed(); + effect eMind = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DISABLED); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); + effect eLink = EffectLinkEffects(eMind, eStink); + eLink = EffectLinkEffects(eLink, eDur); + + effect eVis = EffectVisualEffect(VFX_IMP_DAZED_S); + + effect eImpact; // * null + + + if (GetIsObjectValid(oTarget) == TRUE) + { + if(spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, GetAreaOfEffectCreator())) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + //Make a Fort Save + if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_POISON)) + { + if (GetIsImmune(oTarget, IMMUNITY_TYPE_POISON) == FALSE) + { + float fDelay = GetRandomDelay(0.75, 1.75); + //Apply the VFX impact and linked effects + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(2))); + } + } + } + } + else + { + spellsGenericAreaOfEffect(GetAreaOfEffectCreator(), + GetLocation(OBJECT_SELF), // * not relevent for persistent area of effect + SHAPE_CONE, 0.0, // * not relevent for persistent area of effect + GetSpellId(), eImpact, eLink, eVis, + DURATION_TYPE_TEMPORARY, RoundsToSeconds(2), SPELL_TARGET_STANDARDHOSTILE, + TRUE, FALSE, 0, 0, 0, FALSE, OBJECT_TYPE_CREATURE, + TRUE, FALSE, SAVING_THROW_FORT, SAVING_THROW_TYPE_POISON); + } +} + +//:://///////////////////////////////////////////// +//:: RemoveSpellEffects2 +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Advanced version of RemoveSpellEffects to + handle multiple spells (allows code reuse + for shadow conjuration darkness) +*/ +//::////////////////////////////////////////////// +//:: Created By: +//:: Created On: +//::////////////////////////////////////////////// +void RemoveSpellEffects2(int nSpell_ID, object oCaster, object oTarget, int nSpell_ID2, int nSpell_ID3) +{ + + //Declare major variables + int bValid = FALSE; + effect eAOE; + if(GetHasSpellEffect(nSpell_ID, oTarget) || GetHasSpellEffect(nSpell_ID2, oTarget) || GetHasSpellEffect(nSpell_ID3, oTarget)) + { + //Search through the valid effects on the target. + eAOE = GetFirstEffect(oTarget); + while (GetIsEffectValid(eAOE) && bValid == FALSE) + { + if (GetEffectCreator(eAOE) == oCaster) + { + //If the effect was created by the spell then remove it + if(GetEffectSpellId(eAOE) == nSpell_ID || GetEffectSpellId(eAOE) == nSpell_ID2 + || GetEffectSpellId(eAOE) == nSpell_ID3) + { + RemoveEffect(oTarget, eAOE); + bValid = TRUE; + } + } + //Get next effect on the target + eAOE = GetNextEffect(oTarget); + } + } +} + + +// * returns true if the creature has flesh +int spellsIsImmuneToPetrification(object oCreature) +{ + // * GZ: Sept 2003 - Prevent people from petrifying DM, resulting in GUI even when + // effect is not successful. + // I think this is now prevention. -- TK. + if ( GetIsDM(oCreature) || GetPlotFlag(oCreature) ) + return TRUE; + + // We are identifying appearances that have no flesh. + // (Plus the petrifiers -- medusa, gorgon, cockatrice.) + // This operation is optimized into a two-tiered decision tree. + int nAppearance = GetAppearanceType(oCreature); + switch ( nAppearance / 100 ) + { + case 0: // BioWare appearances 0 - 99. + switch ( nAppearance ) + { + case 11: // APPEARANCE_TYPE_BAT_HORROR + case 24: // APPEARANCE_TYPE_GOLEM_BONE + case 36: // APPEARANCE_TYPE_SKELETAL_DEVOURER + case 39: // APPEARANCE_TYPE_LICH + case 52: // APPEARANCE_TYPE_ELEMENTAL_AIR + case 53: // APPEARANCE_TYPE_ELEMENTAL_AIR_ELDER + case 56: // APPEARANCE_TYPE_ELEMENTAL_EARTH + case 57: // APPEARANCE_TYPE_ELEMENTAL_EARTH_ELDER + return TRUE; + } + if ( 60 <= nAppearance && nAppearance <= 64 ) // APPEARANCE_TYPE_ELEMENTAL_FIRE, APPEARANCE_TYPE_ELEMENTAL_FIRE_ELDER, + return TRUE; // APPEARANCE_TYPE_SKELETON_PRIEST, APPEARANCE_TYPE_SKELETON_COMMON, + // APPEARANCE_TYPE_INVISIBLE_STALKER + if ( 68 <= nAppearance && nAppearance <= 71 ) // APPEARANCE_TYPE_ELEMENTAL_WATER_ELDER, APPEARANCE_TYPE_ELEMENTAL_WATER, + return TRUE; // APPEARANCE_TYPE_SKELETON_WARRIOR_1, APPEARANCE_TYPE_SKELETON_WARRIOR_2 + if ( 89 <= nAppearance && nAppearance <= 92 ) // APPEARANCE_TYPE_GOLEM_IRON, APPEARANCE_TYPE_SHIELD_GUARDIAN, + return TRUE; // APPEARANCE_TYPE_GOLEM_CLAY, APPEARANCE_TYPE_GOLEM_STONE + break; + + case 1: // BioWare appearances 100 - 199. + switch ( nAppearance ) + { + case 100: // APPEARANCE_TYPE_HELMED_HORROR + case 103: // APPEARANCE_TYPE_LANTERN_ARCHON + case 116: // APPEARANCE_TYPE_WILL_O_WISP + case 119: // APPEARANCE_TYPE_MINOGON + case 156: // APPEARANCE_TYPE_SPECTRE + case 169: // Golem, Emerald + case 173: // Golem, Ruby + case 182: // APPEARANCE_TYPE_SKELETON_CHIEFTAIN + case 186: // APPEARANCE_TYPE_ALLIP + case 187: // APPEARANCE_TYPE_WRAITH + return TRUE; + } + if ( 146 <= nAppearance && nAppearance <= 150 ) // APPEARANCE_TYPE_SHADOW, APPEARANCE_TYPE_SHADOW_FIEND + return TRUE; // APPEARANCE_TYPE_SKELETON_MAGE, Golem Diamond, + // APPEARANCE_TYPE_SKELETON_WARRIOR + break; + + case 2: // BioWare appearances 200-299. + switch ( nAppearance ) + { + case 200: // APPEARANCE_TYPE_ARCH_TARGET + case 201: // APPEARANCE_TYPE_COMBAT_DUMMY + return TRUE; + } + break; + + case 3: // BioWare appearances 300-399. + if ( 352 == nAppearance ) // APPEARANCE_TYPE_MEDUSA + return TRUE; + if ( 367 <= nAppearance && nAppearance <= 370 ) // APPEARANCE_TYPE_GORGON, APPEARANCE_TYPE_COCKATRICE, + return TRUE; // APPEARANCE_TYPE_BASILISK, APPEARANCE_TYPE_HEURODIS_LICH + break; + + case 4: // BioWare appearances 400-499. + switch ( nAppearance ) + { + case 405: // APPEARANCE_TYPE_DRACOLICH + case 415: // APPEARANCE_TYPE_MINDFLAYER_ALHOON + case 418: // APPEARANCE_TYPE_DRAGON_SHADOW + case 420: // APPEARANCE_TYPE_GOLEM_MITHRAL + case 421: // APPEARANCE_TYPE_GOLEM_ADAMANTIUM + return TRUE; + } + if ( 430 <= nAppearance && nAppearance <= 445 ) // APPEARANCE_TYPE_DEMI_LICH, APPEARANCE_TYPE_OBJECT_CHAIR + return TRUE; // APPEARANCE_TYPE_OBJECT_TABLE, APPEARANCE_TYPE_OBJECT_CANDLE, + // APPEARANCE_TYPE_OBJECT_CHEST, APPEARANCE_TYPE_OBJECT_WHITE, + // APPEARANCE_TYPE_OBJECT_BLUE, APPEARANCE_TYPE_OBJECT_CYAN, + // APPEARANCE_TYPE_OBJECT_GREEN, APPEARANCE_TYPE_OBJECT_YELLOW, + // APPEARANCE_TYPE_OBJECT_ORANGE, APPEARANCE_TYPE_OBJECT_RED, + // APPEARANCE_TYPE_OBJECT_PURPLE, APPEARANCE_TYPE_OBJECT_FLAME_SMALL, + // APPEARANCE_TYPE_OBJECT_FLAME_MEDIUM, APPEARANCE_TYPE_OBJECT_FLAME_LARGE + if ( 469 == nAppearance ) // APPEARANCE_TYPE_ANIMATED_CHEST + return TRUE; + if ( 473 <= nAppearance && nAppearance <= 475 ) // APPEARANCE_TYPE_OBJECT_BOAT, APPEARANCE_TYPE_DWARF_GOLEM, + return TRUE; // APPEARANCE_TYPE_DWARF_HALFORC + break; + + // Skipping cases 5-9. There are BioWare appearances, but all have flesh. + + case 10: // CEP appearances 1000-1099. + switch ( nAppearance ) + { + case 1030: // Armor Stand* + case 1031: // Dracolich B* + case 1047: // Scarecrow* + case 1049: // Skeleton: Small* + case 1066: // Ghost Human: F-Red 3** + case 1095: // Wraith: Hooded 1* + case 1096: // Wraith: Hooded 2* + case 1099: // Visage* + return TRUE; + } + break; + + case 11: // CEP appearances 1100-1199. + switch ( nAppearance ) + { + case 1100: // Visage, Greater* + case 1101: // Demon: Vorlan* + case 1104: // Belker* + return TRUE; + } + break; + + case 12: // CEP appearances 1200-1299. + switch ( nAppearance ) + { + case 1216: // Mechanon, Spiker* + case 1217: // Mechanon, Spider* + case 1218: // Mechanon, Cutter* + case 1257: // Minogon B* + case 1259: // Vampiric Mist 2* + case 1277: // Skeleton: Dwarf* + case 1281: // Bat, Battle* + case 1282: // Bat, Bone* + return TRUE; + } + if ( 1285 <= nAppearance && nAppearance <= 1289 ) // Skeleton: Red Eyes*; Skeleton: Flaming*; Skeleton: Green* + return TRUE; // Skeleton: Purple*; Skeleton: Yellow* + break; + + case 13: // CEP appearances 1300-1399. + if ( 1307 == nAppearance || 1325 == nAppearance ) // Demilich B*; Vecna* + return TRUE; + if ( 1342 <= nAppearance && nAppearance <= 1389 ) // Elemental, Air L*; Elemental, Air M*; Elemental, Air S*; + return TRUE; // Elemental, Smoke L*; Elemental, Smoke M*; Elemental, Smoke S*; + // Elemental, Magma L*; Elemental, Magma M*; Elemental, Magma S*; + // Elemental, Ooze L*; Elemental, Ooze M*; Elemental, Ooze S*; + // Elemental, Water L*; Elemental, Water M*; Elemental, Water S*; + // Elemental, Fire L*; Elemental, Fire M*; Elemental, Fire S*; + // Elemental, Earth L*; Elemental, Earth M*; Elemental, Earth S*; + // Elemental, Ice L*; Elemental, Ice M*; Elemental, Ice S*; + // Elemental, Radiance L*; Elemental, Radiance M*; Elemental, Radiance S*; + // Elemental, Mineral L*; Elemental, Mineral M*; Elemental, Mineral S*; + // Elemental, Steam L*; Elemental, Steam M*; Elemental, Steam S*; + // Elemental, Lightning L*; Elemental, Lightning M*; Elemental, Lightning S*; + // Elemental, Salt L*; Elemental, Salt M*; Elemental, Salt S*; + // Elemental, Dust L*; Elemental, Dust M*; Elemental, Dust S*; + // Elemental, Ash L*; Elemental, Ash M*; Elemental, Ash S*; + break; // Elemental, Vacuum L*; Elemental, Vacuum M*; Elemental, Vacuum S* + + case 14: // CEP appearances 1400-1499. + if ( 1421 <= nAppearance && nAppearance <= 1426 ) // Animated Wheel*; Animated Table*; [1423 skipped]; Animated Chest*; + // Exclude Jagre** // Animated Tome*; Animated Chest, Flying* + return nAppearance != 1423; + if ( 1435 <= nAppearance && nAppearance <= 1437 ) // Flying Book A*; Flying Book B*; Flying Book C* + return TRUE; + if ( 1440 <= nAppearance && nAppearance <= 1447 ) // Skeleton, Pirate 1*; Skeleton, Pirate 2*; Skeleton, Pirate 3*; [1443 and 1444 skipped]; + // Exclude Zombie, Pirate 2*; Zombie, Pirate 3*.// Skeleton, Pirate 4*; Skeleton, Pirate 5*; Skeleton, Pirate 6* + return nAppearance != 1443 && nAppearance != 1444; + if ( 1449 == nAppearance || 1451 == nAppearance ) // Ghost Pirate*; Skeleton, Ogre* + return TRUE; + if ( 1486 <= nAppearance && nAppearance <= 1491 ) // Golem: Ruby*; Golem: Emerald*; Golem: Citrine*; Golem: Sapphire*; + return TRUE; // Golem: Amethyst*; Golem: Obsidian* + if ( 1498 <= nAppearance ) // Maug*; Maug, Lieutenant* + return TRUE; + break; + + case 15: // CEP appearances 1500-1599. + if ( 1500 == nAppearance || 1504 == nAppearance ) // Maug, Commander*; Maug, Captain* + return TRUE; + if ( 1509 <= nAppearance && nAppearance <= 1514 ) // Golem: Hematite**; Golem: Topaz**; Golem: Diamond**; [1512 skipped]; + // Exclude Dragon: Saphire** // Golem: Blackrock**; Golem: Maztica** + return nAppearance != 1512; + if ( 1532 <= nAppearance && nAppearance <= 1536 ) // Golem: Weathered**; Golem: Damaged 1**; Golem: Damaged 2**; + // Exclude Ogre, 3.5e DLA** // [1535 skipped]; Basilisk - Large** + return nAppearance != 1535; + if ( 1579 <= nAppearance && nAppearance <= 1581 ) // Lizard: Lich**; Lizard: Lich, Chief**; Lizard: Lich, Risen** + return TRUE; + break; + + // Skipping case 16. All appearances have flesh. + + case 17: // CEP appearances 1700-1799. + if ( 1755 <= nAppearance && nAppearance <= 1769 ) // Shield Guard Blue**; Shield Guard Vuong**; Shield Guard Wood**; + // Exclude CEP reserved line. // Elemental: Ice 2**; [1759 skipped]; Shield Guard: Gold**; + return nAppearance != 1759; // Shield Guard: Fatal**; Shield Guard: Black**; Shield Guard: Clan**; + // Shield Guard: Mage**; Shield Guard: Knight**; Shield Guard: Mortar**; + break; // Shield Guard: Bizarro**; Shield Guard: Rust**; Skeleton, Dynamic** + + case 18: // CEP appearances 1800-1899. + if ( 1869 <= nAppearance && nAppearance <= 1875 ) // Shadow Lord**; Elemental: Ice**; Elemental: Lava**; Elemental: Death**; + // Exclude Elemental: Floral** // [1873 skipped]; Flying Book: Death**; Flying Book: Myst** + return nAppearance != 1873; + break; + + case 19: // CEP appearances 1900-1999. + if ( 1942 == nAppearance ) // Golem: Atlantis** + return TRUE; + if ( 1994 <= nAppearance && nAppearance <= 1998 ) // Will-O-Wisp: Pink**; Will-O-Wisp: Yellow**; Will-O-Wisp: Purple**; + return TRUE; // Will-O-Wisp: Orange**; Will-O-Wisp: Green** + break; + + // Skipping cases 20 to 24. All appearances have flesh. + + case 25: // CEP appearances 2500-2599. + if ( nAppearance == 2507 ) // Skully + return TRUE; + break; + + // Skipping cases 26 to 30. All appearances have flesh. + + case 31: // CEP appearances 3100-3199. + if ( nAppearance <= 3116 ) // Ghost Human: F-Red 1**; Ghost Human: F-Red 2**; Ghost Human: F-Blue 1**; + return TRUE; // Ghost Human: F-Blue 2**; Ghost Human: F-Blue 3**; Ghost Human: F-Green 1**; + // Ghost Human: F-Green 2**; Ghost Human: F-Green 3**; Ghost Human: M-Red 1**; + // Ghost Human: M-Red 2**; Ghost Human: M-Red 3**; Ghost Human: M-Blue 1**; + // Ghost Human: M-Blue 2**; Ghost Human: M-Blue 3**; Ghost Human: M-Green 1**; + // Ghost Human: M-Green 2**; Ghost Human: M-Green 3** + if ( 3126 <= nAppearance && nAppearance <= 3130 ) // Ice Fiend 1**; Ice Fiend 2**; Ice Fiend 3**; + return TRUE; // Elemental: Fire, Grue; Elemental: Air, Grue + break; + }//switch (nAppearance/100) + + // 03/07/2005 CraigW - Petrification immunity can also be granted as an item property. + // Default: not immune, unless protected by an item property. + return ResistSpell(OBJECT_SELF, oCreature) == 2; +} + + +// * Returns TRUE or FALSE depending on whether the creature is flying or not. +int spellsIsFlying(object oCreature) +{ + // First check for a flying phenotype. + int nPheno = GetPhenoType(oCreature); + if ( nPheno == 16 || nPheno == 25 ) + // Part-based creature set to appear to be flying. + return TRUE; + + // We are identifying appearances that are "flying". + // This operation is optimized into a two-tiered decision tree. + int nAppearance = GetAppearanceType(oCreature); + switch ( nAppearance / 100 ) + { + case 0: // BioWare appearances 0 - 99. + switch ( nAppearance ) + { + case 10: // APPEARANCE_TYPE_BAT + case 11: // APPEARANCE_TYPE_BAT_HORROR + case 52: // APPEARANCE_TYPE_ELEMENTAL_AIR + case 53: // APPEARANCE_TYPE_ELEMENTAL_AIR_ELDER + case 55: // APPEARANCE_TYPE_FAIRY + case 68: // APPEARANCE_TYPE_ELEMENTAL_WATER_ELDER + case 69: // APPEARANCE_TYPE_ELEMENTAL_WATER + return TRUE; + } + break; + + case 1: // BioWare appearances 100 - 199. + // Take care of a largish range. + if ( 103 <= nAppearance && nAppearance <= 116 ) // LANTERN_ARCHON, QUASIT, IMP, MEPHIT_AIR, MEPHIT_DUST, MEPHIT_EARTH, + return TRUE; // MEPHIT_FIRE, MEPHIT_ICE, MEPHIT_SALT, MEPHIT_OOZE, MEPHIT_STEAM, + // MEPHIT_MAGMA, MEPHIT_WATER, and WILL_O_WISP. + // The rest can be done via a switch. + switch ( nAppearance ) + { + case 100: // APPEARANCE_TYPE_HELMED_HORROR + case 144: // APPEARANCE_TYPE_FALCON + case 145: // APPEARANCE_TYPE_RAVEN + case 146: // APPEARANCE_TYPE_SHADOW + case 147: // APPEARANCE_TYPE_SHADOW_FIEND + case 156: // APPEARANCE_TYPE_SPECTRE + case 186: // APPEARANCE_TYPE_ALLIP + case 187: // APPEARANCE_TYPE_WRAITH + return TRUE; + } + break; + + case 2: // BioWare appearances 200-299. + switch ( nAppearance ) + { + case 291: // APPEARANCE_TYPE_SEAGULL_FLYING + case 299: // Beholder, G'Zhorb + return TRUE; + } + break; + + case 3: // BioWare appearances 300-399. + if ( 374 <= nAppearance && nAppearance <= 385 ) // FAERIE_DRAGON, PSEUDODRAGON, WYRMLING_RED, WYRMLING_BLUE, + return TRUE; // WYRMLING_BLACK, WYRMLING_GREEN, WYRMLING_WHITE, WYRMLING_BRASS, + break; // WYRMLING_COPPER, WYRMLING_BRONZE, WYRMLING_SILVER, WYRMLING_GOLD + + case 4: // BioWare appearances 400-499. + switch ( nAppearance ) + { + case 401: // APPEARANCE_TYPE_BEHOLDER + case 402: // APPEARANCE_TYPE_BEHOLDER_MAGE + case 403: // APPEARANCE_TYPE_BEHOLDER_EYEBALL + case 419: // APPEARANCE_TYPE_HARPY + case 430: // APPEARANCE_TYPE_DEMI_LICH + case 447: // APPEARANCE_TYPE_SHARK_MAKO + case 448: // APPEARANCE_TYPE_SHARK_HAMMERHEAD + case 449: // APPEARANCE_TYPE_SHARK_GOBLIN + case 472: // APPEARANCE_TYPE_BEHOLDER_MOTHER + return TRUE; + } + break; + + // Skipping cases 5-9. There are BioWare appearances, but none fly. + + case 10: // CEP appearances 1000-1099. + switch ( nAppearance ) + { + case 1046: // Beholder: B* + case 1050: // Stirge: Cave* + case 1072: // Terradon + case 1073: // Flying Eye* + case 1087: // Terradon: Large + case 1099: // Visage* + return TRUE; + } + break; + + case 11: // CEP appearances 1100-1199. + switch ( nAppearance ) + { + case 1100: // Visage, Greater* + case 1104: // Belker* + case 1171: // Bugs* + case 1172: // Bugs, Large* + return TRUE; + } + break; + + case 12: // CEP appearances 1200-1299. + switch ( nAppearance ) + { + case 1218: // Mechanon, Cutter* + case 1259: // Vampiric Mist 2* + case 1275: // Eagle* + case 1281: // Bat, Battle* + case 1282: // Bat, Bone* + case 1290: // Wendigo* + return TRUE; + } + break; + + case 13: // CEP appearances 1300-1399. + if ( nAppearance == 1307 ) // Demilich B* + return TRUE; + if ( 1342 <= nAppearance && nAppearance <= 1347 ) // Elemental, Air L*; Elemental, Air M*; Elemental, Air S*; + return TRUE; // Elemental, Smoke L*; Elemental, Smoke M*; Elemental, Smoke S* + if ( 1354 <= nAppearance && nAppearance <= 1359 ) // Elemental, Water L*; Elemental, Water M*; Elemental, Water S*; + return TRUE; // Elemental, Fire L*; Elemental, Fire M*; Elemental, Fire S* + if ( 1366 <= nAppearance && nAppearance <= 1368 ) // Elemental, Radiance L*; Elemental, Radiance M*; Elemental, Radiance S* + return TRUE; + if ( 1372 <= nAppearance && nAppearance <= 1377 ) // Elemental, Steam L*; Elemental, Steam M*; Elemental, Steam S*; + return TRUE; // Elemental, Lightning L*; Elemental, Lightning M*; Elemental, Lightning S* + if ( 1384 <= nAppearance && nAppearance <= 1389 ) // Elemental, Ash L*; Elemental, Ash M*; Elemental, Ash S*; + return TRUE; // Elemental, Vacuum L*; Elemental, Vacuum M*; Elemental, Vacuum S* + break; + + case 14: // CEP appearances 1400-1499. + switch ( nAppearance ) + { + case 1419: // Feather Snake** + case 1421: // Animated Wheel* + case 1425: // Animated Tome* + case 1426: // Animated Chest, Flying* + case 1431: // Stirge A* + case 1432: // Stirge B* + case 1435: // Flying Book A* + case 1436: // Flying Book B* + case 1437: // Flying Book C* + case 1494: // Wasp, Giant* + return TRUE; + } + break; + + case 15: // CEP appearances 1500-1599. + if ( nAppearance == 1508 ) // Beholder:Death Tyrant** + return TRUE; + if ( 1556 <= nAppearance && nAppearance <= 1565 ) // Dragon: Flying - Red**; Dragon: Flying - Black**; Dragon: Flying - Blue**; + return TRUE; // Dragon: Flying - Gold**; Dragon: Flying - White**; Dragon: Flying - Silver**; + // Dragon: Flying - Copper**; Dragon: Flying - Green**; + // Dragon: Flying - Brass**; Dragon: Flying - Bronze** + break; + + // Skipping cases 16 and 17. No flying appearances. + + case 18: // CEP appearances 1800-1899. + if ( 1807 <= nAppearance && nAppearance <= 1817 ) // Flying Vampire Female**; Flying Vampire Male**; Flying Kobold**; + // exclude Werecat Artic [SB]** // Flying Succubus**; [1811 skipped]; Flying Erinyes**; Flying Kobold B**; + return nAppearance != 1811; // Flying Kobold Chief A**; Flying Kobold Chief B**; Flying Kobold ShamanA**; + // Flying Kobold ShamanB** + if ( 1871 <= nAppearance && nAppearance <= 1882 ) // Elemental: Lava**; Elemental: Death**; Elemental: Floral**; Flying Book: Death**; + // exclude Barghest v2** // Flying Book: Myst**; Shark: Mako - low**; Shark: Goblin - low**; [1878 skipped]; + return nAppearance != 1878; // Shark: Great White**; Shark: Great White - low**; Shark: Tiger**; + // Shark: Tiger - low** + if ( 1891 <= nAppearance && nAppearance <= 1893 ) // Eagle, Legend**; Bat: Fruit**; Bat: LeafNosed** + return TRUE; + break; + + case 19: // CEP appearances 1900-1999. + if ( 1947 <= nAppearance && nAppearance <= 1952 ) // Bird: Owl, Brown**; Bird: Owl, Snowy**; Bird: Owl, Barn**; Bird: Owl, Great**; + return TRUE; // Bird: Owl, Gray**; Bird: Owl, Black** + if ( 1956 <= nAppearance && nAppearance <= 1965 ) // Bird: Macaw**; Bird: Macaw, Red**; Bird: Macaw, Blue**; Bird: Parrot, Grey**; + return TRUE; // Bird: Cockatoo, White**; Bird: Cockatoo, Black**; Bird: Parrot, Green**; + // Bird: Toucan**; Bird: Albatross**; Bird: Puffin** + if ( 1975 <= nAppearance && nAppearance <= 1979 ) // Bird: Blue Jay**; Bird: Cardinal**; Bird: Mockingbird**; Bird: Blackbird**; + return TRUE; // Bird: Oriole** + if ( nAppearance == 1988 ) // Dragonfly** + return TRUE; + if ( 1990 <= nAppearance && nAppearance <= 1998 ) // Fairy: Blue**; Fairy: Purple**; Fairy: Orange**; Fairy: Pink**; + return TRUE; // Will-O-Wisp: Pink**; Will-O-Wisp: Yellow**; Will-O-Wisp: Purple**; + // Will-O-Wisp: Orange**; Will-O-Wisp: Green** + break; + + // Skipping cases 20 to 24. No flying appearances. + + case 25: // CEP appearances 2500-2599. + if ( nAppearance == 2507 ) // Skully + return TRUE; + break; + + // Skipping cases 26 to 30. No flying appearances. + + case 31: // CEP appearances 3100-3199. + switch ( nAppearance ) + { + case 3121: // Efreeti: Noble** + case 3122: // Dao** + case 3123: // Marid** + case 3124: // Djinni** + case 3127: // Ice Fiend 2** + case 3129: // Elemental: Fire, Grue + case 3130: // Elemental: Air, Grue + return TRUE; + } + break; + + // Skipping cases 32 to 38. No flying appearances. + + case 39: // CEP appearances 3900-3999. + if ( nAppearance == 3999 ) // Bat: Fruit, Small** + return TRUE; + break; + }//switch (nAppearance/100) + + // Default: not flying. + return FALSE; +}//spellsIsFlying() + + +// * returns true if oCreature does not have a mind +int spellsIsMindless(object oCreature) +{ + switch ( GetRacialType(oCreature) ) + { + case RACIAL_TYPE_ELEMENTAL: + case RACIAL_TYPE_UNDEAD: + case RACIAL_TYPE_VERMIN: + case RACIAL_TYPE_CONSTRUCT: + case RACIAL_TYPE_OOZE: + case 52: // CEP: Plant + return TRUE; + } + + // Default: has a mind. + return FALSE; +} + + +//------------------------------------------------------------------------------ +// Doesn't care who the caster was removes the effects of the spell nSpell_ID. +// will ignore the subtype as well... +// GZ: Removed the check that made it remove only one effect. +//------------------------------------------------------------------------------ +void RemoveAnySpellEffects(int nSpell_ID, object oTarget) +{ + //Declare major variables + + effect eAOE; + if(GetHasSpellEffect(nSpell_ID, oTarget)) + { + //Search through the valid effects on the target. + eAOE = GetFirstEffect(oTarget); + while (GetIsEffectValid(eAOE)) + { + //If the effect was created by the spell then remove it + if(GetEffectSpellId(eAOE) == nSpell_ID) + { + RemoveEffect(oTarget, eAOE); + } + //Get next effect on the target + eAOE = GetNextEffect(oTarget); + } + } +} + +//------------------------------------------------------------------------------ +// Attempts a dispel on one target, with all safety checks put in. +//------------------------------------------------------------------------------ +void spellsDispelMagic(object oTarget, int nCasterLevel, effect eVis, effect eImpac, int bAll = TRUE, int bBreachSpells = FALSE) +{ + //-------------------------------------------------------------------------- + // Don't dispel magic on petrified targets + // this change is in to prevent weird things from happening with 'statue' + // creatures. Also creature can be scripted to be immune to dispel + // magic as well. + //-------------------------------------------------------------------------- + if (GetHasEffect(EFFECT_TYPE_PETRIFY, oTarget) == TRUE || GetLocalInt(oTarget, "X1_L_IMMUNE_TO_DISPEL") == 10) + { + return; + } + + effect eDispel; + float fDelay = GetRandomDelay(0.1, 0.3); + int nId = GetSpellId(); + + //-------------------------------------------------------------------------- + // Fire hostile event only if the target is hostile... + //-------------------------------------------------------------------------- + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, nId)); + } + else + { + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, nId, FALSE)); + } + + //-------------------------------------------------------------------------- + // GZ: Bugfix. Was always dispelling all effects, even if used for AoE + //-------------------------------------------------------------------------- + if (bAll == TRUE ) + { + eDispel = EffectDispelMagicAll(nCasterLevel); + //---------------------------------------------------------------------- + // GZ: Support for Mord's disjunction + //---------------------------------------------------------------------- + if (bBreachSpells) + { + DoSpellBreach(oTarget, 6, 10, nId); + } + } + else + { + eDispel = EffectDispelMagicBest(nCasterLevel); + if (bBreachSpells) + { + DoSpellBreach(oTarget, 2, 10, nId); + } + } + + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + /// TK change: + ///DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDispel, oTarget)); + DelayCommand(fDelay, TK_ApplyDispel(eDispel, oTarget, nCasterLevel)); +} + +//------------------------------------------------------------------------------ +// GZ: Aug 27 2003 +// Return the hightest spellcasting class of oCreature, used for dispel magic +// workaround +//------------------------------------------------------------------------------ +int GZGetHighestSpellcastingClassLevel(object oCreature) +{ + int nMax; + if (GetIsPC(oCreature)) + { + int i; + int nClass; + int nLevel; + for (i =1; i<= 3; i++) + { + // This is kind of hacky as high level pally's and ranger's will + // dispell at their full class level... + nClass= GetClassByPosition(i,oCreature); + if (nClass != CLASS_TYPE_INVALID) + { + if (nClass == CLASS_TYPE_SORCERER || nClass == CLASS_TYPE_WIZARD || + nClass == CLASS_TYPE_PALEMASTER || nClass == CLASS_TYPE_CLERIC || + nClass == CLASS_TYPE_DRUID || nClass == CLASS_TYPE_BARD || + nClass == CLASS_TYPE_RANGER || nClass == CLASS_TYPE_PALADIN) + { + nLevel = GetLevelByClass(nClass,oCreature); + + if (nLevel> nMax) + { + nMax = nLevel; + } + } + } + } + } + + else + { + //* not a creature ... be unfair and count full HD :) + nMax = GetHitDice(oCreature); + } + + return nMax; +} + +//------------------------------------------------------------------------------ +// returns TRUE if a creature is not in the condition to use gaze attacks +// i.e. blindness +//------------------------------------------------------------------------------ +int GZCanNotUseGazeAttackCheck(object oCreature) +{ + if (GetHasEffect( EFFECT_TYPE_BLINDNESS,oCreature)) + { + FloatingTextStrRefOnCreature(84530, oCreature ,FALSE); // * blinded + return TRUE; + } + return FALSE; +} + +//------------------------------------------------------------------------------ +// Handle Dispelling Area of Effects +// Before adding this AoE's got automatically destroyed. Since NWN does not give +// the required information to do proper dispelling on AoEs, we do some simulated +// stuff here: +// - Base chance to dispel is 25, 50, 75 or 100% depending on the spell +// - Chance is modified positive by the caster level of the spellcaster as well +// - as the relevant ability score +// - Chance is modified negative by the highest spellcasting class level of the +// AoE creator and the releavant ability score. +// Its bad, but its not worse than just dispelling the AoE as the game did until +// now +//------------------------------------------------------------------------------ +void spellsDispelAoE(object oTargetAoE, object oCaster, int nCasterLevel) +{ + object oCreator = GetAreaOfEffectCreator(oTargetAoE); + int nChance; + int nId = GetSpellId(); + if ( nId == SPELL_LESSER_DISPEL ) + { + nChance = 25; + } + else if ( nId == SPELL_DISPEL_MAGIC) + { + nChance = 50; + } + else if ( nId == SPELL_GREATER_DISPELLING ) + { + nChance = 75; + } + else if ( nId == SPELL_MORDENKAINENS_DISJUNCTION ) + { + nChance = 100; + } + + + nChance += ((nCasterLevel + GetCasterAbilityModifier(oCaster)) - (10 + GetCasterAbilityModifier(oCreator))*2) ; + + //-------------------------------------------------------------------------- + // the AI does cheat here, because it can not react as well as a player to + // AoE effects. Also DMs are always successful + //-------------------------------------------------------------------------- + if (!GetIsPC(oCaster)) + { + nChance +=30; + } + + if (oCaster == oCreator) + { + nChance = 100; + } + + int nRand = Random(100); + + if ((nRand < nChance )|| GetIsDM(oCaster) || GetIsDMPossessed(oCaster)) + { + FloatingTextStrRefOnCreature(100929,oCaster); // "AoE dispelled" + DestroyObject (oTargetAoE); + } + else + { + FloatingTextStrRefOnCreature(100930,oCaster); // "AoE not dispelled" + } + +} + + diff --git a/src/_removed/x0_s0_bane.nss b/src/_removed/x0_s0_bane.nss new file mode 100644 index 0000000..23a3dfe --- /dev/null +++ b/src/_removed/x0_s0_bane.nss @@ -0,0 +1,96 @@ +//:://///////////////////////////////////////////// +//:: Bane +//:: X0_S0_Bane.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + All enemies within 30ft of the caster gain a + -1 attack penalty and a -1 save penalty vs fear + effects +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: July 24, 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 20, 2001 +#include "X0_I0_SPELLS" + +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oTarget; + effect eVis = EffectVisualEffect(VFX_IMP_HEAD_EVIL); + effect eImpact = EffectVisualEffect(VFX_FNF_LOS_EVIL_30); + effect eAttack = EffectAttackDecrease(1); + effect eSave = EffectSavingThrowDecrease(SAVING_THROW_ALL, 1, SAVING_THROW_TYPE_FEAR); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); + effect eLink = EffectLinkEffects(eAttack, eSave); + eLink = EffectLinkEffects(eLink, eDur); + int nDuration = GetCasterLevel(OBJECT_SELF); + int nMetaMagic = GetMetaMagicFeat(); + float fDelay; + //Metamagic duration check + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + location lLoc = GetSpellTargetLocation(); + //Apply Impact + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpact, lLoc); + + //Get the first target in the radius around the caster + oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lLoc); + while(GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget,SPELL_TARGET_SELECTIVEHOSTILE, OBJECT_SELF)) + { + //Fire spell cast at event for target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, 449, FALSE)); + if (!MyResistSpell(OBJECT_SELF, oTarget) ) + { + + /*Will Save*/ + int nWillResult = WillSave(oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_MIND_SPELLS); + // * Bane is a mind affecting spell BUT its affects are not classified + // * as mind affecting. To make this work I have to only apply + // * the effects on the case of a failure, unlike most other spells. + if (nWillResult == 0) + { + + fDelay = GetRandomDelay(0.4, 1.1); + //Apply VFX impact and bonus effects + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, TurnsToSeconds(nDuration))); + } else if (GetIsPC(OBJECT_SELF)) + { + FloatingTextStrRefOnCreature(84525, OBJECT_SELF, FALSE); // * Target Immune + } + } + } + //Get the next target in the specified area around the caster + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lLoc); + } +} + + + diff --git a/src/_removed/x0_s0_banishment.nss b/src/_removed/x0_s0_banishment.nss new file mode 100644 index 0000000..9c5b8a7 --- /dev/null +++ b/src/_removed/x0_s0_banishment.nss @@ -0,0 +1,107 @@ +//:://///////////////////////////////////////////// +//:: Banishment +//:: x0_s0_banishment.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + All summoned creatures within 30ft of caster + make a save and SR check or be banished + + As well any Outsiders being must make a + save and SR check or be banished (up to + 2 HD creatures / level can be banished) +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Oct 22, 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 20, 2001 +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" +void main() +{ +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more +*/ + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } +// End of Spell Cast Hook + + //Declare major variables + object oMaster; + effect eVis = EffectVisualEffect(VFX_IMP_UNSUMMON); + effect eImpact = EffectVisualEffect(VFX_FNF_LOS_EVIL_30); + location lTarget = GetSpellTargetLocation(); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpact, lTarget); + int nSpellDC; + //Get the first object in the are of effect + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lTarget); + // * the pool is the number of hit dice of creatures that can be banished + int nPool = 2* GetCasterLevel(OBJECT_SELF); + while(GetIsObjectValid(oTarget)) + { + //does the creature have a master. + oMaster = GetMaster(oTarget); + if (oMaster == OBJECT_INVALID) + { + oMaster = OBJECT_SELF; // TO prevent problems with invalid objects + // passed into GetAssociate + } + // * BK: Removed the master check, only applys to Dismissal not banishment + //Is that master valid and is he an enemy + // if(GetIsObjectValid(oMaster) && GetIsEnemy(oMaster)) + { + // * Is the creature a summoned associate + // * or is the creature an outsider + // * and is there enough points in the pool + if( + (GetAssociate(ASSOCIATE_TYPE_SUMMONED, oMaster) == oTarget || + GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oMaster) == oTarget || + GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oMaster) == oTarget ) || + (GetRacialType((oTarget)) == RACIAL_TYPE_OUTSIDER) && + (nPool > 0) + ) + { + // * March 2003. Added a check so that 'friendlies' will not be + // * unsummoned. + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, 430)); + //Determine correct save + nSpellDC = GetSpellSaveDC()+6; + // * Must be enough points in the pool to destroy target + if (nPool >= GetHitDice(oTarget)) + // * Make SR and will save checks + if (!MyResistSpell(OBJECT_SELF, oTarget) && !MySavingThrow(SAVING_THROW_WILL, oTarget, nSpellDC)) + { + //Apply the VFX and delay the destruction of the summoned monster so + //that the script and VFX can play. + nPool = nPool - GetHitDice(oTarget); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, GetLocation(oTarget)); + if (CanCreatureBeDestroyed(oTarget) == TRUE) + { + //bugfix: Simply destroying the object won't fire it's OnDeath script. + //Which is bad when you have plot-specific things being done in that + //OnDeath script... so lets kill it. + effect eKill = EffectDamage(GetCurrentHitPoints(oTarget)); + //just to be extra-sure... :) + effect eDeath = SupernaturalEffect(EffectDeath(FALSE, FALSE)); + DelayCommand(0.25, ApplyEffectToObject(DURATION_TYPE_INSTANT, eKill, oTarget)); + DelayCommand(0.25, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDeath, oTarget)); + //Destroying a player object is a bad idea + if(GetIsPC(oTarget) == FALSE) + DestroyObject(oTarget, 0.3); + } + } + } // rep check + } + } + //Get next creature in the shape. + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lTarget); + } +} diff --git a/src/_removed/x0_s0_bombard.nss b/src/_removed/x0_s0_bombard.nss new file mode 100644 index 0000000..9fcf797 --- /dev/null +++ b/src/_removed/x0_s0_bombard.nss @@ -0,0 +1,110 @@ +//:://///////////////////////////////////////////// +//:: Bombardment +//:: X0_S0_Bombard +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* +// Rocks fall from sky +// 1d8 damage/level to a max of 10d8 +// Reflex save for half +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 22 2002 +//::////////////////////////////////////////////// +//:: Last Updated By: Andrew Nobbs May 01, 2003 + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oCaster = OBJECT_SELF; + int nCasterLvl = GetCasterLevel(oCaster); + int nMetaMagic = GetMetaMagicFeat(); + int nDamage; + float fDelay; + effect eExplode = EffectVisualEffect(VFX_FNF_METEOR_SWARM); + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_M); + effect eDam; + //Get the spell target location as opposed to the spell target. + location lTarget = GetSpellTargetLocation(); + //Limit Caster level for the purposes of damage + + int nDice; + nDice = ((nCasterLvl/2)); + if (nDice < 10) + { + nDice = 10; + } + + //Apply the fireball explosion at the location captured above. + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, lTarget); + //Declare the spell shape, size and the location. Capture the first target object in the shape. + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget)) + { + if(spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF) == TRUE) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + //Get the distance between the explosion and the target to calculate delay + fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oTarget))/20; + if (!MyResistSpell(OBJECT_SELF, oTarget, fDelay)) + { + //Roll damage for each target + nDamage = d8(nDice); + //Resolve metamagic + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 8 * nDice; + } + else if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + nDamage / 2; + } + //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_ALL); + //Set the damage effect + eDam = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING); + effect eEffect; + eEffect = EffectDazed(); + if(nDamage > 0) + { + + // Apply effects to the currently selected target. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEffect, oTarget); + //This visual effect is applied to the target object not the location as above. This visual effect + //represents the flame that erupts on the target not on the ground. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + } + //Select the next target within the spell shape. + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } +} + + + diff --git a/src/_removed/x0_s0_clight.nss b/src/_removed/x0_s0_clight.nss new file mode 100644 index 0000000..0b9ba22 --- /dev/null +++ b/src/_removed/x0_s0_clight.nss @@ -0,0 +1,70 @@ +//:://///////////////////////////////////////////// +//:: Continual Flame +//:: x0_s0_clight.nss +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* + Permanent Light spell + + XP2 + If cast on an item, item will get permanently + get the property "light". + Previously existing permanent light properties + will be removed! + +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent Knowles +//:: Created On: July 18, 2002 +//::////////////////////////////////////////////// +//:: VFX Pass By: +//:: Added XP2 cast on item code: Georg Z, 2003-06-05 +//::////////////////////////////////////////////// + +//#include "NW_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run + // this spell. + if (!X2PreSpellCastCode()) + { + return; + } + int nDuration; + int nMetaMagic; + + object oTarget = GetSpellTargetObject(); + + // Handle spell cast on item.... + if (GetObjectType(oTarget) == OBJECT_TYPE_ITEM && ! CIGetIsCraftFeatBaseItem(oTarget)) + { + // Do not allow casting on not equippable items + if (!IPGetIsItemEquipable(oTarget)) + { + // Item must be equipable... + FloatingTextStrRefOnCreature(83326,OBJECT_SELF); + return; + } + itemproperty ip = ItemPropertyLight (IP_CONST_LIGHTBRIGHTNESS_BRIGHT, IP_CONST_LIGHTCOLOR_WHITE); + IPSafeAddItemProperty(oTarget, ip, 0.0f,X2_IP_ADDPROP_POLICY_REPLACE_EXISTING,TRUE,TRUE); + } + else + { + + //Declare major variables + effect eVis = (EffectVisualEffect(VFX_DUR_LIGHT_WHITE_20)); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); + effect eLink = SupernaturalEffect(EffectLinkEffects(eVis, eDur)); + + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, 419, FALSE)); + + //Apply the VFX impact and effects + ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oTarget); + } +} + + + diff --git a/src/_removed/x0_s0_dirgeex.nss b/src/_removed/x0_s0_dirgeex.nss new file mode 100644 index 0000000..e6a2005 --- /dev/null +++ b/src/_removed/x0_s0_dirgeex.nss @@ -0,0 +1,54 @@ +//:://///////////////////////////////////////////// +//:: Dirge: On Exit +//:: x0_s0_dirgeET.nss +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* + MARCH 2003 + Remove the negative effects of the dirge. +*/ +//::////////////////////////////////////////////// +//:: Created By: +//:: Created On: +//::////////////////////////////////////////////// +//:: Update Pass By: + +#include "x2_inc_spellhook" + +void main() +{ + + //Declare major variables + //Get the object that is exiting the AOE + object oTarget = GetExitingObject(); + effect eAOE; + // SpawnScriptDebugger(); + if(GetHasSpellEffect(SPELL_DIRGE, oTarget)) + { + DeleteLocalInt(oTarget, "X0_L_LASTPENALTY"); + + //Search through the valid effects on the target. + eAOE = GetFirstEffect(oTarget); + + while (GetIsEffectValid(eAOE) ) + { + if (GetEffectCreator(eAOE) == GetAreaOfEffectCreator()) + { + //If the effect was created by the Dirge spell then remove it + if(GetEffectSpellId(eAOE) == SPELL_DIRGE) + { + if(GetEffectDurationType(eAOE) == DURATION_TYPE_PERMANENT) + { + RemoveEffect(oTarget, eAOE); + //bValid = TRUE; + } + } + } + //Get next effect on the target + eAOE = GetNextEffect(oTarget); + } + } +} + + + diff --git a/src/_removed/x0_s0_drown.nss b/src/_removed/x0_s0_drown.nss new file mode 100644 index 0000000..944fe0f --- /dev/null +++ b/src/_removed/x0_s0_drown.nss @@ -0,0 +1,77 @@ +//:://///////////////////////////////////////////// +//:: Drown +//:: [X0_S0_Drown.nss] +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* + if the creature fails a FORT throw. + Does not work against Undead, Constructs, or Elementals. + +January 2003: + - Changed to instant kill the target. +May 2003: + - Changed damage to 90% of current HP, instead of instant kill. + +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 26 2002 +//::////////////////////////////////////////////// +//:: Last Update By: Andrew Nobbs May 01, 2003 + +#include "tk_inc_water" +#include "NW_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + + /* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + */ + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not + // run this spell + return; + } + // End of Spell Cast Hook + + + // Declare major variables. + object oTarget = GetSpellTargetObject(); + object oCaster = OBJECT_SELF; + + // Exclude friendly targets. + if ( GetIsReactionTypeFriendly(oTarget) ) + return; + + // Fire cast spell at event for the specified target. + SignalEvent(oTarget, EventSpellCastAt(oCaster, 437)); + // Make SR Check. + if ( MyResistSpell(oCaster, oTarget) ) + return; + + // Target is affected. Check to see what actually happens to the target. + if ( !NeedsToBreathe(oTarget) || CanBreatheWater(oTarget) ) + SendMessageToPC(oCaster, GetName(oTarget) + " suffers no ill effects from a breath of water."); + + // Make a fortitude save. + else if ( !MySavingThrow(SAVING_THROW_FORT, oTarget, GetSpellSaveDC()) ) + { + int nDam = GetCurrentHitPoints(oTarget) * 9 / 10; + effect eDam = EffectDamage(nDam, DAMAGE_TYPE_BLUDGEONING); + effect eVis = EffectVisualEffect(VFX_IMP_FROST_S); + //Apply the VFX impact and damage effect + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); + } +} + + + + + diff --git a/src/_removed/x0_s0_earthquake.nss b/src/_removed/x0_s0_earthquake.nss new file mode 100644 index 0000000..c02f22a --- /dev/null +++ b/src/_removed/x0_s0_earthquake.nss @@ -0,0 +1,113 @@ +//:://///////////////////////////////////////////// +//:: Earthquake +//:: X0_S0_Earthquake +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* +// Ground shakes. 1d6 damage, max 10d6 +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 22 2002 +//::////////////////////////////////////////////// +//:: Last Updated By: Andrew Nobbs May 01, 2003 + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + + object oCaster = OBJECT_SELF; + int nCasterLvl = GetCasterLevel(oCaster); + int nMetaMagic = GetMetaMagicFeat(); + int nDamage; + float fDelay; + float nSize = RADIUS_SIZE_COLOSSAL; + effect eExplode = EffectVisualEffect(VFX_FNF_LOS_NORMAL_30); + effect eVis = EffectVisualEffect(VFX_IMP_HEAD_NATURE); + effect eDam; + effect eShake = EffectVisualEffect(356); + //Get the spell target location as opposed to the spell target. + location lTarget = GetSpellTargetLocation(); + //Limit Caster level for the purposes of damage + + int nDice; + nDice = (10+((nCasterLvl-10)/2)); + if (nDice < 10) + { + nDice = 10; + } + + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eShake, OBJECT_SELF, RoundsToSeconds(6)); + + //Apply epicenter explosion on caster + //ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, GetLocation(OBJECT_SELF)); + + + //Declare the spell shape, size and the location. Capture the first target object in the shape. + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, nSize, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_EARTHQUAKE)); + //Get the distance between the explosion and the target to calculate delay + fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oTarget))/20; +// Earthquake does not allow spell resistance +// if (!MyResistSpell(OBJECT_SELF, oTarget, fDelay)) + { + + nDamage = MaximizeOrEmpower(6, nDice, GetMetaMagicFeat()); + //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. (Don't bother for caster) + if (oTarget != oCaster) + { + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_ALL); + } + //Set the damage effect + eDam = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING); + effect eEffect; + eEffect = EffectKnockdown(); + // * caster can't be affected by the spell + if( (nDamage > 0) && (oTarget != oCaster)) + { + + // Apply effects to the currently selected target. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEffect, oTarget); + //This visual effect is applied to the target object not the location as above. This visual effect + //represents the flame that erupts on the target not on the ground. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + } + //Select the next target within the spell shape. + oTarget = GetNextObjectInShape(SHAPE_SPHERE, nSize, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } +} + + + + + diff --git a/src/_removed/x0_s0_ether.nss b/src/_removed/x0_s0_ether.nss new file mode 100644 index 0000000..0544cdf --- /dev/null +++ b/src/_removed/x0_s0_ether.nss @@ -0,0 +1,61 @@ +//:://///////////////////////////////////////////// +//:: Etherealness +//:: x0_s0_ether.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Like sanctuary except almost always guaranteed + to work. + Lasts one turn per level. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Jan 7, 2002 +//::////////////////////////////////////////////// + +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oTarget = GetSpellTargetObject(); + effect eVis = EffectVisualEffect(VFX_DUR_SANCTUARY); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); + effect eSanc = EffectEthereal(); + + effect eLink = EffectLinkEffects(eVis, eSanc); + eLink = EffectLinkEffects(eLink, eDur); + + int nDuration = GetCasterLevel(OBJECT_SELF); + //Enter Metamagic conditions + int nMetaMagic = GetMetaMagicFeat(); + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_ETHEREALNESS, FALSE)); + //Apply the VFX impact and effects + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration)); +} + + + diff --git a/src/_removed/x0_s0_fleshsto.nss b/src/_removed/x0_s0_fleshsto.nss new file mode 100644 index 0000000..8c87b1e --- /dev/null +++ b/src/_removed/x0_s0_fleshsto.nss @@ -0,0 +1,37 @@ +// HCR v3.2.0 - Had to recompile for change in DoPetrification to take effect. +//:://///////////////////////////////////////////// +//:: Flesh to Stone +//:: FileName: x0_s0_fleshsto +//::////////////////////////////////////////////// +/* + The target freezes in place, standing helpless. +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent Knowles +//:: Created On: October 16, 2002 +//::////////////////////////////////////////////// + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + + // Spellcast hook code + // Added 2003-06-20 by Georg + // If you want to make changes to all spells, + // check x2_inc_spellhook.nss to find out more. + if ( !X2PreSpellCastCode() ) + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell. + return; + // End of spell cast hook + + + object oCaster = OBJECT_SELF; + object oTarget = GetSpellTargetObject(); + + // Check spell resistance. + if ( MyResistSpell(oCaster, oTarget) < 1 ) + // Petrified. + DoPetrification(GetCasterLevel(oCaster), oCaster, oTarget, GetSpellId(), GetSpellSaveDC()); +} diff --git a/src/_removed/x0_s0_missstorm2.nss b/src/_removed/x0_s0_missstorm2.nss new file mode 100644 index 0000000..24ce9a5 --- /dev/null +++ b/src/_removed/x0_s0_missstorm2.nss @@ -0,0 +1,65 @@ +//:://///////////////////////////////////////////// +//:: Isaacs Greater Missile Storm +//:: x0_s0_MissStorm2 +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* + Up to 20 missiles, each doing 3d6 damage to each + target in area. +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 31, 2002 +//::////////////////////////////////////////////// +//:: Last Updated By: + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + location lTarget = GetSpellTargetLocation(); // missile spread centered around caster + int nEnemies = 0, nMaxMissiles = 20; + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + // Copied from x0_i0_spells to limit max. missiles per target without needing to touch includes + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_GARGANTUAN, lTarget, TRUE, OBJECT_TYPE_CREATURE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget) ) + { + // * caster cannot be harmed by this spell + if (spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, OBJECT_SELF) && (oTarget != OBJECT_SELF)) + { + // GZ: You can only fire missiles on visible targets + if (GetObjectSeen(oTarget,OBJECT_SELF)) + { + nEnemies++; + } + } + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_GARGANTUAN, lTarget, TRUE, OBJECT_TYPE_CREATURE); + } + + if(nEnemies == 1) + { + nMaxMissiles = 15; + } + + DoMissileStorm(2, nMaxMissiles, SPELL_ISAACS_GREATER_MISSILE_STORM); +} + + diff --git a/src/_removed/x0_s0_planar.nss b/src/_removed/x0_s0_planar.nss new file mode 100644 index 0000000..6a530d3 --- /dev/null +++ b/src/_removed/x0_s0_planar.nss @@ -0,0 +1,87 @@ +//:://///////////////////////////////////////////// +//:: Planar Ally +//:: X0_S0_Planar.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Summons an outsider dependant on alignment, or + holds an outsider if the creature fails a save. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 12, 2001 +//::////////////////////////////////////////////// +//:: Modified from Planar binding +//:: Hold ability removed for cleric version of spell + +#include "NW_I0_SPELLS" + +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oTarget = GetSpellTargetObject(); + int nMetaMagic = GetMetaMagicFeat(); + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + int nDuration = GetCasterLevel(OBJECT_SELF); + effect eSummon; + effect eGate; + + + int nRacial = GetRacialType(oTarget); + int nAlign = GetAlignmentGoodEvil(OBJECT_SELF); + if(nDuration == 0) + { + nDuration == 1; + } + //Check for metamagic extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + + //Set the summon effect based on the alignment of the caster + float fDelay = 3.0; + switch (nAlign) + { + case ALIGNMENT_EVIL: + eSummon = EffectSummonCreature("wogsumsucubusa01",VFX_FNF_SUMMON_GATE, fDelay); + //eGate = EffectVisualEffect(VFX_FNF_SUMMON_GATE); + break; + case ALIGNMENT_GOOD: + eSummon = EffectSummonCreature("chound002", VFX_FNF_SUMMON_CELESTIAL, fDelay); + //eGate = EffectVisualEffect(219); + break; + case ALIGNMENT_NEUTRAL: + eSummon = EffectSummonCreature("slaadgrn001",VFX_FNF_SUMMON_MONSTER_3, 1.0); + //eGate = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_3); + //fDelay = 1.0; + break; + } + //Apply the summon effect and VFX impact + //ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eGate, GetSpellTargetLocation()); + if(GetLocalInt(OBJECT_SELF, "DW_FLAG_PLANAR") == 0) + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), RoundsToSeconds(nDuration)); + SetLocalInt(OBJECT_SELF, "DW_FLAG_PLANAR", 1); + DelayCommand(3.0, DeleteLocalInt(OBJECT_SELF, "DW_FLAG_PLANAR")); +} + diff --git a/src/_removed/x0_s0_udetfoe.nss b/src/_removed/x0_s0_udetfoe.nss new file mode 100644 index 0000000..43e3eb1 --- /dev/null +++ b/src/_removed/x0_s0_udetfoe.nss @@ -0,0 +1,108 @@ +//:://///////////////////////////////////////////// +//:: Undeath's Eternal Foe +//:: x0_s0_udetfoe.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Grants many protections against undead + to allies in a small area + of effect (everyone gets negative energy protection) + immunity to poison and disease too + +4 AC bonus to all creatures +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 31, 2002 +//::////////////////////////////////////////////// +//:: VFX Pass By: +#include "NW_I0_SPELLS" +#include "x2_inc_spellhook" + +void GrantProtection(object oTarget) +{ + effect eVis = EffectVisualEffect(VFX_IMP_HOLY_AID); + + effect eNeg = EffectDamageImmunityIncrease(DAMAGE_TYPE_NEGATIVE, 100); + effect eLevel = EffectImmunity(IMMUNITY_TYPE_NEGATIVE_LEVEL); + effect eAbil = EffectImmunity(IMMUNITY_TYPE_ABILITY_DECREASE); + effect ePoison = EffectImmunity(IMMUNITY_TYPE_POISON); + effect eDisease = EffectImmunity(IMMUNITY_TYPE_DISEASE); + effect eAC = EffectACIncrease(4); + + int nDuration = GetCasterLevel(OBJECT_SELF); + int nMetaMagic = GetMetaMagicFeat(); + + //Enter Metamagic conditions + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + + //Link Effects + effect eLink = EffectLinkEffects(eNeg, eLevel); + eLink = EffectLinkEffects(eLink, eAbil); + eLink = EffectLinkEffects(eLink, eAC); + eLink = EffectLinkEffects(eLink, ePoison); + eLink = EffectLinkEffects(eLink, eDisease); + + //Prevent stacking effects + RemoveEffectsFromSpell(oTarget, SPELL_UNDEATHS_ETERNAL_FOE); + + //Apply the VFX impact and effects + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration)); + +} + + + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oTarget; + effect eVis = EffectVisualEffect(VFX_IMP_HEAD_HOLY); + effect eImpact = EffectVisualEffect(VFX_FNF_LOS_HOLY_30); + + + float fDelay; + //Metamagic duration check + + //Apply Impact + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpact, GetSpellTargetLocation()); + + //Get the first target in the radius around the caster + oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, GetSpellTargetLocation()); + while(GetIsObjectValid(oTarget)) + { + if(GetIsReactionTypeFriendly(oTarget) || GetFactionEqual(oTarget)) + { + fDelay = GetRandomDelay(0.4, 1.1); + //Fire spell cast at event for target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, 444, FALSE)); + GrantProtection(oTarget); + } + //Get the next target in the specified area around the caster + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, GetSpellTargetLocation()); + } +} + + + diff --git a/src/_removed/x0_s1_petrbreath.nss b/src/_removed/x0_s1_petrbreath.nss new file mode 100644 index 0000000..df98c6a --- /dev/null +++ b/src/_removed/x0_s1_petrbreath.nss @@ -0,0 +1,34 @@ +// HCR v3.2.0 - Had to recompile for change in DoPetrification to take effect. +//:://////////////////////////////////////////////////////////////////////////// +//:: FileName: X0_S1_PetrBreath +//:://////////////////////////////////////////////////////////////////////////// +/* + Petrification breath monster ability. Fortitude save (DC 17) or be turned to + stone permanently. This will be changed to a temporary effect. +*/ +//:://////////////////////////////////////////////////////////////////////////// +//:: Created By: Naomi Novik +//:: Created On: 11/14/2002 +//:://////////////////////////////////////////////////////////////////////////// +#include "x0_i0_spells" +//:://////////////////////////////////////////////////////////////////////////// +void main() +{ + object oTarget = GetSpellTargetObject(); + int nHitDice = GetHitDice(OBJECT_SELF); + location lTargetLocation = GetSpellTargetLocation(); + + // Get first target in spell area. + oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 11.0, lTargetLocation, TRUE); + while (GetIsObjectValid(oTarget)) + { + float fDelay = GetDistanceBetween(OBJECT_SELF, oTarget)/20; + int nSpellID = GetSpellId(); + object oSelf = OBJECT_SELF; + DelayCommand(fDelay, DoPetrification(nHitDice, oSelf, oTarget, nSpellID, 17)); + + // Get next target in spell area. + oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 11.0, lTargetLocation, TRUE); + } +} +//:://////////////////////////////////////////////////////////////////////////// diff --git a/src/_removed/x0_s1_petrgaze.nss b/src/_removed/x0_s1_petrgaze.nss new file mode 100644 index 0000000..f3ff8ac --- /dev/null +++ b/src/_removed/x0_s1_petrgaze.nss @@ -0,0 +1,34 @@ +// HCR v3.2.0 - Had to recompile for change in DoPetrification to take effect. +//:://////////////////////////////////////////////////////////////////////////// +//:: FileName: X0_S1_PetrGaze +//:://////////////////////////////////////////////////////////////////////////// +/* + Petrification gaze monster ability. Fortitude save (DC 15) or be turned to + stone permanently. This will be changed to a temporary effect. +*/ +//:://////////////////////////////////////////////////////////////////////////// +//:: Created By: Naomi Novik +//:: Created On: 11/14/2002 +//:://////////////////////////////////////////////////////////////////////////// +#include "x0_i0_spells" +//:://////////////////////////////////////////////////////////////////////////// +void main() +{ + object oTarget = GetSpellTargetObject(); + int nHitDice = GetHitDice(OBJECT_SELF); + location lTargetLocation = GetSpellTargetLocation(); + + // Get first target in spell area. + oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); + while (GetIsObjectValid(oTarget)) + { + float fDelay = GetDistanceBetween(OBJECT_SELF, oTarget)/20; + int nSpellID = GetSpellId(); + object oSelf = OBJECT_SELF; + DelayCommand(fDelay, DoPetrification(nHitDice, oSelf, oTarget, nSpellID, 13)); + + // Get next target in spell area. + oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); + } +} +//:://////////////////////////////////////////////////////////////////////////// diff --git a/src/_removed/x0_s1_petrtouch.nss b/src/_removed/x0_s1_petrtouch.nss new file mode 100644 index 0000000..0e159a4 --- /dev/null +++ b/src/_removed/x0_s1_petrtouch.nss @@ -0,0 +1,17 @@ +//:://///////////////////////////////////////////////// +//:: X0_S1_PETRGAZE +//:: Petrification touch attack monster ability. +//:: Fortitude save (DC 15) or be turned to stone permanently. +//:: Copyright (c) 2002 Floodgate Entertainment +//:: Created By: Naomi Novik +//:: Created On: 11/14/2002 +//:://///////////////////////////////////////////////// + +#include "x0_i0_spells" + +void main() +{ + DoPetrification(GetHitDice(OBJECT_SELF), OBJECT_SELF, GetSpellTargetObject(), + GetSpellId(), 15); +} + diff --git a/src/_removed/x0_s2_blkdead.nss b/src/_removed/x0_s2_blkdead.nss new file mode 100644 index 0000000..6820e33 --- /dev/null +++ b/src/_removed/x0_s2_blkdead.nss @@ -0,0 +1,38 @@ +//:://///////////////////////////////////////////// +//:: x0_s2_blkdead +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Level 3 - 6: Summons Ghast + Level 7 - 10: Doom Knight +*/ +//::////////////////////////////////////////////// +//:: Created By: +//:: Created On: +//::////////////////////////////////////////////// + +void main() +{ + + int nLevel = GetLevelByClass(CLASS_TYPE_BLACKGUARD, OBJECT_SELF); + float fDelay = 3.0; + int nDuration = nLevel; + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); + string sResRef = ""; + object oBook = GetItemPossessedBy(OBJECT_SELF, "libramofnecroman"); + if ( oBook != OBJECT_INVALID ) + { + sResRef = GetLocalString(oBook, "undead2"); + } + + if ( sResRef == "" ) + { + if (nLevel >= 7) + sResRef = "NW_S_DOOMKGHT"; + else + sResRef = "NW_S_GHAST"; + } + effect eSummon = EffectSummonCreature(sResRef); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), HoursToSeconds(nDuration)); +} diff --git a/src/_removed/x1_s2_imbuearrow.nss b/src/_removed/x1_s2_imbuearrow.nss new file mode 100644 index 0000000..f1a97ee --- /dev/null +++ b/src/_removed/x1_s2_imbuearrow.nss @@ -0,0 +1,111 @@ +//:://///////////////////////////////////////////// +//:: x1_s2_imbuearrow +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Imbue Arrow + - creates a fireball arrow that when it explodes + acts like a fireball. + - Must have shortbow or longbow in hand. + + GZ: Updated + +*/ +//::////////////////////////////////////////////// +//:: Created By: +//:: Created On: +//::////////////////////////////////////////////// + + +#include "x2_inc_spellhook" +#include "X0_I0_SPELLS" + + +void main() +{ + // WoG "spell" hook -- Inverness reacts to all explosions, so this needs to get + // routed through the spellhook. Don't need the full pre-spell-cast code, though. + if ( !X2RunUserDefinedSpellScript() ) + return; + + + //Declare major variables + object oCaster = OBJECT_SELF; + int nCasterLvl = GetLevelByClass(CLASS_TYPE_ARCANE_ARCHER,oCaster); // * get a bonus of +10 to make this useful for arcane archer + int nDamage; + float fDelay; + effect eExplode = EffectVisualEffect(VFX_FNF_FIREBALL); + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_M); + effect eDam; + //Get the spell target location as opposed to the spell target. + location lTarget = GetSpellTargetLocation(); + //Limit Caster level for the purposes of damage + if (nCasterLvl > 10) + { + nCasterLvl = 10 + ((nCasterLvl-10)/2); // add some epic progression of 1d6 per 2 levels after 10 + } + else // * preserve minimum damage of 10d6 + { + nCasterLvl = 10; + } + object oTarget = GetSpellTargetObject(); + // * GZ: Add arrow damage if targeted on creature... + if (GetIsObjectValid(oTarget )) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, oCaster)) + { + int nTouch = TouchAttackRanged(oTarget, TRUE); + if (nTouch > 0) + { + + nDamage = ArcaneArcherDamageDoneByBow(nTouch ==2); + + int nBonus = ArcaneArcherCalculateBonus() ; + effect ePhysical = EffectDamage(nDamage, DAMAGE_TYPE_PIERCING,IPGetDamagePowerConstantFromNumber(nBonus)); + effect eMagic = EffectDamage(nBonus, DAMAGE_TYPE_MAGICAL); + ApplyEffectToObject(DURATION_TYPE_INSTANT, ePhysical, oTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eMagic, oTarget); + } + } + } + + //Apply the fireball explosion at the location captured above. + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, lTarget); + //Declare the spell shape, size and the location. Capture the first target object in the shape. + oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget)) + { + if(spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, oCaster) ) + { + + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(oCaster, GetSpellId(), TRUE)); + //Get the distance between the explosion and the target to calculate delay + fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oTarget))/20; + if (!MyResistSpell(oCaster, oTarget, fDelay)) + { + //Roll damage for each target + nDamage = d6(nCasterLvl); + //Resolve metamagic + //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_FIRE); + //Set the damage effect + eDam = EffectDamage(nDamage, DAMAGE_TYPE_FIRE); + if(nDamage > 0) + { + // Apply effects to the currently selected target. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + //This visual effect is applied to the target object not the location as above. This visual effect + //represents the flame that erupts on the target not on the ground. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + } + //Select the next target within the spell shape. + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } +} + + + diff --git a/src/_removed/x2_i0_spells.nss b/src/_removed/x2_i0_spells.nss new file mode 100644 index 0000000..709d51a --- /dev/null +++ b/src/_removed/x2_i0_spells.nss @@ -0,0 +1,727 @@ +//:://///////////////////////////////////////////// +//:: x2_i0_spells +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Expansion 2 and above include file for spells +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: Nov 2002 +//:: Updated On: 2003/09/10 - Georg Zoeller +//::////////////////////////////////////////////// +#include "prc_x2_itemprop" +#include "x0_i0_spells" + +//------------------------------------------------------------------------------ +// GZ: These constants are used with for the AOE behavior AI +//------------------------------------------------------------------------------ +const int X2_SPELL_AOEBEHAVIOR_FLEE = 0; +const int X2_SPELL_AOEBEHAVIOR_IGNORE = 1; +const int X2_SPELL_AOEBEHAVIOR_GUST = 2; +const int X2_SPELL_AOEBEHAVIOR_DISPEL_L = SPELL_LESSER_DISPEL; +const int X2_SPELL_AOEBEHAVIOR_DISPEL_N = SPELL_DISPEL_MAGIC; +const int X2_SPELL_AOEBEHAVIOR_DISPEL_G = SPELL_GREATER_DISPELLING; +const int X2_SPELL_AOEBEHAVIOR_DISPEL_M = SPELL_MORDENKAINENS_DISJUNCTION; +const int X2_SPELL_AOEBEHAVIOR_DISPEL_C = 727; + + +// * Will pass back a linked effect for all of the bad tide of battle effects. +effect CreateBadTideEffectsLink(); +// * Will pass back a linked effect for all of the good tide of battle effects. +effect CreateGoodTideEffectsLink(); +// * Passes in the slashing weapon type +int GetSlashingWeapon(object oItem); +// * Passes in the melee weapon type +int GetMeleeWeapon(object oItem); +// * Passes in if the item is magical or not. +int GetIsMagicalItem(object oItem); +// * Passes back the stat bonus of the characters magical stat, if any. +int GetIsMagicStatBonus(object oCaster); + +// * Save DC against Epic Spells is the relevant ability score of the caster +// * + 20. The hightest ability score of the casting relevants is 99.99% identical +// * with the one that is used for casting, so we just take it. +// * if used by a placeable, it is equal to the placeables WILL save field. +int GetEpicSpellSaveDC(object oCaster); + +// * Hub function for the epic barbarian feats that upgrade rage. Call from +// * the end of the barbarian rage spellscript +void CheckAndApplyEpicRageFeats(int nRounds); + +// * Checks the character for the thundering rage feat and will apply temporary massive critical +// * to the worn weapons +// * called by CheckAndApplyEpicRageFeats( +void CheckAndApplyThunderingRage(int nRounds); + +// * Checks and runs Rerrifying Rage feat +// * called by CheckAndApplyEpicRageFeats( +void CheckAndApplyTerrifyingRage(int nRounds); + + +// * Do a mind blast +// nDC - DC of the Save to resist +// nRounds - Rounds the stun effect holds +// fRange - Range of the EffectCone +void DoMindBlast(int nDC, int nDuration, float fRange); + + +//:://///////////////////////////////////////////// +//:: CreateBadTideEffectsLink +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Creates the linked bad effects for Battletide. +*/ +//::////////////////////////////////////////////// +//:: Created By: +//:: Created On: +//::////////////////////////////////////////////// + +effect CreateBadTideEffectsLink() +{ + //Declare major variables + effect eSaves = EffectSavingThrowDecrease(SAVING_THROW_ALL, 2); + effect eAttack = EffectAttackDecrease(2); + effect eDamage = EffectDamageDecrease(2); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); + //Link the effects + effect eLink = EffectLinkEffects(eAttack, eDamage); + eLink = EffectLinkEffects(eLink, eSaves); + eLink = EffectLinkEffects(eLink, eDur); + + return eLink; +} + +//:://///////////////////////////////////////////// +//:: CreateGoodTideEffectsLink +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Creates the linked good effects for Battletide. +*/ +//::////////////////////////////////////////////// +//:: Created By: +//:: Created On: +//::////////////////////////////////////////////// + +effect CreateGoodTideEffectsLink() +{ + //Declare major variables + effect eSaves = EffectSavingThrowIncrease(SAVING_THROW_ALL, 2); + effect eAttack = EffectAttackIncrease(2); + effect eDamage = EffectDamageIncrease(2); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); + //Link the effects + effect eLink = EffectLinkEffects(eAttack, eDamage); + eLink = EffectLinkEffects(eLink, eSaves); + eLink = EffectLinkEffects(eLink, eDur); + + return eLink; +} + + +//------------------------------------------------------------------------------ +// AN, 2003 +// Returns TRUE if oItem is a slashing weapon. +//------------------------------------------------------------------------------ +int GetSlashingWeapon(object oItem) +{ + int nItemType = GetBaseItemType(oItem); + if ( nItemType < 200 ) + // BioWare weapons. + switch ( nItemType ) + { + case BASE_ITEM_BASTARDSWORD: + case BASE_ITEM_BATTLEAXE: + case BASE_ITEM_DOUBLEAXE: + case BASE_ITEM_DWARVENWARAXE: + case BASE_ITEM_GREATAXE: + case BASE_ITEM_GREATSWORD: + case BASE_ITEM_HALBERD: + case BASE_ITEM_HANDAXE: + case BASE_ITEM_KAMA: + case BASE_ITEM_KATANA: + case BASE_ITEM_KUKRI: + case BASE_ITEM_LONGSWORD: + case BASE_ITEM_SCIMITAR: + case BASE_ITEM_SCYTHE: + case BASE_ITEM_SICKLE: + case BASE_ITEM_THROWINGAXE: + case BASE_ITEM_TWOBLADEDSWORD: + case BASE_ITEM_WHIP: + return TRUE; + } + else + // CEP weapons. + switch ( nItemType ) + { + case 305: // falchion + case 313: // kukri2 + case 316: // falchion2 + case 319: // mercurial longsword + case 320: // mercurial greatsword + case 321: // double scimitar + case 323: // wind-fire wheel + case 324: // maug double sword + case 330: // longsword2 + return TRUE; + } + + // Default: not a slashing weapon. + return FALSE; +} + + +//------------------------------------------------------------------------------ +// AN, 2003 +// Returns TRUE if oItem is a ranged weapon +//------------------------------------------------------------------------------ +int GetIsRangedWeapon(object oItem) +{ + // GZ: replaced if statement with engine function + return GetWeaponRanged(oItem); +} + + +//------------------------------------------------------------------------------ +// AN, 2003 +// Returns TRUE, if oItem is a melee weapon +//------------------------------------------------------------------------------ +int GetMeleeWeapon(object oItem) +{ + int nItemType = GetBaseItemType(oItem); + if ( nItemType < 200 ) + // BioWare weapons. + switch ( nItemType ) + { + case BASE_ITEM_BASTARDSWORD: + case BASE_ITEM_BATTLEAXE: + case BASE_ITEM_CLUB: + case BASE_ITEM_DAGGER: + case BASE_ITEM_DIREMACE: + case BASE_ITEM_DOUBLEAXE: + case BASE_ITEM_DWARVENWARAXE: + case BASE_ITEM_GREATAXE: + case BASE_ITEM_GREATSWORD: + case BASE_ITEM_HALBERD: + case BASE_ITEM_HANDAXE: + case BASE_ITEM_HEAVYFLAIL: + case BASE_ITEM_KAMA: + case BASE_ITEM_KATANA: + case BASE_ITEM_KUKRI: + case BASE_ITEM_LIGHTFLAIL: + case BASE_ITEM_LIGHTHAMMER: + case BASE_ITEM_LIGHTMACE: + case BASE_ITEM_LONGSWORD: + case BASE_ITEM_MAGICSTAFF: + case BASE_ITEM_MORNINGSTAR: + case BASE_ITEM_QUARTERSTAFF: + case BASE_ITEM_RAPIER: + case BASE_ITEM_SCIMITAR: + case BASE_ITEM_SCYTHE: + case BASE_ITEM_SHORTSPEAR: + case BASE_ITEM_SHORTSWORD: + case BASE_ITEM_SICKLE: + case BASE_ITEM_TRIDENT: + case BASE_ITEM_TWOBLADEDSWORD: + case BASE_ITEM_WARHAMMER: + case BASE_ITEM_WHIP: + return TRUE; + } + else + // CEP weapons. + switch ( nItemType ) + { + case 210: // CEP short spear + case 300: // CEP trident + case 301: // heavy pick + case 302: // light pick + case 303: // sai + case 304: // nunchaku + case 305: // falchion + case 308: // sap + case 309: // assassin dagger + case 310: // katar + case 312: // mace2 + case 313: // kukri2 + case 314: // fashion accessory + case 316: // falchion2 + case 317: // heavy mace + case 318: // maul + case 319: // mercurial longsword + case 320: // mercurial greatsword + case 321: // double scimitar + case 322: // goad + case 323: // wind-fire wheel + case 324: // maug double sword + case 330: // longsword2 + return TRUE; + } + + // Default: not a melee weapon. + return FALSE; +} + + +//------------------------------------------------------------------------------ +// AN, 2003 +// Returns TRUE if oItem has any item property that classifies it as magical item +//------------------------------------------------------------------------------ +int GetIsMagicalItem(object oItem) +{ + //Declare major variables + int nProperty; + + if((GetItemHasItemProperty(oItem, ITEM_PROPERTY_ABILITY_BONUS)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_AC_BONUS)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_AC_BONUS_VS_ALIGNMENT_GROUP)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_AC_BONUS_VS_DAMAGE_TYPE)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_AC_BONUS_VS_RACIAL_GROUP)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_AC_BONUS_VS_SPECIFIC_ALIGNMENT)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_ATTACK_BONUS)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_ATTACK_BONUS_VS_ALIGNMENT_GROUP)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_ATTACK_BONUS_VS_RACIAL_GROUP)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_ATTACK_BONUS_VS_SPECIFIC_ALIGNMENT)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_BASE_ITEM_WEIGHT_REDUCTION)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_BONUS_FEAT)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_CAST_SPELL)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_DAMAGE_BONUS)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_DAMAGE_BONUS_VS_ALIGNMENT_GROUP)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_DAMAGE_BONUS_VS_RACIAL_GROUP)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_DAMAGE_BONUS_VS_SPECIFIC_ALIGNMENT)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_DAMAGE_REDUCTION)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_DAMAGE_RESISTANCE)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_DAMAGE_VULNERABILITY)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_DARKVISION)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_DECREASED_ABILITY_SCORE)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_DECREASED_AC)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_DECREASED_ATTACK_MODIFIER)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_DECREASED_DAMAGE)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_DECREASED_ENHANCEMENT_MODIFIER)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_DECREASED_SAVING_THROWS)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_DECREASED_SAVING_THROWS_SPECIFIC)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_DECREASED_SKILL_MODIFIER)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_ENHANCED_CONTAINER_REDUCED_WEIGHT)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_ENHANCEMENT_BONUS)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_ALIGNMENT_GROUP)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_RACIAL_GROUP)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_SPECIFIC_ALIGNEMENT)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_EXTRA_MELEE_DAMAGE_TYPE)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_EXTRA_RANGED_DAMAGE_TYPE)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_FREEDOM_OF_MOVEMENT)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_HASTE)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_HOLY_AVENGER)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_IMMUNITY_DAMAGE_TYPE)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_IMMUNITY_MISCELLANEOUS)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_IMMUNITY_SPECIFIC_SPELL)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_IMMUNITY_SPELL_SCHOOL)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_IMMUNITY_SPELLS_BY_LEVEL)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_IMPROVED_EVASION)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_KEEN)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_LIGHT)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_MASSIVE_CRITICALS)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_MIGHTY)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_MIND_BLANK)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_MONSTER_DAMAGE)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_NO_DAMAGE)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_ON_HIT_PROPERTIES)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_ON_MONSTER_HIT)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_POISON)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_REGENERATION)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_REGENERATION_VAMPIRIC)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_SAVING_THROW_BONUS)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_SAVING_THROW_BONUS_SPECIFIC)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_SKILL_BONUS)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_SPELL_RESISTANCE)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_THIEVES_TOOLS)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_TRAP)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_TRUE_SEEING)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_TURN_RESISTANCE)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_UNLIMITED_AMMUNITION)) || + (GetItemHasItemProperty(oItem, ITEM_PROPERTY_ONHITCASTSPELL)) + ) + { + return TRUE; + } + return FALSE; +} + + +//:://///////////////////////////////////////////// +//:: GetIsMagicStatBonus +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Returns the modifier from the ability + score that matters for this caster +*/ +//::////////////////////////////////////////////// +//:: Created By: +//:: Created On: +//::////////////////////////////////////////////// + +int GetIsMagicStatBonus(object oCaster) +{ + //Declare major variables + int nClass; + int nAbility; + + if(nClass = GetLevelByClass(CLASS_TYPE_WIZARD, oCaster)) + { + if(nClass > 0) + { + nAbility = ABILITY_INTELLIGENCE; + } + } + if(nClass = GetLevelByClass(CLASS_TYPE_BARD, oCaster) || GetLevelByClass(CLASS_TYPE_SORCERER, oCaster)) + { + if(nClass > 0) + { + nAbility = ABILITY_CHARISMA; + } + } + else if(nClass = GetLevelByClass(CLASS_TYPE_CLERIC, oCaster) || GetLevelByClass(CLASS_TYPE_DRUID, oCaster) + || GetLevelByClass(CLASS_TYPE_PALADIN, oCaster) || GetLevelByClass(CLASS_TYPE_RANGER, oCaster)) + { + if(nClass > 0) + { + nAbility = ABILITY_WISDOM; + } + } + + return GetAbilityModifier(nAbility, oCaster); +} + +//------------------------------------------------------------------------------ +// GZ, 2003-07-09 +// Hub function for the epic barbarian feats that upgrade rage. Call from +// the end of the barbarian rage spellscript +//------------------------------------------------------------------------------ +void CheckAndApplyEpicRageFeats(int nRounds) +{ + CheckAndApplyThunderingRage(nRounds); + CheckAndApplyTerrifyingRage(nRounds); +} + +//------------------------------------------------------------------------------ +// GZ, 2003-07-09 +// If the character calling this function from a spellscript has the thundering +// rage feat, his weapons are upgraded to deafen and cause 2d6 points of massive +// criticals +//------------------------------------------------------------------------------ +void CheckAndApplyThunderingRage(int nRounds) +{ + if (GetHasFeat(988, OBJECT_SELF)) + { + object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND); + + if (GetIsObjectValid(oWeapon)) + { + IPSafeAddItemProperty(oWeapon, ItemPropertyMassiveCritical(IP_CONST_DAMAGEBONUS_2d6), RoundsToSeconds(nRounds), X2_IP_ADDPROP_POLICY_KEEP_EXISTING,TRUE,TRUE); + IPSafeAddItemProperty(oWeapon, ItemPropertyVisualEffect(ITEM_VISUAL_SONIC), RoundsToSeconds(nRounds), X2_IP_ADDPROP_POLICY_REPLACE_EXISTING,FALSE,TRUE); + IPSafeAddItemProperty(oWeapon, ItemPropertyOnHitProps(IP_CONST_ONHIT_DEAFNESS,IP_CONST_ONHIT_SAVEDC_20,IP_CONST_ONHIT_DURATION_25_PERCENT_3_ROUNDS), RoundsToSeconds(nRounds), X2_IP_ADDPROP_POLICY_REPLACE_EXISTING,FALSE,TRUE); + } + + oWeapon = GetItemInSlot(INVENTORY_SLOT_LEFTHAND); + + if (GetIsObjectValid(oWeapon) ) + { + IPSafeAddItemProperty(oWeapon, ItemPropertyMassiveCritical(IP_CONST_DAMAGEBONUS_2d6), RoundsToSeconds(nRounds), X2_IP_ADDPROP_POLICY_KEEP_EXISTING,TRUE,TRUE); + IPSafeAddItemProperty(oWeapon,ItemPropertyVisualEffect(ITEM_VISUAL_SONIC), RoundsToSeconds(nRounds), X2_IP_ADDPROP_POLICY_REPLACE_EXISTING,FALSE,TRUE); + } + + + } +} + +//------------------------------------------------------------------------------ +// GZ, 2003-07-09 +// If the character calling this function from a spellscript has the terrifying +// rage feat, he gets an aura of fear for the specified duration +// The saving throw against this fear is a check opposed to the character's +// intimidation skill +//------------------------------------------------------------------------------ +void CheckAndApplyTerrifyingRage(int nRounds) +{ + if (GetHasFeat(989, OBJECT_SELF)) + { + effect eAOE = EffectAreaOfEffect(AOE_MOB_FEAR,"x2_s2_terrage_A", "",""); + eAOE = ExtraordinaryEffect(eAOE); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eAOE,OBJECT_SELF,RoundsToSeconds(nRounds)); + } +} + + + +//------------------------------------------------------------------------------ +//Keith Warner +// Do a mind blast +// nHitDice - HitDice/Caster Level of the creator +// nDC - DC of the Save to resist +// nRounds - Rounds the stun effect holds +// fRange - Range of the EffectCone +//------------------------------------------------------------------------------ +void DoMindBlast(int nDC, int nDuration, float fRange) +{ + int nStunTime; + float fDelay; + + location lTargetLocation = GetSpellTargetLocation(); + object oTarget; + effect eCone; + effect eVis = EffectVisualEffect(VFX_IMP_SONIC); + + oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, fRange, lTargetLocation, TRUE); + + while(GetIsObjectValid(oTarget)) + { + int nApp = GetAppearanceType(oTarget); + int bImmune = FALSE; + //---------------------------------------------------------------------- + // Hack to make mind flayers immune to their psionic attacks... + //---------------------------------------------------------------------- + if (nApp == 413 ||nApp== 414 || nApp == 415) + { + bImmune = TRUE; + } + + if(spellsIsTarget(oTarget,SPELL_TARGET_STANDARDHOSTILE,OBJECT_SELF) && oTarget != OBJECT_SELF && !bImmune ) + { + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + fDelay = GetDistanceBetween(OBJECT_SELF, oTarget)/20; + // already stunned + if (GetHasSpellEffect(GetSpellId(),oTarget)) + { + // only affects the targeted object + ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_STUN), oTarget); + int nDamage; + if (GetLevelByClass(CLASS_TYPE_SHIFTER,OBJECT_SELF)>0) + { + nDamage = d6(GetLevelByClass(CLASS_TYPE_SHIFTER,OBJECT_SELF)/3); + } + else + { + nDamage = d6(GetHitDice(OBJECT_SELF)/2); + } + ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDamage), oTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_BIGBYS_FORCEFUL_HAND), oTarget); + } + else if (WillSave(oTarget, nDC) < 1) + { + //Calculate the length of the stun + nStunTime = nDuration; + //Set stunned effect + eCone = EffectStunned(); + //Apply the VFX impact and effects + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCone, oTarget, RoundsToSeconds(nStunTime))); + } + } + //Get next target in spell area + oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, fRange, lTargetLocation, TRUE); + } +} + + +// * Gelatinous Cube Paralyze attack +int DoCubeParalyze(object oTarget, object oSource, int nSaveDC = 16) +{ + if (GetIsImmune(oTarget,IMMUNITY_TYPE_PARALYSIS) ) + { + return FALSE; + } + + if (FortitudeSave(oTarget,nSaveDC, SAVING_THROW_TYPE_POISON,oSource) == 0) + { + effect ePara = EffectParalyze(); + effect eDur = EffectVisualEffect(VFX_DUR_PARALYZED); + ePara = EffectLinkEffects(eDur,ePara); + ePara = EffectLinkEffects(EffectVisualEffect(VFX_DUR_FREEZE_ANIMATION),ePara); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,ePara,oTarget,RoundsToSeconds(3+d3())); // not 3 d6, thats not fun + return TRUE; + } + else + { + effect eSave = EffectVisualEffect(VFX_IMP_FORTITUDE_SAVING_THROW_USE); + ApplyEffectToObject(DURATION_TYPE_INSTANT,eSave,oTarget); + } + return FALSE; +} + + +// -------------------------------------------------------------------------------- +// GZ: Gel. Cube special abilities +// -------------------------------------------------------------------------------- +void EngulfAndDamage(object oTarget, object oSource) +{ + + if (ReflexSave(oTarget, 13 + GetHitDice(oSource) - 4, SAVING_THROW_TYPE_NONE,oSource) == 0) + { + + FloatingTextStrRefOnCreature(84610,oTarget); // * Engulfed + int nDamage = d6(1); + + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_ACID); + effect eVis = EffectVisualEffect(VFX_IMP_ACID_S); + ApplyEffectToObject(DURATION_TYPE_INSTANT,eDamage,oTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT,eVis,oTarget); + if (!GetIsImmune(oTarget,IMMUNITY_TYPE_PARALYSIS) ) + { + if (DoCubeParalyze(oTarget,oSource,16)) + { + FloatingTextStrRefOnCreature(84609,oTarget); + } + } + + } else + { + effect eSave = EffectVisualEffect(VFX_IMP_REFLEX_SAVE_THROW_USE); + ApplyEffectToObject(DURATION_TYPE_INSTANT,eSave,oTarget); + } + + +} +// -------------------------------------------------------------------------------- +// Georg Zoeller, 2003-09-19 +// Save DC against Epic Spells is the relevant ability score of the caster +// + 20. The hightest ability score of the casting relevants is 99.99% identical +// with the one that is used for casting, so we just take it. +// if used by a placeable, it is equal to the placeables WILL save field. +// -------------------------------------------------------------------------------- +int GetEpicSpellSaveDC(object oCaster) +{ + + // * Placeables use their WILL Save field as caster level + if (GetObjectType(oCaster) == OBJECT_TYPE_PLACEABLE) + { + return GetWillSavingThrow(oCaster); + } + + int nWis = GetAbilityModifier(ABILITY_WISDOM,oCaster); + int nInt = GetAbilityModifier(ABILITY_INTELLIGENCE,oCaster); + int nCha = GetAbilityModifier(ABILITY_CHARISMA,oCaster); + + int nHigh = nWis; + if (nHigh < nInt) + { + nHigh = nInt; + } + if (nHigh < nCha) + { + nHigh = nCha; + } + int nRet = 20 + nHigh; + return nRet; +} + +// -------------------------------------------------------------------------------- +// GZ: Sept 2003 +// Determines the optimal behavior against AoESpell nSpellId for a NPC +// use in OnSpellCastAt +// -------------------------------------------------------------------------------- +int GetBestAOEBehavior(int nSpellID) +{ + if (nSpellID == SPELL_GREASE) + { + if (spellsIsFlying(OBJECT_SELF)) + return X2_SPELL_AOEBEHAVIOR_IGNORE; + } + +// if (GetHasSpell(SPELL_GUST_OF_WIND) == TRUE) + if (GetHasSpell(SPELL_GUST_OF_WIND)) + return X2_SPELL_AOEBEHAVIOR_GUST; + + if (GetModuleSwitchValue(MODULE_SWITCH_DISABLE_AI_DISPEL_AOE) == 0 ) + { + if (d100() > GetLocalInt(GetModule(),MODULE_VAR_AI_NO_DISPEL_AOE_CHANCE)) + { +// if (GetHasSpell(SPELL_LESSER_DISPEL) == TRUE) + if (GetHasSpell(SPELL_LESSER_DISPEL)) + return X2_SPELL_AOEBEHAVIOR_DISPEL_L; +// if (GetHasSpell(SPELL_DISPEL_MAGIC) == TRUE) + if (GetHasSpell(SPELL_DISPEL_MAGIC)) + return X2_SPELL_AOEBEHAVIOR_DISPEL_N; +// if (GetHasSpell(SPELL_GREATER_DISPELLING) == TRUE) + if (GetHasSpell(SPELL_GREATER_DISPELLING)) + return X2_SPELL_AOEBEHAVIOR_DISPEL_G; +// if (GetHasSpell(SPELL_MORDENKAINENS_DISJUNCTION) == TRUE) + if (GetHasSpell(SPELL_MORDENKAINENS_DISJUNCTION)) + return X2_SPELL_AOEBEHAVIOR_DISPEL_M; + } + } + + return X2_SPELL_AOEBEHAVIOR_FLEE; +} + + +//-------------------------------------------------------------------------- +// GZ: 2003-Oct-15 +// Removes all effects from nID without paying attention to the caster as +// the spell can from only one caster anyway +// By default, it will only cancel magical effects +//-------------------------------------------------------------------------- +void GZRemoveSpellEffects(int nID,object oTarget, int bMagicalEffectsOnly = TRUE) +{ + effect eEff = GetFirstEffect(oTarget); + while (GetIsEffectValid(eEff)) + { + if (GetEffectSpellId(eEff) == nID) + { + if (GetEffectSubType(eEff) != SUBTYPE_MAGICAL && bMagicalEffectsOnly) + { + // ignore + } + else + { + RemoveEffect(oTarget,eEff); + } + } + eEff = GetNextEffect(oTarget); + } +} + +//------------------------------------------------------------------------------ +// GZ: 2003-Oct-15 +// A different approach for timing these spells that has the positive side +// effects of making the spell dispellable as well. +// I am using the VFX applied by the spell to track the remaining duration +// instead of adding the remaining runtime on the stack +// +// This function returns FALSE if a delayed Spell effect from nSpell_ID has +// expired. See x2_s0_bigby4.nss for details +//------------------------------------------------------------------------------ +int GZGetDelayedSpellEffectsExpired(int nSpell_ID, object oTarget, object oCaster) +{ + + if (!GetHasSpellEffect(nSpell_ID,oTarget) ) + { + DeleteLocalInt(oTarget,"XP2_L_SPELL_SAVE_DC_" + IntToString (nSpell_ID)); + return TRUE; + } + + //-------------------------------------------------------------------------- + // GZ: 2003-Oct-15 + // If the caster is dead or no longer there, cancel the spell, as it is + // directed + //-------------------------------------------------------------------------- + if( !GetIsObjectValid(oCaster)) + { + GZRemoveSpellEffects(nSpell_ID, oTarget); + DeleteLocalInt(oTarget,"XP2_L_SPELL_SAVE_DC_" + IntToString (nSpell_ID)); + return TRUE; + } + + if (GetIsDead(oCaster)) + { + DeleteLocalInt(oTarget,"XP2_L_SPELL_SAVE_DC_" + IntToString (nSpell_ID)); + GZRemoveSpellEffects(nSpell_ID, oTarget); + return TRUE; + } + + return FALSE; + +} + + + diff --git a/src/_removed/x2_mod_def_equ.nss b/src/_removed/x2_mod_def_equ.nss new file mode 100644 index 0000000..6eedfbe --- /dev/null +++ b/src/_removed/x2_mod_def_equ.nss @@ -0,0 +1,66 @@ +//:://///////////////////////////////////////////// +//:: Example XP2 OnItemEquipped +//:: x2_mod_def_equ +//:: (c) 2003 Bioware Corp. +//::////////////////////////////////////////////// +/* + Put into: OnEquip Event +*/ +//::////////////////////////////////////////////// +//:: Created By: Georg Zoeller +//:: Created On: 2003-07-16 +//::////////////////////////////////////////////// +#include "x2_inc_switches" +#include "x2_inc_intweapon" +void main() +{ + + object oItem = GetPCItemLastEquipped(); + object oPC = GetPCItemLastEquippedBy(); + // ------------------------------------------------------------------------- + // Intelligent Weapon System + // ------------------------------------------------------------------------- + if (IPGetIsIntelligentWeapon(oItem)) + { + IWSetIntelligentWeaponEquipped(oPC,oItem); + // prevent players from reequipping their weapon in + if (IWGetIsInIntelligentWeaponConversation(oPC)) + { + object oConv = GetLocalObject(oPC,"X2_O_INTWEAPON_SPIRIT"); + IWEndIntelligentWeaponConversation(oConv, oPC); + } + else + { + //------------------------------------------------------------------ + // Trigger Drain Health Event + //------------------------------------------------------------------ + if (GetLocalInt(oPC,"X2_L_ENSERRIC_ASKED_Q3")==1) + { + ExecuteScript ("x2_ens_dodrain",oPC); + } + else + { + IWPlayRandomEquipComment(oPC,oItem); + } + } + } + + + // ------------------------------------------------------------------------- + // Generic Item Script Execution Code + // If MODULE_SWITCH_EXECUTE_TAGBASED_SCRIPTS is set to TRUE on the module, + // it will execute a script that has the same name as the item's tag + // inside this script you can manage scripts for all events by checking against + // GetUserDefinedItemEventNumber(). See x2_it_example.nss + // ------------------------------------------------------------------------- + if (GetModuleSwitchValue(MODULE_SWITCH_ENABLE_TAGBASED_SCRIPTS) == TRUE) + { + SetUserDefinedItemEventNumber(X2_ITEM_EVENT_EQUIP); + int nRet = ExecuteScriptAndReturnInt(GetUserDefinedItemEventScriptName(oItem),OBJECT_SELF); + if (nRet == X2_EXECUTE_SCRIPT_END) + { + return; + } + } + +} diff --git a/src/_removed/x2_pc_umdcheck.nss b/src/_removed/x2_pc_umdcheck.nss new file mode 100644 index 0000000..af41dfc --- /dev/null +++ b/src/_removed/x2_pc_umdcheck.nss @@ -0,0 +1,187 @@ +//------------------------------------------------------------------------------ +// x2_pc_umdcheck +//------------------------------------------------------------------------------ +#include "x2_inc_switches" +// ----------------------------------------------------------------------------- +// SETTINGS +// ----------------------------------------------------------------------------- + +// Setting the following to TRUE means a UMD check is needed if the user lacks +// sufficient casting stat. (i.e. Wisdom, Intelligence, or Charisma < 10 + spell level) +const int ENFORCE_ABILITY_MINIMUM = TRUE; + +// Setting the following to TRUE means the unmodified ability score will be used +// for the check. (i.e. does nothing if the above constant is FALSE). +const int USE_BASE_ABILITY = FALSE; + + +// ----------------------------------------------------------------------------- +// FUNCTIONS +// ----------------------------------------------------------------------------- + + +// Returns TRUE if oUser's casting ability for class nClass is at least +// 10 + nSpellLevel. +int CheckAbility(object oUser, int nClass, int nSpellLevel); +int CheckAbility(object oUser, int nClass, int nSpellLevel) +{ + int nAbility = -1; // Invalid ability. + switch ( nClass ) + { + case CLASS_TYPE_WIZARD: + nAbility = ABILITY_INTELLIGENCE; + break; + + case CLASS_TYPE_CLERIC: + case CLASS_TYPE_DRUID: + case CLASS_TYPE_PALADIN: + case CLASS_TYPE_RANGER: + nAbility = ABILITY_WISDOM; + break; + + case CLASS_TYPE_BARD: + case CLASS_TYPE_SORCERER: + nAbility = ABILITY_CHARISMA; + break; + + default: + // No other classes have a casting stat. Assume we passed. + return TRUE; + } + + return 10 + nSpellLevel <= GetAbilityScore(oUser, nAbility, USE_BASE_ABILITY); +} + + +// Returns TRUE if oUser is able to use oItem based on class, and if oItem +// has class restrictions, then oUser's casting ability is at least +// 10 + nSpellLevel. +int CheckClassAndAbilityMatch(object oUser, object oItem, int nSpellLevel); +int CheckClassAndAbilityMatch(object oUser, object oItem, int nSpellLevel) +{ + int nClass1 = GetClassByPosition(1, oUser); + int nClass2 = GetClassByPosition(2, oUser); + int nClass3 = GetClassByPosition(3, oUser); + int nItemClass = CLASS_TYPE_INVALID; + int bNoRestrictionFound = TRUE; + + itemproperty ipRestriction = GetFirstItemProperty(oItem); + while ( GetIsItemPropertyValid(ipRestriction) ) + { + switch ( GetItemPropertyType(ipRestriction) ) + { + case ITEM_PROPERTY_USE_LIMITATION_CLASS: + bNoRestrictionFound = FALSE; + // See if oUser matches the class. + nItemClass = GetItemPropertySubType(ipRestriction); + if ( nItemClass == nClass1 || nItemClass == nClass2 || + nItemClass == nClass3 ) + // User is allowed to use this scroll. Check ability. + if ( !ENFORCE_ABILITY_MINIMUM || + CheckAbility(oUser, nItemClass, nSpellLevel) ) + // We matched! + return TRUE; + break; + } + + ipRestriction = GetNextItemProperty(oItem); + } + + // We did not match any found class restrictions. + // Therefore we only matched the item if no restrictions were found. + return bNoRestrictionFound; +} + +// Performs the UMD check for using a scroll. +// Note: There is no UMD roll if the UMD is overcoming racial or alignment +// restrictions, but not class restrictions. +int X2_UMD(); +int X2_UMD() +{ + // The following variables will be defined later. + // They are listed here for clarity, and defined as needed for efficiency. + // object oUser = OBJECT_SELF; + // object oItem = PRCGetSpellCastItem(); + // int nInnateLevel = StringToInt(Get2DAString("des_crft_spells", "Level", PRCGetSpellId())); + + + // ------------------------------------------------------------------------- + // 1: Check the switch is enabled + // ------------------------------------------------------------------------- + if ( !GetModuleSwitchValue(MODULE_SWITCH_ENABLE_UMD_SCROLLS) ) + // UMD Scrolls are not being used + return TRUE; + + // ------------------------------------------------------------------------- + // 2: Check the source + // ------------------------------------------------------------------------- + // Need the item at this point. + object oItem = PRCGetSpellCastItem(); + if ( GetBaseItemType(oItem) != BASE_ITEM_SPELLSCROLL ) + // Spell not cast from a scroll; no UMD check needed. + return TRUE; + + // ------------------------------------------------------------------------- + // 3: Check use limitations (includes minimum casting ability, if desired). + // ------------------------------------------------------------------------- + // Need remaining variables at this point. + object oUser = OBJECT_SELF; + int nInnateLevel = StringToInt(Get2DAString("des_crft_spells", "Level", PRCGetSpellId())); + // Note from BioWare: + // des_crft_spells.2da Innate Level column is used here, not (as would be + // correct) the IPPR_Spells.2da InnateLvl column, because some of the + // scrolls in the game (i.e. light) would not be useable (DC 30+) + if ( CheckClassAndAbilityMatch(oUser, oItem, nInnateLevel) ) + // Scroll has no class limitations, or oUser matches those limitations. + return TRUE; + + // ------------------------------------------------------------------------- + // 4: Having UMD is a pre-requisite + // ------------------------------------------------------------------------- + // If we get to this point, that means oUser was allowed to use the scroll + // by the engine, but did not pass our class/ability match. Therefore, + // if oUser lacks UMD, then oUser's primary casting abililty is too low. + if ( !GetHasSkill(SKILL_USE_MAGIC_DEVICE, oUser) ) + { + // Inform the player. + SendMessageToPC(oUser, "You lack the prerequisite ability score for casting that spell."); + effect ePuff = EffectVisualEffect(VFX_IMP_MAGIC_RESISTANCE_USE); + ApplyEffectToObject(DURATION_TYPE_INSTANT, ePuff, oUser); + return FALSE; + } + + // ------------------------------------------------------------------------- + // 5: Check the skill + // ------------------------------------------------------------------------- + // Base DC for casting a spell from a scroll was 25 + SpellLevel. + // WoG uses 5 + 3 * SpellLevel. + // We do not have a way to check for misshaps here because GetIsSkillSuccessful + // does not return the required information + if ( !GetIsSkillSuccessful(oUser, SKILL_USE_MAGIC_DEVICE, (5 + 3*nInnateLevel)) ) + { + effect ePuff = EffectVisualEffect(VFX_IMP_MAGIC_RESISTANCE_USE); + ApplyEffectToObject(DURATION_TYPE_INSTANT, ePuff, oUser); + return FALSE; + } + + return TRUE; +} + + +void main() +{ + //-------------------------------------------------------------------------- + // Reset + //-------------------------------------------------------------------------- + if (GetLocalInt(GetModule(),"X2_L_STOP_EXPERTISE_ABUSE") == TRUE) + { + SetActionMode(OBJECT_SELF,ACTION_MODE_EXPERTISE,FALSE); + SetActionMode(OBJECT_SELF,ACTION_MODE_IMPROVED_EXPERTISE,FALSE); + } + + //-------------------------------------------------------------------------- + // Do use magic device check + //-------------------------------------------------------------------------- + int nRet = X2_UMD(); + SetExecutedScriptReturnValue (nRet); +} diff --git a/src/_removed/x2_s0_blckstff.nss b/src/_removed/x2_s0_blckstff.nss new file mode 100644 index 0000000..be010c1 --- /dev/null +++ b/src/_removed/x2_s0_blckstff.nss @@ -0,0 +1,91 @@ +//:://///////////////////////////////////////////// +//:: Blackstaff +//:: X2_S0_Blckstff +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Adds +4 enhancement bonus, On Hit: Dispel. +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: Nov 29, 2002 +//::////////////////////////////////////////////// +//:: Updated by Andrew Nobbs May 07, 2003 +//:: 2003-07-07: Stacking Spell Pass, Georg Zoeller +//:: 2003-07-15: Complete Rewrite to make use of Item Property System + +#include "nw_i0_spells" +#include "x2_i0_spells" +#include "x2_inc_spellhook" + + +void AddBlackStaffEffectOnWeapon (object oTarget, float fDuration) +{ + IPSafeAddItemProperty(oTarget, ItemPropertyEnhancementBonus(5), fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING,FALSE, TRUE); + IPSafeAddItemProperty(oTarget, ItemPropertyOnHitProps(IP_CONST_ONHIT_DISPELMAGIC, IP_CONST_ONHIT_SAVEDC_20), fDuration,X2_IP_ADDPROP_POLICY_REPLACE_EXISTING ); + IPSafeAddItemProperty(oTarget, ItemPropertyDamageBonus(IP_CONST_DAMAGETYPE_SONIC, IP_CONST_DAMAGEBONUS_1d8), fDuration,X2_IP_ADDPROP_POLICY_REPLACE_EXISTING ); + IPSafeAddItemProperty(oTarget, ItemPropertyVisualEffect(ITEM_VISUAL_EVIL), fDuration,X2_IP_ADDPROP_POLICY_REPLACE_EXISTING,FALSE,TRUE ); + return; +} + + +void main() +{ + + /* + Spellcast Hook Code + Added 2003-07-07 by Georg Zoeller + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + + */ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + + // End of Spell Cast Hook + + + //Declare major variables + effect eVis = EffectVisualEffect(VFX_IMP_EVIL_HELP); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); + int nDuration = GetCasterLevel(OBJECT_SELF); + int nBSDuration = (nDuration * 6); + int nMetaMagic = GetMetaMagicFeat(); + + object oMyWeapon = IPGetTargetedOrEquippedMeleeWeapon(); + + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration * 2; //Duration is +100% + } + + if(GetIsObjectValid(oMyWeapon) ) + { + SignalEvent(GetItemPossessor(oMyWeapon), EventSpellCastAt(OBJECT_SELF, GetSpellId(), FALSE)); + + if (GetBaseItemType(oMyWeapon) == BASE_ITEM_QUARTERSTAFF || BASE_ITEM_MAGICSTAFF) + { + if (nDuration>0) + { + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, GetItemPossessor(oMyWeapon)); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDur, GetItemPossessor(oMyWeapon), RoundsToSeconds(nDuration)); + AddBlackStaffEffectOnWeapon(oMyWeapon, RoundsToSeconds(nBSDuration)); + } + return; + } + else + { + FloatingTextStrRefOnCreature(83620, OBJECT_SELF); // not a qstaff + return; + } + } + else + { + FloatingTextStrRefOnCreature(83615, OBJECT_SELF); + return; + } +} diff --git a/src/_removed/x2_s0_bldethst.nss b/src/_removed/x2_s0_bldethst.nss new file mode 100644 index 0000000..a8fe8ce --- /dev/null +++ b/src/_removed/x2_s0_bldethst.nss @@ -0,0 +1,86 @@ +//:://///////////////////////////////////////////// +//:: Blade Thrist +//:: X2_S0_BldeThst +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Grants a +3 enhancement bonus to a slashing weapon +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: Nov 27, 2002 +//::////////////////////////////////////////////// +//:: Updated by Andrew Nobbs May 08, 2003 +//:: 2003-07-07: Stacking Spell Pass, Georg Zoeller +//:: 2003-07-21: Complete Rewrite to make use of Item Property System + +// DM Nocturne: bonuses changed to +1 per 4 levels, duration increased +// to hours/level (equal to GMW): enhancement for ranger weapons only +// (see wog_wpn_inc) + +//#include "x2_i0_spells" +#include "x2_inc_spellhook" +#include "wog_wpn_inc" + +void main() +{ + /* + Spellcast Hook Code + Added 2003-07-07 by Georg Zoeller + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + */ + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + // End of Spell Cast Hook + + + + //Declare major variables + effect eVis = EffectVisualEffect(VFX_IMP_SUPER_HEROISM); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + int nDuration = nCasterLevel; + int nMetaMagic = GetMetaMagicFeat(); + int nBonus = nCasterLevel / 4; + if(nBonus > 5) + nBonus = 5; + + //object oMyWeapon = IPGetTargetedOrEquippedMeleeWeapon(); + object oMyWeapon = GetTargetedOrEquippedWeapon(WEAPON_TYPE_RANGER); + + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration * 2; //Duration is +100% + } + + if(GetIsObjectValid(oMyWeapon) ) + { + SignalEvent(GetItemPossessor(oMyWeapon), EventSpellCastAt(OBJECT_SELF, GetSpellId(), FALSE)); + + //if (GetSlashingWeapon(oMyWeapon)) + //{ + if (nDuration>0) + { + float fDuration = HoursToSeconds(nDuration); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, GetItemPossessor(oMyWeapon)); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDur, GetItemPossessor(oMyWeapon), fDuration); + AddEnhancementEffectToWeapon(oMyWeapon, fDuration, nBonus); + } + return; + //} + //else + //{ + // FloatingTextStrRefOnCreature(83621, OBJECT_SELF); // not a slashing weapon + // return; + //} + } + else + { + FloatingTextStrRefOnCreature(83615, OBJECT_SELF); + return; + } +} diff --git a/src/_removed/x2_s0_blssweap.nss b/src/_removed/x2_s0_blssweap.nss new file mode 100644 index 0000000..dfb1c19 --- /dev/null +++ b/src/_removed/x2_s0_blssweap.nss @@ -0,0 +1,106 @@ +//:://///////////////////////////////////////////// +//:: Bless Weapon +//:: X2_S0_BlssWeap +//:: Copyright (c) 2003 Bioware Corp. +//::////////////////////////////////////////////// +/* + + If cast on a crossbow bolt, it adds the ability to + slay rakshasa's on hit + + If cast on a melee weapon, it will add the + grants a +1 enhancement bonus. + grants a +2d6 damage divine to undead + + will add a holy vfx when command becomes available + + If cast on a creature it will pick the first + melee weapon without these effects + +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: Nov 28, 2002 +//::////////////////////////////////////////////// +//:: Updated by Andrew Nobbs May 09, 2003 +//:: 2003-07-07: Stacking Spell Pass, Georg Zoeller +//:: 2003-07-15: Complete Rewrite to make use of Item Property System + +#include "x2_inc_spellhook" +#include "wog_wpn_inc" + + +void AddBlessEffectToWeapon(object oTarget, float fDuration) +{ + // If the spell is cast again, any previous enhancement boni are kept + wog_AddTempItemProp(oTarget, ItemPropertyEnhancementBonus(1), fDuration, FALSE, X2_IP_ADDPROP_POLICY_KEEP_EXISTING); + // Replace existing temporary anti undead boni + wog_AddTempItemProp(oTarget, ItemPropertyDamageBonusVsRace(IP_CONST_RACIALTYPE_UNDEAD, IP_CONST_DAMAGETYPE_DIVINE, IP_CONST_DAMAGEBONUS_2d6), fDuration); + wog_AddTempItemProp(oTarget, ItemPropertyVisualEffect(ITEM_VISUAL_HOLY), fDuration, TRUE); +} + + +void main() +{ + /* + Spellcast Hook Code + Added 2003-07-07 by Georg Zoeller + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + + */ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + // End of Spell Cast Hook + + + //Declare major variables + effect eVis = EffectVisualEffect(VFX_IMP_SUPER_HEROISM); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); + object oTarget = GetSpellTargetObject(); + int nDuration = 2 * GetCasterLevel(OBJECT_SELF); // Rounds for bolts, turns for melee weapons + int nMetaMagic = GetMetaMagicFeat(); + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration * 2; //Duration is +100% + } + + // ---------------- TARGETED ON BOLT ------------------- + if ( GetObjectType(oTarget) == OBJECT_TYPE_ITEM ) + { + // special handling for blessing crossbow bolts that can slay rakshasa's + if (GetBaseItemType(oTarget) == BASE_ITEM_BOLT) + { + float fDuration = RoundsToSeconds(nDuration); + SignalEvent(GetItemPossessor(oTarget), EventSpellCastAt(OBJECT_SELF, GetSpellId(), FALSE)); + IPSafeAddItemProperty(oTarget, ItemPropertyOnHitCastSpell(123,1), fDuration, X2_IP_ADDPROP_POLICY_KEEP_EXISTING ); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, GetItemPossessor(oTarget)); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDur, GetItemPossessor(oTarget), fDuration); + return; + } + } + + //object oMyWeapon = IPGetTargetedOrEquippedMeleeWeapon(); + object oMyWeapon = GetTargetedOrEquippedWeapon(WEAPON_TYPE_MELEE); + + if( GetIsObjectValid(oMyWeapon) ) + { + SignalEvent(GetItemPossessor(oMyWeapon), EventSpellCastAt(OBJECT_SELF, GetSpellId(), FALSE)); + + if (nDuration>0) + { + float fDuration = TurnsToSeconds(nDuration); + AddBlessEffectToWeapon(oMyWeapon, fDuration); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, GetItemPossessor(oMyWeapon)); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDur, GetItemPossessor(oMyWeapon), fDuration); + } + } + else + { + FloatingTextStrRefOnCreature(83615, OBJECT_SELF); + } +} diff --git a/src/_removed/x2_s0_darkfire.nss b/src/_removed/x2_s0_darkfire.nss new file mode 100644 index 0000000..7059e82 --- /dev/null +++ b/src/_removed/x2_s0_darkfire.nss @@ -0,0 +1,83 @@ +//:://///////////////////////////////////////////// +//:: Darkfire +//:: X2_S0_Darkfire +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Gives a melee weapon 1d6 fire damage +1 per two caster + levels to a maximum of +10. +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: Dec 04, 2002 +//::////////////////////////////////////////////// +//:: Updated by Andrew Nobbs May 08, 2003 +//:: 2003-07-29: Rewritten, Georg Zoeller + + +#include "x2_inc_spellhook" +#include "wog_wpn_inc" + + +void AddFlamingEffectToWeapon(object oTarget, float fDuration, int nCasterLevel) +{ + // If the spell is cast again, any previous itemproperties matching are removed. + wog_AddTempItemProp(oTarget, ItemPropertyOnHitCastSpell(127,nCasterLevel), fDuration); + wog_AddTempItemProp(oTarget, ItemPropertyVisualEffect(ITEM_VISUAL_FIRE), fDuration, TRUE); +} + +void main() +{ + /* + Spellcast Hook Code + Added 2003-07-07 by Georg Zoeller + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + */ + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + // End of Spell Cast Hook + + + //Declare major variables + effect eVis = EffectVisualEffect(VFX_IMP_PULSE_FIRE); + eVis = EffectLinkEffects(EffectVisualEffect(VFX_IMP_FLAME_M),eVis); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); + int nMetaMagic = GetMetaMagicFeat(); + int nCasterLvl = GetCasterLevel(OBJECT_SELF); + int nDuration = nCasterLvl; + + //Limit nCasterLvl to 10, so it max out at +10 to the damage. + //Bugfix: Limiting nCasterLvl to *20* - the damage calculation + // divides it by 2. + if(nCasterLvl > 20) + { + nCasterLvl = 20; + } + + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration * 2; //Duration is +100% + } + + //object oMyWeapon = IPGetTargetedOrEquippedMeleeWeapon(); + object oMyWeapon = GetTargetedOrEquippedWeapon(WEAPON_TYPE_DAMAGING); + if(GetIsObjectValid(oMyWeapon) ) + { + object oPossessor = GetItemPossessor(oMyWeapon); + SignalEvent(oPossessor, EventSpellCastAt(OBJECT_SELF, GetSpellId(), FALSE)); + + if (nDuration>0) + { + float fDuration = HoursToSeconds(nDuration); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oPossessor); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDur, oPossessor, fDuration); + AddFlamingEffectToWeapon(oMyWeapon, fDuration, nCasterLvl); + } + } + else + FloatingTextStrRefOnCreature(83615, OBJECT_SELF); +} diff --git a/src/_removed/x2_s0_deafclng.nss b/src/_removed/x2_s0_deafclng.nss new file mode 100644 index 0000000..605bc60 --- /dev/null +++ b/src/_removed/x2_s0_deafclng.nss @@ -0,0 +1,80 @@ +//:://///////////////////////////////////////////// +//:: Deafening Clang +//:: X2_S0_DeafClng +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Grants a +1 to attack and +3 bonus sonic damage to + a weapon. Also the weapon will deafen on hit. +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: Nov 28, 2002 +//::////////////////////////////////////////////// +//:: Updated by Andrew Nobbs May 08, 2003 +//:: 2003-07-07: Stacking Spell Pass, Georg Zoeller +//:: 2003-07-17: Complete Rewrite to make use of Item Property System +// +//:: Updated for WoG + +#include "x2_inc_spellhook" +#include "wog_wpn_inc" + + +void AddDeafeningClangEffectToWeapon(object oMyWeapon, float fDuration) +{ + wog_AddTempItemProp(oMyWeapon, ItemPropertyAttackBonus(1), fDuration, TRUE, X2_IP_ADDPROP_POLICY_KEEP_EXISTING); + wog_AddTempItemProp(oMyWeapon, ItemPropertyDamageBonus(IP_CONST_DAMAGETYPE_SONIC, IP_CONST_DAMAGEBONUS_3), fDuration, TRUE); + wog_AddTempItemProp(oMyWeapon, ItemPropertyOnHitCastSpell(137, 5),fDuration, FALSE, X2_IP_ADDPROP_POLICY_KEEP_EXISTING); + wog_AddTempItemProp(oMyWeapon, ItemPropertyVisualEffect(ITEM_VISUAL_SONIC), fDuration, TRUE); +} + +void main() +{ + /* + Spellcast Hook Code + Added 2003-07-07 by Georg Zoeller + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + + */ + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + // End of Spell Cast Hook + + + //Declare major variables + effect eVis = EffectVisualEffect(VFX_IMP_SUPER_HEROISM); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); + int nDuration = GetCasterLevel(OBJECT_SELF); + int nMetaMagic = GetMetaMagicFeat(); + + object oMyWeapon = GetTargetedOrEquippedWeapon(); + + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration * 2; //Duration is +100% + } + if (nDuration == 0) + { + nDuration = 1; + } + + if(GetIsObjectValid(oMyWeapon) ) + { + SignalEvent(GetItemPossessor(oMyWeapon), EventSpellCastAt(OBJECT_SELF, GetSpellId(), FALSE)); + + if (nDuration>0) + { + float fDuration = RoundsToSeconds(nDuration); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, GetItemPossessor(oMyWeapon)); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDur, GetItemPossessor(oMyWeapon), fDuration); + AddDeafeningClangEffectToWeapon(oMyWeapon, fDuration); + } + } + else + FloatingTextStrRefOnCreature(83615, OBJECT_SELF); +} diff --git a/src/_removed/x2_s0_flmeweap.nss b/src/_removed/x2_s0_flmeweap.nss new file mode 100644 index 0000000..a0d3089 --- /dev/null +++ b/src/_removed/x2_s0_flmeweap.nss @@ -0,0 +1,86 @@ +//:://///////////////////////////////////////////// +//:: Flame Weapon +//:: X2_S0_FlmeWeap +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Gives a melee weapon 1d4 fire damage +1 per caster + level to a maximum of +10. +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: Nov 29, 2002 +//::////////////////////////////////////////////// +//:: Updated by Andrew Nobbs May 08, 2003 +//:: 2003-07-07: Stacking Spell Pass, Georg Zoeller +//:: 2003-07-15: Complete Rewrite to make use of Item Property System +//:: +//:: DM Nocturne: use GetTargettedWeapon from wog_wpn_inc +//:: DM Nocturne: remove 2x multiplier and use HoursToSeconds instead of TurnsToSeconds for duration + +#include "x2_inc_spellhook" +#include "wog_wpn_inc" + + +void AddFlamingEffectToWeapon(object oTarget, float fDuration, int nCasterLevel) +{ + // If the spell is cast again, any previous itemproperties matching are removed. + wog_AddTempItemProp(oTarget, ItemPropertyOnHitCastSpell(124,nCasterLevel), fDuration); + wog_AddTempItemProp(oTarget, ItemPropertyVisualEffect(ITEM_VISUAL_FIRE), fDuration, TRUE); +} + +void main() +{ + /* + Spellcast Hook Code + Added 2003-07-07 by Georg Zoeller + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + + */ + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + // End of Spell Cast Hook + + + //Declare major variables + effect eVis = EffectVisualEffect(VFX_IMP_PULSE_FIRE); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); + int nCasterLvl = GetCasterLevel(OBJECT_SELF); + int nDuration = nCasterLvl; + int nMetaMagic = GetMetaMagicFeat(); + + //Limit nCasterLvl to 10, so it max out at +10 to the damage. + if(nCasterLvl > 10) + { + nCasterLvl = 10; + } + + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration * 2; //Duration is +100% + } + + //object oMyWeapon = IPGetTargetedOrEquippedMeleeWeapon(); + object oMyWeapon = GetTargetedOrEquippedWeapon(WEAPON_TYPE_DAMAGING); + + if(GetIsObjectValid(oMyWeapon) ) + { + object oPossessor = GetItemPossessor(oMyWeapon); + SignalEvent(oPossessor, EventSpellCastAt(OBJECT_SELF, GetSpellId(), FALSE)); + + if ( nDuration > 0 ) + { + float fDuration = HoursToSeconds(nDuration); + // haaaack: store caster level on item for the on hit spell to work properly + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oPossessor); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDur, oPossessor, fDuration); + AddFlamingEffectToWeapon(oMyWeapon, fDuration, nCasterLvl); + } + } + else + FloatingTextStrRefOnCreature(83615, OBJECT_SELF); +} diff --git a/src/_removed/x2_s0_glphward.nss b/src/_removed/x2_s0_glphward.nss new file mode 100644 index 0000000..c299615 --- /dev/null +++ b/src/_removed/x2_s0_glphward.nss @@ -0,0 +1,75 @@ +//:://///////////////////////////////////////////// +//:: Glyph of Warding +//:: X2_S0_GlphWard +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + The caster creates a trapped area which detects + the entrance of enemy creatures into 3 m area + around the spell location. When tripped it + causes a sonic explosion that does 1d8 per + two caster levels up to a max of 5d8 damage. +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: Dec 04, 2002 +//:: Modified by Krit and Wise on 2/11/10 +//::////////////////////////////////////////////// + +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-07-07 by Georg Zoeller + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + object oGlyph = CreateObject(OBJECT_TYPE_PLACEABLE,"x2_plc_glyph",GetSpellTargetLocation()); + object oTest = GetNearestObjectByTag("X2_PLC_GLYPH",oGlyph); + + if (GetIsObjectValid(oTest) && GetDistanceBetween(oGlyph, oTest) <5.0f) + { + FloatingTextStrRefOnCreature(84612,OBJECT_SELF); + DestroyObject(oGlyph); + return; + } + + + // Store the caster + SetLocalObject(oGlyph,"X2_PLC_GLYPH_CASTER",OBJECT_SELF); + + // Store the caster level + SetLocalInt (oGlyph,"X2_PLC_GLYPH_CASTER_LEVEL",GetCasterLevel(OBJECT_SELF)); + + // Store Meta Magic + SetLocalInt (oGlyph,"X2_PLC_GLYPH_CASTER_METAMAGIC",GetMetaMagicFeat()); + + // Store the DC. + SetLocalInt(oGlyph, "X2_PLC_GLYPH_DC", GetSpellSaveDC()); + + // This spell (default = line 768 in spells.2da) will run when someone enters the glyph + SetLocalInt(oGlyph,"X2_PLC_GLYPH_SPELL",764); + + // Tell the system that this glyph was player and not toolset created + SetLocalInt (oGlyph,"X2_PLC_GLYPH_PLAYERCREATED",TRUE); + + // Tell the game the glyph is not a permanent one + DeleteLocalInt(oGlyph,"X2_PLC_GLYPH_PERMANENT"); + + // Force first hb + ExecuteScript("x2_o0_glyphhb",oGlyph); + +} diff --git a/src/_removed/x2_s0_glphwardx.nss b/src/_removed/x2_s0_glphwardx.nss new file mode 100644 index 0000000..66efe89 --- /dev/null +++ b/src/_removed/x2_s0_glphwardx.nss @@ -0,0 +1,118 @@ +//:://///////////////////////////////////////////// +//:: Glyph of Warding Triggered +//:: x2_s0_glyphwardx +//:: Copyright (c) 2003 Bioware Corp. +//::////////////////////////////////////////////// +/* + Default Glyph of warding damage script + + This spellscript is fired when someone triggers + a player cast Glyph of Warding + + + Check x2_o0_glyphhb.nss and the Glyph of Warding + placeable object for details + +*/ +//::////////////////////////////////////////////// +//:: Created By: Georg Zoeller +//:: Created On: 2003-09-02 +//:: Modified by Krit and Wise on 2/11/10 +//::////////////////////////////////////////////// + +#include "x0_i0_spells" + +void DoDamage(int nDamage, object oTarget) +{ + effect eVis = EffectVisualEffect(VFX_IMP_SONIC); + effect eDam = EffectDamage(nDamage, DAMAGE_TYPE_SONIC); + if(nDamage > 0) + { + //Apply VFX impact and damage effect + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + DelayCommand(0.01, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + } +} + +void main() +{ + //Declare major variables + object oTarget = GetLocalObject(OBJECT_SELF,"X2_GLYPH_LAST_ENTER"); + location lTarget = GetLocation(OBJECT_SELF); + effect eDur = EffectVisualEffect(445); + int nDamage; + int nDC = GetLocalInt(OBJECT_SELF, "X2_PLC_GLYPH_DC"); + int nCasterLevel = GetLocalInt(OBJECT_SELF,"X2_PLC_GLYPH_CASTER_LEVEL"); + int nMetaMagic = GetLocalInt(OBJECT_SELF,"X2_PLC_GLYPH_CASTER_METAMAGIC"); + object oCreator = GetLocalObject(OBJECT_SELF,"X2_PLC_GLYPH_CASTER") ; + + + if ( GetLocalInt (OBJECT_SELF,"X2_PLC_GLYPH_PLAYERCREATED") == 0 ) + { + oCreator = OBJECT_SELF; + } + + if (!GetIsObjectValid(oCreator)) + { + DestroyObject(OBJECT_SELF); + return; + } + + int nDice = nCasterLevel /2; + + if (nDice > 5) + nDice = 5; + else if (nDice <1 ) + nDice = 1; + + effect eDam; + effect eExplode = EffectVisualEffect(459); + + //Check the faction of the entering object to make sure the entering object is not in the casters faction + + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, lTarget); + //Cycle through the targets in the explosion area + oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + while(GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget,SPELL_TARGET_STANDARDHOSTILE,oCreator)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(oCreator, GetSpellId())); + //Make SR check + if (!MyResistSpell(oCreator, oTarget)) + { + nDamage = d8(nDice); + //Enter Metamagic conditions + + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 8 * 5;//Damage is at max + } + else if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + (nDamage/2);//Damage/Healing is +50% + } + + //Change damage according to Reflex, Evasion and Improved Evasion + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, nDC, SAVING_THROW_TYPE_SONIC, oCreator); + + + //---------------------------------------------------------- + // Have the creator do the damage so he gets feedback strings + //---------------------------------------------------------- + if (oCreator != OBJECT_SELF) + { + AssignCommand(oCreator, DoDamage(nDamage,oTarget)); + } + else + { + DoDamage(nDamage,oTarget); + } + + } + } + //Get next target in the sequence + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } +} diff --git a/src/_removed/x2_s0_grmagweap.nss b/src/_removed/x2_s0_grmagweap.nss new file mode 100644 index 0000000..040bfc5 --- /dev/null +++ b/src/_removed/x2_s0_grmagweap.nss @@ -0,0 +1,75 @@ +//:://///////////////////////////////////////////// +//:: Greater Magic Weapon +//:: X2_S0_GrMagWeap +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Grants a +1 enhancement bonus per 3 caster levels + (maximum of +5). + lasts 1 hour per level +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: Nov 28, 2002 +//::////////////////////////////////////////////// +//:: Updated by Andrew Nobbs May 08, 2003 +//:: 2003-07-07: Stacking Spell Pass, Georg Zoeller +//:: 2003-07-17: Complete Rewrite to make use of Item Property System + + +#include "x2_inc_spellhook" +#include "wog_wpn_inc" + +void main() +{ + /* + Spellcast Hook Code + Added 2003-07-07 by Georg Zoeller + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + */ + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + // End of Spell Cast Hook + + + //Declare major variables + effect eVis = EffectVisualEffect(VFX_IMP_SUPER_HEROISM); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); + int nCasterLvl = GetCasterLevel(OBJECT_SELF); + int nDuration = nCasterLvl; + int nBonus = nCasterLvl / 3; + int nMetaMagic = GetMetaMagicFeat(); + + //Limit nBonus to 5, so it max out at +5 enhancement to the weapon. + if(nBonus > 5) + { + nBonus = 5; + } + + //object oMyWeapon = IPGetTargetedOrEquippedMeleeWeapon(); + object oMyWeapon = GetTargetedOrEquippedWeapon(); + + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration * 2; //Duration is +100% + } + + if(GetIsObjectValid(oMyWeapon) ) + { + SignalEvent(GetItemPossessor(oMyWeapon), EventSpellCastAt(OBJECT_SELF, GetSpellId(), FALSE)); + + if (nDuration>0) + { + float fDuration = HoursToSeconds(nDuration); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, GetItemPossessor(oMyWeapon)); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDur, GetItemPossessor(oMyWeapon), fDuration); + AddEnhancementEffectToWeapon(oMyWeapon, fDuration, nBonus); + } + } + else + FloatingTextStrRefOnCreature(83615, OBJECT_SELF); +} diff --git a/src/_removed/x2_s0_holyswrd.nss b/src/_removed/x2_s0_holyswrd.nss new file mode 100644 index 0000000..8af9078 --- /dev/null +++ b/src/_removed/x2_s0_holyswrd.nss @@ -0,0 +1,71 @@ +//:://///////////////////////////////////////////// +//:: Holy Sword +//:: X2_S0_HolySwrd +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Grants holy avenger properties. +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: Nov 28, 2002 +//::////////////////////////////////////////////// +//:: Updated by Andrew Nobbs May 08, 2003 +//:: 2003-07-07: Stacking Spell Pass, Georg Zoeller + + +#include "x2_inc_spellhook" +#include "x2_inc_toollib" + + +void AddHolyAvengerEffectToWeapon(object oWeapon, float fDuration) +{ + IPSafeAddItemProperty(oWeapon, ItemPropertyHolyAvenger(), fDuration, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, TRUE, TRUE); +} + + +void main() +{ + // Spellcast Hook Code + // Added 2003-07-07 by Georg Zoeller + // If you want to make changes to all spells, + // check x2_inc_spellhook.nss to find out more + if ( !X2PreSpellCastCode() ) + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell. + return; + // End of Spellcast Hook. + + + //Declare major variables + int nMetaMagic = GetMetaMagicFeat(); + float fDuration = RoundsToSeconds(GetCasterLevel(OBJECT_SELF)); + if ( nMetaMagic == METAMAGIC_EXTEND ) + fDuration *= 2.0; //Duration is +100% + + + // Get the true target. + object oWeapon = IPGetTargetedOrEquippedMeleeWeapon(); + + if ( GetIsObjectValid(oWeapon) ) + { + object oPossessor = GetItemPossessor(oWeapon); + SignalEvent(oPossessor, EventSpellCastAt(OBJECT_SELF, GetSpellId(), FALSE)); + + if ( fDuration > 0.0 ) + { + // Impact visual effect. + ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_GOOD_HELP), oPossessor); + // Spell expiration visual. + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE), oPossessor, fDuration); + // Add the bonus to the weapon. + AddHolyAvengerEffectToWeapon(oWeapon, fDuration); + } + // Special visual effects for casting this spell. + location lTarget = GetLocation(GetSpellTargetObject()); + TLVFXPillar(VFX_IMP_GOOD_HELP, lTarget, 4, 0.0, 6.0); + DelayCommand(1.0, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, + EffectVisualEffect(VFX_IMP_SUPER_HEROISM), lTarget)); + } + else + FloatingTextStrRefOnCreature(83615, OBJECT_SELF); // "* Spell Failed - Target must be a melee weapon or creature with a melee weapon equipped *" +} diff --git a/src/_removed/x2_s0_keenedge.nss b/src/_removed/x2_s0_keenedge.nss new file mode 100644 index 0000000..974bd1c --- /dev/null +++ b/src/_removed/x2_s0_keenedge.nss @@ -0,0 +1,77 @@ +//:://///////////////////////////////////////////// +//:: Keen Edge +//:: X2_S0_KeenEdge +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Adds the keen property to one melee weapon, + increasing its critical threat range. +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: Nov 28, 2002 +//::////////////////////////////////////////////// +//:: Updated by Andrew Nobbs May 08, 2003 +//:: 2003-07-07: Stacking Spell Pass, Georg Zoeller +//:: 2003-07-17: Complete Rewrite to make use of Item Property System + +#include "x2_i0_spells" +#include "x2_inc_spellhook" +#include "wog_wpn_inc" + +void AddKeenEffectToWeapon(object oMyWeapon, float fDuration) +{ + wog_AddTempItemProp(oMyWeapon, ItemPropertyKeen(), fDuration, TRUE, X2_IP_ADDPROP_POLICY_KEEP_EXISTING); +} + +void main() +{ + /* + Spellcast Hook Code + Added 2003-07-07 by Georg Zoeller + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + */ + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + // End of Spell Cast Hook + + + //Declare major variables + effect eVis = EffectVisualEffect(VFX_IMP_SUPER_HEROISM); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); + int nDuration = 10 * GetCasterLevel(OBJECT_SELF); + int nMetaMagic = GetMetaMagicFeat(); + + //object oMyWeapon = IPGetTargetedOrEquippedMeleeWeapon(); + object oMyWeapon = GetTargetedOrEquippedWeapon(); + + // 10 turns per level + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration * 2; //Duration is +100% + } + + if(GetIsObjectValid(oMyWeapon) ) + { + SignalEvent(GetItemPossessor(oMyWeapon), EventSpellCastAt(OBJECT_SELF, GetSpellId(), FALSE)); + + if (GetSlashingWeapon(oMyWeapon)) + { + if (nDuration>0) + { + float fDuration = TurnsToSeconds(nDuration); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, GetItemPossessor(oMyWeapon)); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDur, GetItemPossessor(oMyWeapon), fDuration); + AddKeenEffectToWeapon(oMyWeapon, fDuration); + } + } + else + FloatingTextStrRefOnCreature(83621, OBJECT_SELF); // not a slashing weapon + } + else + FloatingTextStrRefOnCreature(83615, OBJECT_SELF); +} diff --git a/src/_removed/x2_s0_magcvest.nss b/src/_removed/x2_s0_magcvest.nss new file mode 100644 index 0000000..6e1f722 --- /dev/null +++ b/src/_removed/x2_s0_magcvest.nss @@ -0,0 +1,94 @@ +//:://///////////////////////////////////////////// +//:: Magic Vestment +//:: X2_S0_MagcVest +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Grants a +1 AC bonus to armor touched per 3 caster + levels (maximum of +5). +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: Nov 28, 2002 +//::////////////////////////////////////////////// +//:: Updated by Andrew Nobbs May 09, 2003 +//:: 2003-07-29: Rewritten, Georg Zoeller + +#include "nw_i0_spells" +#include "x2_i0_spells" + +#include "x2_inc_spellhook" + + + +void AddACBonusToArmor(object oMyArmor, float fDuration, int nAmount) +{ + IPSafeAddItemProperty(oMyArmor,ItemPropertyACBonus(nAmount), fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING ,FALSE,TRUE); + return; +} + +void main() +{ + + /* + Spellcast Hook Code + Added 2003-07-07 by Georg Zoeller + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + + */ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + + //Declare major variables + effect eVis = EffectVisualEffect(VFX_IMP_GLOBE_USE); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); + + int nDuration = GetCasterLevel(OBJECT_SELF); + int nMetaMagic = GetMetaMagicFeat(); + int nAmount = GetCasterLevel(OBJECT_SELF)/3; + if (nAmount <0) + { + nAmount =1; + } + else if (nAmount>5) + { + nAmount =5; + } + + object oMyArmor = IPGetTargetedOrEquippedArmor(TRUE); + + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration * 2; //Duration is +100% + } + + + if(GetIsObjectValid(oMyArmor) ) + { + SignalEvent(GetItemPossessor(oMyArmor ), EventSpellCastAt(OBJECT_SELF, GetSpellId(), FALSE)); + + if (nDuration>0) + { + + location lLoc = GetLocation(GetSpellTargetObject()); + DelayCommand(1.3f, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, GetItemPossessor(oMyArmor))); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDur, GetItemPossessor(oMyArmor), HoursToSeconds(nDuration)); + AddACBonusToArmor(oMyArmor, HoursToSeconds(nDuration),nAmount); + } + return; + } + else + { + FloatingTextStrRefOnCreature(83826, OBJECT_SELF); + return; + } +} diff --git a/src/_removed/x2_s0_magcweap.nss b/src/_removed/x2_s0_magcweap.nss new file mode 100644 index 0000000..a9bc1ee --- /dev/null +++ b/src/_removed/x2_s0_magcweap.nss @@ -0,0 +1,64 @@ +//:://///////////////////////////////////////////// +//:: Magic Weapon +//:: X2_S0_MagcWeap +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Grants a +1 enhancement bonus. +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: Nov 28, 2002 +//::////////////////////////////////////////////// +//:: Updated by Andrew Nobbs May 08, 2003 +//:: 2003-07-07: Stacking Spell Pass, Georg Zoeller +//:: 2003-07-17: Complete Rewrite to make use of Item Property System + +#include "x2_inc_spellhook" +#include "wog_wpn_inc" + +void main() +{ + /* + Spellcast Hook Code + Added 2003-07-07 by Georg Zoeller + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + */ + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + // End of Spell Cast Hook + + + //Declare major variables + effect eVis = EffectVisualEffect(VFX_IMP_SUPER_HEROISM); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); + int nDuration = GetCasterLevel(OBJECT_SELF); + int nMetaMagic = GetMetaMagicFeat(); + + //object oMyWeapon = IPGetTargetedOrEquippedMeleeWeapon(); + object oMyWeapon = GetTargetedOrEquippedWeapon(); + + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration * 2; //Duration is +100% + } + + if(GetIsObjectValid(oMyWeapon) ) + { + SignalEvent(GetItemPossessor(oMyWeapon), EventSpellCastAt(OBJECT_SELF, GetSpellId(), FALSE)); + + if (nDuration>0) + { + float fDuration = HoursToSeconds(nDuration); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, GetItemPossessor(oMyWeapon)); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDur, GetItemPossessor(oMyWeapon), fDuration); + AddEnhancementEffectToWeapon(oMyWeapon, fDuration, 1); + } + } + else + FloatingTextStrRefOnCreature(83615, OBJECT_SELF); +} diff --git a/src/_removed/x2_s1_beholdray.nss b/src/_removed/x2_s1_beholdray.nss new file mode 100644 index 0000000..0778145 --- /dev/null +++ b/src/_removed/x2_s1_beholdray.nss @@ -0,0 +1,129 @@ +//:://///////////////////////////////////////////// +//:: Beholder Ray Attacks +//:: x2_s2_beholdray +//:: Copyright (c) 2003 Bioware Corp. +//::////////////////////////////////////////////// +/* + Implementation for the new version of the + beholder rays, using projectiles instead of + rays +*/ +//::////////////////////////////////////////////// +//:: Created By: Georg Zoeller +//:: Created On: 2003-09-16 +//::////////////////////////////////////////////// + +#include "prc_inc_spells" + + +// Adds an extra visual effect for the petrification ray. +void PetrificationVisual(object oTarget); + +void main() +{ + int nSpell = PRCGetSpellId(); + object oTarget = GetSpellTargetObject(); + int nSaveDC = 15; + + // Special handling for petrification. + if ( nSpell == 778 ) // BEHOLDER_RAY_PETRI + { + // The save DC is also the duration (if not permanent). + PRCDoPetrification(nSaveDC, OBJECT_SELF, oTarget, 778, nSaveDC); + DelayCommand(0.1, PetrificationVisual(oTarget)); + return; + } + + // Signal this ability being used. + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, nSpell)); + + // Perform a saving throw. + int bSave = FALSE; // Was the saving throw successful? + switch (nSpell) + { + case 776: // BEHOLDER_RAY_DEATH + case 783: // BEHOLDER_RAY_WOUND + bSave = 0 < PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nSaveDC); + break; + + case 777: // BEHOLDER_RAY_TK (knockdown) + case 779: // BEHOLDER_RAY_CHARM + case 780: // BEHOLDER_RAY_SLOW + case 784: // BEHOLDER_RAY_FEAR + bSave = 0 < PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nSaveDC); + break; + + // The remaining rays have no defined effects. + //case 785: // Undefined beholder ray. + //case 786: // Undefined beholder ray. + //case 787: // Undefined beholder ray. + } + + // If the save failed. + if ( !bSave ) + { + // Determine the effects to produce. + effect eDuration, eInstant; + float fDuration = 0.0; + switch ( nSpell ) + { + case 776: eInstant = EffectLinkEffects(EffectVisualEffect(VFX_IMP_DEATH), + EffectDeath(TRUE)); + break; + + case 777: eInstant = EffectVisualEffect(VFX_IMP_STUN); + eDuration = ExtraordinaryEffect(EffectKnockdown()); + fDuration = 6.0; + break; + + case 779: eInstant = EffectVisualEffect(VFX_IMP_CHARM); + eDuration = EffectCharmed(); + fDuration = 24.0; + break; + + case 780: eInstant = EffectVisualEffect(VFX_IMP_SLOW); + eDuration = EffectSlow(); + fDuration = RoundsToSeconds(6); + break; + + case 783: eInstant = EffectLinkEffects(EffectVisualEffect(VFX_COM_BLOOD_REG_RED), + EffectDamage(d8(2) + 10)); + break; + + case 784: eInstant = EffectVisualEffect(VFX_IMP_FEAR_S); + eDuration = EffectLinkEffects(EffectVisualEffect(VFX_DUR_MIND_AFFECTING_FEAR), + EffectFrightened()); + fDuration = RoundsToSeconds(d4() + 1); + break; + + // Provide a default just in case another spell makes it here. + default: eInstant = EffectVisualEffect(VFX_IMP_DESTRUCTION); + }//switch + + // Apply the effects + ApplyEffectToObject(DURATION_TYPE_INSTANT, eInstant, oTarget); + if ( fDuration > 0.0 ) + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDuration, oTarget, fDuration); + }//if (!bSave) + else + { + // Only one ray has an effect if the save was made. + if ( nSpell == 776 ) // Death ray + { + effect eDamage = EffectLinkEffects(EffectVisualEffect(VFX_IMP_NEGATIVE_ENERGY), + EffectDamage(d6(3) + 13)); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget); + } + } +} + + +// Adds an extra visual effect to petrification. +void PetrificationVisual(object oTarget) +{ + // See if oTarget has been petrified by this ray. + // (Or an earlier petrification ray. Close enough.) + if ( GetHasSpellEffect(778, oTarget) ) + ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_POLYMORPH), oTarget); +} + diff --git a/src/_removed/x2_s2_cursesong.nss b/src/_removed/x2_s2_cursesong.nss new file mode 100644 index 0000000..30bdf72 --- /dev/null +++ b/src/_removed/x2_s2_cursesong.nss @@ -0,0 +1,412 @@ +//:://///////////////////////////////////////////// +//:: Curse Song +//:: X2_S2_CurseSong +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + This spells applies penalties to all of the + bard's enemies within 30ft for a set duration of + 10 rounds. +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: May 16, 2003 +//::////////////////////////////////////////////// +//:: Last Updated By: Andrew Nobbs May 20, 2003 + +#include "tk_song_inc" // -- TK +#include "x2_i0_spells" + +void main() +{ + + if (!GetHasFeat(FEAT_BARD_SONGS, OBJECT_SELF)) + { + FloatingTextStrRefOnCreature(85587,OBJECT_SELF); // no more bardsong uses left + return; + } + + if (GetHasEffect(EFFECT_TYPE_SILENCE,OBJECT_SELF)) + { + FloatingTextStrRefOnCreature(85764,OBJECT_SELF); // not useable when silenced + return; + } + + + //Declare major variables + int nLevel = GetLevelByClass(CLASS_TYPE_BARD); + int nRanks = GetSkillRank(SKILL_PERFORM); + int nPerform = nRanks; + int nDuration = 10; //+ nChr; + + effect eAttack; + effect eDamage; + effect eWill; + effect eFort; + effect eReflex; + effect eHP; + effect eAC; + effect eSkill; + + int nAttack; + int nDamage; + int nWill; + int nFort; + int nReflex; + int nHP; + int nAC; + int nSkill; + //Check to see if the caster has Lasting Impression and increase duration. + if(GetHasFeat(870)) + { + nDuration *= 10; + } + + if(GetHasFeat(424)) // lingering song + { + nDuration += 5; + } + + if(nPerform >= 100 && nLevel >= 30) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 48; + nAC = 7; + nSkill = 18; + } + else if(nPerform >= 95 && nLevel >= 29) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 46; + nAC = 6; + nSkill = 17; + } + else if(nPerform >= 90 && nLevel >= 28) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 44; + nAC = 6; + nSkill = 16; + } + else if(nPerform >= 85 && nLevel >= 27) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 42; + nAC = 6; + nSkill = 15; + } + else if(nPerform >= 80 && nLevel >= 26) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 40; + nAC = 6; + nSkill = 14; + } + else if(nPerform >= 75 && nLevel >= 25) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 38; + nAC = 6; + nSkill = 13; + } + else if(nPerform >= 70 && nLevel >= 24) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 36; + nAC = 5; + nSkill = 12; + } + else if(nPerform >= 65 && nLevel >= 23) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 34; + nAC = 5; + nSkill = 11; + } + else if(nPerform >= 60 && nLevel >= 22) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 32; + nAC = 5; + nSkill = 10; + } + else if(nPerform >= 55 && nLevel >= 21) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 30; + nAC = 5; + nSkill = 9; + } + else if(nPerform >= 50 && nLevel >= 20) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 28; + nAC = 5; + nSkill = 8; + } + else if(nPerform >= 45 && nLevel >= 19) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 26; + nAC = 5; + nSkill = 7; + } + else if(nPerform >= 40 && nLevel >= 18) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 24; + nAC = 5; + nSkill = 6; + } + else if(nPerform >= 35 && nLevel >= 17) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 22; + nAC = 5; + nSkill = 5; + } + else if(nPerform >= 30 && nLevel >= 16) + { + nAttack = 2; + nDamage = 3; + nWill = 3; + nFort = 2; + nReflex = 2; + nHP = 20; + nAC = 5; + nSkill = 4; + } + else if(nPerform >= 24 && nLevel >= 15) + { + nAttack = 2; + nDamage = 3; + nWill = 2; + nFort = 2; + nReflex = 2; + nHP = 16; + nAC = 4; + nSkill = 3; + } + else if(nPerform >= 21 && nLevel >= 14) + { + nAttack = 2; + nDamage = 3; + nWill = 1; + nFort = 1; + nReflex = 1; + nHP = 16; + nAC = 3; + nSkill = 2; + } + else if(nPerform >= 18 && nLevel >= 12) + { + nAttack = 2; + nDamage = 2; + nWill = 1; + nFort = 1; + nReflex = 1; + nHP = 8; + nAC = 2; + nSkill = 2; + } + else if(nPerform >= 15 && nLevel >= 8) + { + nAttack = 2; + nDamage = 2; + nWill = 1; + nFort = 1; + nReflex = 1; + nHP = 8; + nAC = 0; + nSkill = 1; + } + else if(nPerform >= 12 && nLevel >= 6) + { + nAttack = 1; + nDamage = 2; + nWill = 1; + nFort = 1; + nReflex = 1; + nHP = 0; + nAC = 0; + nSkill = 1; + } + else if(nPerform >= 9 && nLevel >= 3) + { + nAttack = 1; + nDamage = 2; + nWill = 1; + nFort = 1; + nReflex = 0; + nHP = 0; + nAC = 0; + nSkill = 0; + } + else if(nPerform >= 6 && nLevel >= 2) + { + nAttack = 1; + nDamage = 1; + nWill = 1; + nFort = 0; + nReflex = 0; + nHP = 0; + nAC = 0; + nSkill = 0; + } + else if(nPerform >= 3 && nLevel >= 1) + { + nAttack = 1; + nDamage = 1; + nWill = 0; + nFort = 0; + nReflex = 0; + nHP = 0; + nAC = 0; + nSkill = 0; + } + effect eVis = EffectVisualEffect(VFX_IMP_DOOM); + + eAttack = EffectAttackDecrease(nAttack); + eDamage = EffectDamageDecrease(nDamage, DAMAGE_TYPE_SLASHING); + effect eLink = EffectLinkEffects(eAttack, eDamage); + + if(nWill > 0) + { + eWill = EffectSavingThrowDecrease(SAVING_THROW_WILL, nWill); + eLink = EffectLinkEffects(eLink, eWill); + } + if(nFort > 0) + { + eFort = EffectSavingThrowDecrease(SAVING_THROW_FORT, nFort); + eLink = EffectLinkEffects(eLink, eFort); + } + if(nReflex > 0) + { + eReflex = EffectSavingThrowDecrease(SAVING_THROW_REFLEX, nReflex); + eLink = EffectLinkEffects(eLink, eReflex); + } + if(nHP > 0) + { + //SpeakString("HP Bonus " + IntToString(nHP)); + eHP = EffectDamage(nHP, DAMAGE_TYPE_SONIC, DAMAGE_POWER_NORMAL); +// eLink = EffectLinkEffects(eLink, eHP); + } + if(nAC > 0) + { + eAC = EffectACDecrease(nAC, AC_DODGE_BONUS); + eLink = EffectLinkEffects(eLink, eAC); + } + if(nSkill > 0) + { + eSkill = EffectSkillDecrease(SKILL_ALL_SKILLS, nSkill); + eLink = EffectLinkEffects(eLink, eSkill); + } + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); + effect eDur2 = EffectVisualEffect(507); + eLink = EffectLinkEffects(eLink, eDur); + + effect eImpact = EffectVisualEffect(VFX_IMP_HEAD_SONIC); + effect eFNF = EffectVisualEffect(VFX_FNF_LOS_EVIL_30); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eFNF, GetLocation(OBJECT_SELF)); + + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(OBJECT_SELF)); + + eHP = ExtraordinaryEffect(eHP); + eLink = ExtraordinaryEffect(eLink); + + if(!GetHasFeatEffect(871, oTarget)&& !GetHasSpellEffect(GetSpellId(),oTarget)) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDur2, OBJECT_SELF, RoundsToSeconds(nDuration)); + } + float fDelay; + while(GetIsObjectValid(oTarget)) + { + if(spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, OBJECT_SELF)) + { + // * GZ Oct 2003: If we are deaf, we do not have negative effects from curse song + if (!GetHasEffect(EFFECT_TYPE_DEAF,oTarget)) + { + if(!GetHasFeatEffect(871, oTarget)&& !GetHasSpellEffect(GetSpellId(),oTarget)) + { + if (nHP > 0) + { + ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_SONIC), oTarget); + DelayCommand(0.01, ApplyEffectToObject(DURATION_TYPE_INSTANT, eHP, oTarget)); + } + + if (!GetIsDead(oTarget)) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration)); + DelayCommand(GetRandomDelay(0.1,0.5),ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + } + else + { + ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_MAGIC_RESISTANCE_USE), oTarget); + } + } + + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(OBJECT_SELF)); + } + DecrementRemainingFeatUses(OBJECT_SELF, FEAT_BARD_SONGS); + + // Sing lyrics, if any. -- TK + StartLyrics(nDuration, TRUE); +} diff --git a/src/_removed/x2_s2_discbreath.nss b/src/_removed/x2_s2_discbreath.nss new file mode 100644 index 0000000..2450967 --- /dev/null +++ b/src/_removed/x2_s2_discbreath.nss @@ -0,0 +1,325 @@ +//:://///////////////////////////////////////////// +//:: Breath Weapon for Dragon Disciple Class +//:: x2_s2_discbreath +//:: Copyright (c) 2003 Bioware Corp. +//::////////////////////////////////////////////// +/* + Damage type is Fire or by RDD variant + Damage die is d10 or by damage type + Save is Reflex + Save DC depends on damage type + Shape is cone, 30' == 10m + + Level Fire damage Fire save + --------------------------------- + 3 2d10 19 + 7 4d10 19 + 10 6d10 19 + + after 10: + damage: 6d10 + 1d10 per 3 levels after 10 + save DC: increases by 1 every 4 levels after 10 +*/ +//::////////////////////////////////////////////// +//:: Created By: Georg Zoeller +//:: Created On: June, 17, 2003 +//::////////////////////////////////////////////// +//:: Modified By: The Krit +//:: Modified On: January 7, 2017 +//:: Modified to accommodate RDD variants. +//::////////////////////////////////////////////// + + +#include "nw_i0_spells" +#include "tk_rdd_include" + + +const float CONE_SIZE = 10.0; + + +// Determines the type of breath to use (acid, cold, fire, electric). +// Returns a DAMAGE_TYPE_* constant. +int GetBreathType(object oDragon); +// Calculates the damage to inflict on each target, before saves. +int GetDamage(int nLevel, int nType); +// Determines how many dice to roll for damage. +int GetNumberOfDice(int nLevel); +// Calculates the DC for the save. +int GetDC(int nLevel, int nType); +// The breath DC can be modified if the disciple's ethos no longer matches the +// dragon type. +int BeathDCAdjustment(object oDragon); +// Calculates the target location. This can differ from the intrinsic spell +// target location when self-targeting is used. +location GetAdjustedTargetLocation(object oCaster); +// Selects an appropriate area of effect visual and shows it. +void ApplyAreaVisual(location lTarget, int nType); +// Selects an appropriate impact visual effect. +int GetImpactVisualIndex(int nType); +// Converts a DAMAGE_TYPE_* constant to the corresponding SAVING_THROW_TYPE_*. +int DamageTypeToSaveType(int nDamageType); + +// Adds a vector to a location. +location LocationOffset(location lSource, float fDirection, float fDistance); +// Shorthand for applying a fire-and-forget visual to a location. +void FireAndForgetLocation(int nVFX, location lTarget); +// Applies several copies of a fire-and-forget visual around a location. +void FireAndForgetScatter(int nVFX, location lTarget, float fRadius, int nCount = 60); +// Shorthand for applying a duration visual to a location. +void VisualAtLocation(int nVFX, location lTarget, float fDuration = 1.0); +// Uses a persistent area of effect visual without the normal effects. +void VisualAOEAtLocation(int nAreaEffectID, location lTarget, float fDuration = 1.0); + + +void main() +{ + object oDragon = OBJECT_SELF; + int nLevel = GetLevelByClass(CLASS_TYPE_DRAGON_DISCIPLE, oDragon); + int nType = GetBreathType(oDragon); + int nDamage = GetDamage(nLevel, nType); + int nSaveDC = GetDC(nLevel, nType) + BeathDCAdjustment(oDragon); + int nSaveType = DamageTypeToSaveType(nType); + int nSpellID = GetSpellId(); + location lFinalTarget = GetAdjustedTargetLocation(oDragon); + effect eImpactVFX = EffectVisualEffect(GetImpactVisualIndex(nType)); + int nObjectFilter = OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE; + + // Snazzy visuals. + ApplyAreaVisual(lFinalTarget, nType); + + //Get first target in spell area + object oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, CONE_SIZE, lFinalTarget, TRUE, nObjectFilter); + while ( OBJECT_INVALID != oTarget ) + { + if ( oTarget != oDragon && !GetIsReactionTypeFriendly(oTarget, oDragon) ) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(oDragon, nSpellID)); + //Determine effect delay + float fDelay = GetDistanceBetween(oDragon, oTarget)/20; + //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. + int nPersonalDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nSaveDC, nSaveType, oDragon); + if ( nPersonalDamage > 0 ) + { + //Set Damage and VFX + effect eBreath = EffectDamage(nPersonalDamage, nType); + //Apply the VFX impact and effects + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpactVFX, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eBreath, oTarget)); + } + } + //Get next target in spell area + oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, CONE_SIZE, lFinalTarget, TRUE, nObjectFilter); + } +} + + +// Determines the type of breath to use (acid, cold, fire, electric). +// Returns a DAMAGE_TYPE_* constant. +int GetBreathType(object oDragon) +{ + // Check for a variant breath. + int nCode = RDD_GetVariantCode(oDragon); + if ( nCode > 0 ) { + int nDamageType = RDD_GetBreath(nCode); + if ( nDamageType > 0 ) + return nDamageType; + // The variant is set but not the damage type. That means choose randomly. + switch ( d4() ) { + case 1: return DAMAGE_TYPE_ACID; + case 2: return DAMAGE_TYPE_COLD; + case 3: return DAMAGE_TYPE_FIRE; + case 4: return DAMAGE_TYPE_ELECTRICAL; + } + } + + // Default backup case. + return DAMAGE_TYPE_FIRE; +} + +// Calculates the damage to inflict on each target, before saves. +int GetDamage(int nLevel, int nType) +{ + int nNumDice = GetNumberOfDice(nLevel); + + // The type determines which dice get rolled. + switch ( nType ) { + case DAMAGE_TYPE_ACID: return d8(nNumDice); + case DAMAGE_TYPE_COLD: return d10(nNumDice); + case DAMAGE_TYPE_ELECTRICAL: return d12(nNumDice); + case DAMAGE_TYPE_FIRE: return d10(nNumDice); + } + // This should not be reached, but better safe than sorry. + return d10(nNumDice); // BioWare default. +} + +// Determines how many dice to roll for damage. +int GetNumberOfDice(int nLevel) +{ + if ( nLevel < 7 ) + return 2; + else if ( nLevel < 10 ) + return 4; + else + return 6 + ((nLevel - 10)/3); +} + + +// Calculates the DC for the save. +int GetDC(int nLevel, int nType) +{ + int nDC = 19; // BioWare default + + // Epic progression. + if ( nLevel > 10 ) + nDC += (nLevel - 10)/4; + + // The type affects the DC. + switch ( nType ) { + case DAMAGE_TYPE_ACID: nDC += 3; break; + case DAMAGE_TYPE_ELECTRICAL: nDC -= 3; break; + } + + return nDC; +} + + +// The breath DC can be modified if the disciple's ethos no longer matches the +// dragon type. +int BeathDCAdjustment(object oDragon) +{ + int nModifier = 0; + int nCode = RDD_GetVariantCode(oDragon); + + if ( nCode > 0 ) { + if ( GetAlignmentGoodEvil(oDragon) != RDD_GetGoodEvil(nCode) ) + nModifier -= 2; + if ( GetAlignmentLawChaos(oDragon) != RDD_GetLawChaos(nCode) ) + nModifier -= 2; + } + + return nModifier; +} + + +// Calculates the target location. This can differ from the intrinsic spell +// target location when self-targeting is used. +location GetAdjustedTargetLocation(object oCaster) +{ + // Typically we use the official spell target location. + location lFinalTarget = GetSpellTargetLocation(); + if ( GetPositionFromLocation(lFinalTarget) == GetPosition(oCaster) ) + { + // Since the target and origin are the same, we haveto determine the + // direction of the spell from the facing of the caster (which is more + // intuitive than defaulting to East everytime). To use that direction, + // we select a location in front of the caster. + lFinalTarget = LocationOffset(lFinalTarget, GetFacing(oCaster), CONE_SIZE/2.0); + } + + return lFinalTarget; +} + +// Selects an appropriate area of effect visual and shows it. +void ApplyAreaVisual(location lTarget, int nType) +{ + // Pick the visual. + switch ( nType ) { + case DAMAGE_TYPE_ACID: + VisualAOEAtLocation(AOE_PER_FOGACID, lTarget); + FireAndForgetScatter(VFX_IMP_ACID_L, lTarget, CONE_SIZE/2.5); + break; + case DAMAGE_TYPE_COLD: + VisualAtLocation(1781, lTarget); // CEPVFX_AOE_FOG_COLD + FireAndForgetScatter(821, lTarget, CONE_SIZE/2.5); // PRCVFX_IMP_SPELLFAIL_FLAME + break; + case DAMAGE_TYPE_ELECTRICAL: + FireAndForgetLocation(VFX_FNF_ELECTRIC_EXPLOSION, lTarget); + break; + case DAMAGE_TYPE_FIRE: + FireAndForgetLocation(494, lTarget); // VFX_FNF_DRAGBREATHGROUND + break; + default: + // This should not be reached, but no harm in being cautious. + FireAndForgetLocation(494, lTarget); // BioWare default. + } +} + +// Selects an appropriate impact visual effect. +int GetImpactVisualIndex(int nType) +{ + switch ( nType ) { + case DAMAGE_TYPE_ACID: return VFX_FNF_GAS_EXPLOSION_ACID; + case DAMAGE_TYPE_COLD: return 1810; // CEPVFX_FNF_GAS_EXPLOSION_COLD; + case DAMAGE_TYPE_ELECTRICAL: return VFX_IMP_LIGHTNING_S; + case DAMAGE_TYPE_FIRE: return VFX_IMP_FLAME_M; + } + + // This should not be reached, but better safe than sorry. + return VFX_IMP_FLAME_M; // BioWare default. +} + +// Converts a DAMAGE_TYPE_* constant to the corresponding SAVING_THROW_TYPE_*. +int DamageTypeToSaveType(int nDamageType) +{ + // This includes more damage types than we currently need in case someone + // decides to expand the possibilities later. + switch ( nDamageType ) { + case DAMAGE_TYPE_ACID: return SAVING_THROW_TYPE_ACID; + case DAMAGE_TYPE_COLD: return SAVING_THROW_TYPE_COLD; + case DAMAGE_TYPE_DIVINE: return SAVING_THROW_TYPE_DIVINE; + case DAMAGE_TYPE_ELECTRICAL: return SAVING_THROW_TYPE_ELECTRICITY; + case DAMAGE_TYPE_FIRE: return SAVING_THROW_TYPE_FIRE; + case DAMAGE_TYPE_NEGATIVE: return SAVING_THROW_TYPE_NEGATIVE; + case DAMAGE_TYPE_POSITIVE: return SAVING_THROW_TYPE_POSITIVE; + case DAMAGE_TYPE_SONIC: return SAVING_THROW_TYPE_SONIC; + } + // There are no special saving throw types for bludgeoning, piercing, + // slashing, or magical damage. + return SAVING_THROW_TYPE_NONE; +} + +// Adds a vector to a location. +location LocationOffset(location lSource, float fDirection, float fDistance) +{ + return Location(GetAreaFromLocation(lSource), + GetPositionFromLocation(lSource) + fDistance*AngleToVector(fDirection), + GetFacingFromLocation(lSource)); +} + +// Shorthand for applying a fire-and-forget visual to a location. +void FireAndForgetLocation(int nVFX, location lTarget) +{ + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(nVFX), lTarget); +} + +// Applies several copies of a fire-and-forget visual around a location. +void FireAndForgetScatter(int nVFX, location lTarget, float fRadius, int nCount = 60) +{ + effect eVisual = EffectVisualEffect(nVFX); + + while ( nCount-- > 0 ) { + // Choose a random location in the circle. + float fAngle = IntToFloat(Random(360)); + float fDistance = IntToFloat(Random(FloatToInt(fRadius * 1000.0)) + 1) / 1000.0; + location lApplyAt = LocationOffset(lTarget, fAngle, fDistance); + + // Fire the visual (delayed to de-synchronize the visuals). + float fDelay = fDistance / fRadius; + DelayCommand(fDelay, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVisual, lApplyAt)); + } +} + +// Shorthand for applying a duration visual to a location. +void VisualAtLocation(int nVFX, location lTarget, float fDuration = 1.0) +{ + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, EffectVisualEffect(nVFX), lTarget, fDuration); +} + +// Uses a persistent area of effect visual without the normal effects. +void VisualAOEAtLocation(int nAreaEffectID, location lTarget, float fDuration = 1.0) +{ + effect eVisual = EffectAreaOfEffect(nAreaEffectID, "****", "****", "****"); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVisual, lTarget, fDuration); +} + diff --git a/src/_removed/x2_s2_dragknght.nss b/src/_removed/x2_s2_dragknght.nss new file mode 100644 index 0000000..04d6a72 --- /dev/null +++ b/src/_removed/x2_s2_dragknght.nss @@ -0,0 +1,50 @@ +//:://///////////////////////////////////////////// +//:: Dragon Knight +//:: X2_S2_DragKnght +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Summons an adult red dragon for you to + command. +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: Feb 07, 2003 +//::////////////////////////////////////////////// +#include "x2_inc_toollib" + +#include "x2_inc_spellhook" +void main() +{ + + /* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + */ + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + + + //Declare major variables + int nDuration = GetCasterLevel(OBJECT_SELF); + if (nDuration < 20) + { + nDuration = 20; + } + effect eSummon; + effect eVis = EffectVisualEffect(460); + eSummon = EffectSummonCreature("wog_s_dragonknig",481,0.0f,TRUE); + + // * make it so dragon cannot be dispelled + eSummon = ExtraordinaryEffect(eSummon); + //Apply the summon visual and summon the dragon. + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon,GetSpellTargetLocation(), RoundsToSeconds(nDuration)); + DelayCommand(1.0f,ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis,GetSpellTargetLocation())); +} + + diff --git a/src/_removed/x2_s2_dyearmor.nss b/src/_removed/x2_s2_dyearmor.nss new file mode 100644 index 0000000..18757e2 --- /dev/null +++ b/src/_removed/x2_s2_dyearmor.nss @@ -0,0 +1,194 @@ +//:://///////////////////////////////////////////// +//:: Dye Item Spellscript +//:: x2_s2_dyearmor +//:: Copyright (c) 2003 Bioware Corp. +//::////////////////////////////////////////////// +/* + Spellscript for all Dye: Material Spells + + Some Notes: + + The color of the dye is taken from the + last two letters of the item's tag + ** unless the local integer "DYE_INDEX" is + set on the item. This local integer will + override the color indicated by the tag. + (Set this integer to -1 to force the color + to be index 0.) + ** // TK -- 10/11/07 + ** Setting the local integer "DYE_INDEX" on + the item to -2 will cause the dyeing to turn + into sampling, resulting in the local being + set to the color of the target, after which + the script whose name is stored in the local + string "DYE_POSTSAMPLE_HANDLER" (also on the + item) will be executed by the item. + ** // TK -- 10/11/07 + + The colortype which to change (cloth1, cloth2, + leather1, ...) is determined by the spell ID + + Restrictions: + - you cannot dye armor in combat + - you can only dye armor && helmets + - you can only dye items in your inventory + - you can now dye cloaks as well + + - the IPWork container (see prc_x2_itemprop) + must be set up for this to work properly + +*/ +//::////////////////////////////////////////////// +//:: Modified: The Krit, 11/10/2007 - local variable color +//:: Modified: Georg Zoeller, 24/03/2006 - Cloaks +//:: Created By: Georg Zoeller +//:: Created On: 2003-05-10 +//::////////////////////////////////////////////// +#include "prc_x2_itemprop" +const int DYE_MAX_COLOR_INDEX = 175; + +// Maps the Spell ID to the appropriate ITEM_APPR_ARMOR_COLOR_* constant +int GetApprArmorColorFromSpellID(int nID) +{ + switch ( nID ) + { + case 648 : return ITEM_APPR_ARMOR_COLOR_CLOTH1; + case 649 : return ITEM_APPR_ARMOR_COLOR_CLOTH2; + case 650 : return ITEM_APPR_ARMOR_COLOR_LEATHER1; + case 651 : return ITEM_APPR_ARMOR_COLOR_LEATHER2; + case 652 : return ITEM_APPR_ARMOR_COLOR_METAL1; + case 653 : return ITEM_APPR_ARMOR_COLOR_METAL2; + } + return 0; +} + + +// Handles those things that must wait until the main script finishes. +void FinishDyeScript(object oPC, object oTarget, int bEquipped, int nSlot) +{ + // Move the armor back from the IP Container + object oNew = CopyItem(oTarget, oPC); + DestroyObject(oTarget); + + //---------------------------------------------------------------------------- + // We need to remove all temporary item properties here + //---------------------------------------------------------------------------- + IPRemoveAllItemProperties(oNew,DURATION_TYPE_TEMPORARY); + + // Reequip armor if it was equipped before + if (bEquipped) + { + AssignCommand(oPC,ClearAllActions(TRUE)); + AssignCommand(oPC,ActionEquipItem(oNew,nSlot)); + } +} + + +void main() +{ + // declare major variables + object oItem = GetSpellCastItem(); // The "dye" item that cast the spell + object oPC = OBJECT_SELF; // the user of the item + object oTarget = GetSpellTargetObject(); + string sTag = GetStringLowerCase(GetTag(oItem)); + // Determine the color to edit from the spell ID + int nColorType = GetApprArmorColorFromSpellID(GetSpellId()); + + if ( GetIsInCombat(oPC) ) // abort if in combat + { + FloatingTextStrRefOnCreature(83352,oPC); //"This item cannot be used in combat" + return; + } + + if ( GetObjectType(oTarget) != OBJECT_TYPE_ITEM || oTarget == OBJECT_INVALID ) + { + FloatingTextStrRefOnCreature(83353,oPC); //"Invalid Target, must select armor or helmet" + return; + } + + int nBase = GetBaseItemType(oTarget); + // GZ@2006/03/26: Added cloak support + if ( nBase != BASE_ITEM_ARMOR && nBase != BASE_ITEM_HELMET && nBase != BASE_ITEM_CLOAK ) + { + FloatingTextStrRefOnCreature(83353,oPC); //"Invalid Target, must select armor or helmet" + return; + } + + if ( GetItemPossessor(oTarget) != oPC ) + { + FloatingTextStrRefOnCreature(83354,oPC); //"target must be in inventory" + return; + } + + + // save if the item was equipped before the process + int bEquipped; + int nSlot; + if ( nBase == BASE_ITEM_HELMET ) + { + nSlot = INVENTORY_SLOT_HEAD; + bEquipped = (GetItemInSlot(nSlot,oPC) == oTarget); + } + // GZ@2006/03/26: Added cloak support + else if (nBase == BASE_ITEM_CLOAK ) + { + nSlot = INVENTORY_SLOT_CLOAK; + bEquipped = (GetItemInSlot(nSlot,oPC) == oTarget); + } + else + { + nSlot = INVENTORY_SLOT_CHEST; + bEquipped = (GetItemInSlot(nSlot,oPC) == oTarget); + } + + + // GZ@2006/03/26: Added new color palette support. Note: Will only work + // if craig updates the in engine functions as well. + // TK 2007/10/11: Rewrote and added support for specifying color via local variable. + int nColor = GetLocalInt(oItem, "DYE_INDEX"); + + // A value of -2 flags sampling instead of dyeing. + if ( nColor == -2 ) + { + // Set the local variable to the target's color. + SetLocalInt(oItem, "DYE_INDEX", + GetItemAppearance(oTarget, ITEM_APPR_TYPE_ARMOR_COLOR, nColorType)); + // Run the item-specific script. + ExecuteScript(GetLocalString(oItem, "DYE_POSTSAMPLE_HANDLER"), oItem); + // Done. Do not continue. + return; + } + + // Allow -1 (or any unhandled negative) in the local variable to force color 0. + else if ( nColor < 0 ) + nColor = 0; + // If local variable was not set, try the item's tag. + else if ( nColor == 0 ) + { + // Check the last three letters of the tag. + string sColor = GetStringRight(GetTag(oItem), 3); + // Legacy support for two character numbers: + if ( StringToInt(GetStringLeft(sColor, 1)) == 0 ) + sColor = GetStringRight(sColor, 2); + // Convert string to integer. + nColor = StringToInt(sColor); + } + + // I don't think this check needs to be here, but I'm not sure, so I'll + // comment it out instead of deleting it. + //if ( nColor < 0 || nColor > DYE_MAX_COLOR_INDEX ) + // nColor = 0; + // End TK revisions. + + + // move the item into the IP work container + object oNew = CopyItem(oTarget, IPGetIPWorkContainer()); + + DestroyObject(oTarget); + + // Dye the armor + oTarget = IPDyeArmor(oNew, nColorType, nColor); + + DelayCommand(0.01f, FinishDyeScript(oPC, oTarget, bEquipped, nSlot)); +} + diff --git a/src/_removed/x2_s2_epicward.nss b/src/_removed/x2_s2_epicward.nss new file mode 100644 index 0000000..97a1efe --- /dev/null +++ b/src/_removed/x2_s2_epicward.nss @@ -0,0 +1,55 @@ +//:://///////////////////////////////////////////// +//:: Epic Ward +//:: X2_S2_EpicWard. +//:: Copyright (c) 2003 Bioware Corp. +//::////////////////////////////////////////////// +/* + Makes the caster invulnerable to damage + (equals damage reduction 50/+20) + Lasts 1 round per level + +*/ +//::////////////////////////////////////////////// +//:: Created By: Georg Zoeller +//:: Created On: Aug 12, 2003 +//::////////////////////////////////////////////// + + +#include "nw_i0_spells" + +#include "x2_inc_spellhook" + + + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + +// End of Spell Cast Hook + //Declare major variables + object oTarget = GetSpellTargetObject(); + int nDuration = 40; + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId(), FALSE)); + int nLimit = 50*nDuration; + effect eDur = EffectVisualEffect(495); + effect eProt = EffectDamageReduction(50, DAMAGE_POWER_PLUS_TWENTY, nLimit); + effect eLink = EffectLinkEffects(eDur, eProt); + eLink = EffectLinkEffects(eLink, eDur); + + // * Brent, Nov 24, making extraodinary so cannot be dispelled + eLink = ExtraordinaryEffect(eLink); + + RemoveEffectsFromSpell(OBJECT_SELF, GetSpellId()); + //Apply the armor bonuses and the VFX impact + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration)); + +} diff --git a/src/_removed/x2_s2_hellball.nss b/src/_removed/x2_s2_hellball.nss new file mode 100644 index 0000000..20497da --- /dev/null +++ b/src/_removed/x2_s2_hellball.nss @@ -0,0 +1,148 @@ +//:://///////////////////////////////////////////// +//:: Hellball +//:: X2_S2_HELLBALL +//:: Copyright (c) 2003 Bioware Corp. +//::////////////////////////////////////////////// +/* + Long range area of effect spell + 10d6 sonic, acid, fire and lightning damage to all + objects in the area + + 10d6 points of negative energy damage to caster + if MODULE_SWITCH_EPIC_SPELLS_HURT_CASTER switch + was enabled on the module. + + This spell is supposed to hurt the caster if he + is stupid enough to stand in the area of effect + when all hell breaks loose. It will hurt other + players allied with the caster as well. These + effects are dependent on your difficulty setting + + Save is 20 + relevant ability score, or, when cast + by a placeable, equal to the placeables WILL Save + + There is no benefit from the evasion feats here + as the are of the spell is too large to avoid it + + +*/ + +#include "X0_I0_SPELLS" +#include "x2_i0_spells" +#include "x2_inc_spellhook" + + +void main() +{ + + /* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + + */ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + + // End of Spell Cast Hook + //Declare major variables + int nDamage1, nDamage2, nDamage3, nDamage4; + object oCaster = OBJECT_SELF; + int nCasterLvl = GZGetHighestSpellcastingClassLevel(oCaster); + int nDamageLvlDice; + if (nCasterLvl>20) + { + int nDamageLvlDice = ((nCasterLvl - 20)/2); + } + else + { + int nDamageLvlDice = 0; + } + float fDelay; + effect eExplode = EffectVisualEffect(464); + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_M); + effect eVis2 = EffectVisualEffect(VFX_IMP_ACID_L); + effect eVis3 = EffectVisualEffect(VFX_IMP_SONIC); + + int nSpellDC = GetEpicSpellSaveDC(OBJECT_SELF); + + // if this option has been enabled, the caster will take damage for casting + // epic spells, as descripbed in the ELHB + if (GetModuleSwitchValue( MODULE_SWITCH_EPIC_SPELLS_HURT_CASTER) == TRUE) + { + effect eCast = EffectVisualEffect(VFX_IMP_NEGATIVE_ENERGY); + int nDamage5 = d6(10); + effect eDam5 = EffectDamage(nDamage5, DAMAGE_TYPE_NEGATIVE); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eCast, OBJECT_SELF); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam5, OBJECT_SELF); + } + + + + effect eDam1, eDam2, eDam3, eDam4, eDam5, eKnock; + eKnock= EffectKnockdown(); + + location lTarget = GetSpellTargetLocation(); + + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, lTarget); + + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, 20.0f, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + + int nTotalDamage; + while (GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + + fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oTarget))/20 + 0.5f; + //Roll damage for each target + nDamage1 = d6(10+nDamageLvlDice); + nDamage2 = d6(10+nDamageLvlDice); + nDamage3 = d6(10+nDamageLvlDice); + nDamage4 = d6(10+nDamageLvlDice); + // no we don't care about evasion. there is no evasion to hellball + if (MySavingThrow(SAVING_THROW_REFLEX,oTarget,nSpellDC,SAVING_THROW_TYPE_SPELL,OBJECT_SELF,fDelay) >0) + { + nDamage1 /=2; + nDamage2 /=2; + nDamage3 /=2; + nDamage4 /=2; + } + nTotalDamage = nDamage1+nDamage2+nDamage3+nDamage4; + //Set the damage effect + eDam1 = EffectDamage(nDamage1, DAMAGE_TYPE_ACID); + eDam2 = EffectDamage(nDamage2, DAMAGE_TYPE_ELECTRICAL); + eDam3 = EffectDamage(nDamage3, DAMAGE_TYPE_FIRE); + eDam4 = EffectDamage(nDamage4, DAMAGE_TYPE_SONIC); + + if(nTotalDamage > 0) + { + if (nTotalDamage > 50) + { + DelayCommand(fDelay+0.3f, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eKnock, oTarget,3.0f)); + } + + // Apply effects to the currently selected target. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam1, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam2, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam3, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam4, oTarget)); + //This visual effect is applied to the target object not the location as above. This visual effect + //represents the flame that erupts on the target not on the ground. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + DelayCommand(fDelay+0.2f, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis2, oTarget)); + DelayCommand(fDelay+0.5f, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis3, oTarget)); + } + } + //Select the next target within the spell shape. + oTarget = GetNextObjectInShape(SHAPE_SPHERE, 20.0f, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } +} + diff --git a/src/_removed/x2_s2_mumdust.nss b/src/_removed/x2_s2_mumdust.nss new file mode 100644 index 0000000..cf82e6e --- /dev/null +++ b/src/_removed/x2_s2_mumdust.nss @@ -0,0 +1,46 @@ +//:://///////////////////////////////////////////// +//:: Mummy Dust +//:: X2_S2_MumDust +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Summons a strong warrior mummy for you to + command. +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: Feb 07, 2003 +//::////////////////////////////////////////////// + +#include "x2_inc_spellhook" +void main() +{ + /* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + + */ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + + + //Declare major variables + int nDuration = 24; + //effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); + effect eSummon; + //Summon the appropriate creature based on the summoner level + //Warrior Mummy + eSummon = EffectSummonCreature("summonedmummykin",496,1.0f); + eSummon = ExtraordinaryEffect(eSummon); + //Apply the summon visual and summon the undead. + //ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), HoursToSeconds(nDuration)); +} + + diff --git a/src/_removed/x2_s2_poisonwp.nss b/src/_removed/x2_s2_poisonwp.nss new file mode 100644 index 0000000..97b0985 --- /dev/null +++ b/src/_removed/x2_s2_poisonwp.nss @@ -0,0 +1,281 @@ +//:://///////////////////////////////////////////// +//:: Poison Weapon spellscript +//:: x2_s2_poisonwp +//:: Copyright (c) 2003 Bioware Corp. +//::////////////////////////////////////////////// +//:: WoG: Updated for CEP/C.R.A.P. poisons +//:: Notes: These poisons work only if the server +//:: uses a modified itemprops.2da. +//:: These poisons work well only if some +//:: setup has been done. +//::////////////////////////////////////////////// +/* + Spell allows to add temporary poison properties + to a melee weapon or stack of arrows + + The exact details of the poison are loaded from + a 2da defined in prc_x2_itemprop X2_IP_POSIONWEAPON_2DA + taken from the row that matches the last three letters + of GetTag(GetSpellCastItem()) + ** CRAPoisons use only the last two letters, and they + correspond to rows in poison.2da. + + Example: if an item is given the poison weapon property + and its tag ending on 004, the 4th row of the + 2da will be used (1d2IntDmg DC14 18 seconds) + + Rows 0 to 99 are bioware reserved + + Non Assassins have a chance of poisoning themselves + when handling an item with this spell + + Restrictions + ... only weapons and ammo can be poisoned + ... restricted to piercing / slashing damage + + + SETUP FOR CRAPOISONS: + There must exist items in the server with the tags + Z_POISON_PROP00 through Z_POISON_PROP44. Each of these + items must have a single item property, and that property + must be on monster hit: poison for the poison corresponding + to the number at the end of the tag. + (Sorry, a BioBug prevents me from getting around this setup.) +*/ +//::////////////////////////////////////////////// +//:: Created By: Georg Zoeller +//:: Created On: 2003-05-11 +//:: Updated On: 2018-03-29 +//::////////////////////////////////////////////// +#include "prc_x2_itemprop" +#include "X2_inc_switches" + +const string CRAPOISON_2DA = "poison"; + + +// Performs a "skill check", with feedback similar to GetIsSkillSuccessful(). +// oPC is the one performing the check, sSkill is displayed to the player as the +// name of the skill being used, nAbility indicates the modifier to use, nDC is +// the number to beat, and bEasy causes an easier roll (d20 becomes 10+d10). +int FakeSkillRoll(object oPC, string sSkill, int nAbility, int nDC, int bEasy); +// Performs a check to see if oPC successfully applies a poison. +// If bEasy is TRUE, use BioWare's 10 + d10. Otherwise, roll a d20. +int GetIsPoisonSuccessful(object oPC, int nApplyDC, int bEasy); +// Returns TRUE iff an item has an on-hit: poison or on-monster-hit: poison property. +int HasPoisonProperty(object oTarget); +// Creates an on-monster-hit poison item property. +// sPoison should be a two-digit number indicating which poison to use. +itemproperty ItemPropertyOnMonsterHitPoison(string sPoison); +// Returns TRUE if oTarget can be coated with poison. +// Otherwise, send a message to oPC and return FALSE. +int ValidPoisonTarget(object oTarget, object oPC); + + +void main() +{ + object oPC = OBJECT_SELF; + object oTarget = GetSpellTargetObject(); + string sTag = GetTag(GetSpellCastItem()); + int bCRAPoison = ("z_" == GetStringLeft(sTag, 2)); + + // Valid? + if ( !ValidPoisonTarget(oTarget, oPC) ) + return; + + // Determine the poison being used. + itemproperty ipPoison; // Added to the target if successful + effect ePoison; // Applied to the PC upon failure + int nDuration; // In seconds + int nApplyDC; + + if ( bCRAPoison ) { + // A specific poison will be used. + string sPoison = GetStringRight(sTag, 2); + int nPoison = StringToInt(sPoison); + + ipPoison = ItemPropertyOnMonsterHitPoison(sPoison); + ePoison = EffectPoison(nPoison); + nDuration = 45 + 5*GetLevelByClass(CLASS_TYPE_ASSASSIN, oPC); // Simplified CRAPoison duration that does not depend on weapon type. + nApplyDC = StringToInt(Get2DAString(CRAPOISON_2DA, "Handle_DC", nPoison)); + } + else { + // BioWare standard: generic ability damage + int nRow = StringToInt(GetStringRight(sTag, 3)); + if ( nRow == 0 ) { + FloatingTextStrRefOnCreature(83360, oPC); //"Nothing happens + WriteTimestampedLogEntry ("Error: Item with tag " + sTag + " has the PoisonWeapon spellscript attached but tag does not contain 3 letter receipe code at the end!"); + return; + } + + int nPoisonType = StringToInt(Get2DAString(X2_IP_POISONWEAPON_2DA, "PoisonType", nRow)); + int nSaveDC = StringToInt(Get2DAString(X2_IP_POISONWEAPON_2DA, "SaveDC", nRow)); + + ipPoison = ItemPropertyOnHitProps(IP_CONST_ONHIT_ITEMPOISON, nSaveDC, nPoisonType); + //ePoison = There is no effect to apply upon failure. + nDuration = StringToInt(Get2DAString(X2_IP_POISONWEAPON_2DA, "Duration", nRow)); + nApplyDC = StringToInt(Get2DAString(X2_IP_POISONWEAPON_2DA, "ApplyCheckDC", nRow)); + } + + // Possibility of failure. + if ( !GetIsPoisonSuccessful(oPC, nApplyDC, !bCRAPoison) ) { + ApplyEffectToObject(DURATION_TYPE_PERMANENT, ePoison, oPC); // Does nothing if ePoison was not assigned an effect. + return; + } + + // Make sure the duration is temporary. + float fDuration = (nDuration < 1) ? 18.0 : IntToFloat(nDuration); // 18 is Bio-default. + // Apply the poison + IPSafeAddItemProperty(oTarget, ipPoison, fDuration, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, TRUE, TRUE); + if ( HasPoisonProperty(oTarget) ) { + // Success! + effect eVis = EffectVisualEffect(VFX_IMP_PULSE_NATURE); + itemproperty ipVis = ItemPropertyVisualEffect(ITEM_VISUAL_ACID); + IPSafeAddItemProperty(oTarget, ipVis, fDuration, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, TRUE, FALSE); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, GetItemPossessor(oTarget)); + + FloatingTextStrRefOnCreature(83361, oPC); //"Weapon is coated with poison" + } + else + FloatingTextStrRefOnCreature(83360, oPC); //"Nothing happens +} + + +// Performs a "skill check", with feedback similar to GetIsSkillSuccessful(). +// oPC is the one performing the check, sSkill is displayed to the player as the +// name of the skill being used, nAbility indicates the modifier to use, nDC is +// the number to beat, and bEasy causes an easier roll (d20 becomes 10+d10). +int FakeSkillRoll(object oPC, string sSkill, int nAbility, int nDC, int bEasy) +{ + int nRoll = bEasy ? (10 + d10()) : d20(); + int nModifier = GetAbilityModifier(nAbility, oPC); + int nCheck = nRoll + nModifier; + int bSuccess = nCheck >= nDC; + string sSuccess = + GetStringByStrRef((20 + nModifier < nDC) ? 8101 : bSuccess ? 5352 : 5353, + GetGender(oPC)); + + string sMessage = + GetNamePCColor(oPC) + ColorTokenSkillCheck() + " : " + + sSkill + " : *" + sSuccess + "* : (" + IntToString(nRoll) + " + " + + IntToString(nModifier) + " = " + IntToString(nCheck) + " vs. DC: " + + IntToString(nDC) + ")" + + ColorTokenEnd(); + SendMessageToPC(oPC, sMessage); + + return bSuccess; +} + +// Performs a check to see if oPC successfully applies a poison. +// If bEasy is TRUE, use BioWare's 10 + d10. Otherwise, roll a d20. +int GetIsPoisonSuccessful(object oPC, int nApplyDC, int bEasy) +{ + // According to BioWare: Force attacks of opportunity. + // (To me, looks more like force flat-footed.) + AssignCommand(oPC, ClearAllActions(TRUE)); + + // Feat allows using poison without a check. + if ( GetHasFeat(FEAT_USE_POISON, oPC) ) { + FloatingTextStrRefOnCreature(83369, oPC); // "Auto success " + return TRUE; + } + + // Poison restricted to assassins and blackguards only? + if ( GetModuleSwitchValue(MODULE_SWITCH_RESTRICT_USE_POISON_TO_FEAT) ) { + FloatingTextStrRefOnCreature(84420, oPC); //"Failed" + return FALSE; + } + + // Without the handle poison feat, do an ability check. + // (Feedback is now provided via the skill check.) + if ( !FakeSkillRoll(oPC, GetStringByStrRef(83371), ABILITY_DEXTERITY, nApplyDC, bEasy) ) { // "Use Poison" + //FloatingTextStrRefOnCreature(83368, oPC); //"Failed" + return FALSE; + } + + //FloatingTextStrRefOnCreature(83370, oPC); //"Success" + return TRUE; +} + + +// Returns TRUE iff an item has an on-hit: poison or on-monster-hit: poison property. +int HasPoisonProperty(object oTarget) +{ + // Loop over item properties. + itemproperty ipTest = GetFirstItemProperty(oTarget); + while ( GetIsItemPropertyValid(ipTest) ) { + int nType = GetItemPropertyType(ipTest); + // Check for on-hit item poison. + if ( ITEM_PROPERTY_ON_HIT_PROPERTIES == nType ) { + if ( IP_CONST_ONHIT_ITEMPOISON == GetItemPropertySubType(ipTest) ) + return TRUE; + } + // Check for on-monster-hit poison. + if ( ITEM_PROPERTY_ON_MONSTER_HIT == nType ) { + if ( IP_CONST_ONMONSTERHIT_POISON == GetItemPropertySubType(ipTest) ) + return TRUE; + } + + // Update the loop. + ipTest = GetNextItemProperty(oTarget); + } + return FALSE; +} + +// Creates an on-monster-hit poison item property. +// sPoison should be a two-digit number indicating which poison to use. +itemproperty ItemPropertyOnMonsterHitPoison(string sPoison) +{ + // This function exists because ItemPropertyOnMonsterHitProperties is bugged + // in that it always uses Large Scorpion Venom, ignoring the poison + // specified via parameters. As a workaround, the desired property can be + // pulled from a reference item, provided the module contains one for the + // poison in question. + object oReference = GetObjectByTag("Z_POISON_PROP" + sPoison); + if ( OBJECT_INVALID != oReference ) + return GetFirstItemProperty(oReference); + + // No reference object, so fall back on the bugged behavior. + // (Still specify the poison to use, in case the bug gets fixed.) + return ItemPropertyOnMonsterHitProperties(IP_CONST_ONMONSTERHIT_POISON, + StringToInt(sPoison)); +} + +// Returns TRUE if oTarget can be coated with poison. +// Otherwise, send a message to oPC and return FALSE. +int ValidPoisonTarget(object oTarget, object oPC) +{ + // Must be an item. + if ( GetObjectType(oTarget) != OBJECT_TYPE_ITEM ) { + FloatingTextStrRefOnCreature(83359, oPC); //"Invalid target " + return FALSE; + } + + // Must be a weapon + int nType = GetBaseItemType(oTarget); + if ( !IPGetIsMeleeWeapon(oTarget) && + !IPGetIsProjectile(oTarget) && + nType != BASE_ITEM_SHURIKEN && + nType != BASE_ITEM_DART && + nType != BASE_ITEM_THROWINGAXE ) + { + FloatingTextStrRefOnCreature(83359, oPC); // "Invalid target " + return FALSE; + } + + // Cannot do bludgeoning damage. + if ( IPGetIsBludgeoningWeapon(oTarget) || + nType == BASE_ITEM_BULLET ) + { + FloatingTextStrRefOnCreature(83367, oPC); // "Weapon does not do slashing or piercing damage " + return FALSE; + } + + // Cannot be already poisoned. + if ( HasPoisonProperty(oTarget) ) { + FloatingTextStrRefOnCreature(83407, oPC); // weapon already poisoned + return FALSE; + } + + // Looks OK. + return TRUE; +} diff --git a/src/_removed/x2_s2_ruin.nss b/src/_removed/x2_s2_ruin.nss new file mode 100644 index 0000000..7ad550f --- /dev/null +++ b/src/_removed/x2_s2_ruin.nss @@ -0,0 +1,62 @@ +//:://///////////////////////////////////////////// +//:: Greater Ruin +//:: X2_S2_Ruin +//:: Copyright (c) 2003 Bioware Corp. +//::////////////////////////////////////////////// + +#include "x2_I0_SPELLS" +#include "x2_inc_spellhook" +#include "x0_I0_SPELLS" +void main() +{ + + /* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + + */ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + + // End of Spell Cast Hook + + //Declare major variables + object oTarget = GetSpellTargetObject(); + object oCaster = OBJECT_SELF; + int nCasterLvl = GZGetHighestSpellcastingClassLevel(oCaster); + int nDamageLvlDice = 0; + if ( nCasterLvl > 20 ) + nDamageLvlDice = 2 * (nCasterLvl - 20); + + float fDist = GetDistanceBetween(OBJECT_SELF, oTarget); + float fDelay = fDist/(3.0 * log(fDist) + 2.0); + + int nSpellDC = GetEpicSpellSaveDC(OBJECT_SELF); + + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + //Roll damage + int nDam = d6(35 + nDamageLvlDice); + //Set damage effect + + if (MySavingThrow(SAVING_THROW_FORT,oTarget,nSpellDC,SAVING_THROW_TYPE_SPELL,OBJECT_SELF) != 0 ) + { + nDam /=2; + } + + effect eDam = EffectDamage(nDam, DAMAGE_TYPE_POSITIVE, DAMAGE_POWER_PLUS_TWENTY); + ApplyEffectAtLocation (DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_SCREEN_SHAKE), GetLocation(oTarget)); + ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(487), oTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_BLOOD_CRT_RED), oTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_BONE_MEDIUM), oTarget); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + } +} diff --git a/src/_removed/x2_s2_sumgrund.nss b/src/_removed/x2_s2_sumgrund.nss new file mode 100644 index 0000000..a1ed38a --- /dev/null +++ b/src/_removed/x2_s2_sumgrund.nss @@ -0,0 +1,147 @@ +//:://///////////////////////////////////////////// +//:: Summon Greater Undead +//:: X2_S2_SumGrUnd +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + 2003-10-03 - GZ: Added Epic Progression + The level of the Pale Master determines the + type of undead that is summoned. + + Level 9 <= Mummy Warrior + Level 10 <= Spectre + Level 12 <= Vampire Rogue + Level 14 <= Bodak + Level 16 <= Ghoul King + Level 18 <= Vampire Mage + Level 20 <= Skeleton Blackguard + Level 22 <= Lich + Level 24 <= Lich Lord + Level 26 <= Alhoon + Level 28 <= Elder Alhoon + Level 30 <= Lesser Demi Lich + + Lasts 14 + Casterlevel rounds +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: Feb 05, 2003 +//::////////////////////////////////////////////// + +void PMUpgradeSummon(object oSelf, string sScript) +{ + object oSummon = GetAssociate(ASSOCIATE_TYPE_SUMMONED,oSelf); + ExecuteScript ( sScript, oSummon); +} + +void main() +{ + + int nCasterLevel = GetLevelByClass(CLASS_TYPE_PALEMASTER,OBJECT_SELF); + int nDuration = 14 + nCasterLevel; + effect eVis; + string sResRef = ""; + object oBook = GetItemPossessedBy(OBJECT_SELF, "libramofnecroman"); + if ( oBook != OBJECT_INVALID ) + { + sResRef = GetLocalString(oBook, "undead5"); + } + + if ( sResRef == "" ) + { + + //-------------------------------------------------------------------------- + // Summon the appropriate creature based on the summoner level + //-------------------------------------------------------------------------- + if (nCasterLevel >= 30) + { + // * Demi Lich + sResRef = "wogsumdemilich02"; + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); + } + else if (nCasterLevel >= 28) + { + // * Mega Alhoon + sResRef = "wogsumeldalh001"; + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); + } + else if (nCasterLevel >= 26) + { + // * Alhoon + sResRef = "wogsummindflay05"; + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); + } + else if (nCasterLevel >= 24) + { + // * Lich + sResRef = "wogsumlichboss02"; + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); + } + else if (nCasterLevel >= 22) + { + // * Lich + sResRef = "wogsumlich004"; + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); + } + else if (nCasterLevel >= 20) + { + // * Skeleton Blackguard + sResRef = "wogsumskelbg002"; + effect eVis = EffectVisualEffect(VFX_IMP_HARM); + } + else if (nCasterLevel >= 18) + { + // * Vampire Mage + sResRef = "wogsumwizvamp4"; + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); + } + else if (nCasterLevel >= 16) + { + // * Ghoul King + sResRef = "wogsumghoulking1"; + effect eVis = EffectVisualEffect(VFX_IMP_HARM); + } + else if (nCasterLevel >= 14) + { + // * Greater Bodak + sResRef = "wogsumbodak001"; + effect eVis = EffectVisualEffect(VFX_IMP_HARM); + } + else if (nCasterLevel >= 12) + { + // * Vampire Rogue + sResRef = "wogsumvampire003"; + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); + } + else if (nCasterLevel >= 10) + { + sResRef = "wogsumspectre001"; + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); + } + else + { + // * Mummy + sResRef = "wogsummumfight01"; + effect eVis = EffectVisualEffect(VFX_IMP_HARM); + } + } + effect eSummon = EffectSummonCreature(sResRef); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT,EffectVisualEffect(VFX_FNF_LOS_EVIL_10),GetSpellTargetLocation()); + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), HoursToSeconds(nDuration)); + + // * If the character has a special pale master item equipped (variable set via OnEquip) + // * run a script on the summoned monster. + string sScript = GetLocalString(OBJECT_SELF,"X2_S_PM_SPECIAL_ITEM"); + if (sScript != "") + { + object oSelf = OBJECT_SELF; + DelayCommand(1.0,PMUpgradeSummon(oSelf,sScript)); + } +} + + + + + diff --git a/src/_removed/x2_s2_sumundead.nss b/src/_removed/x2_s2_sumundead.nss new file mode 100644 index 0000000..bdfb720 --- /dev/null +++ b/src/_removed/x2_s2_sumundead.nss @@ -0,0 +1,87 @@ +//:://///////////////////////////////////////////// +//:: Summon Undead +//:: X2_S2_SumUndead +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + The level of the Pale Master determines the + type of undead that is summoned. +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: Feb 05, 2003 +//:: Updated By: Georg Zoeller, Oct 2003 +//::////////////////////////////////////////////// + +void PMUpgradeSummon(object oSelf, string sScript) +{ + object oSummon = GetAssociate(ASSOCIATE_TYPE_SUMMONED,oSelf); + ExecuteScript ( sScript, oSummon); +} + +void main() +{ + //Declare major variables + int nCasterLevel = GetLevelByClass(CLASS_TYPE_PALEMASTER,OBJECT_SELF); + int nDuration = 14 + nCasterLevel; + effect eVis; + string sResRef = ""; + object oBook = GetItemPossessedBy(OBJECT_SELF, "libramofnecroman"); + if ( oBook != OBJECT_INVALID ) + { + sResRef = GetLocalString(oBook, "undead4"); + } + + if ( sResRef == "" ) + { + //effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); + + //Summon the appropriate creature based on the summoner level + if (nCasterLevel <= 5) + { + //Ghoul + sResRef = "sogsumghoul001"; + effect eVis = EffectVisualEffect(VFX_IMP_HARM); + } + else if (nCasterLevel == 6) + { + //Shadow + sResRef = "wogsumshadow002"; + effect eVis = EffectVisualEffect(VFX_IMP_HARM); + } + else if (nCasterLevel == 7) + { + //Ghast + sResRef = "wogsumghoul001"; + effect eVis = EffectVisualEffect(VFX_IMP_HARM); + } + else if (nCasterLevel == 8) + { + //Wight + sResRef = "wogsumwight002"; + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); + } + else if (nCasterLevel >= 9) + { + //Wraith + sResRef = "wogsumwraith001"; + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); + } + } + effect eSummon = EffectSummonCreature(sResRef); + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_INSTANT,EffectVisualEffect(VFX_FNF_LOS_EVIL_10),GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), HoursToSeconds(nDuration)); + + // * If the character has a special pale master item equipped (variable set via OnEquip) + // * run a script on the summoned monster. + string sScript = GetLocalString(OBJECT_SELF,"X2_S_PM_SPECIAL_ITEM"); + if (sScript != "") + { + object oSelf = OBJECT_SELF; + DelayCommand(1.0,PMUpgradeSummon(oSelf,sScript)); + } +} + + diff --git a/src/_removed/x2_s2_terrage_a.nss b/src/_removed/x2_s2_terrage_a.nss new file mode 100644 index 0000000..fc21d3e --- /dev/null +++ b/src/_removed/x2_s2_terrage_a.nss @@ -0,0 +1,87 @@ +//:://///////////////////////////////////////////// +//:: Terrifying Rage Script +//:: x2_s2_terrage_a.nss +//:: Copyright (c) 2003 Bioware Corp. +//::////////////////////////////////////////////// +/* + + Upon entering the aura of the creature the player + must make a will save or be struck with fear because + of the creatures presence. + + - Save DC is a Intimidate check result of the raging character + + - If the creature has less HitDice than the barbarian they freeze in terror 1d3 rounds + + - if the creature has less HD than the BarbarianHD*2, they are shaken (-2 to attack, -2 to saves) + + - if the creature has more than double HD than the Barb, they are immune to the effect + +*/ +//::////////////////////////////////////////////// +//:: Created By: Georg Zoeller +//:: Created On: 2003-07-10 +//::////////////////////////////////////////////// +#include "NW_I0_SPELLS" +#include "x2_i0_spells" + +void main() +{ + //Declare major variables + object oTarget = GetEnteringObject(); + effect eVis = EffectVisualEffect(VFX_IMP_FEAR_S); + effect eDur = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_FEAR); + effect eDur2 = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); + effect eLink; + + object oBarb = GetAreaOfEffectCreator(); + int nHD = GetHitDice(GetAreaOfEffectCreator()); + + int nRoll = d20(1); //sorry but d20() was just too unbalancing for the game, if you are a rules layer, just put the d20 here... + int nDC = nRoll + GetSkillRank(SKILL_INTIMIDATE,oBarb); + int nDuration = d4(4); + if(GetIsEnemy(oTarget, oBarb)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(oBarb, GetSpellId())); + //Make a saving throw check + + if(!MySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_FEAR, oBarb)) + { + // Respect the fear immunity! + if(GetIsImmune(oTarget, IMMUNITY_TYPE_FEAR, oBarb) == TRUE) + { + if (GetIsPC(oBarb)) + { + FloatingTextStrRefOnCreature(84525, oBarb, FALSE); + } + } + // Hit dice below barb.... run like hell! + else if (GetHitDice(oTarget) < GetHitDice(oBarb)) + { + //Apply the VFX impact and effects + effect eFear = EffectFrightened(); + eLink = EffectLinkEffects(eFear, eDur); + eLink = EffectLinkEffects(eLink, eDur2); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration)); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + PlayVoiceChat(VOICE_CHAT_HELP,oTarget); + } + // Up to twice the barbs HD ... shaken + else if (GetHitDice(oTarget)< GetHitDice(oBarb)*2) + { + effect eShake1 = EffectSavingThrowDecrease(SAVING_THROW_ALL,2); + effect eShake2 = EffectAttackDecrease(2); + eLink = EffectLinkEffects(eShake1, eDur); + eLink = EffectLinkEffects(eLink, eShake2); + eLink = EffectLinkEffects(eLink, eDur2); + eLink = ExtraordinaryEffect(eLink); + FloatingTextStrRefOnCreature(83583,oTarget); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration)); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + } + // else immune + } + } + +} diff --git a/src/hakpak/wog_prc8_top/2da/classes.2da b/src/hakpak/wog_prc8_top/2da/classes.2da index f70ecce..5a59699 100644 --- a/src/hakpak/wog_prc8_top/2da/classes.2da +++ b/src/hakpak/wog_prc8_top/2da/classes.2da @@ -12,247 +12,247 @@ 8 Rogue 112195 16 17 4898 248 IR_ROGUE 6 CLS_ATK_2 CLS_FEAT_ROG CLS_SAVTHR_ROG CLS_SKILL_ROG CLS_BFEAT_ROG 8 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_ROGUE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ROG 0 1 0 0 -1 8 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 9 Sorcerer 112196 18 19 4899 249 IR_SORCERER 4 CLS_ATK_3 CLS_FEAT_SORC CLS_SAVTHR_SORC CLS_SKILL_SORC CLS_BFEAT_SORC 2 CLS_SPGN_SORC CLS_SPKN_SORC 1 1 10 14 14 10 12 16 CHA 0X00 0X0 0 CLASS_TYPE_SORCERER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SORC 0 1 0 0 -1 9 131 **** 0 1 0 0 0 1 1 CHA Wiz_Sorc 1 1 1 0 0 10 Wizard 112197 20 21 4900 250 IR_WIZARD 4 CLS_ATK_3 CLS_FEAT_WIZ CLS_SAVTHR_WIZ CLS_SKILL_WIZ CLS_BFEAT_WIZ 2 CLS_SPGN_WIZ **** 1 1 10 14 14 12 16 10 INT 0X00 0X0 0 CLASS_TYPE_WIZARD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WIZ 0 1 0 0 -1 10 209 **** 1 1 0 1 1 1 1 INT Wiz_Sorc 1 1 1 0 0 -11 Aberration 112198 525 525 4901 8154 IR_WIZARD 8 CLS_ATK_2 CLS_FEAT_ABER CLS_SAVTHR_WIZ CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 1 0 14 14 11 14 3 5 STR 0X00 0X0 0 CLASS_TYPE_ABERRATION 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ABER 0 0 0 0 -1 73 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +11 Aberration 112198 525 525 4901 8154 IR_WIZARD 8 CLS_ATK_2 CLS_FEAT_ABER CLS_SAVTHR_WIZ CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 1 0 14 14 11 14 3 5 STR 0X00 0X0 0 CLASS_TYPE_ABERRATION 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ABER 0 0 0 0 -1 73 0 **** **** **** **** **** **** **** **** **** Aberration **** **** **** **** **** 12 Animal 112199 526 526 4902 8154 IR_WIZARD 8 CLS_ATK_2 CLS_FEAT_CREA CLS_SAVTHR_WILD CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 0 0 13 17 15 12 2 6 STR 0X00 0X0 0 CLASS_TYPE_ANIMAL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ANI 0 0 0 0 -1 74 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 13 Construct 112200 528 528 4903 8154 IR_WIZARD 10 CLS_ATK_2 CLS_FEAT_CREA CLS_SAVTHR_CONS CLS_SKILL_CREA CLS_BFEAT_BARB 0 **** **** 1 0 21 9 10 11 10 3 STR 0X00 0X0 0 CLASS_TYPE_CONSTRUCT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_CON 0 0 0 0 -1 75 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 14 Humanoid 112201 1763 1764 4904 8154 IR_WIZARD 8 CLS_ATK_2 CLS_FEAT_CREA CLS_SAVTHR_FIGHT CLS_SKILL_CREA CLS_BFEAT_BARB 6 **** **** 1 0 15 10 13 11 8 8 STR 0X00 0X0 0 CLASS_TYPE_HUMANOID 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HUM 0 0 0 0 -1 76 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -15 Monstrous 112202 536 536 4905 8154 IR_WIZARD 8 CLS_ATK_1 CLS_FEAT_MONHUM CLS_SAVTHR_BARD CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 1 0 19 10 15 10 7 8 STR 0X00 0X0 0 CLASS_TYPE_MONSTEROUS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MON 0 0 0 0 -1 77 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +15 Monstrous 112202 536 536 4905 8154 IR_WIZARD 8 CLS_ATK_1 CLS_FEAT_MONHUM CLS_SAVTHR_BARD CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 1 0 19 10 15 10 7 8 STR 0X00 0X0 0 CLASS_TYPE_MONSTEROUS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MON 0 0 0 0 -1 77 0 **** **** **** **** **** **** **** **** **** Monstrous **** **** **** **** **** 16 Elemental 112203 539 539 4906 8154 IR_WIZARD 8 CLS_ATK_2 CLS_FEAT_CREA CLS_SAVTHR_FIGHT CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 1 0 17 8 13 11 4 11 STR 0X00 0X0 0 CLASS_TYPE_ELEMENTAL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ELE 0 0 0 0 -1 78 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -17 Fey 112204 540 540 4907 8154 IR_WIZARD 6 CLS_ATK_3 CLS_FEAT_FEY CLS_SAVTHR_BARD CLS_SKILL_FEY CLS_BFEAT_BARB 6 **** **** 1 0 10 15 11 15 14 18 DEX 0X00 0X0 0 CLASS_TYPE_FEY 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FEY 0 0 0 0 -1 79 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +17 Fey 112204 540 540 4907 8154 IR_WIZARD 6 CLS_ATK_3 CLS_FEAT_FEY CLS_SAVTHR_BARD CLS_SKILL_FEY CLS_BFEAT_BARB 6 **** **** 1 0 10 15 11 15 14 18 DEX 0X00 0X0 0 CLASS_TYPE_FEY 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FEY 0 0 0 0 -1 79 0 **** **** **** **** **** **** **** **** **** Fey **** **** **** **** **** 18 Dragon 112205 529 529 4908 8154 IR_DRGNFIREADPT 12 CLS_ATK_1 CLS_FEAT_DRAG CLS_SAVTHR_MONK CLS_SKILL_DRAGON CLS_BFEAT_BARB 6 **** **** 1 0 13 10 13 10 11 10 STR 0X00 0X0 0 CLASS_TYPE_DRAGON 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DRAG 0 0 0 0 -1 80 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 19 Undead 112206 547 547 4909 8154 IR_WIZARD 12 CLS_ATK_3 CLS_FEAT_CREA CLS_SAVTHR_WIZ CLS_SKILL_CREA CLS_BFEAT_BARB 4 **** **** 1 0 10 12 10 10 10 11 STR 0X00 0X0 0 CLASS_TYPE_UNDEAD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_UNDEAD 0 0 0 0 -1 81 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 20 Commoner 112207 2291 2292 4910 8155 IR_WIZARD 4 CLS_ATK_3 CLS_FEAT_COMM CLS_SAVTHR_CONS CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 1 0 10 10 12 10 10 10 STR 0X00 0X0 0 CLASS_TYPE_COMMONER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 **** 0 0 0 0 -1 82 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 21 Beast 112208 527 527 4911 8154 IR_WIZARD 10 CLS_ATK_2 CLS_FEAT_CREA CLS_SAVTHR_WILD CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 0 0 16 13 16 3 12 8 STR 0X00 0X0 0 CLASS_TYPE_BEAST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BEAST 0 0 0 0 -1 83 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 22 Giant 112209 541 541 4912 8154 IR_WIZARD 8 CLS_ATK_2 CLS_FEAT_GIAN CLS_SAVTHR_FIGHT CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 1 0 25 8 19 10 6 17 STR 0X00 0X0 0 CLASS_TYPE_GIANT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_GIANT 0 0 0 0 -1 84 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 23 MagicBeast 112210 542 542 4913 8154 IR_WIZARD 10 CLS_ATK_1 CLS_FEAT_CREA CLS_SAVTHR_WILD CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 0 0 15 8 15 12 2 10 STR 0X00 0X0 0 CLASS_TYPE_MAGICAL_BEAST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MAGBST 0 0 0 0 -1 85 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -24 Outsider 112211 4812 4812 4914 8154 IR_WIZARD 8 CLS_ATK_1 CLS_FEAT_OUTS CLS_SAVTHR_MONK CLS_SKILL_OUTS CLS_BFEAT_BARB 8 **** **** 1 0 15 10 13 13 10 12 STR 0X00 0X0 0 CLASS_TYPE_OUTSIDER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_OUTS 0 0 0 0 -1 86 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -25 Shapechanger 112212 546 546 4915 8154 IR_WIZARD 8 CLS_ATK_2 CLS_FEAT_SHCHNG CLS_SAVTHR_MONK CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 1 0 15 11 17 10 10 10 STR 0X00 0X0 0 CLASS_TYPE_SHAPECHANGER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHAPE 0 0 0 0 -1 87 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +24 Outsider 112211 4812 4812 4914 8154 IR_WIZARD 8 CLS_ATK_1 CLS_FEAT_OUTS CLS_SAVTHR_MONK CLS_SKILL_OUTS CLS_BFEAT_BARB 8 **** **** 1 0 15 10 13 13 10 12 STR 0X00 0X0 0 CLASS_TYPE_OUTSIDER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_OUTS 0 0 0 0 -1 86 0 **** **** **** **** **** **** **** **** **** Outsider **** **** **** **** **** +25 Shapechanger 112212 546 546 4915 8154 IR_WIZARD 8 CLS_ATK_2 CLS_FEAT_SHCHNG CLS_SAVTHR_MONK CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 1 0 15 11 17 10 10 10 STR 0X00 0X0 0 CLASS_TYPE_SHAPECHANGER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHAPE 0 0 0 0 -1 87 0 **** **** **** **** **** **** **** **** **** Shapechanger **** **** **** **** **** 26 Vermin 112213 548 548 4916 8154 IR_WIZARD 8 CLS_ATK_2 CLS_FEAT_CREA CLS_SAVTHR_FIGHT CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 0 0 11 17 12 10 10 3 STR 0X00 0X0 0 CLASS_TYPE_VERMIN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_VERMIN 0 0 0 0 -1 88 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -27 Shadowdancer 112214 2944 2945 2946 2947 IR_X1_SHADOW 8 CLS_ATK_2 CLS_FEAT_SHADOW CLS_SAVTHR_ROG CLS_SKILL_SHADOW CLS_BFEAT_SHADOW 6 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_SHADOWDANCER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHADOW 30 0 0 0 10 63 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +27 Shadowdancer 112214 2944 2945 2946 2947 IR_X1_SHADOW 8 CLS_ATK_2 CLS_FEAT_SHADOW CLS_SAVTHR_ROG CLS_SKILL_SHADOW CLS_BFEAT_SHADOW 6 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_SHADOWDANCER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHADOW 40 0 0 0 10 63 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 28 Harper 112215 2956 2957 2958 2959 IR_X1_HARPER 6 CLS_ATK_2 CLS_FEAT_HARPER CLS_SAVTHR_BARD CLS_SKILL_HARPER CLS_BFEAT_HARPER 4 CLS_SPGN_HARPER CLS_SPKN_HARPER 0 1 12 16 14 8 14 12 DEX 0X10 0X2 0 CLASS_TYPE_HARPER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HARPER 5 0 0 0 5 64 130 **** **** **** **** **** **** **** **** **** Harper **** **** **** **** **** -29 Arcane_Archer 112216 9003 9004 9005 9006 IR_ARCHER 8 CLS_ATK_1 CLS_FEAT_ARCHER CLS_SAVTHR_WILD CLS_SKILL_ARCHER CLS_BFEAT_ARCHER 4 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_ARCANE_ARCHER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ARCHER 30 0 0 0 10 65 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -30 Assassin 112217 9007 9008 9009 16790386 IR_ASASIN 6 CLS_ATK_2 CLS_FEAT_ASASIN CLS_SAVTHR_ROG CLS_SKILL_ASASIN CLS_BFEAT_ASASIN 4 CLS_SPGN_ASASIN CLS_SPKN_ASASIN 1 1 12 16 14 8 14 12 DEX 0X09 0X2 0 CLASS_TYPE_ASSASSIN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ASASIN 30 0 0 0 10 66 131 **** **** **** **** **** **** **** **** **** Assassin **** **** **** **** **** -31 Blackguard 112218 9011 9012 9013 16790387 IR_BLKGRD 10 CLS_ATK_1 CLS_FEAT_BLKGRD CLS_SAVTHR_FIGHT CLS_SKILL_BLKGRD CLS_BFEAT_BLKGRD 2 CLS_SPGN_BLKGRD **** 1 1 12 16 14 8 14 12 CON 0X09 0X2 0 CLASS_TYPE_BLACKGUARD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BLKGRD 30 0 0 0 10 67 0 **** 1 0 0 0 0 0 0 WIS Blackguard 1 1 255 0 0 -32 Champion_Torm 112219 9015 9016 9017 9018 IR_DIVCHA 10 CLS_ATK_1 CLS_FEAT_DIVCHA CLS_SAVTHR_WILD CLS_SKILL_DIVCHA CLS_BFEAT_DIVCHA 2 **** **** 0 0 12 16 14 8 14 12 CHA 0X10 0X2 0 CLASS_TYPE_DIVINE_CHAMPION 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DIVCHA 30 0 0 0 10 109 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -33 WeaponMaster 112220 9019 9019 9021 9022 IR_WM 10 CLS_ATK_1 CLS_FEAT_WM CLS_SAVTHR_ROG CLS_SKILL_WM CLS_BFEAT_WM 2 **** **** 1 0 12 16 14 8 14 12 STR 0X00 0X0 0 CLASS_TYPE_WEAPON_MASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WM 30 0 0 0 10 112 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -34 Pale_Master 112221 9020 9023 9024 16834511 IR_PALEMA 6 CLS_ATK_3 CLS_FEAT_PALEMA CLS_SAVTHR_DRU CLS_SKILL_PALEMA CLS_BFEAT_PALEMA 2 **** **** 1 0 12 16 14 8 14 12 INT 0X08 0X2 0 CLASS_TYPE_PALE_MASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_PALEMA 30 0 2 0 10 110 0 cls_stat_palema **** **** **** **** **** **** **** **** **** **** **** **** **** **** -35 Shifter 112222 9026 9027 9028 9029 IR_SHIFTR 8 CLS_ATK_2 CLS_FEAT_SHIFTR CLS_SAVTHR_WILD CLS_SKILL_SHIFTR CLS_BFEAT_SHIFTR 4 **** **** 1 0 12 16 14 8 14 12 WIS 0X00 0X0 0 CLASS_TYPE_SHIFTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHIFTR 30 0 0 0 10 108 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -36 Dwarven_Defender 112223 76418 76419 76420 76422 IR_DWDEF 12 CLS_ATK_1 CLS_FEAT_DWDEF CLS_SAVTHR_CLER CLS_SKILL_DWDEF CLS_BFEAT_DWDEF 2 **** **** 1 0 16 8 15 14 10 12 STR 0X05 0X1 0 CLASS_TYPE_DWARVEN_DEFENDER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DWDEF 30 0 0 0 10 89 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -37 Dragon_Disciple 112224 16832127 16832128 16832129 16832130 IR_DRAGOND 6 CLS_ATK_2 CLS_FEAT_DRADIS CLS_SAVTHR_CLER CLS_SKILL_DRADIS CLS_BFEAT_DRADIS 2 **** **** 1 0 14 8 14 16 10 14 STR 0X00 0X0 0 CLASS_TYPE_DRAGON_DISCIPLE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DRADIS 30 0 0 0 10 111 0 cls_stat_dradis **** **** **** **** **** **** **** **** **** **** **** **** **** **** +29 Arcane_Archer 112216 9003 9004 9005 9006 IR_ARCHER 8 CLS_ATK_1 CLS_FEAT_ARCHER CLS_SAVTHR_WILD CLS_SKILL_ARCHER CLS_BFEAT_ARCHER 4 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_ARCANE_ARCHER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ARCHER 40 0 0 0 10 65 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +30 Assassin 112217 9007 9008 9009 16790386 IR_ASASIN 6 CLS_ATK_2 CLS_FEAT_ASASIN CLS_SAVTHR_ROG CLS_SKILL_ASASIN CLS_BFEAT_ASASIN 4 CLS_SPGN_ASASIN CLS_SPKN_ASASIN 1 1 12 16 14 8 14 12 DEX 0X09 0X2 0 CLASS_TYPE_ASSASSIN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ASASIN 40 0 0 0 10 66 131 **** 1 1 0 0 1 1 1 INT Assassin 1 1 255 0 0 +31 Blackguard 112218 9011 9012 9013 16790387 IR_BLKGRD 10 CLS_ATK_1 CLS_FEAT_BLKGRD CLS_SAVTHR_FIGHT CLS_SKILL_BLKGRD CLS_BFEAT_BLKGRD 2 CLS_SPGN_BLKGRD **** 1 1 12 16 14 8 14 12 CON 0X09 0X2 0 CLASS_TYPE_BLACKGUARD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BLKGRD 40 0 0 0 10 67 0 **** 1 0 0 0 0 0 0 WIS Blackguard 1 1 255 0 0 +32 Champion_Torm 112219 9015 9016 9017 9018 IR_DIVCHA 10 CLS_ATK_1 CLS_FEAT_DIVCHA CLS_SAVTHR_WILD CLS_SKILL_DIVCHA CLS_BFEAT_DIVCHA 2 **** **** 0 0 12 16 14 8 14 12 CHA 0X10 0X2 0 CLASS_TYPE_DIVINE_CHAMPION 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DIVCHA 40 0 0 0 10 109 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +33 WeaponMaster 112220 9019 9019 9021 9022 IR_WM 10 CLS_ATK_1 CLS_FEAT_WM CLS_SAVTHR_ROG CLS_SKILL_WM CLS_BFEAT_WM 2 **** **** 1 0 12 16 14 8 14 12 STR 0X00 0X0 0 CLASS_TYPE_WEAPON_MASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WM 40 0 0 0 10 112 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +34 Pale_Master 112221 9020 9023 9024 16834511 IR_PALEMA 6 CLS_ATK_3 CLS_FEAT_PALEMA CLS_SAVTHR_DRU CLS_SKILL_PALEMA CLS_BFEAT_PALEMA 2 **** **** 1 0 12 16 14 8 14 12 INT 0X08 0X2 0 CLASS_TYPE_PALE_MASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_PALEMA 40 0 2 0 10 110 0 cls_stat_palema **** **** **** **** **** **** **** **** **** **** **** **** **** **** +35 Shifter 112222 9026 9027 9028 9029 IR_SHIFTR 8 CLS_ATK_2 CLS_FEAT_SHIFTR CLS_SAVTHR_WILD CLS_SKILL_SHIFTR CLS_BFEAT_SHIFTR 4 **** **** 1 0 12 16 14 8 14 12 WIS 0X00 0X0 0 CLASS_TYPE_SHIFTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHIFTR 40 0 0 0 10 108 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +36 Dwarven_Defender 112223 76418 76419 76420 76422 IR_DWDEF 12 CLS_ATK_1 CLS_FEAT_DWDEF CLS_SAVTHR_CLER CLS_SKILL_DWDEF CLS_BFEAT_DWDEF 2 **** **** 1 0 16 8 15 14 10 12 STR 0X05 0X1 0 CLASS_TYPE_DWARVEN_DEFENDER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DWDEF 40 0 0 0 10 89 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +37 Dragon_Disciple 112224 16832127 16832128 16832129 16832130 IR_DRAGOND 6 CLS_ATK_2 CLS_FEAT_DRADIS CLS_SAVTHR_CLER CLS_SKILL_DRADIS CLS_BFEAT_DRADIS 2 **** **** 1 0 14 8 14 16 10 14 STR 0X00 0X0 0 CLASS_TYPE_DRAGON_DISCIPLE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DRADIS 40 0 0 0 10 111 0 cls_stat_dradis **** **** **** **** **** **** **** **** **** **** **** **** **** **** 38 Ooze 112225 84438 84438 84437 8154 IR_CLERIC 10 CLS_ATK_2 CLS_FEAT_CLER CLS_SAVTHR_CLER CLS_SKILL_CLER CLS_BFEAT_CLER 0 **** **** 0 0 14 8 14 16 10 14 STR 0X00 0X0 0 CLASS_TYPE_OOZE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_OOZE 0 0 0 0 -1 75 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -39 Eye_of_Gruumsh 16790665 16824294 16824295 16824296 16824297 IR_GRUUMSH 12 CLS_ATK_1 CLS_FEAT_EOG CLS_SAVTHR_BARB CLS_SKILL_EOG CLS_BFEAT_EOG 2 **** **** 1 0 16 14 14 14 10 8 STR 0X0A 0X3 0 CLASS_TYPE_PRC_EYE_OF_GRUUMSH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_EOG 0 0 0 0 10 17 0 cls_stat_eog **** **** **** **** **** **** **** **** **** **** **** **** **** **** +39 Eye_of_Gruumsh 16790665 16824294 16824295 16824296 16824297 IR_GRUUMSH 12 CLS_ATK_1 CLS_FEAT_EOG CLS_SAVTHR_BARB CLS_SKILL_EOG CLS_BFEAT_EOG 2 **** **** 1 0 16 14 14 14 10 8 STR 0X0A 0X3 0 CLASS_TYPE_PRC_EYE_OF_GRUUMSH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_EOG 40 0 0 0 10 17 0 cls_stat_eog **** **** **** **** **** **** **** **** **** **** **** **** **** **** 40 Shou_Disciple 16790649 16823346 16823347 16823348 16823349 IR_SHOUDISC 10 CLS_ATK_1 CLS_FEAT_SHOU CLS_SAVTHR_WILD CLS_SKILL_SHOU CLS_BFEAT_SHOU 2 **** **** 0 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_SHOU 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHOU 5 0 0 0 5 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 41 Purple_Dragon_Knight 112226 111710 111711 111712 111713 IR_PDK 10 CLS_ATK_1 CLS_FEAT_PDK CLS_SAVTHR_FIGHT CLS_SKILL_PDK CLS_BFEAT_PDK 2 **** **** 0 0 12 16 14 8 14 12 STR 0X14 0X3 0 CLASS_TYPE_PDK 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_PDK 5 0 0 0 5 131 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -42 UrPriest 16790529 16835606 16835607 16835608 16835609 IR_WARLOCK 8 CLS_ATK_2 CLS_FEAT_URPRST CLS_SAVTHR_WIZ CLS_SKILL_URPRST CLS_BFEAT_BLANK 2 CLS_SPGN_BLIGHT **** 1 1 15 9 14 13 10 15 WIS 0X09 0X2 0 CLASS_TYPE_UR_PRIEST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_URPRST 10 0 0 0 10 10 0 **** 1 0 0 0 0 0 0 WIS Cleric 1 1 255 0 0 +42 UrPriest 16790529 16835606 16835607 16835608 16835609 IR_WARLOCK 8 CLS_ATK_2 CLS_FEAT_URPRST CLS_SAVTHR_WIZ CLS_SKILL_URPRST CLS_BFEAT_URPRST 2 CLS_SPGN_BLIGHT **** 1 1 15 9 14 13 10 15 WIS 0X09 0X2 0 CLASS_TYPE_UR_PRIEST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_URPRST 40 0 0 0 10 10 0 **** 1 0 0 0 0 0 0 WIS Cleric 1 1 255 0 0 43 Binder 16790530 16835216 16835217 16835218 16835219 IR_HFWRLK 8 CLS_ATK_2 CLS_FEAT_BINDER CLS_SAVTHR_CLER CLS_SKILL_BINDER CLS_BFEAT_BINDER 2 **** **** 1 0 15 12 14 10 15 10 STR 0X00 0X0 0 CLASS_TYPE_BINDER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BINDER 20 1 0 0 -1 5 131 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -44 AnimaMage 16790531 16835425 16835426 16835427 16835428 IR_MAESTER 4 CLS_ATK_3 CLS_FEAT_ANIMA CLS_SAVTHR_WIZ CLS_SKILL_ANIMA CLS_BFEAT_ANIMA 2 **** **** 1 0 12 14 14 10 12 15 CHA 0X08 0X2 **** CLASS_TYPE_ANIMA_MAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ANIMA 10 0 1 0 10 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +44 AnimaMage 16790531 16835425 16835426 16835427 16835428 IR_MAESTER 4 CLS_ATK_3 CLS_FEAT_ANIMA CLS_SAVTHR_WIZ CLS_SKILL_ANIMA CLS_BFEAT_ANIMA 2 **** **** 1 0 12 14 14 10 12 15 CHA 0X08 0X2 **** CLASS_TYPE_ANIMA_MAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ANIMA 40 0 1 0 10 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 45 KnightOfTheSacredSeal 16790532 16835453 16835454 16835455 16835456 IR_BLKGRD 10 CLS_ATK_1 CLS_FEAT_KSS CLS_SAVTHR_FIGHT CLS_SKILL_KSS CLS_BFEAT_KSS 2 **** **** 1 0 12 14 14 10 12 15 CHA 0X04 0X1 0 CLASS_TYPE_KNIGHT_SACRED_SEAL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_KSS 5 0 0 0 5 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 46 ScionOfDantalion 16790533 16835519 16835520 16835521 16835522 IR_CEREBRE 8 CLS_ATK_2 CLS_FEAT_SCION CLS_SAVTHR_CLER CLS_SKILL_SCION CLS_BFEAT_BLANK 2 **** **** 1 0 12 16 14 8 14 12 WIS 0X00 0X0 0 CLASS_TYPE_SCION_DANTALION 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SCION 5 0 0 0 5 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 47 TenebrousApostate 16790534 16835441 16835442 16835443 16835444 IR_SHADADEPT 8 CLS_ATK_2 CLS_FEAT_TENEB CLS_SAVTHR_CLER CLS_SKILL_TENEB CLS_BFEAT_TENEB 2 **** **** 1 0 12 16 14 8 14 12 WIS 0X08 0X2 0 CLASS_TYPE_TENEBROUS_APOSTATE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_TENEB 5 0 0 1 5 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 48 ReapingMauler 16790535 16834902 16834903 16834904 16834905 IR_MONK 10 CLS_ATK_1 CLS_FEAT_RPMLR CLS_SAVTHR_RANG CLS_SKILL_RPMLR CLS_BFEAT_RPMLR 2 **** **** 1 0 16 15 14 10 10 10 STR 0X00 0X0 0 CLASS_TYPE_REAPING_MAULER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_RPMLR 5 0 0 0 5 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -49 SereneGuardian 16790536 16834537 16834538 16834539 16834540 IR_REDAVNG 8 CLS_ATK_1 CLS_FEAT_SERGRD CLS_SAVTHR_RANG CLS_SKILL_SERGRD CLS_BFEAT_SERGRD 2 **** **** 1 0 15 9 14 13 10 15 WIS 0X02 0X1 1 CLASS_TYPE_SERENE_GUARDIAN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SERGRD 10 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +49 SereneGuardian 16790536 16834537 16834538 16834539 16834540 IR_REDAVNG 8 CLS_ATK_1 CLS_FEAT_SERGRD CLS_SAVTHR_RANG CLS_SKILL_SERGRD CLS_BFEAT_SERGRD 2 **** **** 1 0 15 9 14 13 10 15 WIS 0X02 0X1 1 CLASS_TYPE_SERENE_GUARDIAN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SERGRD 40 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 50 SacredPurifer 16790537 16834528 16834529 16834530 16834531 IR_MAA 8 CLS_ATK_2 CLS_FEAT_SACPUR CLS_SAVTHR_CLER CLS_SKILL_SACPUR CLS_BFEAT_SACPUR 2 **** **** 1 0 12 16 14 8 14 12 WIS 0X08 0X2 1 CLASS_TYPE_SACPUR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SACPUR 5 0 0 1 5 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -51 Ocular_Adept 16790538 16789504 16789505 16789506 16789507 IR_OCULAR 6 CLS_ATK_2 CLS_FEAT_OCU CLS_SAVTHR_CLER CLS_SKILL_OCULAR CLS_BFEAT_OCU 2 CLS_SPGN_OCU **** 1 1 14 8 14 16 10 14 WIS 0X09 0X2 0 CLASS_TYPE_OCULAR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_OCULAR 30 0 0 0 10 2 0 **** 1 0 1 0 0 0 0 WIS Cleric 1 1 255 0 0 +51 Ocular_Adept 16790538 16789504 16789505 16789506 16789507 IR_OCULAR 6 CLS_ATK_2 CLS_FEAT_OCU CLS_SAVTHR_CLER CLS_SKILL_OCULAR CLS_BFEAT_OCU 2 CLS_SPGN_OCU **** 1 1 14 8 14 16 10 14 WIS 0X09 0X2 0 CLASS_TYPE_OCULAR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_OCULAR 40 0 0 0 10 2 0 **** 1 0 1 0 0 0 0 WIS Cleric 1 1 255 0 0 52 Battlerager 16790539 16789530 16789531 16789532 16789533 IR_BTLRAGE 12 CLS_ATK_1 CLS_FEAT_BRAGE CLS_SAVTHR_FIGHT CLS_SKILL_BRAGE CLS_BFEAT_BRAGE 2 **** **** 1 0 16 15 14 10 10 10 STR 0X02 0X1 0 CLASS_TYPE_BATTLERAGER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BRAGE 5 0 0 0 5 0 0 cls_stat_brage **** **** **** **** **** **** **** **** **** **** **** **** **** **** -53 Mystic_Theurge 16790540 16789584 16789585 16789586 16789587 IR_MYSTIC 4 CLS_ATK_3 CLS_FEAT_MYSTIC CLS_SAVTHR_WIZ CLS_SKILL_MYSTIC CLS_BFEAT_MYSTIC 2 **** **** 1 0 10 11 11 16 16 10 INT 0X00 0X0 0 CLASS_TYPE_MYSTIC_THEURGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MYSTIC 30 0 1 1 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -54 Ninja_Spy 16790541 16789568 16789569 16789570 16789571 IR_ASASIN 8 CLS_ATK_2 CLS_FEAT_NINJA CLS_SAVTHR_MONK CLS_SKILL_NINJA CLS_BFEAT_ASASIN 6 **** **** 0 0 12 16 14 8 14 12 DEX 0X0C 0X3 0 CLASS_TYPE_NINJA_SPY 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_NINJA 30 0 0 0 10 8 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +53 Mystic_Theurge 16790540 16789584 16789585 16789586 16789587 IR_MYSTIC 4 CLS_ATK_3 CLS_FEAT_MYSTIC CLS_SAVTHR_WIZ CLS_SKILL_MYSTIC CLS_BFEAT_MYSTIC 2 **** **** 1 0 10 11 11 16 16 10 INT 0X00 0X0 0 CLASS_TYPE_MYSTIC_THEURGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MYSTIC 40 0 1 1 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +54 Ninja_Spy 16790541 16789568 16789569 16789570 16789571 IR_ASASIN 8 CLS_ATK_2 CLS_FEAT_NINJA CLS_SAVTHR_MONK CLS_SKILL_NINJA CLS_BFEAT_ASASIN 6 **** **** 0 0 12 16 14 8 14 12 DEX 0X0C 0X3 0 CLASS_TYPE_NINJA_SPY 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_NINJA 40 0 0 0 10 8 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 55 Samurai 16790542 16789537 16789538 16789539 16789540 IR_SAMURAI 10 CLS_ATK_1 CLS_FEAT_SAMUR CLS_SAVTHR_CLER CLS_SKILL_SAMUR CLS_BFEAT_SAMUR 4 **** **** 0 0 16 13 16 10 10 9 STR 0X05 0X1 0 CLASS_TYPE_SAMURAI 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SAMUR 0 1 0 0 -1 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -56 Warpriest 16790543 16789541 16789542 16789543 16789544 IR_CLERIC 8 CLS_ATK_1 CLS_FEAT_WARPR CLS_SAVTHR_CLER CLS_SKILL_WARPR CLS_BFEAT_WARPR 2 **** **** 1 0 10 14 14 12 16 10 WIS 0X00 0X0 0 CLASS_TYPE_WARPRIEST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WARPR 30 0 0 2 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -57 Spellfire_Channeler 16790544 16824664 16824665 16824666 16824667 IR_SPELLFIRE 4 CLS_ATK_3 CLS_FEAT_SPELLF CLS_SAVTHR_CLER CLS_SKILL_SPELLF CLS_BFEAT_SPELLF 2 **** **** 0 0 16 13 16 10 10 9 CON 0X00 0X0 0 CLASS_TYPE_SPELLFIRE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SPELLF 10 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -58 Virtuoso 16790545 16828436 16828437 16828438 16828439 IR_BARD 6 CLS_ATK_3 CLS_FEAT_VIRT CLS_SAVTHR_WIZ CLS_SKILL_VIRT CLS_BFEAT_VIRT 4 **** **** 1 0 12 14 14 10 12 15 CHA 0X00 0X0 0 CLASS_TYPE_VIRTUOSO 1 2 3 4 5 6 7 8 9 10 11 12 12 14 15 16 17 18 19 20 CLS_PRES_VIRT 10 0 1 0 10 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +56 Warpriest 16790543 16789541 16789542 16789543 16789544 IR_CLERIC 8 CLS_ATK_1 CLS_FEAT_WARPR CLS_SAVTHR_CLER CLS_SKILL_WARPR CLS_BFEAT_WARPR 2 **** **** 1 0 10 14 14 12 16 10 WIS 0X00 0X0 0 CLASS_TYPE_WARPRIEST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WARPR 40 0 0 2 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +57 Spellfire_Channeler 16790544 16824664 16824665 16824666 16824667 IR_SPELLFIRE 4 CLS_ATK_3 CLS_FEAT_SPELLF CLS_SAVTHR_CLER CLS_SKILL_SPELLF CLS_BFEAT_SPELLF 2 **** **** 0 0 16 13 16 10 10 9 CON 0X00 0X0 0 CLASS_TYPE_SPELLFIRE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SPELLF 40 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +58 Virtuoso 16790545 16828436 16828437 16828438 16828439 IR_BARD 6 CLS_ATK_3 CLS_FEAT_VIRT CLS_SAVTHR_WIZ CLS_SKILL_VIRT CLS_BFEAT_VIRT 4 **** **** 1 0 12 14 14 10 12 15 CHA 0X00 0X0 0 CLASS_TYPE_VIRTUOSO 1 2 3 4 5 6 7 8 9 10 11 12 12 14 15 16 17 18 19 20 CLS_PRES_VIRT 40 0 1 0 10 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 59 Marshal 16790546 16828255 16828256 16828257 16828258 IR_MARSH 8 CLS_ATK_2 CLS_FEAT_MARSH CLS_SAVTHR_DRU CLS_SKILL_MARSH CLS_BFEAT_MARSH 4 **** **** 1 0 14 12 12 8 14 16 CHA 0X00 0X0 0 CLASS_TYPE_MARSHAL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MARSH 0 1 0 0 -1 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 60 Swashbuckler 16790547 16828217 16828218 16828219 16828220 IR_SWASH 10 CLS_ATK_1 CLS_FEAT_SWASH CLS_SAVTHR_FIGHT CLS_SKILL_SWASH CLS_BFEAT_SWASH 4 **** **** 1 0 12 14 12 8 16 14 DEX 0X00 0X0 0 CLASS_TYPE_SWASHBUCKLER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SWASH 0 1 0 0 -1 8 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 61 Hexblade 16790548 16823462 16823463 16823464 16823465 IR_ELDKNI 10 CLS_ATK_1 CLS_FEAT_HEXBL CLS_SAVTHR_CLER CLS_SKILL_HEXBL CLS_BFEAT_HEXBL 2 CLS_SPGN_HEXBL CLS_SPKN_HEXBL 1 1 14 14 14 10 12 14 CHA 0X08 0X2 0 CLASS_TYPE_HEXBLADE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HEXBL 0 1 0 0 -1 5 131 **** **** **** **** **** **** **** **** **** Hexblade **** **** **** **** **** 62 Duskblade 16790549 16824168 16824169 16824170 16824171 IR_HAVOCMAGE 8 CLS_ATK_1 CLS_FEAT_DUSKBL CLS_SAVTHR_CLER CLS_SKILL_DUSKBL CLS_BFEAT_DUSKBL 2 CLS_SPGN_DUSKBL CLS_SPKN_DUSKBL 1 1 15 12 14 10 15 10 STR 0X00 0X0 0 CLASS_TYPE_DUSKBLADE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DUSKBL 0 1 0 0 -1 5 131 **** **** **** **** **** **** **** **** **** Duskblade **** **** **** **** **** 63 Scout 16790550 16822486 16822513 16822514 16822515 IR_ARCHER 8 CLS_ATK_2 CLS_FEAT_SCOUT CLS_SAVTHR_ROG CLS_SKILL_SCOUT CLS_BFEAT_SCOUT 8 **** **** 1 0 12 16 12 14 12 10 DEX 0X00 0X0 0 CLASS_TYPE_SCOUT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SCOUT 0 1 0 0 -1 7 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 64 Healer 16790551 16822656 16822657 16822658 16822659 IR_CBTMEDIC 8 CLS_ATK_3 CLS_FEAT_HEALER CLS_SAVTHR_CLER CLS_SKILL_HEALER CLS_BFEAT_HEALER 4 CLS_SPGN_HEALER **** 1 1 10 12 12 15 10 16 WIS 0X11 0X2 0 CLASS_TYPE_HEALER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HEALER 0 1 0 0 -1 2 0 **** 1 0 0 0 0 0 0 WIS Healer 1 1 255 0 0 -65 Mage_Killer 16790552 16822219 16822220 16822221 16822222 IR_MAGEKILL 4 CLS_ATK_3 CLS_FEAT_MAGEK CLS_SAVTHR_WIZ CLS_SKILL_MAGEK CLS_BFEAT_MAGEK 2 **** **** 1 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_MAGEKILLER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MAGEK 30 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +65 Mage_Killer 16790552 16822219 16822220 16822221 16822222 IR_MAGEKILL 4 CLS_ATK_3 CLS_FEAT_MAGEK CLS_SAVTHR_WIZ CLS_SKILL_MAGEK CLS_BFEAT_MAGEK 2 **** **** 1 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_MAGEKILLER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MAGEK 40 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 66 Harper_Mage 16790553 16822223 16822224 16822225 16822226 IEF_HARPWIZ 4 CLS_ATK_3 CLS_FEAT_HMAGE CLS_SAVTHR_WIZ CLS_SKILL_HMAGE CLS_BFEAT_HMAGE 4 **** **** 0 0 12 16 14 8 14 12 INT 0X10 0X2 0 CLASS_TYPE_HARPERMAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HMAGE 5 0 1 0 5 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -67 Spell_Sword 16790554 16822227 16822228 16822229 16822230 IR_SPELLS 8 CLS_ATK_1 CLS_FEAT_SPELLS CLS_SAVTHR_CLER CLS_SKILL_SPELLS CLS_BFEAT_SPELLS 2 **** **** 1 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_SPELLSWORD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SPELLS 30 0 2 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -68 Acolyte_Skin 16790555 16822237 16822238 16822239 16822240 IR_ACOLYTE 4 CLS_ATK_3 CLS_FEAT_AOTS CLS_SAVTHR_CLER CLS_SKILL_AOTS CLS_BFEAT_AOTS 2 **** **** 1 0 12 16 14 8 14 12 INT 0X08 0X2 0 CLASS_TYPE_ACOLYTE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_AOTS 30 0 2 0 10 10 0 cls_stat_aots **** **** **** **** **** **** **** **** **** **** **** **** **** **** -69 UnseenSeer 16790556 16822302 16822303 16822304 16822305 IR_BEGUIL 4 CLS_ATK_2 CLS_FEAT_UNSEER CLS_SAVTHR_WIZ CLS_SKILL_UNSEER CLS_BFEAT_UNSEER 6 **** **** 1 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_UNSEER_SEER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_UNSEER 30 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -70 Eldritch_Knight 16790557 16822308 16822309 16822310 16822311 IR_ELDKNI 6 CLS_ATK_1 CLS_FEAT_ELDKNI CLS_SAVTHR_FIGHT CLS_SKILL_ELDKNI CLS_BFEAT_ELDKNI 2 **** **** 1 0 14 13 14 10 14 13 INT 0X00 0X0 0 CLASS_TYPE_ELDRITCH_KNIGHT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ELDKNI 30 0 1 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -71 Elemental_Savant 16790558 16822312 16822313 16822314 16822315 IR_ELEMFIRE 4 CLS_ATK_3 CLS_FEAT_SAVANT CLS_SAVTHR_WIZ CLS_SKILL_SAVANT CLS_BFEAT_SAVANT 2 **** **** 1 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_ELEMENTAL_SAVANT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SAVANT 30 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +67 Spell_Sword 16790554 16822227 16822228 16822229 16822230 IR_SPELLS 8 CLS_ATK_1 CLS_FEAT_SPELLS CLS_SAVTHR_CLER CLS_SKILL_SPELLS CLS_BFEAT_SPELLS 2 **** **** 1 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_SPELLSWORD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SPELLS 40 0 2 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +68 Acolyte_Skin 16790555 16822237 16822238 16822239 16822240 IR_ACOLYTE 4 CLS_ATK_3 CLS_FEAT_AOTS CLS_SAVTHR_CLER CLS_SKILL_AOTS CLS_BFEAT_AOTS 2 **** **** 1 0 12 16 14 8 14 12 INT 0X08 0X2 0 CLASS_TYPE_ACOLYTE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_AOTS 40 0 2 0 10 10 0 cls_stat_aots **** **** **** **** **** **** **** **** **** **** **** **** **** **** +69 UnseenSeer 16790556 16822302 16822303 16822304 16822305 IR_BEGUIL 4 CLS_ATK_2 CLS_FEAT_UNSEER CLS_SAVTHR_WIZ CLS_SKILL_UNSEER CLS_BFEAT_UNSEER 6 **** **** 1 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_UNSEER_SEER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_UNSEER 40 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +70 Eldritch_Knight 16790557 16822308 16822309 16822310 16822311 IR_ELDKNI 6 CLS_ATK_1 CLS_FEAT_ELDKNI CLS_SAVTHR_FIGHT CLS_SKILL_ELDKNI CLS_BFEAT_ELDKNI 2 **** **** 1 0 14 13 14 10 14 13 INT 0X00 0X0 0 CLASS_TYPE_ELDRITCH_KNIGHT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ELDKNI 40 0 1 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +71 Elemental_Savant 16790558 16822312 16822313 16822314 16822315 IR_ELEMFIRE 4 CLS_ATK_3 CLS_FEAT_SAVANT CLS_SAVTHR_WIZ CLS_SKILL_SAVANT CLS_BFEAT_SAVANT 2 **** **** 1 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_ELEMENTAL_SAVANT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SAVANT 40 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 72 Factotum 16790559 16823092 16823093 16823094 16823095 IR_BEGUIL 8 CLS_ATK_2 CLS_FEAT_FACTUM CLS_SAVTHR_ROG CLS_SKILL_FACTUM CLS_BFEAT_FACTUM 6 **** **** 1 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_FACTOTUM 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FACTUM 20 1 0 0 -1 8 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -73 CelebrantSharess 16790560 16826321 16826322 16826323 16826324 IR_HEARTW 6 CLS_ATK_3 CLS_FEAT_SHARSS CLS_SAVTHR_WIZ CLS_SKILL_SHARSS CLS_BFEAT_SHARSS 6 CLS_SPGN_SHARSS CLS_SPKN_SHARSS 0 1 12 16 14 8 14 12 CHA 0X13 0X3 0 CLASS_TYPE_CELEBRANT_SHARESS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHARSS 10 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** Celebrant **** **** **** **** **** +73 CelebrantSharess 16790560 16826321 16826322 16826323 16826324 IR_HEARTW 6 CLS_ATK_3 CLS_FEAT_SHARSS CLS_SAVTHR_WIZ CLS_SKILL_SHARSS CLS_BFEAT_SHARSS 6 CLS_SPGN_SHARSS CLS_SPKN_SHARSS 0 1 12 16 14 8 14 12 CHA 0X13 0X3 0 CLASS_TYPE_CELEBRANT_SHARESS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHARSS 40 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** Celebrant **** **** **** **** **** 74 CultistShatteredPeak 16790561 16789654 16789655 16789656 16789657 IR_SPARCDLST 6 CLS_ATK_2 CLS_FEAT_CULTST CLS_SAVTHR_RANG CLS_SKILL_CULTST CLS_BFEAT_CULTST 6 CLS_SPGN_CULTST **** 0 1 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_CULTIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_CULTST 5 0 0 0 5 64 130 **** 1 1 0 0 1 1 1 INT Cultist 1 1 255 0 0 -75 Forsaker 16790562 16847610 16847611 16847612 16847613 IC_LEGDREAD 12 CLS_ATK_1 CLS_FEAT_FORSAK CLS_SAVTHR_CLER CLS_SKILL_FORSAK CLS_BFEAT_FORSAK 2 **** **** 1 0 16 13 16 10 10 9 STR 0X00 0X0 0 CLASS_TYPE_FORSAKER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FORSAK 30 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +75 Forsaker 16790562 16847610 16847611 16847612 16847613 IC_LEGDREAD 12 CLS_ATK_1 CLS_FEAT_FORSAK CLS_SAVTHR_CLER CLS_SKILL_FORSAK CLS_BFEAT_FORSAK 2 **** **** 1 0 16 13 16 10 10 9 STR 0X00 0X0 0 CLASS_TYPE_FORSAKER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FORSAK 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 76 Incarnate 16790563 16836706 16836707 16836708 16836709 IR_PSION 6 CLS_ATK_3 CLS_FEAT_INCARN CLS_SAVTHR_CLER CLS_SKILL_INCARN CLS_BFEAT_INCARN 2 **** **** 1 0 10 14 14 12 16 10 INT 0X01 0X3 1 CLASS_TYPE_INCARNATE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_INCARN 0 1 0 0 -1 8 130 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 77 Soulborn 16790564 16836718 16836719 16836720 16836721 IR_SOULKNIFE 10 CLS_ATK_1 CLS_FEAT_SOULBN CLS_SAVTHR_FIGHT CLS_SKILL_SOULBN CLS_BFEAT_SOULBN 2 **** **** 1 0 16 13 16 10 10 9 STR 0X01 0X3 0 CLASS_TYPE_SOULBORN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SOULBN 0 1 0 0 -1 8 130 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 78 Totemist 16790565 16836722 16836723 16836724 16836725 IR_PSYWARRIOR 8 CLS_ATK_2 CLS_FEAT_TOTEM CLS_SAVTHR_RANG CLS_SKILL_TOTEM CLS_BFEAT_TOTEM 4 **** **** 1 0 16 13 16 10 10 9 STR 0X00 0X0 0 CLASS_TYPE_TOTEMIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_TOTEM 0 1 0 0 -1 8 130 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 79 Beguiler 16790566 16789870 16789871 16789872 16789873 IR_BEGUIL 6 CLS_ATK_3 CLS_FEAT_BEGUIL CLS_SAVTHR_WIZ CLS_SKILL_BEGUIL CLS_BFEAT_BEGUIL 6 CLS_SPGN_BEGUIL CLS_SPKN_BEGUIL 1 1 10 14 14 12 16 10 INT 0X00 0X0 0 CLASS_TYPE_BEGUILER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BEGUIL 20 1 0 0 -1 8 130 **** **** **** **** **** **** **** **** **** Beguiler **** **** **** **** **** -80 Duelist 16790567 16822716 16822717 16822718 16822719 IR_DUEL 10 CLS_ATK_1 CLS_FEAT_DUEL CLS_SAVTHR_ROG CLS_SKILL_DUEL CLS_BFEAT_DUEL 4 **** **** 1 0 14 16 14 8 14 10 DEX 0X00 0X0 0 CLASS_TYPE_DUELIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DUEL 30 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +80 Duelist 16790567 16822716 16822717 16822718 16822719 IR_DUEL 10 CLS_ATK_1 CLS_FEAT_DUEL CLS_SAVTHR_ROG CLS_SKILL_DUEL CLS_BFEAT_DUEL 4 **** **** 1 0 14 16 14 8 14 10 DEX 0X00 0X0 0 CLASS_TYPE_DUELIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DUEL 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 81 Hierophant 16790568 16822744 16822745 16822746 16822747 IR_HIERO 8 CLS_ATK_2 CLS_FEAT_HIERO CLS_SAVTHR_CLER CLS_SKILL_HIERO CLS_BFEAT_HIERO 2 **** **** 1 0 14 8 14 16 10 14 WIS 0X00 0X0 0 CLASS_TYPE_HIEROPHANT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HIERO 5 0 0 0 5 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -82 RedAvenger 16790569 16822765 16822766 16822767 16822768 IR_REDAVNG 8 CLS_ATK_2 CLS_FEAT_REDAV CLS_SAVTHR_MONK CLS_SKILL_REDAV CLS_BFEAT_REDAV 4 **** **** 1 0 14 14 14 15 10 10 DEX 0X00 0X0 0 CLASS_TYPE_RED_AVENGER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_REDAV 30 0 0 0 10 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -83 KnightOfTheChalice 16790570 16822787 16822788 16822789 16822790 IR_CHALICE 12 CLS_ATK_1 CLS_FEAT_KCHAL CLS_SAVTHR_FIGHT CLS_SKILL_KCHAL CLS_BFEAT_KCHAL 2 CLS_SPGN_KCHAL **** 1 1 15 9 14 13 10 15 WIS 0X15 0X3 0 CLASS_TYPE_KNIGHT_CHALICE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_KCHAL 10 0 0 0 10 6 0 **** 1 0 0 0 0 0 0 WIS Chalice 1 1 255 0 0 -84 Hathran 16790571 16825132 16825133 16825134 16825135 IR_CLERIC 4 CLS_ATK_3 CLS_FEAT_HATH CLS_SAVTHR_CLER CLS_SKILL_HATH CLS_BFEAT_HATH 2 **** **** 0 0 8 14 12 16 14 12 WIS 0X14 0X3 0 CLASS_TYPE_HATHRAN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HATH 30 0 2 2 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -85 IronsoulForgemaster 16790572 16837815 16837816 16837817 16837818 IR_DWDEF 8 CLS_ATK_2 CLS_FEAT_IRNFRG CLS_SAVTHR_CLER CLS_SKILL_IRNFRG CLS_BFEAT_IRNFRG 4 **** **** 1 0 16 12 12 14 12 10 STR 0X10 0X2 0 CLASS_TYPE_IRONSOUL_FORGEMASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_IRNFRG 10 0 0 0 10 7 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -86 Stormlord 16790573 16823307 16823308 16823309 16823310 IR_STORMLORD 8 CLS_ATK_2 CLS_FEAT_STORML CLS_SAVTHR_CLER CLS_SKILL_STORML CLS_BFEAT_STORML 2 **** **** 0 0 12 16 14 8 14 12 WIS 0X0A 0X3 0 CLASS_TYPE_STORMLORD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_STORML 30 0 0 1 10 108 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -87 HeartWarder 16790574 16822916 16822917 16822918 16822919 IR_HEARTW 4 CLS_ATK_2 CLS_FEAT_HEARTW CLS_SAVTHR_CLER CLS_SKILL_HEARTW CLS_BFEAT_HEARTW 2 **** **** 0 0 12 16 14 8 14 12 WIS 0X13 0X3 0 CLASS_TYPE_HEARTWARDER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HEARTW 30 0 0 1 10 108 0 cls_stat_heartw **** **** **** **** **** **** **** **** **** **** **** **** **** **** -88 FistRaziel 16790575 16823311 16823312 16823313 16823314 IR_PALADIN 10 CLS_ATK_1 CLS_FEAT_FISTRA CLS_SAVTHR_PAL CLS_SKILL_FISTRA CLS_BFEAT_FISTRA 2 **** **** 1 0 16 10 14 12 10 14 CHA 0X15 0X3 0 CLASS_TYPE_FISTRAZIEL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FISTRA 30 0 0 1 10 6 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -89 VassalOfBahamut 16790576 16823216 16823217 16823218 16823219 IR_VASSAL 10 CLS_ATK_1 CLS_FEAT_VASSAL CLS_SAVTHR_PAL CLS_SKILL_VASSAL CLS_BFEAT_VASSAL 2 CLS_SPGN_VASSAL **** 1 1 15 9 14 13 10 15 WIS 0X15 0X3 0 CLASS_TYPE_VASSAL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_VASSAL 10 0 0 0 10 6 0 **** 1 0 0 0 0 0 0 WIS Bahamut 1 1 255 0 0 +82 RedAvenger 16790569 16822765 16822766 16822767 16822768 IR_REDAVNG 8 CLS_ATK_2 CLS_FEAT_REDAV CLS_SAVTHR_MONK CLS_SKILL_REDAV CLS_BFEAT_REDAV 4 **** **** 1 0 14 14 14 15 10 10 DEX 0X00 0X0 0 CLASS_TYPE_RED_AVENGER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_REDAV 40 0 0 0 10 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +83 KnightOfTheChalice 16790570 16822787 16822788 16822789 16822790 IR_CHALICE 12 CLS_ATK_1 CLS_FEAT_KCHAL CLS_SAVTHR_FIGHT CLS_SKILL_KCHAL CLS_BFEAT_KCHAL 2 CLS_SPGN_KCHAL **** 1 1 15 9 14 13 10 15 WIS 0X15 0X3 0 CLASS_TYPE_KNIGHT_CHALICE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_KCHAL 40 0 0 0 10 6 0 **** 1 0 0 0 0 0 0 WIS Chalice 1 1 255 0 0 +84 Hathran 16790571 16825132 16825133 16825134 16825135 IR_CLERIC 4 CLS_ATK_3 CLS_FEAT_HATH CLS_SAVTHR_CLER CLS_SKILL_HATH CLS_BFEAT_HATH 2 **** **** 0 0 8 14 12 16 14 12 WIS 0X14 0X3 0 CLASS_TYPE_HATHRAN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HATH 40 0 2 2 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +85 IronsoulForgemaster 16790572 16837815 16837816 16837817 16837818 IR_DWDEF 8 CLS_ATK_2 CLS_FEAT_IRNFRG CLS_SAVTHR_CLER CLS_SKILL_IRNFRG CLS_BFEAT_IRNFRG 4 **** **** 1 0 16 12 12 14 12 10 STR 0X10 0X2 0 CLASS_TYPE_IRONSOUL_FORGEMASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_IRNFRG 40 0 0 0 10 7 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +86 Stormlord 16790573 16823307 16823308 16823309 16823310 IR_STORMLORD 8 CLS_ATK_2 CLS_FEAT_STORML CLS_SAVTHR_CLER CLS_SKILL_STORML CLS_BFEAT_STORML 2 **** **** 0 0 12 16 14 8 14 12 WIS 0X0A 0X3 0 CLASS_TYPE_STORMLORD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_STORML 40 0 0 1 10 108 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +87 HeartWarder 16790574 16822916 16822917 16822918 16822919 IR_HEARTW 4 CLS_ATK_2 CLS_FEAT_HEARTW CLS_SAVTHR_CLER CLS_SKILL_HEARTW CLS_BFEAT_HEARTW 2 **** **** 0 0 12 16 14 8 14 12 WIS 0X13 0X3 0 CLASS_TYPE_HEARTWARDER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HEARTW 40 0 0 1 10 108 0 cls_stat_heartw **** **** **** **** **** **** **** **** **** **** **** **** **** **** +88 FistRaziel 16790575 16823311 16823312 16823313 16823314 IR_PALADIN 10 CLS_ATK_1 CLS_FEAT_FISTRA CLS_SAVTHR_PAL CLS_SKILL_FISTRA CLS_BFEAT_FISTRA 2 **** **** 1 0 16 10 14 12 10 14 CHA 0X15 0X3 0 CLASS_TYPE_FISTRAZIEL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FISTRA 40 0 0 1 10 6 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +89 VassalOfBahamut 16790576 16823216 16823217 16823218 16823219 IR_VASSAL 10 CLS_ATK_1 CLS_FEAT_VASSAL CLS_SAVTHR_PAL CLS_SKILL_VASSAL CLS_BFEAT_VASSAL 2 CLS_SPGN_VASSAL **** 1 1 15 9 14 13 10 15 WIS 0X15 0X3 0 CLASS_TYPE_VASSAL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_VASSAL 40 0 0 0 10 6 0 **** 1 0 0 0 0 0 0 WIS Bahamut 1 1 255 0 0 90 Lich 16790577 16823128 16823128 16823129 16823127 IR_PALEMA 4 CLS_ATK_4 CLS_FEAT_LICH CLS_SAVTHR_LICH CLS_SKILL_WIZ CLS_BFEAT_LICH 0 **** **** 1 0 13 13 13 13 13 13 INT 0X08 0X2 0 CLASS_TYPE_LICH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_LICH 10 0 0 0 4 10 0 cls_stat_lich **** **** **** **** **** **** **** **** **** **** **** **** **** **** -91 PnPShifter 16790578 16824335 9027 9028 16824370 IR_SHIFTR 8 CLS_ATK_2 CLS_FEAT_PNPSFR CLS_SAVTHR_WILD CLS_SKILL_SHIFTR CLS_BFEAT_SHIFTR 4 **** **** 1 0 12 16 14 8 14 12 WIS 0X00 0X0 0 CLASS_TYPE_PNP_SHIFTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_PNPSFR 30 0 0 0 10 108 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -92 ChampionCorellon 16790579 16828364 16828365 16828387 16828388 IR_COC 10 CLS_ATK_1 CLS_FEAT_COC CLS_SAVTHR_CLER CLS_SKILL_COC CLS_BFEAT_COC 2 **** **** 1 0 14 16 14 10 10 12 DEX 0X10 0X2 0 CLASS_TYPE_COC 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_COC 10 0 0 0 10 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -93 SublimeChord 16790580 16829452 16829453 16829454 16829455 IR_X1_HARPER 6 CLS_ATK_3 CLS_FEAT_SCHORD CLS_SAVTHR_WIZ CLS_SKILL_SCHORD CLS_BFEAT_SCHORD 4 CLS_SPGN_SCHORD CLS_SPKN_SCHORD 1 1 10 14 12 10 14 16 CHA 0X00 0X0 0 CLASS_TYPE_SUBLIME_CHORD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SCHORD 10 0 0 0 10 46 131 **** **** **** **** **** **** **** **** **** SublimeCh **** **** **** **** **** +91 PnPShifter 16790578 16824335 9027 9028 16824370 IR_SHIFTR 8 CLS_ATK_2 CLS_FEAT_PNPSFR CLS_SAVTHR_WILD CLS_SKILL_SHIFTR CLS_BFEAT_SHIFTR 4 **** **** 1 0 12 16 14 8 14 12 WIS 0X00 0X0 0 CLASS_TYPE_PNP_SHIFTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_PNPSFR 40 0 0 0 10 108 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +92 ChampionCorellon 16790579 16828364 16828365 16828387 16828388 IR_COC 10 CLS_ATK_1 CLS_FEAT_COC CLS_SAVTHR_CLER CLS_SKILL_COC CLS_BFEAT_COC 2 **** **** 1 0 14 16 14 10 10 12 DEX 0X10 0X2 0 CLASS_TYPE_COC 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_COC 40 0 0 0 10 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +93 SublimeChord 16790580 16829452 16829453 16829454 16829455 IR_X1_HARPER 6 CLS_ATK_3 CLS_FEAT_SCHORD CLS_SAVTHR_WIZ CLS_SKILL_SCHORD CLS_BFEAT_SCHORD 4 CLS_SPGN_SCHORD CLS_SPKN_SCHORD 1 1 10 14 12 10 14 16 CHA 0X00 0X0 0 CLASS_TYPE_SUBLIME_CHORD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SCHORD 40 0 0 0 10 46 131 **** **** **** **** **** **** **** **** **** SublimeCh **** **** **** **** **** 94 Artificer 16790581 16827101 16827102 16827103 16827104 **** 6 CLS_ATK_2 CLS_FEAT_ARTI CLS_SAVTHR_WIZ CLS_SKILL_ARTI CLS_BFEAT_ARTI 4 **** **** 0 0 10 14 12 10 16 14 CHA 0X00 0X0 0 CLASS_TYPE_ARTIFICER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ARTI 0 1 0 0 -1 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -95 Arcane_Duelist 16790582 16823520 16823521 16823522 16823523 IR_SPARCDLST 8 CLS_ATK_3 CLS_FEAT_ADST CLS_SAVTHR_BARD CLS_SKILL_ADST CLS_BFEAT_ADST 4 **** **** 1 0 12 16 14 8 14 12 CHA 0X00 0X0 0 CLASS_TYPE_ARCANE_DUELIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ADST 10 0 0 0 10 **** 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +95 Arcane_Duelist 16790582 16823520 16823521 16823522 16823523 IR_SPARCDLST 8 CLS_ATK_3 CLS_FEAT_ADST CLS_SAVTHR_BARD CLS_SKILL_ADST CLS_BFEAT_ADST 4 **** **** 1 0 12 16 14 8 14 12 CHA 0X00 0X0 0 CLASS_TYPE_ARCANE_DUELIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ADST 40 0 0 0 10 **** 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 96 ForceMissileMage 16790583 16836426 16836427 16836428 16836429 IR_HAVOCMAGE 4 CLS_ATK_3 CLS_FEAT_FMM CLS_SAVTHR_ROG CLS_SKILL_FMM CLS_BFEAT_FMM 2 **** **** 1 0 12 14 14 10 12 15 CHA 0X00 0X0 0 CLASS_TYPE_FMM 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FMM 5 0 1 0 10 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -97 WildMage 16790584 16836416 16836417 16836418 16836419 IR_WILDER 4 CLS_ATK_3 CLS_FEAT_WILDMG CLS_SAVTHR_ROG CLS_SKILL_WILDMG CLS_BFEAT_WILDMG 2 **** **** 1 0 12 14 14 10 12 15 CHA 0X04 0X0 0 CLASS_TYPE_WILD_MAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WILDMG 10 0 1 0 10 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -98 Shadowsmith 16790585 16847414 16847415 16847416 16847417 IR_TEMPUS 8 CLS_ATK_1 CLS_FEAT_SHDSMT CLS_SAVTHR_ROG CLS_SKILL_SHDSMT CLS_BFEAT_SHDSMT 6 **** **** 1 0 14 13 14 10 14 13 INT 0x00 0x0 0 CLASS_TYPE_SHADOWSMITH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHDSMT 10 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +97 WildMage 16790584 16836416 16836417 16836418 16836419 IR_WILDER 4 CLS_ATK_3 CLS_FEAT_WILDMG CLS_SAVTHR_ROG CLS_SKILL_WILDMG CLS_BFEAT_WILDMG 2 **** **** 1 0 12 14 14 10 12 15 CHA 0X04 0X0 0 CLASS_TYPE_WILD_MAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WILDMG 40 0 1 0 10 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +98 Shadowsmith 16790585 16847414 16847415 16847416 16847417 IR_TEMPUS 8 CLS_ATK_1 CLS_FEAT_SHDSMT CLS_SAVTHR_ROG CLS_SKILL_SHDSMT CLS_BFEAT_SHDSMT 6 **** **** 1 0 14 13 14 10 14 13 INT 0x00 0x0 0 CLASS_TYPE_SHADOWSMITH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHDSMT 40 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 99 Abjurant_Champion 16790586 16847652 16847653 16847654 16847655 IR_ELDKNI 10 CLS_ATK_1 CLS_FEAT_ABCHAM CLS_SAVTHR_WIZ CLS_SKILL_ABCHAM CLS_BFEAT_ABCHAM 2 **** **** 1 0 14 13 14 10 14 13 INT 0X00 0X0 0 CLASS_TYPE_ABJURANT_CHAMPION 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ABCHAM 5 0 1 0 5 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 100 Archmage 16790587 16825000 16825001 16825002 16825003 IR_EPICSPELL 4 CLS_ATK_3 CLS_FEAT_ARCH CLS_SAVTHR_WIZ CLS_SKILL_ARCH CLS_BFEAT_ARCH 2 **** **** 1 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_ARCHMAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ARCH 5 0 2 0 5 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -101 Oozemaster 16790588 16825036 16825037 16825038 16825039 IR_GENSUMMON 8 CLS_ATK_2 CLS_FEAT_OOZE CLS_SAVTHR_FIGHT CLS_SKILL_OOZE CLS_BFEAT_OOZE 4 **** **** 1 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_OOZEMASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_OOZE 10 0 2 2 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +101 Oozemaster 16790588 16825036 16825037 16825038 16825039 IR_GENSUMMON 8 CLS_ATK_2 CLS_FEAT_OOZE CLS_SAVTHR_FIGHT CLS_SKILL_OOZE CLS_BFEAT_OOZE 4 **** **** 1 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_OOZEMASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_OOZE 40 0 2 2 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 102 Psychic_Rogue 16790589 16835172 16835173 16835174 16835175 IR_PSYWARRIOR 6 CLS_ATK_2 CLS_FEAT_PSYROG CLS_SAVTHR_ROG CLS_SKILL_PSYROG CLS_BFEAT_PSYROG 6 **** **** 1 0 14 12 14 16 10 10 WIS 0X00 0X0 0 CLASS_TYPE_PSYROG 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_PSYROG 20 1 0 0 -1 7 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 103 Spelldancer 16790590 16835157 16835158 16835159 16835160 IR_HAVOCMAGE 6 CLS_ATK_3 CLS_FEAT_SPLDNC CLS_SAVTHR_BARD CLS_SKILL_SPLDNC CLS_BFEAT_SPLDNC 4 **** **** 1 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_SPELLDANCER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SPLDNC 5 0 1 0 5 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -104 KnightoftheWeave 16790591 16835149 16835150 16835151 16835152 IR_MAGEKILL 8 CLS_ATK_2 CLS_FEAT_KNGTWV CLS_SAVTHR_DRU CLS_SKILL_KNGTWV CLS_BFEAT_KNGTWV 2 CLS_SPGN_KNGTWV CLS_SPKN_KNGTWV 0 1 12 16 14 8 14 12 INT 0X10 0X2 0 CLASS_TYPE_KNIGHT_WEAVE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_KNGTWV 10 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** KnightWeave **** **** **** **** **** -105 Drow_Judicator 16790592 16822863 16822864 16822865 16822866 IR_JUDICATOR 8 CLS_ATK_1 CLS_FEAT_DROWJ CLS_SAVTHR_FIGHT CLS_SKILL_DROWJ CLS_BFEAT_DROWJ 2 **** **** 1 0 16 12 16 10 10 10 STR 0X09 0X2 0 CLASS_TYPE_JUDICATOR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DROWJ 10 0 3 3 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -106 ShadowbaneInquisitor 16790593 16835121 16835122 16835123 16835124 IR_MAA 10 CLS_ATK_1 CLS_FEAT_SDHINQ CLS_SAVTHR_BARD CLS_SKILL_SDHINQ CLS_BFEAT_BLANK 4 **** **** 1 0 12 12 12 15 10 15 WIS 0X15 0X3 0 CLASS_TYPE_ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SDHINQ 10 0 0 0 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -107 ShadowbaneStalker 16790594 16835125 16835126 16835127 16835128 IR_TFSHAD 8 CLS_ATK_2 CLS_FEAT_SDHSTK CLS_SAVTHR_BARD CLS_SKILL_SDHSTK CLS_BFEAT_BLANK 6 **** **** 1 0 12 12 12 15 10 15 WIS 0X15 0X3 0 CLASS_TYPE_ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SDHSTK 10 0 0 1 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +104 KnightoftheWeave 16790591 16835149 16835150 16835151 16835152 IR_MAGEKILL 8 CLS_ATK_2 CLS_FEAT_KNGTWV CLS_SAVTHR_DRU CLS_SKILL_KNGTWV CLS_BFEAT_KNGTWV 2 CLS_SPGN_KNGTWV CLS_SPKN_KNGTWV 0 1 12 16 14 8 14 12 INT 0X10 0X2 0 CLASS_TYPE_KNIGHT_WEAVE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_KNGTWV 40 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** KnightWeave **** **** **** **** **** +105 Drow_Judicator 16790592 16822863 16822864 16822865 16822866 IR_JUDICATOR 8 CLS_ATK_1 CLS_FEAT_DROWJ CLS_SAVTHR_FIGHT CLS_SKILL_DROWJ CLS_BFEAT_DROWJ 2 **** **** 1 0 16 12 16 10 10 10 STR 0X09 0X2 0 CLASS_TYPE_JUDICATOR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DROWJ 40 0 3 3 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +106 ShadowbaneInquisitor 16790593 16835121 16835122 16835123 16835124 IR_MAA 10 CLS_ATK_1 CLS_FEAT_SDHINQ CLS_SAVTHR_BARD CLS_SKILL_SDHINQ CLS_BFEAT_SDHINQ 4 **** **** 1 0 12 12 12 15 10 15 WIS 0X15 0X3 0 CLASS_TYPE_SHADOWBANE_INQUISITOR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SDHINQ 40 0 0 0 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +107 ShadowbaneStalker 16790594 16835125 16835126 16835127 16835128 IR_TFSHAD 8 CLS_ATK_2 CLS_FEAT_SDHSTK CLS_SAVTHR_BARD CLS_SKILL_SDHSTK CLS_BFEAT_SDHSTK 6 **** **** 1 0 12 12 12 15 10 15 WIS 0X15 0X3 0 CLASS_TYPE_SHADOWBANE_STALKER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SDHSTK 40 0 0 1 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 108 WayfarerGuide 16790595 16835113 16835114 16835115 16835116 IR_MAESTER 6 CLS_ATK_3 CLS_FEAT_WAYFAR CLS_SAVTHR_WIZ CLS_SKILL_WAYFAR CLS_BFEAT_WAYFAR 2 **** **** 1 0 12 16 14 8 14 12 INT 0X14 0X3 0 CLASS_TYPE_WAR_WIZARD_OF_CORMYR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WAYFAR 3 0 2 0 3 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -109 Umbral_Disciple 16790596 16837827 16837828 16837829 16837830 IR_ASASIN 6 CLS_ATK_2 CLS_FEAT_UMBRAL CLS_SAVTHR_BARD CLS_SKILL_UMBRAL CLS_BFEAT_ASASIN 6 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_UMBRAL_DISCIPLE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_UMBRAL 10 0 0 0 10 8 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -110 Alienist 16790597 16789710 16789711 16789712 16789713 IR_ALIEN 4 CLS_ATK_3 CLS_FEAT_ALIEN CLS_SAVTHR_WIZ CLS_SKILL_ALIEN CLS_BFEAT_ALIEN 2 **** **** 1 0 10 14 14 12 16 10 INT 0X00 0X0 0 CLASS_TYPE_ALIENIST 1 1 1 2 2 4 6 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ALIEN 10 0 1 0 10 10 0 cls_stat_alien **** **** **** **** **** **** **** **** **** **** **** **** **** **** -111 BlackBloodCultist 16790598 16823068 16823077 16823078 16823079 IR_WILDWOLF 12 CLS_ATK_2 CLS_FEAT_BBC CLS_SAVTHR_BARB CLS_SKILL_BBC CLS_BFEAT_BBC 4 **** **** 0 0 16 14 14 14 10 8 STR 0X0A 0X3 0 CLASS_TYPE_BLACK_BLOOD_CULTIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BBC 10 0 0 0 10 17 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -112 Warlock 16790599 16827934 16827935 16827936 16827937 IR_WARLOCK 6 CLS_ATK_2 CLS_FEAT_WARLOK CLS_SAVTHR_WIZ CLS_SKILL_WARLOK CLS_BFEAT_WARLOK 2 **** **** 1 0 12 14 14 10 12 15 CHA 0X14 0X3 1 CLASS_TYPE_WARLOCK 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WARLOK 0 1 0 0 -1 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -113 Fochlucan_Lyrist 16852476 16825142 16825143 16825144 16825145 IR_DRUID 6 CLS_ATK_1 CLS_FEAT_FOCLYR CLS_SAVTHR_BARD CLS_SKILL_FOCLYR CLS_BFEAT_FOCLYR 6 **** **** 1 0 10 12 12 14 12 16 CHA 0X02 0X0 0 CLASS_TYPE_FOCHLUCAN_LYRIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FOCLYR 30 0 1 1 10 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +109 Umbral_Disciple 16790596 16837827 16837828 16837829 16837830 IR_ASASIN 6 CLS_ATK_2 CLS_FEAT_UMBRAL CLS_SAVTHR_BARD CLS_SKILL_UMBRAL CLS_BFEAT_UMBRAL 6 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_UMBRAL_DISCIPLE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_UMBRAL 40 0 0 0 10 8 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +110 Alienist 16790597 16789710 16789711 16789712 16789713 IR_ALIEN 4 CLS_ATK_3 CLS_FEAT_ALIEN CLS_SAVTHR_WIZ CLS_SKILL_ALIEN CLS_BFEAT_ALIEN 2 **** **** 1 0 10 14 14 12 16 10 INT 0X00 0X0 0 CLASS_TYPE_ALIENIST 1 1 1 2 2 4 6 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ALIEN 40 0 1 0 10 10 0 cls_stat_alien **** **** **** **** **** **** **** **** **** **** **** **** **** **** +111 BlackBloodCultist 16790598 16823068 16823077 16823078 16823079 IR_WILDWOLF 12 CLS_ATK_2 CLS_FEAT_BBC CLS_SAVTHR_BARB CLS_SKILL_BBC CLS_BFEAT_BBC 4 **** **** 0 0 16 14 14 14 10 8 STR 0X0A 0X3 0 CLASS_TYPE_BLACK_BLOOD_CULTIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BBC 40 0 0 0 10 17 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +112 Warlock 16790599 16827934 16827935 16827936 16827937 IR_WARLOCK 6 CLS_ATK_2 CLS_FEAT_WARLOK CLS_SAVTHR_WIZ CLS_SKILL_WARLOK CLS_BFEAT_WARLOK 2 **** **** 1 1 12 14 14 10 12 15 CHA 0X14 0X3 1 CLASS_TYPE_WARLOCK 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WARLOK 0 1 0 0 -1 10 0 **** **** **** **** **** **** **** **** **** Warlock **** **** **** **** **** +113 Fochlucan_Lyrist 16852476 16825142 16825143 16825144 16825145 IR_DRUID 6 CLS_ATK_1 CLS_FEAT_FOCLYR CLS_SAVTHR_BARD CLS_SKILL_FOCLYR CLS_BFEAT_FOCLYR 6 **** **** 1 0 10 12 12 14 12 16 CHA 0X02 0X0 0 CLASS_TYPE_FOCHLUCAN_LYRIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FOCLYR 40 0 1 1 10 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 114 Dragonsong_Lyrist 16790600 16825459 16825460 16825461 16825462 IR_DRSLYR 6 CLS_ATK_2 CLS_FEAT_DRSLYR CLS_SAVTHR_BARD CLS_SKILL_DRSLYR CLS_BFEAT_DRSLYR 4 **** **** 1 0 12 14 14 10 12 15 CHA 0X10 0X2 0 CLASS_TYPE_DRAGONSONG_LYRIST 1 2 3 4 5 6 7 8 9 10 11 12 12 14 15 16 17 18 19 20 CLS_PRES_DSLYR 5 0 2 0 5 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -115 SpinemeldWarrior 16790601 16836998 16836999 16837000 16837001 IR_TEMPEST 10 CLS_ATK_1 CLS_FEAT_SPNMLD CLS_SAVTHR_FIGHT CLS_SKILL_SPNMLD CLS_BFEAT_SPNMLD 4 **** **** 1 0 16 14 14 14 10 8 STR 0X02 0X1 1 CLASS_TYPE_SPINEMELD_WARRIOR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SPNMLD 10 0 0 0 10 17 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -116 Nightshade 16790602 16825413 16825414 16825415 16825416 IR_ASASIN 8 CLS_ATK_2 CLS_FEAT_NIGHTS CLS_SAVTHR_ROG CLS_SKILL_NIGHTS CLS_BFEAT_ASASIN 6 **** **** 1 0 12 16 14 8 14 12 DEX 0X09 0X2 0 CLASS_TYPE_NIGHTSHADE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_NIGHTS 10 0 0 0 10 8 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -117 ShadowAdept 16790603 16825409 16825410 16825411 16825412 IR_SHADADEPT 4 CLS_ATK_3 CLS_FEAT_SHADEP CLS_SAVTHR_WIZ CLS_SKILL_SHADEP CLS_BFEAT_SHADEP 2 **** **** 1 0 14 16 14 8 14 10 DEX 0X08 0X2 0 CLASS_TYPE_SHADOW_ADEPT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHADEP 30 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -118 Soldier_of_Light 16790604 16825874 16825875 16825876 16825877 IR_PALADIN 10 CLS_ATK_1 CLS_FEAT_SOL CLS_SAVTHR_PAL CLS_SKILL_SOL CLS_BFEAT_SOL 2 CLS_SPGN_SOL **** 0 1 15 9 14 13 10 15 WIS 0X16 0X3 0 CLASS_TYPE_SOLDIER_OF_LIGHT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SOL 30 0 0 0 10 6 0 **** 1 0 0 0 0 0 0 WIS SoLight 1 1 255 0 0 -119 SapphireHierarch 16790605 16837004 16837005 16837006 16837007 IC_HOSPITALER 6 CLS_ATK_3 CLS_FEAT_SAPPHR CLS_SAVTHR_WIZ CLS_SKILL_SAPPHR CLS_BFEAT_SAPPHR 2 **** **** 1 0 15 9 14 13 10 15 WIS 0X02 0X1 1 CLASS_TYPE_SAPPHIRE_HIERARCH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SAPPHR 30 0 0 1 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +115 SpinemeldWarrior 16790601 16836998 16836999 16837000 16837001 IR_TEMPEST 10 CLS_ATK_1 CLS_FEAT_SPNMLD CLS_SAVTHR_FIGHT CLS_SKILL_SPNMLD CLS_BFEAT_SPNMLD 4 **** **** 1 0 16 14 14 14 10 8 STR 0X02 0X1 1 CLASS_TYPE_SPINEMELD_WARRIOR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SPNMLD 40 0 0 0 10 17 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +116 Nightshade 16790602 16825413 16825414 16825415 16825416 IR_ASASIN 8 CLS_ATK_2 CLS_FEAT_NIGHTS CLS_SAVTHR_ROG CLS_SKILL_NIGHTS CLS_BFEAT_NIGHTS 6 **** **** 1 0 12 16 14 8 14 12 DEX 0X09 0X2 0 CLASS_TYPE_NIGHTSHADE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_NIGHTS 40 0 0 0 10 8 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +117 ShadowAdept 16790603 16825409 16825410 16825411 16825412 IR_SHADADEPT 4 CLS_ATK_3 CLS_FEAT_SHADEP CLS_SAVTHR_WIZ CLS_SKILL_SHADEP CLS_BFEAT_SHADEP 2 **** **** 1 0 14 16 14 8 14 10 DEX 0X08 0X2 0 CLASS_TYPE_SHADOW_ADEPT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHADEP 40 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +118 Soldier_of_Light 16790604 16825874 16825875 16825876 16825877 IR_PALADIN 10 CLS_ATK_1 CLS_FEAT_SOL CLS_SAVTHR_PAL CLS_SKILL_SOL CLS_BFEAT_SOL 2 CLS_SPGN_SOL **** 0 1 15 9 14 13 10 15 WIS 0X16 0X3 0 CLASS_TYPE_SOLDIER_OF_LIGHT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SOL 40 0 0 0 10 6 0 **** 1 0 0 0 0 0 0 WIS SoLight 1 1 255 0 0 +119 SapphireHierarch 16790605 16837004 16837005 16837006 16837007 IC_HOSPITALER 6 CLS_ATK_3 CLS_FEAT_SAPPHR CLS_SAVTHR_WIZ CLS_SKILL_SAPPHR CLS_BFEAT_SAPPHR 2 **** **** 1 0 15 9 14 13 10 15 WIS 0X02 0X1 1 CLASS_TYPE_SAPPHIRE_HIERARCH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SAPPHR 40 0 0 1 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 120 Telflammar_Shadowlord 16790606 16822992 16822993 16822994 16822995 IR_TFSHAD 6 CLS_ATK_2 CLS_FEAT_TFSHAD CLS_SAVTHR_ROG CLS_SKILL_TFSHAD CLS_BFEAT_TFSHAD 4 CLS_SPGN_TFSHAD **** 0 1 12 16 14 10 14 10 DEX 0X00 0X0 0 CLASS_TYPE_SHADOWLORD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_TFSHAD 6 0 0 0 6 8 128 **** 1 1 0 0 1 1 1 INT Telflammar 1 1 255 0 0 -121 BondedSummoner 16790607 16823012 16823013 16823014 16823015 IR_WIZARD 4 CLS_ATK_3 CLS_FEAT_BONDED CLS_SAVTHR_WIZ CLS_SKILL_BONDED CLS_BFEAT_BONDED 2 **** **** 1 0 12 14 12 12 16 10 DEX 0X00 0X0 0 CLASS_TYPE_BONDED_SUMMONNER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BONDED 10 0 2 0 10 8 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -122 Initiate_Draconic 16790608 16826056 16826057 16826058 16826059 IR_IODM 8 CLS_ATK_2 CLS_FEAT_INIDRA CLS_SAVTHR_MONK CLS_SKILL_INIDRA CLS_BFEAT_MONK 4 **** **** 1 0 14 14 14 15 10 10 DEX 0X00 0X0 0 CLASS_TYPE_INITIATE_DRACONIC 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_INIDRA 30 0 0 0 10 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -123 Battleguard_Tempus 16790609 16822940 16822941 16822942 16822943 IR_TEMPUS 10 CLS_ATK_1 CLS_FEAT_TEMPUS CLS_SAVTHR_PAL CLS_SKILL_TEMPUS CLS_BFEAT_TEMPUS 2 **** **** 0 0 14 12 12 14 12 14 WIS 0X02 0X1 0 CLASS_TYPE_TEMPUS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_TEMPUS 10 0 0 2 10 6 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -124 Bladesinger 16790610 16825986 16825987 16825988 16825989 IR_SPELLS 8 CLS_ATK_1 CLS_FEAT_BLADES CLS_SAVTHR_BARD CLS_SKILL_BLADES CLS_BFEAT_BLADES 2 **** **** 1 0 14 16 14 8 14 10 DEX 0X00 0X0 0 CLASS_TYPE_BLADESINGER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BLADES 30 0 2 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -125 Soulcaster 16790611 16837012 16837013 16837014 16837015 IR_MYSTIC 4 CLS_ATK_3 CLS_FEAT_SOULC CLS_SAVTHR_WIZ CLS_SKILL_SOULC CLS_BFEAT_SOULC 2 **** **** 1 0 10 11 11 16 16 10 INT 0X00 0X0 0 CLASS_TYPE_SOULCASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SOULC 10 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -126 Sacred_Fist 16790612 16825367 16825368 16825369 16825370 IR_SACREDFIST 8 CLS_ATK_1 CLS_FEAT_SACFIS CLS_SAVTHR_WILD CLS_SKILL_SACFIS CLS_BFEAT_SACFIS 4 **** **** 1 0 14 14 12 16 10 10 WIS 0X00 0X0 0 CLASS_TYPE_SACREDFIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SACFIS 30 0 0 1 10 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -127 Legendary_Dreadnought 16790613 16826086 16826087 16826088 16826089 IC_LEGDREAD 12 CLS_ATK_1 CLS_FEAT_LGDR CLS_SAVTHR_FIGHT CLS_SKILL_LGDR CLS_BFEAT_LGDR 2 **** **** 1 0 16 13 16 10 10 9 STR 0X00 0X0 0 CLASS_TYPE_LEGENDARY_DREADNOUGHT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_LGDR 30 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -128 Disciple_of_Baalzebul 16790614 16826094 16826095 16826096 16826097 IC_BAALZEBUL 6 CLS_ATK_2 CLS_FEAT_BAAL CLS_SAVTHR_BARD CLS_SKILL_BAAL CLS_BFEAT_BAAL 6 **** **** 1 0 12 14 14 10 12 15 CHA 0X09 0X2 0 CLASS_TYPE_DISC_BAALZEBUL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BAAL 10 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -129 Mighty_Contender_of_Kord 16790615 16824935 16824936 16824937 16824938 IC_LEGDREAD 10 CLS_ATK_2 CLS_FEAT_KORD CLS_SAVTHR_CLER CLS_SKILL_KORD CLS_BFEAT_KORD 2 **** **** 1 0 14 8 14 16 10 14 WIS 0X00 0X0 0 CLASS_TYPE_MIGHTY_CONTENDER_KORD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_KORD 10 0 0 1 10 4 0 cls_stat_kord **** **** **** **** **** **** **** **** **** **** **** **** **** **** -130 Iaijutsu_Master 16790616 16826114 16826115 16826116 16826117 IC_IAIJUTSU 10 CLS_ATK_1 CLS_FEAT_IAIJ CLS_SAVTHR_ROG CLS_SKILL_IAIJ CLS_BFEAT_IAIJ 4 **** **** 1 0 16 13 16 10 10 9 CHA 0X05 0X1 0 CLASS_TYPE_IAIJUTSU_MASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_IAIJ 30 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -131 Disciple_of_Dispater 16790617 16826136 16826137 16826138 16826139 IR_BLKGRD 10 CLS_ATK_1 CLS_FEAT_DISP CLS_SAVTHR_MONK CLS_SKILL_DISP CLS_BFEAT_DISP 4 **** **** 1 0 16 13 16 10 10 9 CON 0X09 0X2 0 CLASS_TYPE_DISPATER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DISP 10 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +121 BondedSummoner 16790607 16823012 16823013 16823014 16823015 IR_WIZARD 4 CLS_ATK_3 CLS_FEAT_BONDED CLS_SAVTHR_WIZ CLS_SKILL_BONDED CLS_BFEAT_BONDED 2 **** **** 1 0 12 14 12 12 16 10 DEX 0X00 0X0 0 CLASS_TYPE_BONDED_SUMMONNER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BONDED 40 0 2 0 10 8 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +122 Initiate_Draconic 16790608 16826056 16826057 16826058 16826059 IR_IODM 8 CLS_ATK_2 CLS_FEAT_INIDRA CLS_SAVTHR_MONK CLS_SKILL_INIDRA CLS_BFEAT_INIDRA 4 **** **** 1 0 14 14 14 15 10 10 DEX 0X00 0X0 0 CLASS_TYPE_INITIATE_DRACONIC 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_INIDRA 40 0 0 0 10 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +123 Battleguard_Tempus 16790609 16822940 16822941 16822942 16822943 IR_TEMPUS 10 CLS_ATK_1 CLS_FEAT_TEMPUS CLS_SAVTHR_PAL CLS_SKILL_TEMPUS CLS_BFEAT_TEMPUS 2 **** **** 0 0 14 12 12 14 12 14 WIS 0X02 0X1 0 CLASS_TYPE_TEMPUS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_TEMPUS 40 0 0 2 10 6 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +124 Bladesinger 16790610 16825986 16825987 16825988 16825989 IR_SPELLS 8 CLS_ATK_1 CLS_FEAT_BLADES CLS_SAVTHR_BARD CLS_SKILL_BLADES CLS_BFEAT_BLADES 2 **** **** 1 0 14 16 14 8 14 10 DEX 0X00 0X0 0 CLASS_TYPE_BLADESINGER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BLADES 40 0 2 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +125 Soulcaster 16790611 16837012 16837013 16837014 16837015 IR_MYSTIC 4 CLS_ATK_3 CLS_FEAT_SOULC CLS_SAVTHR_WIZ CLS_SKILL_SOULC CLS_BFEAT_SOULC 2 **** **** 1 0 10 11 11 16 16 10 INT 0X00 0X0 0 CLASS_TYPE_SOULCASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SOULC 40 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +126 Sacred_Fist 16790612 16825367 16825368 16825369 16825370 IR_SACREDFIST 8 CLS_ATK_1 CLS_FEAT_SACFIS CLS_SAVTHR_WILD CLS_SKILL_SACFIS CLS_BFEAT_SACFIS 4 **** **** 1 0 14 14 12 16 10 10 WIS 0X00 0X0 0 CLASS_TYPE_SACREDFIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SACFIS 40 0 0 1 10 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +127 Legendary_Dreadnought 16790613 16826086 16826087 16826088 16826089 IC_LEGDREAD 12 CLS_ATK_1 CLS_FEAT_LGDR CLS_SAVTHR_FIGHT CLS_SKILL_LGDR CLS_BFEAT_LGDR 2 **** **** 1 0 16 13 16 10 10 9 STR 0X00 0X0 0 CLASS_TYPE_LEGENDARY_DREADNOUGHT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_LGDR 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +128 Disciple_of_Baalzebul 16790614 16826094 16826095 16826096 16826097 IC_BAALZEBUL 6 CLS_ATK_2 CLS_FEAT_BAAL CLS_SAVTHR_BARD CLS_SKILL_BAAL CLS_BFEAT_BAAL 6 **** **** 1 0 12 14 14 10 12 15 CHA 0X09 0X2 0 CLASS_TYPE_DISC_BAALZEBUL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BAAL 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +129 Mighty_Contender_of_Kord 16790615 16824935 16824936 16824937 16824938 IC_LEGDREAD 10 CLS_ATK_2 CLS_FEAT_KORD CLS_SAVTHR_CLER CLS_SKILL_KORD CLS_BFEAT_KORD 2 **** **** 1 0 14 8 14 16 10 14 WIS 0X00 0X0 0 CLASS_TYPE_MIGHTY_CONTENDER_KORD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_KORD 40 0 0 1 10 4 0 cls_stat_kord **** **** **** **** **** **** **** **** **** **** **** **** **** **** +130 Iaijutsu_Master 16790616 16826114 16826115 16826116 16826117 IC_IAIJUTSU 10 CLS_ATK_1 CLS_FEAT_IAIJ CLS_SAVTHR_ROG CLS_SKILL_IAIJ CLS_BFEAT_IAIJ 4 **** **** 1 0 16 13 16 10 10 9 CHA 0X05 0X1 0 CLASS_TYPE_IAIJUTSU_MASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_IAIJ 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +131 Disciple_of_Dispater 16790617 16826136 16826137 16826138 16826139 IR_BLKGRD 10 CLS_ATK_1 CLS_FEAT_DISP CLS_SAVTHR_MONK CLS_SKILL_DISP CLS_BFEAT_DISP 4 **** **** 1 0 16 13 16 10 10 9 CON 0X09 0X2 0 CLASS_TYPE_DISPATER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DISP 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 132 CW_Samurai 16790618 16826168 16826169 16826170 16826171 IR_SAMURAI 10 CLS_ATK_1 CLS_FEAT_CWSM CLS_SAVTHR_FIGHT CLS_SKILL_SAMUR CLS_BFEAT_CWSM 2 **** **** 0 0 16 13 16 10 10 9 STR 0X05 0X1 0 CLASS_TYPE_CW_SAMURAI 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_CWSM 20 1 0 0 -1 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -133 Ravager 16790619 16826156 16826157 16826158 16826159 IC_RAVA 10 CLS_ATK_1 CLS_FEAT_RAVA CLS_SAVTHR_FIGHT CLS_SKILL_RAVA CLS_BFEAT_RAVA 2 **** **** 1 0 16 13 16 10 10 9 STR 0X0A 0X3 0 CLASS_TYPE_RAVAGER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_RAVA 30 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -134 Runescarred_Berserker 16790620 16826187 16826188 16826189 16826190 IC_RUNE 10 CLS_ATK_1 CLS_FEAT_RUNE CLS_SAVTHR_FIGHT CLS_SKILL_RUNE CLS_BFEAT_RUNE 4 **** **** 1 0 16 13 16 10 10 9 STR 0X02 0X1 0 CLASS_TYPE_RUNESCARRED 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_RUNE 10 0 0 0 10 4 0 cls_stat_rune **** **** **** **** **** **** **** **** **** **** **** **** **** **** -135 Talontar_Blightlord 16790621 16824917 16824918 16824919 16824920 IR_CLERIC 8 CLS_ATK_2 CLS_FEAT_BLTL CLS_SAVTHR_CLER CLS_SKILL_BLTL CLS_BFEAT_BLTL 2 **** **** 0 0 16 13 16 10 10 9 WIS 0X09 0X2 0 CLASS_TYPE_BLIGHTLORD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BLTL 10 0 0 1 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +133 Ravager 16790619 16826156 16826157 16826158 16826159 IC_RAVA 10 CLS_ATK_1 CLS_FEAT_RAVA CLS_SAVTHR_FIGHT CLS_SKILL_RAVA CLS_BFEAT_RAVA 2 **** **** 1 0 16 13 16 10 10 9 STR 0X0A 0X3 0 CLASS_TYPE_RAVAGER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_RAVA 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +134 Runescarred_Berserker 16790620 16826187 16826188 16826189 16826190 IC_RUNE 10 CLS_ATK_1 CLS_FEAT_RUNE CLS_SAVTHR_FIGHT CLS_SKILL_RUNE CLS_BFEAT_RUNE 4 **** **** 1 0 16 13 16 10 10 9 STR 0X02 0X1 0 CLASS_TYPE_RUNESCARRED 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_RUNE 40 0 0 0 10 4 0 cls_stat_rune **** **** **** **** **** **** **** **** **** **** **** **** **** **** +135 Talontar_Blightlord 16790621 16824917 16824918 16824919 16824920 IR_CLERIC 8 CLS_ATK_2 CLS_FEAT_BLTL CLS_SAVTHR_CLER CLS_SKILL_BLTL CLS_BFEAT_BLTL 2 **** **** 0 0 16 13 16 10 10 9 WIS 0X09 0X2 0 CLASS_TYPE_BLIGHTLORD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BLTL 40 0 0 1 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 136 Shadowcaster 16790622 16847394 16847395 16847396 16847397 IR_SHADADEPT 6 CLS_ATK_3 CLS_FEAT_SHDCST CLS_SAVTHR_CLER CLS_SKILL_SHDCST CLS_BFEAT_SHDCST 2 **** **** 1 0 10 10 14 12 16 14 CHA 0x00 0x0 0 CLASS_TYPE_SHADOWCASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHDCST 20 1 0 0 -1 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -137 ChildOfNight 16790623 16847398 16847399 16847400 16847401 IR_X1_SHADOW 6 CLS_ATK_3 CLS_FEAT_CHLDNT CLS_SAVTHR_WIZ CLS_SKILL_CHLDNT CLS_BFEAT_CHLDNT 2 **** **** 1 0 10 10 14 12 16 14 CHA 0x00 0x0 0 CLASS_TYPE_CHILD_OF_NIGHT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_CHLDNT 10 0 0 0 10 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -138 MasterofShadow 16790624 16847402 16847403 16847404 16847405 IR_MYSTIC 8 CLS_ATK_3 CLS_FEAT_MSTRSH CLS_SAVTHR_CLER CLS_SKILL_MSTRSH CLS_BFEAT_MSTRSH 2 **** **** 1 0 12 14 14 10 12 15 CHA 0x00 0x0 0 CLASS_TYPE_MASTER_OF_SHADOW 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MSTRSH 10 0 0 0 10 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -139 Noctumancer 16790625 16847406 16847407 16847408 16847409 IR_NOCTM 4 CLS_ATK_3 CLS_FEAT_NOCTM CLS_SAVTHR_CLER CLS_SKILL_NOCTM CLS_BFEAT_NOCTM 2 **** **** 1 0 12 14 14 10 12 15 CHA 0x00 0x0 **** CLASS_TYPE_NOCTUMANCER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_NOCTM 10 0 1 0 10 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -140 Totem_Rager 16790626 16825977 16825978 16825979 16825980 IR_PSYWARRIOR 10 CLS_ATK_2 CLS_FEAT_TOTRAG CLS_SAVTHR_RANG CLS_SKILL_TOTRAG CLS_BFEAT_TOTRAG 4 **** **** 1 0 16 15 14 10 10 10 CON 0X00 0X0 0 CLASS_TYPE_TOTEM_RAGER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_TOTRAG 10 0 0 0 10 142 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -141 Ninja_CA 16790627 16832316 16832317 16832318 16832319 IR_NINJCA 6 CLS_ATK_2 CLS_FEAT_NINJCA CLS_SAVTHR_ROG CLS_SKILL_NINJCA CLS_BFEAT_NINJCA 6 **** **** 0 0 12 16 12 14 14 8 DEX 0X00 0X0 0 CLASS_TYPE_NINJA 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_NINJCA 30 1 0 0 -1 7 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -142 Shadowblade 16790628 16847410 16847411 16847412 16847413 IR_SHADOWBLADE 8 CLS_ATK_2 CLS_FEAT_SHDBLD CLS_SAVTHR_FIGHT CLS_SKILL_SHDBLD CLS_BFEAT_SHDBLD 2 **** **** 1 0 14 15 14 12 12 10 DEX 0X00 0X0 0 CLASS_TYPE_SHADOWBLADE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHDBLD 10 0 0 0 10 8 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -143 DragonShaman 16790629 16832703 16832704 16832705 16832706 IR_DRAGSHMN 10 CLS_ATK_2 CLS_FEAT_DRGSHM CLS_SAVTHR_CLER CLS_SKILL_DRGSHM CLS_BFEAT_DRGSHM 2 **** **** 1 0 12 14 16 10 14 10 CON 0X00 0X0 0 CLASS_TYPE_DRAGON_SHAMAN 1 1 3 4 5 6 7 8 9 10 11 12 12 14 15 16 17 18 19 20 CLS_PRES_DRGSHM 30 1 0 0 -1 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -144 Dragonfire_Adept 16790630 16832914 16832915 16832916 16832917 IR_DRGNFIREADPT 8 CLS_ATK_3 CLS_FEAT_DFA CLS_SAVTHR_CLER CLS_SKILL_DFA CLS_BFEAT_DFA 4 **** **** 1 0 10 14 16 12 10 14 CON 0X00 0X0 0 CLASS_TYPE_DRAGONFIRE_ADEPT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DFA 30 1 0 0 -1 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +137 ChildOfNight 16790623 16847398 16847399 16847400 16847401 IR_X1_SHADOW 6 CLS_ATK_3 CLS_FEAT_CHLDNT CLS_SAVTHR_WIZ CLS_SKILL_CHLDNT CLS_BFEAT_CHLDNT 2 **** **** 1 0 10 10 14 12 16 14 CHA 0x00 0x0 0 CLASS_TYPE_CHILD_OF_NIGHT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_CHLDNT 40 0 0 0 10 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +138 MasterofShadow 16790624 16847402 16847403 16847404 16847405 IR_MYSTIC 8 CLS_ATK_3 CLS_FEAT_MSTRSH CLS_SAVTHR_CLER CLS_SKILL_MSTRSH CLS_BFEAT_MSTRSH 2 **** **** 1 0 12 14 14 10 12 15 CHA 0x00 0x0 0 CLASS_TYPE_MASTER_OF_SHADOW 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MSTRSH 40 0 0 0 10 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +139 Noctumancer 16790625 16847406 16847407 16847408 16847409 IR_NOCTM 4 CLS_ATK_3 CLS_FEAT_NOCTM CLS_SAVTHR_CLER CLS_SKILL_NOCTM CLS_BFEAT_NOCTM 2 **** **** 1 0 12 14 14 10 12 15 CHA 0x00 0x0 **** CLASS_TYPE_NOCTUMANCER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_NOCTM 40 0 1 0 10 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +140 Totem_Rager 16790626 16825977 16825978 16825979 16825980 IR_PSYWARRIOR 10 CLS_ATK_2 CLS_FEAT_TOTRAG CLS_SAVTHR_RANG CLS_SKILL_TOTRAG CLS_BFEAT_TOTRAG 4 **** **** 1 0 16 15 14 10 10 10 CON 0X00 0X0 0 CLASS_TYPE_TOTEM_RAGER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_TOTRAG 40 0 0 0 10 142 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +141 Ninja_CA 16790627 16832316 16832317 16832318 16832319 IR_NINJCA 6 CLS_ATK_2 CLS_FEAT_NINJCA CLS_SAVTHR_ROG CLS_SKILL_NINJCA CLS_BFEAT_NINJCA 6 **** **** 0 0 12 16 12 14 14 8 DEX 0X00 0X0 0 CLASS_TYPE_NINJA 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_NINJCA 0 1 0 0 -1 7 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +142 Shadowblade 16790628 16847410 16847411 16847412 16847413 IR_SHADOWBLADE 8 CLS_ATK_2 CLS_FEAT_SHDBLD CLS_SAVTHR_FIGHT CLS_SKILL_SHDBLD CLS_BFEAT_SHDBLD 2 **** **** 1 0 14 15 14 12 12 10 DEX 0X00 0X0 0 CLASS_TYPE_SHADOWBLADE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHDBLD 40 0 0 0 10 8 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +143 DragonShaman 16790629 16832703 16832704 16832705 16832706 IR_DRAGSHMN 10 CLS_ATK_2 CLS_FEAT_DRGSHM CLS_SAVTHR_CLER CLS_SKILL_DRGSHM CLS_BFEAT_DRGSHM 2 **** **** 1 0 12 14 16 10 14 10 CON 0X00 0X0 0 CLASS_TYPE_DRAGON_SHAMAN 1 1 3 4 5 6 7 8 9 10 11 12 12 14 15 16 17 18 19 20 CLS_PRES_DRGSHM 40 1 0 0 -1 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +144 Dragonfire_Adept 16790630 16832914 16832915 16832916 16832917 IR_DRGNFIREADPT 8 CLS_ATK_3 CLS_FEAT_DFA CLS_SAVTHR_CLER CLS_SKILL_DFA CLS_BFEAT_DFA 4 **** **** 1 1 10 14 16 12 10 14 CON 0X00 0X0 0 CLASS_TYPE_DRAGONFIRE_ADEPT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DFA 40 1 0 0 -1 1 0 **** **** **** **** **** **** **** **** **** Dragonfire **** **** **** **** **** 145 Psion 16790631 16823566 16823567 16823568 16823569 IR_PSION 4 CLS_ATK_3 CLS_FEAT_PSION CLS_SAVTHR_WIZ CLS_SKILL_PSION CLS_BFEAT_PSION 2 **** **** 1 0 10 14 14 12 16 10 INT 0X00 0X0 0 CLASS_TYPE_PSION 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_PSION 0 1 0 0 -1 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 146 Psychic_Warrior 16790632 16823570 16823571 16823572 16823573 IR_PSYWARRIOR 8 CLS_ATK_2 CLS_FEAT_PSYWAR CLS_SAVTHR_FIGHT CLS_SKILL_PSYWAR CLS_BFEAT_PSYWAR 2 **** **** 1 0 14 12 14 16 10 10 WIS 0X00 0X0 0 CLASS_TYPE_PSYWAR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_PSYWAR 0 1 0 0 -1 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 147 Soulknife 16790633 16823574 16823575 16823576 16823577 IR_SOULKNIFE 10 CLS_ATK_2 CLS_FEAT_SOULKN CLS_SAVTHR_BARD CLS_SKILL_SOULKN CLS_BFEAT_SOULKN 4 **** **** 1 0 16 15 14 10 10 10 STR 0X00 0X0 0 CLASS_TYPE_SOULKNIFE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SOULKN 0 1 0 0 -1 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 148 Wilder 16790634 16823578 16823579 16823580 16823581 IR_WILDER 6 CLS_ATK_2 CLS_FEAT_WILDER CLS_SAVTHR_WIZ CLS_SKILL_WILDER CLS_BFEAT_WILDER 4 **** **** 1 0 15 9 14 13 10 15 CHA 0X00 0X0 0 CLASS_TYPE_WILDER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WILDER 0 1 0 0 -1 9 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 149 Thayan_Knight 16790635 16823506 16823507 16823508 16823509 IR_TKNIGHT 10 CLS_ATK_1 CLS_FEAT_THAYKT CLS_SAVTHR_FIGHT CLS_SKILL_THAYKT CLS_BFEAT_THAYKT 2 **** **** 0 0 12 16 14 8 14 12 STR 0X08 0X2 0 CLASS_TYPE_THAYAN_KNIGHT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_THAYKT 5 0 0 0 5 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -150 Red_Wizard 16790636 16822370 16822371 16822372 16822373 RED_WIZARD_PRC 4 CLS_ATK_3 CLS_FEAT_REDWIZ CLS_SAVTHR_WIZ CLS_SKILL_REDWIZ CLS_BFEAT_REDWIZ 2 **** **** 0 0 12 16 14 8 14 12 INT 0X08 0X2 0 CLASS_TYPE_RED_WIZARD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_REDWIZ 30 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -151 True_Necro 16790637 16822374 16822375 16822376 16822377 ir_truenecro 4 CLS_ATK_3 CLS_FEAT_TNECRO CLS_SAVTHR_WIZ CLS_SKILL_TNECRO CLS_BFEAT_TNECRO 2 **** **** 1 0 12 16 14 8 14 12 INT 0x08 0x3 0 CLASS_TYPE_TNECRO 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_TNECRO 30 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -152 Arcane_Trickster 16790638 16822378 16822379 16822380 16822381 IR_MAGEKILL 4 CLS_ATK_3 CLS_FEAT_ARCTRK CLS_SAVTHR_BARD CLS_SKILL_ARCTRK CLS_BFEAT_ARCTRK 4 **** **** 1 0 12 16 14 8 14 12 INT 0X02 0X1 0 CLASS_TYPE_ARCTRICK 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ARCTRK 30 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -153 Blood_Magus 16777216 16822382 16822383 16822384 16822385 IR_BLMAGUS 6 CLS_ATK_3 CLS_FEAT_BLMAGUS CLS_SAVTHR_FIGHT CLS_SKILL_BLMAGU CLS_BFEAT_BLMAGU 2 **** **** 0 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_BLOOD_MAGUS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BLMAGUS 10 0 2 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -154 Diabolist 16790639 16822386 16822387 16822388 16822389 IR_ACOLYTE 4 CLS_ATK_3 CLS_FEAT_DIABOL CLS_SAVTHR_WIZ CLS_SKILL_DIABOL CLS_BFEAT_DIABOL 2 **** **** 1 0 12 16 14 8 14 12 INT 0X0D 0X3 0 CLASS_TYPE_DIABOLIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DIABOL 30 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -155 Fist_Hextor 16790640 16822390 16822391 16822392 16822393 IR_HEXTOR 10 CLS_ATK_1 CLS_FEAT_HEXTOR CLS_SAVTHR_FIGHT CLS_SKILL_HEXTOR CLS_BFEAT_HEXTOR 2 **** **** 1 0 12 16 14 8 14 12 STR 0X0C 0X3 0 CLASS_TYPE_HEXTOR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HEXTOR 30 0 0 0 10 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -156 IncandescentChampion 16790641 16837917 16837918 16837919 16837920 IR_TEMPEST 10 CLS_ATK_2 CLS_FEAT_INCAND CLS_SAVTHR_WIZ CLS_SKILL_INCAND CLS_BFEAT_INCAND 2 **** **** 1 0 16 14 14 14 10 8 STR 0X08 0X2 1 CLASS_TYPE_INCANDESCENT_CHAMPION 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_INCAND 10 0 0 0 10 17 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -157 JusticeOfWealdAndWoe 16790642 16847276 16847277 16847278 16847279 IR_JUSTWW 8 CLS_ATK_2 CLS_FEAT_JUSTWW CLS_SAVTHR_WILD CLS_SKILL_JUSTWW CLS_BFEAT_JUSTWW 4 CLS_SPGN_JUSTWW CLS_SPKN_JUSTWW 1 1 12 16 14 8 14 12 DEX 0x00 0x0 0 CLASS_TYPE_JUSTICEWW 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_JUSTWW 10 0 0 0 10 4 3 **** **** **** **** **** **** **** **** **** Justiceww **** **** **** **** **** -158 AcolyteOfTheEgo 16790643 16834483 16834484 16834484 16834486 ir_acolyteego 8 CLS_ATK_1 CLS_FEAT_ACEGO CLS_SAVTHR_FIGHT CLS_SKILL_ACEGO CLS_BFEAT_ACEGO 4 **** **** 1 0 15 9 14 13 10 15 WIS 0X00 0X0 0 CLASS_TYPE_ACOLYTE_EGO 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ACEGO 10 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -159 Peerless_Archer 16790644 16822520 16822521 16822522 16822523 IR_ARCHER 10 CLS_ATK_1 CLS_FEAT_PARCH CLS_SAVTHR_FIGHT CLS_SKILL_PARCH CLS_BFEAT_PARCH 2 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_PEERLESS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_PARCH 10 0 0 0 10 55 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -160 Lasher 16790645 16824616 16824617 16824618 16824619 IR_LASHER 10 CLS_ATK_1 CLS_FEAT_LASHER CLS_SAVTHR_ROG CLS_SKILL_LASHER CLS_BFEAT_LASHER 2 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_LASHER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_LASHER 30 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -161 Bow_Initiate 16790646 16826374 16826375 16826376 16826377 IR_OOTBI 8 CLS_ATK_1 CLS_FEAT_OOTBI CLS_SAVTHR_BARD CLS_SKILL_OOTBI CLS_BFEAT_OOTBI 2 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_ORDER_BOW_INITIATE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_OOTBI 30 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +150 Red_Wizard 16790636 16822370 16822371 16822372 16822373 RED_WIZARD_PRC 4 CLS_ATK_3 CLS_FEAT_REDWIZ CLS_SAVTHR_WIZ CLS_SKILL_REDWIZ CLS_BFEAT_REDWIZ 2 **** **** 0 0 12 16 14 8 14 12 INT 0X08 0X2 0 CLASS_TYPE_RED_WIZARD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_REDWIZ 40 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +151 True_Necro 16790637 16822374 16822375 16822376 16822377 ir_truenecro 4 CLS_ATK_3 CLS_FEAT_TNECRO CLS_SAVTHR_WIZ CLS_SKILL_TNECRO CLS_BFEAT_TNECRO 2 **** **** 1 0 12 16 14 8 14 12 INT 0x08 0x3 0 CLASS_TYPE_TNECRO 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_TNECRO 40 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +152 Arcane_Trickster 16790638 16822378 16822379 16822380 16822381 IR_MAGEKILL 4 CLS_ATK_3 CLS_FEAT_ARCTRK CLS_SAVTHR_BARD CLS_SKILL_ARCTRK CLS_BFEAT_ARCTRK 4 **** **** 1 0 12 16 14 8 14 12 INT 0X02 0X1 0 CLASS_TYPE_ARCTRICK 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ARCTRK 40 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +153 Blood_Magus 16777216 16822382 16822383 16822384 16822385 IR_BLMAGUS 6 CLS_ATK_3 CLS_FEAT_BLMAGUS CLS_SAVTHR_FIGHT CLS_SKILL_BLMAGU CLS_BFEAT_BLMAGU 2 **** **** 0 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_BLOOD_MAGUS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BLMAGUS 40 0 2 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +154 Diabolist 16790639 16822386 16822387 16822388 16822389 IR_ACOLYTE 4 CLS_ATK_3 CLS_FEAT_DIABOL CLS_SAVTHR_WIZ CLS_SKILL_DIABOL CLS_BFEAT_DIABOL 2 **** **** 1 0 12 16 14 8 14 12 INT 0X0D 0X3 0 CLASS_TYPE_DIABOLIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DIABOL 40 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +155 Fist_Hextor 16790640 16822390 16822391 16822392 16822393 IR_HEXTOR 10 CLS_ATK_1 CLS_FEAT_HEXTOR CLS_SAVTHR_FIGHT CLS_SKILL_HEXTOR CLS_BFEAT_HEXTOR 2 **** **** 1 0 12 16 14 8 14 12 STR 0X0C 0X3 0 CLASS_TYPE_HEXTOR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HEXTOR 40 0 0 0 10 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +156 IncandescentChampion 16790641 16837917 16837918 16837919 16837920 IR_TEMPEST 10 CLS_ATK_2 CLS_FEAT_INCAND CLS_SAVTHR_WIZ CLS_SKILL_INCAND CLS_BFEAT_INCAND 2 **** **** 1 0 16 14 14 14 10 8 STR 0X08 0X2 1 CLASS_TYPE_INCANDESCENT_CHAMPION 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_INCAND 40 0 0 0 10 17 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +157 JusticeOfWealdAndWoe 16790642 16847276 16847277 16847278 16847279 IR_JUSTWW 8 CLS_ATK_2 CLS_FEAT_JUSTWW CLS_SAVTHR_WILD CLS_SKILL_JUSTWW CLS_BFEAT_JUSTWW 4 CLS_SPGN_JUSTWW CLS_SPKN_JUSTWW 1 1 12 16 14 8 14 12 DEX 0x00 0x0 0 CLASS_TYPE_JUSTICEWW 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_JUSTWW 40 0 0 0 10 4 3 **** **** **** **** **** **** **** **** **** Justiceww **** **** **** **** **** +158 AcolyteOfTheEgo 16790643 16834483 16834484 16834484 16834486 ir_acolyteego 8 CLS_ATK_1 CLS_FEAT_ACEGO CLS_SAVTHR_FIGHT CLS_SKILL_ACEGO CLS_BFEAT_ACEGO 4 **** **** 1 0 15 9 14 13 10 15 WIS 0X00 0X0 0 CLASS_TYPE_ACOLYTE_EGO 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ACEGO 40 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +159 Peerless_Archer 16790644 16822520 16822521 16822522 16822523 IR_ARCHER 10 CLS_ATK_1 CLS_FEAT_PARCH CLS_SAVTHR_FIGHT CLS_SKILL_PARCH CLS_BFEAT_PARCH 2 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_PEERLESS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_PARCH 40 0 0 0 10 55 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +160 Lasher 16790645 16824616 16824617 16824618 16824619 IR_LASHER 10 CLS_ATK_1 CLS_FEAT_LASHER CLS_SAVTHR_ROG CLS_SKILL_LASHER CLS_BFEAT_LASHER 2 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_LASHER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_LASHER 40 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +161 Bow_Initiate 16790646 16826374 16826375 16826376 16826377 IR_OOTBI 8 CLS_ATK_1 CLS_FEAT_OOTBI CLS_SAVTHR_BARD CLS_SKILL_OOTBI CLS_BFEAT_OOTBI 2 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_ORDER_BOW_INITIATE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_OOTBI 40 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 162 Hellfire_Warlock 16790647 16789986 16789987 16789988 16789989 IR_HFWRLK 6 CLS_ATK_2 CLS_FEAT_HFWRLK CLS_SAVTHR_WIZ CLS_SKILL_HFWRLK CLS_BFEAT_HFWRLK 2 **** **** 1 0 12 14 14 10 12 15 CHA 0X00 0X0 0 CLASS_TYPE_HELLFIRE_WARLOCK 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HFWRLK 3 0 0 0 3 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -163 Thrall_of_Orcus 16790648 16823320 16823321 16823322 16823323 IR_ORCUS 8 CLS_ATK_1 CLS_FEAT_ORCUS CLS_SAVTHR_CLER CLS_SKILL_ORCUS CLS_BFEAT_ORCUS 2 **** **** 1 0 12 16 14 8 14 12 INT 0X09 0X2 0 CLASS_TYPE_ORCUS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ORCUS 10 0 0 2 10 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +163 Thrall_of_Orcus 16790648 16823320 16823321 16823322 16823323 IR_ORCUS 8 CLS_ATK_1 CLS_FEAT_ORCUS CLS_SAVTHR_CLER CLS_SKILL_ORCUS CLS_BFEAT_ORCUS 2 **** **** 1 0 12 16 14 8 14 12 INT 0X09 0X2 0 CLASS_TYPE_ORCUS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ORCUS 40 0 0 2 10 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 164 Plant 16852499 16833077 16833078 16833079 16833080 IR_WIZARD 8 CLS_ATK_2 CLS_FEAT_CREA CLS_SAVTHR_FIGHT CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 1 0 10 15 11 15 14 18 STR 0X00 0X0 0 CLASS_TYPE_PLANT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_PLANT 0 0 0 0 -1 75 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -165 BlackFlame_Zealot 16790650 16823356 16823357 16823358 16823359 IR_BFZ 6 CLS_ATK_2 CLS_FEAT_BFZ CLS_SAVTHR_BARD CLS_SKILL_BFZ CLS_BFEAT_BFZ 4 **** **** 0 0 12 16 14 8 14 12 WIS 0X08 0X2 0 CLASS_TYPE_BFZ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BFZ 10 0 0 2 10 8 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -166 ShiningBlade 16790651 16823444 16823445 16823446 16823447 IR_HEIRONEOUS 10 CLS_ATK_1 CLS_FEAT_SBHEIR CLS_SAVTHR_CLER CLS_SKILL_SBHEIR CLS_BFEAT_SBHEIR 2 **** **** 1 0 15 9 14 13 10 15 WIS 0X15 0X3 0 CLASS_TYPE_SHINING_BLADE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SBHEIR 30 0 0 2 10 6 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -167 KnightMiddleCircle 16790652 16822468 16822469 16822470 16822471 IR_KOTMC 10 CLS_ATK_1 CLS_FEAT_KOTMC CLS_SAVTHR_WIZ CLS_SKILL_KOTMC CLS_BFEAT_KOTMC 4 CLS_SPGN_KOTMC **** 1 1 15 9 14 13 10 15 WIS 0X11 0X2 0 CLASS_TYPE_KNIGHT_MIDDLECIRCLE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_KOTMC 30 0 0 0 10 6 0 **** 1 0 0 0 0 0 0 WIS MiddleCircle 1 1 255 0 0 +165 BlackFlame_Zealot 16790650 16823356 16823357 16823358 16823359 IR_BFZ 6 CLS_ATK_2 CLS_FEAT_BFZ CLS_SAVTHR_BARD CLS_SKILL_BFZ CLS_BFEAT_BFZ 4 **** **** 0 0 12 16 14 8 14 12 WIS 0X08 0X2 0 CLASS_TYPE_BFZ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BFZ 40 0 0 2 10 8 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +166 ShiningBlade 16790651 16823444 16823445 16823446 16823447 IR_HEIRONEOUS 10 CLS_ATK_1 CLS_FEAT_SBHEIR CLS_SAVTHR_CLER CLS_SKILL_SBHEIR CLS_BFEAT_SBHEIR 2 **** **** 1 0 15 9 14 13 10 15 WIS 0X15 0X3 0 CLASS_TYPE_SHINING_BLADE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SBHEIR 40 0 0 2 10 6 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +167 KnightMiddleCircle 16790652 16822468 16822469 16822470 16822471 IR_KOTMC 10 CLS_ATK_1 CLS_FEAT_KOTMC CLS_SAVTHR_WIZ CLS_SKILL_KOTMC CLS_BFEAT_KOTMC 4 CLS_SPGN_KOTMC **** 1 1 15 9 14 13 10 15 WIS 0X11 0X2 0 CLASS_TYPE_KNIGHT_MIDDLECIRCLE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_KOTMC 40 0 0 0 10 6 0 **** 1 0 0 0 0 0 0 WIS MiddleCircle 1 1 255 0 0 168 Maester 16790653 16824556 16824557 16824558 16824559 IR_MAESTER 4 CLS_ATK_3 CLS_FEAT_MAESTR CLS_SAVTHR_WIZ CLS_SKILL_MAESTR CLS_BFEAT_MAESTR 4 **** **** 1 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_MAESTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MAESTR 5 0 1 0 5 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 169 Combat_Medic 16790654 16825644 16825645 16825646 16825647 IR_CBTMEDIC 6 CLS_ATK_3 CLS_FEAT_CBTMED CLS_SAVTHR_ROG CLS_SKILL_CBTMED CLS_BFEAT_CBTMED 2 **** **** 1 0 14 8 14 16 10 14 WIS 0X10 0X2 0 CLASS_TYPE_COMBAT_MEDIC 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_CBTMED 5 0 0 1 5 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 170 Ollam 16790655 16824982 16824983 16824984 16824985 IR_OLLAM 8 CLS_ATK_3 CLS_FEAT_OLLAM CLS_SAVTHR_WIZ CLS_SKILL_OLLAM CLS_BFEAT_OLLAM 6 **** **** 1 0 12 16 14 8 14 12 WIS 0X15 0X3 0 CLASS_TYPE_OLLAM 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_OLLAM 5 0 0 2 5 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 171 WarslingSniper 16790656 16825661 16825662 16825663 16825664 IR_WARSLING 6 CLS_ATK_1 CLS_FEAT_WRSLNG CLS_SAVTHR_ROG CLS_SKILL_WRSLNG CLS_BFEAT_WRSLNG 2 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_HALFLING_WARSLINGER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WRSLNG 6 0 0 0 6 8 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 172 **SpiritShaman** 16790657 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 173 Werewolf 16790658 16824716 16824717 16824718 16824719 IR_WILDWOLF 8 CLS_ATK_1 CLS_FEAT_WWOLF CLS_SAVTHR_ROG CLS_SKILL_WWOLF CLS_BFEAT_WWOLF 2 **** **** 1 0 14 14 14 15 10 10 DEX 0X02 0X1 0 CLASS_TYPE_WEREWOLF 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WWOLF 5 0 0 0 5 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -174 Hospitaler 16790659 16823380 16823381 16823382 16823383 IC_HOSPITALER 8 CLS_ATK_1 CLS_FEAT_HOSP CLS_SAVTHR_FIGHT CLS_SKILL_HOSP CLS_BFEAT_HOSP 2 **** **** 1 0 15 9 14 13 10 15 WIS 0X04 0X1 0 CLASS_TYPE_HOSPITALER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HOSP 30 0 0 1 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -175 MasterOfShrouds 16790660 16822343 16822344 16822345 16822346 IR_X1_SHADOW 8 CLS_ATK_1 CLS_FEAT_MOS CLS_SAVTHR_SORC CLS_SKILL_MOS CLS_BFEAT_MOS 2 **** **** 1 0 14 8 14 16 10 14 WIS 0X09 0X2 0 CLASS_TYPE_MASTER_OF_SHROUDS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MOS 30 0 0 1 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -176 MASTER_HARPER 16790661 16825217 16825218 16825219 16825220 IR_MH_MASTERH 6 CLS_ATK_2 CLS_FEAT_MHARP CLS_SAVTHR_BARD CLS_SKILL_MHARP CLS_BFEAT_MHARP 4 **** **** 0 0 12 14 14 10 12 15 CHA 0X10 0X2 0 CLASS_TYPE_MASTER_HARPER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MHARP 10 0 1 0 10 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -177 Frenzied_Berserker 16790662 16824216 16824217 16824218 16824219 IR_FREBZK 12 CLS_ATK_1 CLS_FEAT_FREBZK CLS_SAVTHR_BARB CLS_SKILL_FREBZK CLS_BFEAT_FREBZK 2 **** **** 1 0 16 14 14 14 10 8 STR 0X02 0X1 0 CLASS_TYPE_FRE_BERSERKER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FREBZK 30 0 0 0 10 17 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -178 Tempest 16790663 16824242 16824243 16824244 16824245 IR_TEMPEST 10 CLS_ATK_1 CLS_FEAT_TEMPST CLS_SAVTHR_BARB CLS_SKILL_TEMPST CLS_BFEAT_TEMPST 2 **** **** 1 0 10 16 12 10 16 10 DEX 0X00 0X0 0 CLASS_TYPE_TEMPEST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_TEMPST 30 0 0 0 10 7 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -179 Foe_Hunter 16790664 16824256 16824257 16824258 16824259 IR_FH 10 CLS_ATK_1 CLS_FEAT_FH CLS_SAVTHR_WILD CLS_SKILL_FH CLS_BFEAT_FH 2 **** **** 1 0 10 16 12 10 16 10 DEX 0X00 0X0 0 CLASS_TYPE_FOE_HUNTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FH 10 0 0 0 10 58 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -180 ***Eye_of_Gruumsh*** 16790665 16824294 16824295 16824296 16824297 IR_GRUUMSH 12 CLS_ATK_1 CLS_FEAT_EOG CLS_SAVTHR_BARB CLS_SKILL_EOG CLS_BFEAT_EOG 2 **** **** 0 0 16 14 14 14 10 8 STR 0X0A 0X3 0 CLASS_TYPE_PRC_EYE_OF_GRUUMSH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_EOG 10 0 0 0 10 17 0 cls_stat_eog **** **** **** **** **** **** **** **** **** **** **** **** **** **** +174 Hospitaler 16790659 16823380 16823381 16823382 16823383 IC_HOSPITALER 8 CLS_ATK_1 CLS_FEAT_HOSP CLS_SAVTHR_FIGHT CLS_SKILL_HOSP CLS_BFEAT_HOSP 2 **** **** 1 0 15 9 14 13 10 15 WIS 0X04 0X1 0 CLASS_TYPE_HOSPITALER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HOSP 40 0 0 1 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +175 MasterOfShrouds 16790660 16822343 16822344 16822345 16822346 IR_X1_SHADOW 8 CLS_ATK_1 CLS_FEAT_MOS CLS_SAVTHR_SORC CLS_SKILL_MOS CLS_BFEAT_MOS 2 **** **** 1 0 14 8 14 16 10 14 WIS 0X09 0X2 0 CLASS_TYPE_MASTER_OF_SHROUDS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MOS 40 0 0 1 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +176 ArcaneMasterHarper 16790661 16825217 16825218 16825219 16825220 IR_MH_MASTERH 6 CLS_ATK_2 CLS_FEAT_MHARP CLS_SAVTHR_BARD CLS_SKILL_MHARP CLS_BFEAT_MHARP 4 **** **** 0 0 12 14 14 10 12 15 CHA 0X10 0X2 0 CLASS_TYPE_MASTER_HARPER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MHARP 40 0 1 0 10 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +177 Frenzied_Berserker 16790662 16824216 16824217 16824218 16824219 IR_FREBZK 12 CLS_ATK_1 CLS_FEAT_FREBZK CLS_SAVTHR_BARB CLS_SKILL_FREBZK CLS_BFEAT_FREBZK 2 **** **** 1 0 16 14 14 14 10 8 STR 0X02 0X1 0 CLASS_TYPE_FRE_BERSERKER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FREBZK 40 0 0 0 10 17 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +178 Tempest 16790663 16824242 16824243 16824244 16824245 IR_TEMPEST 10 CLS_ATK_1 CLS_FEAT_TEMPST CLS_SAVTHR_BARB CLS_SKILL_TEMPST CLS_BFEAT_TEMPST 2 **** **** 1 0 10 16 12 10 16 10 DEX 0X00 0X0 0 CLASS_TYPE_TEMPEST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_TEMPST 40 0 0 0 10 7 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +179 Foe_Hunter 16790664 16824256 16824257 16824258 16824259 IR_FH 10 CLS_ATK_1 CLS_FEAT_FH CLS_SAVTHR_WILD CLS_SKILL_FH CLS_BFEAT_FH 2 **** **** 1 0 10 16 12 10 16 10 DEX 0X00 0X0 0 CLASS_TYPE_FOE_HUNTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FH 40 0 0 0 10 58 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +180 Verdant_Lord 16855246 16855247 16855248 16855249 16855250 IR_DRUID 8 CLS_ATK_1 CLS_FEAT_VLORD CLS_SAVTHR_DRU CLS_SKILL_VLORD CLS_BFEAT_VLORD 4 **** **** 1 0 14 13 13 16 10 10 WIS 0X10 0X2 0 CLASS_VERDANT_LORD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_VLORD 40 0 0 1 10 3 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 181 Orc_Warlord 16790666 16824312 16824313 16824314 16824315 IR_ORCWAR 12 CLS_ATK_1 CLS_FEAT_ORCWAR CLS_SAVTHR_MONK CLS_SKILL_ORCWAR CLS_BFEAT_ORCWAR 2 **** **** 1 0 16 14 14 14 10 8 STR 0X08 0X2 0 CLASS_TYPE_ORC_WARLORD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ORCWAR 5 0 0 0 5 17 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -182 Thrall_of_Grazzt 16790667 16824516 16824517 16824518 16824519 IR_TOG 6 CLS_ATK_3 CLS_FEAT_TOG CLS_SAVTHR_WIZ CLS_SKILL_TOG CLS_BFEAT_TOG 4 **** **** 1 0 12 16 14 8 14 12 INT 0X09 0X2 0 CLASS_TYPE_THRALL_OF_GRAZZT_A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_TOG_A 30 0 2 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +182 Thrall_of_Grazzt 16790667 16824516 16824517 16824518 16824519 IR_TOG 6 CLS_ATK_3 CLS_FEAT_TOG CLS_SAVTHR_WIZ CLS_SKILL_TOG CLS_BFEAT_TOG 4 **** **** 1 0 12 16 14 8 14 12 INT 0X09 0X2 0 CLASS_TYPE_THRALL_OF_GRAZZT_A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_TOG_A 40 0 2 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 183 Necrocarnate 16790668 16838080 16838081 16838082 16838083 ir_truenecro 6 CLS_ATK_3 CLS_FEAT_NECRNM CLS_SAVTHR_WIZ CLS_SKILL_NECRNM CLS_BFEAT_BLANK 2 **** **** 1 0 12 16 14 8 14 12 INT 0X09 0X2 0 CLASS_TYPE_NECROCARNATE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_NECRNM 13 0 0 0 13 13 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -184 Eldritch_Disciple 16790669 16790013 16790014 16790015 16790016 IR_EDISC 8 CLS_ATK_2 CLS_FEAT_EDISC CLS_SAVTHR_CLER CLS_SKILL_EDISC CLS_BFEAT_EDISC 2 **** **** 1 0 14 8 14 16 10 14 WIS 0X00 0X0 0 CLASS_TYPE_ELDRITCH_DISCIPLE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_EDISC 10 0 0 1 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -185 Eldritch_Theurge 16790670 16790017 16790018 16790019 16790020 IR_ETHEUR 4 CLS_ATK_2 CLS_FEAT_ETHEUR CLS_SAVTHR_WIZ CLS_SKILL_ETHEUR CLS_BFEAT_ETHEUR 2 **** **** 1 0 10 14 14 12 16 10 INT 0X00 0X0 0 CLASS_TYPE_ELDRITCH_THEURGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ETHEUR 30 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -186 Ghost_Faced_Killer 16790671 16832352 16832353 16832354 16832355 IR_GFKILL_PRC 8 CLS_ATK_1 CLS_FEAT_GFKILL CLS_SAVTHR_FIGHT CLS_SKILL_GFKILL CLS_BFEAT_GFKILL 4 **** **** 1 0 16 13 16 10 10 9 STR 0X09 0X2 0 CLASS_TYPE_GHOST_FACED_KILLER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_GFKILL 30 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +184 Eldritch_Disciple 16790669 16790013 16790014 16790015 16790016 IR_EDISC 8 CLS_ATK_2 CLS_FEAT_EDISC CLS_SAVTHR_CLER CLS_SKILL_EDISC CLS_BFEAT_EDISC 2 **** **** 1 0 14 8 14 16 10 14 WIS 0X00 0X0 0 CLASS_TYPE_ELDRITCH_DISCIPLE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_EDISC 40 0 0 1 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +185 Eldritch_Theurge 16790670 16790017 16790018 16790019 16790020 IR_ETHEUR 4 CLS_ATK_2 CLS_FEAT_ETHEUR CLS_SAVTHR_WIZ CLS_SKILL_ETHEUR CLS_BFEAT_ETHEUR 2 **** **** 1 0 10 14 14 12 16 10 INT 0X00 0X0 0 CLASS_TYPE_ELDRITCH_THEURGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ETHEUR 40 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +186 Ghost_Faced_Killer 16790671 16832352 16832353 16832354 16832355 IR_GFKILL_PRC 8 CLS_ATK_1 CLS_FEAT_GFKILL CLS_SAVTHR_FIGHT CLS_SKILL_GFKILL CLS_BFEAT_GFKILL 4 **** **** 1 0 16 13 16 10 10 9 STR 0X09 0X2 0 CLASS_TYPE_GHOST_FACED_KILLER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_GFKILL 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 187 DreadNecromancer 16790672 16847586 16847587 16847588 16847589 IR_PALEMA 6 CLS_ATK_3 CLS_FEAT_DNECRO CLS_SAVTHR_WIZ CLS_SKILL_DNECRO CLS_BFEAT_DNECRO 2 CLS_SPGN_DNECRO CLS_SPKN_DNECRO 1 1 10 14 12 10 14 16 CHA 0X08 0X2 0 CLASS_TYPE_DREAD_NECROMANCER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DNECRO 0 1 0 0 -1 10 130 **** **** **** **** **** **** **** **** **** DreadNecro **** **** **** **** **** -188 UltimateMagus **** 16790350 16790351 16790352 16790353 IR_EPICSPELL 4 CLS_ATK_3 CLS_FEAT_UM CLS_SAVTHR_WIZ CLS_SKILL_UM CLS_BFEAT_UM 2 **** **** 0 0 10 11 11 16 16 10 INT 0X00 0X0 0 CLASS_TYPE_MYSTIC_THEURGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_UM 10 0 2 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -189 ForestMaster 16790673 16793736 16793737 16793738 16793739 IR_DRUID 8 CLS_ATK_2 CLS_FEAT_FORMAS CLS_SAVTHR_DRU CLS_SKILL_FORMAS CLS_BFEAT_FORMAS 2 **** **** 0 0 14 13 13 16 10 10 WIS 0X00 0X0 0 CLASS_TYPE_FORESTMASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FORMAS 10 0 0 1 10 3 0 cls_stat_formas **** **** **** **** **** **** **** **** **** **** **** **** **** **** +188 UltimateMagus **** 16790350 16790351 16790352 16790353 IR_EPICSPELL 4 CLS_ATK_3 CLS_FEAT_UM CLS_SAVTHR_WIZ CLS_SKILL_UM CLS_BFEAT_UM 2 **** **** 0 0 10 11 11 16 16 10 INT 0X00 0X0 0 CLASS_TYPE_MYSTIC_THEURGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_UM 40 0 2 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +189 ForestMaster 16790673 16793736 16793737 16793738 16793739 IR_DRUID 8 CLS_ATK_2 CLS_FEAT_FORMAS CLS_SAVTHR_DRU CLS_SKILL_FORMAS CLS_BFEAT_FORMAS 2 **** **** 0 0 14 13 13 16 10 10 WIS 0X00 0X0 0 CLASS_TYPE_FORESTMASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FORMAS 40 0 0 1 10 3 0 cls_stat_formas **** **** **** **** **** **** **** **** **** **** **** **** **** **** 190 Archivist 16790674 16789866 16789867 16789868 16789869 IR_ARCHIVIST 6 CLS_ATK_3 CLS_FEAT_ARCHV CLS_SAVTHR_CLER CLS_SKILL_ARCHV CLS_BFEAT_ARCHV 4 CLS_SPGN_ARCHV **** 1 1 10 14 14 12 16 10 INT 0X00 0X0 0 CLASS_TYPE_ARCHIVIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ARCHV 0 1 0 0 -1 10 65 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 191 DeepstoneSentinel 16790675 16829771 16829772 16829773 16829774 IR_DWDEF 10 CLS_ATK_2 CLS_FEAT_DEEPST CLS_SAVTHR_FIGHT CLS_SKILL_DEEPST CLS_BFEAT_DEEPST 2 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_DEEPSTONE_SENTINEL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DEEPST 5 0 0 0 5 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -192 JadePhoenixMage 16790676 16827181 16827182 16827183 16827184 IR_JPM 6 CLS_ATK_1 CLS_FEAT_JPM CLS_SAVTHR_FIGHT CLS_SKILL_JPM CLS_BFEAT_JPM 2 **** **** 1 0 14 14 14 10 16 8 INT 0X10 0X2 0 CLASS_TYPE_JADE_PHOENIX_MAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_JPM 10 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +192 JadePhoenixMage 16790676 16827181 16827182 16827183 16827184 IR_JPM 6 CLS_ATK_1 CLS_FEAT_JPM CLS_SAVTHR_FIGHT CLS_SKILL_JPM CLS_BFEAT_JPM 2 **** **** 1 0 14 14 14 10 16 8 INT 0X10 0X2 0 CLASS_TYPE_JADE_PHOENIX_MAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_JPM 40 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 193 BloodclawMaster 16790677 16827149 16827150 16827151 16827152 IR_BLOODCLAW 12 CLS_ATK_2 CLS_FEAT_BLDCLW CLS_SAVTHR_WILD CLS_SKILL_BLDCLW CLS_BFEAT_BLDCLW 2 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_BLOODCLAW_MASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BLDCLW 5 0 0 0 5 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -194 RubyKnightVindicator 16790678 16827167 16827168 16827169 16827170 IR_HEIRONEOUS 8 CLS_ATK_1 CLS_FEAT_RBYKNT CLS_SAVTHR_WIZ CLS_SKILL_RBYKNT CLS_BFEAT_RBYKNT 4 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_RUBY_VINDICATOR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_RBYKNT 10 0 0 1 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +194 RubyKnightVindicator 16790678 16827167 16827168 16827169 16827170 IR_HEIRONEOUS 8 CLS_ATK_1 CLS_FEAT_RBYKNT CLS_SAVTHR_WIZ CLS_SKILL_RBYKNT CLS_BFEAT_RBYKNT 4 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_RUBY_VINDICATOR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_RBYKNT 40 0 0 1 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 195 MasterOfNine 16790679 16847557 16847558 16847559 16847560 IR_PSYWARRIOR 8 CLS_ATK_2 CLS_FEAT_MONINE CLS_SAVTHR_WIZ CLS_SKILL_MONINE CLS_BFEAT_MONINE 6 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_MASTER_OF_NINE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MONINE 5 0 0 0 5 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -196 EternalBlade 16790680 16834750 16834751 16834752 16834753 IR_FH 10 CLS_ATK_1 CLS_FEAT_ETBL CLS_SAVTHR_FIGHT CLS_SKILL_ETBL CLS_BFEAT_ETBL 2 **** **** 1 0 16 13 16 10 10 9 STR 0X00 0X0 0 CLASS_TYPE_ETERNAL_BLADE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ETBL 10 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -197 ShadowSunNinja 16790681 16834778 16834779 16834780 16834781 IR_SHADADEPT 8 CLS_ATK_2 CLS_FEAT_SSN CLS_SAVTHR_MONK CLS_SKILL_SSN CLS_BFEAT_SSN 4 **** **** 0 0 16 13 16 10 10 9 STR 0X11 0X2 0 CLASS_TYPE_SHADOW_SUN_NINJA 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SSN 10 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -198 WitchbornBinder 16790682 16838144 16838145 16838146 16838147 IR_WITCH 6 CLS_ATK_2 CLS_FEAT_WCHBRN CLS_SAVTHR_WIZ CLS_SKILL_WCHBRN CLS_BFEAT_BLANK 4 **** **** 1 0 10 14 14 10 12 16 CHA 0X00 0X0 0 CLASS_TYPE_WITCHBORN_BINDER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WCHBRN 10 0 0 0 10 6 2 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -199 Baelnorn 16790683 16829216 16829217 16829218 16829219 IR_BAELNORN 4 CLS_ATK_4 CLS_FEAT_BAELN CLS_SAVTHR_LICH CLS_SKILL_WIZ CLS_BFEAT_LICH 2 **** **** 1 0 13 13 13 13 13 13 CHA 0X11 0X2 0 CLASS_TYPE_BAELNORN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BAELN 4 0 0 0 4 10 0 cls_stat_baeln **** **** **** **** **** **** **** **** **** **** **** **** **** **** -200 Disciple_of_Meph 16790684 16823016 16823017 16823018 16823019 IR_DISCMEPH 8 CLS_ATK_1 CLS_FEAT_MEPH CLS_SAVTHR_MONK CLS_SKILL_MEPH CLS_BFEAT_MEPH 4 **** **** 1 0 12 16 14 8 14 12 CHA 0X09 0X2 0 CLASS_TYPE_DISCIPLE_OF_MEPH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MEPH 10 0 0 0 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -201 Soul_Eater 16790685 16832116 16832117 16832118 16832119 IR_SOULEATER 8 CLS_ATK_1 CLS_FEAT_SLEAT CLS_SAVTHR_MONK CLS_SKILL_SLEAT CLS_BFEAT_SLEAT 4 **** **** 1 0 14 16 10 12 14 10 INT 0X09 0X2 0 CLASS_TYPE_SOUL_EATER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SLEAT 10 0 0 0 10 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -202 Henshin_Mystic 16790686 16825076 16825078 16825079 16825080 IR_HNSHN 8 CLS_ATK_2 CLS_FEAT_HNSHN CLS_SAVTHR_MONK CLS_SKILL_HNSHN CLS_BFEAT_HNSHN 4 **** **** 1 0 14 14 14 15 10 10 WIS 0X05 0X1 0 CLASS_TYPE_HENSHIN_MYSTIC 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HNSHN 10 0 0 0 10 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -203 Drunken_Master 16790687 16825095 16825097 16825098 16825099 IR_DRNKN 8 CLS_ATK_2 CLS_FEAT_DRNKN CLS_SAVTHR_RANG CLS_SKILL_DRNKN CLS_BFEAT_DRNKN 4 **** **** 1 0 14 14 14 15 10 10 WIS 0X00 0X0 0 CLASS_TYPE_DRUNKEN_MASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DRNKN 10 0 0 0 10 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -204 Enlightened_Fist 16790688 16829416 16829417 16829418 16829419 IR_SACREDFIST 8 CLS_ATK_2 CLS_FEAT_ENLFIS CLS_SAVTHR_BARD CLS_SKILL_ENLFIS CLS_BFEAT_ENLFIS 4 **** **** 1 0 10 14 12 14 16 10 DEX 0X00 0X0 0 CLASS_TYPE_ENLIGHTENEDFIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ENLFIS 10 0 1 0 10 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -205 Morninglord 16790689 16789624 16789625 16789626 16789627 IR_MORNING 8 CLS_ATK_2 CLS_FEAT_ML CLS_SAVTHR_CLER CLS_SKILL_ML CLS_BFEAT_ML 2 **** **** 0 0 14 8 14 16 10 14 CHA 0X11 0X2 0 CLASS_TYPE_MORNINGLORD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ML 30 0 0 1 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +196 EternalBlade 16790680 16834750 16834751 16834752 16834753 IR_FH 10 CLS_ATK_1 CLS_FEAT_ETBL CLS_SAVTHR_FIGHT CLS_SKILL_ETBL CLS_BFEAT_ETBL 2 **** **** 1 0 16 13 16 10 10 9 STR 0X00 0X0 0 CLASS_TYPE_ETERNAL_BLADE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ETBL 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +197 ShadowSunNinja 16790681 16834778 16834779 16834780 16834781 IR_SHADADEPT 8 CLS_ATK_2 CLS_FEAT_SSN CLS_SAVTHR_MONK CLS_SKILL_SSN CLS_BFEAT_SSN 4 **** **** 0 0 16 13 16 10 10 9 STR 0X11 0X2 0 CLASS_TYPE_SHADOW_SUN_NINJA 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SSN 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +198 WitchbornBinder 16790682 16838144 16838145 16838146 16838147 IR_WITCH 6 CLS_ATK_2 CLS_FEAT_WCHBRN CLS_SAVTHR_WIZ CLS_SKILL_WCHBRN CLS_BFEAT_BLANK 4 **** **** 1 0 10 14 14 10 12 16 CHA 0X00 0X0 0 CLASS_TYPE_WITCHBORN_BINDER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WCHBRN 40 0 0 0 10 6 2 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +199 Lion_of_Talisid 16855216 16855217 16855218 16855219 16855220 IR_LIONTALISID 8 CLS_ATK_2 CLS_FEAT_LOT CLS_SAVTHR_DRU CLS_SKILL_LOT CLS_BFEAT_LOT 4 **** **** 1 0 14 13 13 16 10 10 WIS 0X16 0X3 0 CLASS_TYPE_LION_OF_TALISID 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_LOT 40 0 0 1 10 3 0 **** **** **** **** **** **** **** **** **** **** **** **** 1 **** **** +200 Disciple_of_Meph 16790684 16823016 16823017 16823018 16823019 IR_DISCMEPH 8 CLS_ATK_1 CLS_FEAT_MEPH CLS_SAVTHR_MONK CLS_SKILL_MEPH CLS_BFEAT_MEPH 4 **** **** 1 0 12 16 14 8 14 12 CHA 0X09 0X2 0 CLASS_TYPE_DISCIPLE_OF_MEPH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MEPH 40 0 0 0 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +201 Soul_Eater 16790685 16832116 16832117 16832118 16832119 IR_SOULEATER 8 CLS_ATK_1 CLS_FEAT_SLEAT CLS_SAVTHR_MONK CLS_SKILL_SLEAT CLS_BFEAT_SLEAT 4 **** **** 1 0 14 16 10 12 14 10 INT 0X09 0X2 0 CLASS_TYPE_SOUL_EATER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SLEAT 40 0 0 0 10 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +202 Henshin_Mystic 16790686 16825076 16825078 16825079 16825080 IR_HNSHN 8 CLS_ATK_2 CLS_FEAT_HNSHN CLS_SAVTHR_MONK CLS_SKILL_HNSHN CLS_BFEAT_HNSHN 4 **** **** 1 0 14 14 14 15 10 10 WIS 0X05 0X1 0 CLASS_TYPE_HENSHIN_MYSTIC 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HNSHN 40 0 0 0 10 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +203 Drunken_Master 16790687 16825095 16825097 16825098 16825099 IR_DRNKN 8 CLS_ATK_2 CLS_FEAT_DRNKN CLS_SAVTHR_RANG CLS_SKILL_DRNKN CLS_BFEAT_DRNKN 4 **** **** 1 0 14 14 14 15 10 10 WIS 0X00 0X0 0 CLASS_TYPE_DRUNKEN_MASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DRNKN 40 0 0 0 10 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +204 Enlightened_Fist 16790688 16829416 16829417 16829418 16829419 IR_SACREDFIST 8 CLS_ATK_2 CLS_FEAT_ENLFIS CLS_SAVTHR_BARD CLS_SKILL_ENLFIS CLS_BFEAT_ENLFIS 4 **** **** 1 0 10 14 12 14 16 10 DEX 0X00 0X0 0 CLASS_TYPE_ENLIGHTENEDFIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ENLFIS 40 0 1 0 10 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +205 Morninglord 16790689 16789624 16789625 16789626 16789627 IR_MORNING 8 CLS_ATK_2 CLS_FEAT_ML CLS_SAVTHR_CLER CLS_SKILL_ML CLS_BFEAT_ML 2 **** **** 0 0 14 8 14 16 10 14 CHA 0X11 0X2 0 CLASS_TYPE_MORNINGLORD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ML 40 0 0 1 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 206 IncarnumBlade 16790690 16838136 16838137 16838138 16838139 IR_CRUSADER 10 CLS_ATK_1 CLS_FEAT_IBLADE CLS_SAVTHR_FIGHT CLS_SKILL_IBLADE CLS_BFEAT_BLANK 2 **** **** 1 0 16 14 14 14 10 8 STR 0X01 0X3 0 CLASS_TYPE_INCARNUM_BLADE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_IBLADE 5 0 0 0 5 17 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 207 OAShaman 16790691 16827659 16827660 16827661 16827662 IR_CLERIC 6 CLS_ATK_2 CLS_FEAT_SHAMAN CLS_SAVTHR_WIZ CLS_SKILL_SHAMAN CLS_BFEAT_SHAMAN 4 CLS_SPGN_SHAMAN **** 1 1 10 13 12 16 13 12 WIS 0X00 0X0 0 CLASS_TYPE_SHAMAN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHAMAN 0 1 0 0 -1 2 0 **** 1 0 1 0 0 0 0 WIS Shaman 1 1 1 0 0 -208 Pyrokineticist 16790692 16827043 16827044 16827045 16827046 IR_BFZ 8 CLS_ATK_2 CLS_FEAT_PYRO CLS_SAVTHR_WILD CLS_SKILL_PYRO CLS_BFEAT_ELDKNI 2 **** **** 1 0 10 14 14 10 12 16 CHA 0X03 0X1 0 CLASS_TYPE_PYROKINETICIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_PYRO 10 0 0 0 10 9 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -209 Shadowmind 16790693 16829364 16829365 16829366 16829367 IR_TFSHAD 6 CLS_ATK_2 CLS_FEAT_SDMIND CLS_SAVTHR_BARD CLS_SKILL_SDMIND CLS_BFEAT_SDMIND 4 **** **** 1 0 10 11 11 16 16 10 INT 0X00 0X0 0 CLASS_TYPE_SHADOWMIND 1 1 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SDMIND 10 0 0 0 10 8 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -210 Psychic_Thurge 16790694 16823908 16823909 16823910 16823911 IR_PSYCHIC 4 CLS_ATK_3 CLS_FEAT_PSYCH CLS_SAVTHR_WIZ CLS_SKILL_PSYCH CLS_BFEAT_PSYCH 2 **** **** 1 0 10 11 11 16 16 10 INT 0X00 0X0 0 CLASS_TYPE_PSYCHIC_THEURGE 1 1 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_PSYCH 30 0 0 1 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -211 Cerebremancer 16790695 16823912 16823913 16823914 16823915 IR_CEREBRE 4 CLS_ATK_3 CLS_FEAT_CEREB CLS_SAVTHR_WIZ CLS_SKILL_CEREB CLS_BFEAT_CEREB 2 **** **** 1 0 10 11 11 16 16 10 INT 0X00 0X0 0 CLASS_TYPE_CEREBREMANCER 1 1 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_CEREB 30 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -212 Thrallherd 16790696 16823940 16823941 16823942 16823943 IR_THRALLHERD 4 CLS_ATK_3 CLS_FEAT_THRALL CLS_SAVTHR_WIZ CLS_SKILL_THRALL CLS_BFEAT_THRALL 2 **** **** 1 0 10 11 11 16 16 10 INT 0X00 0X0 0 CLASS_TYPE_THRALLHERD 1 1 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_THRALL 10 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -213 FistOfZouken 16790697 16823964 16823965 16823966 16823967 IR_ZUOKEN 6 CLS_ATK_2 CLS_FEAT_FOZ CLS_SAVTHR_BARD CLS_SKILL_FOZ CLS_BFEAT_FOZ 4 **** **** 1 0 10 11 11 16 16 10 INT 0X00 0X0 0 CLASS_TYPE_FIST_OF_ZUOKEN 1 1 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FOZ 10 0 0 0 10 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +208 Pyrokineticist 16790692 16827043 16827044 16827045 16827046 IR_BFZ 8 CLS_ATK_2 CLS_FEAT_PYRO CLS_SAVTHR_WILD CLS_SKILL_PYRO CLS_BFEAT_PYRO 2 **** **** 1 0 10 14 14 10 12 16 CHA 0X03 0X1 0 CLASS_TYPE_PYROKINETICIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_PYRO 40 0 0 0 10 9 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +209 Shadowmind 16790693 16829364 16829365 16829366 16829367 IR_TFSHAD 6 CLS_ATK_2 CLS_FEAT_SDMIND CLS_SAVTHR_BARD CLS_SKILL_SDMIND CLS_BFEAT_SDMIND 4 **** **** 1 0 10 11 11 16 16 10 INT 0X00 0X0 0 CLASS_TYPE_SHADOWMIND 1 1 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SDMIND 40 0 0 0 10 8 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +210 Psychic_Thurge 16790694 16823908 16823909 16823910 16823911 IR_PSYCHIC 4 CLS_ATK_3 CLS_FEAT_PSYCH CLS_SAVTHR_WIZ CLS_SKILL_PSYCH CLS_BFEAT_PSYCH 2 **** **** 1 0 10 11 11 16 16 10 INT 0X00 0X0 0 CLASS_TYPE_PSYCHIC_THEURGE 1 1 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_PSYCH 40 0 0 1 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +211 Cerebremancer 16790695 16823912 16823913 16823914 16823915 IR_CEREBRE 4 CLS_ATK_3 CLS_FEAT_CEREB CLS_SAVTHR_WIZ CLS_SKILL_CEREB CLS_BFEAT_CEREB 2 **** **** 1 0 10 11 11 16 16 10 INT 0X00 0X0 0 CLASS_TYPE_CEREBREMANCER 1 1 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_CEREB 40 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +212 Thrallherd 16790696 16823940 16823941 16823942 16823943 IR_THRALLHERD 4 CLS_ATK_3 CLS_FEAT_THRALL CLS_SAVTHR_WIZ CLS_SKILL_THRALL CLS_BFEAT_THRALL 2 **** **** 1 0 10 11 11 16 16 10 INT 0X00 0X0 0 CLASS_TYPE_THRALLHERD 1 1 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_THRALL 40 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +213 FistOfZouken 16790697 16823964 16823965 16823966 16823967 IR_ZUOKEN 6 CLS_ATK_2 CLS_FEAT_FOZ CLS_SAVTHR_BARD CLS_SKILL_FOZ CLS_BFEAT_FOZ 4 **** **** 1 0 10 11 11 16 16 10 INT 0X00 0X0 0 CLASS_TYPE_FIST_OF_ZUOKEN 1 1 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FOZ 40 0 0 0 10 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 214 HavocMage 16790698 16826709 16826710 16826711 16826712 IR_HAVOCMAGE 8 CLS_ATK_2 CLS_FEAT_HAVOCM CLS_SAVTHR_CLER CLS_SKILL_HAVOCM CLS_BFEAT_HAVOCM 2 **** **** 1 0 10 11 11 16 16 10 INT 0X00 0X0 0 CLASS_TYPE_HAVOC_MAGE 1 1 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HAVOCM 5 0 2 0 5 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -215 Contemplative 16790699 16832016 16832017 16832018 16832019 IR_CONTEMPLATIVE 6 CLS_ATK_3 CLS_FEAT_CNTMP CLS_SAVTHR_WIZ CLS_SKILL_CNTMP CLS_BFEAT_CNTMP 2 **** **** 1 0 12 16 14 8 14 12 WIS 0X00 0X0 0 CLASS_TYPE_CONTEMPLATIVE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_CNTMP 10 0 0 1 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -216 Runecaster 16790700 16831969 16831970 16831971 16831972 IC_RUNECASTER 8 CLS_ATK_2 CLS_FEAT_RUNEC CLS_SAVTHR_CLER CLS_SKILL_RUNEC CLS_BFEAT_RUNEC 2 **** **** 1 0 15 9 14 13 10 15 WIS 0X00 0X0 0 CLASS_TYPE_RUNECASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_RUNEC 30 0 0 1 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -217 Warchief 16790701 16825714 16825715 16825716 16825717 IR_WARCHIEF 10 CLS_ATK_2 CLS_FEAT_WARCHF CLS_SAVTHR_CLER CLS_SKILL_WARCHF CLS_BFEAT_WARCHF 2 **** **** 1 0 14 16 10 12 14 10 INT 0X00 0X0 0 CLASS_TYPE_WARCHIEF 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WARCHF 30 0 0 0 10 0 0 cls_stat_warchf **** **** **** **** **** **** **** **** **** **** **** **** **** **** -218 Warmind 16790702 16825724 16825725 16825726 16825727 IR_ELDKNI 10 CLS_ATK_1 CLS_FEAT_WARMND CLS_SAVTHR_WILD CLS_SKILL_WARMND CLS_BFEAT_WARMND 2 **** **** 1 0 14 12 14 16 10 10 WIS 0X04 0X1 0 CLASS_TYPE_WARMIND 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WARMND 10 0 0 0 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -219 IronMind 16790703 16822552 16822553 16822554 16822555 IC_IRONMIND 10 CLS_ATK_2 CLS_FEAT_IRNMND CLS_SAVTHR_WIZ CLS_SKILL_IRNMND CLS_BFEAT_IRNMND 2 **** **** 1 0 15 9 14 13 10 15 WIS 0X00 0X0 0 CLASS_TYPE_IRONMIND 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_IRNMND 10 0 0 0 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +215 Contemplative 16790699 16832016 16832017 16832018 16832019 IR_CONTEMPLATIVE 6 CLS_ATK_3 CLS_FEAT_CNTMP CLS_SAVTHR_WIZ CLS_SKILL_CNTMP CLS_BFEAT_CNTMP 2 **** **** 1 0 12 16 14 8 14 12 WIS 0X00 0X0 0 CLASS_TYPE_CONTEMPLATIVE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_CNTMP 40 0 0 1 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +216 Runecaster 16790700 16831969 16831970 16831971 16831972 IC_RUNECASTER 8 CLS_ATK_2 CLS_FEAT_RUNEC CLS_SAVTHR_CLER CLS_SKILL_RUNEC CLS_BFEAT_RUNEC 2 **** **** 1 0 15 9 14 13 10 15 WIS 0X00 0X0 0 CLASS_TYPE_RUNECASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_RUNEC 40 0 0 1 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +217 Warchief 16790701 16825714 16825715 16825716 16825717 IR_WARCHIEF 10 CLS_ATK_2 CLS_FEAT_WARCHF CLS_SAVTHR_CLER CLS_SKILL_WARCHF CLS_BFEAT_WARCHF 2 **** **** 1 0 14 16 10 12 14 10 INT 0X00 0X0 0 CLASS_TYPE_WARCHIEF 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WARCHF 40 0 0 0 10 0 0 cls_stat_warchf **** **** **** **** **** **** **** **** **** **** **** **** **** **** +218 Warmind 16790702 16825724 16825725 16825726 16825727 IR_ELDKNI 10 CLS_ATK_1 CLS_FEAT_WARMND CLS_SAVTHR_WILD CLS_SKILL_WARMND CLS_BFEAT_WARMND 2 **** **** 1 0 14 12 14 16 10 10 WIS 0X04 0X1 0 CLASS_TYPE_WARMIND 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WARMND 40 0 0 0 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +219 IronMind 16790703 16822552 16822553 16822554 16822555 IC_IRONMIND 10 CLS_ATK_2 CLS_FEAT_IRNMND CLS_SAVTHR_WIZ CLS_SKILL_IRNMND CLS_BFEAT_IRNMND 2 **** **** 1 0 15 9 14 13 10 15 WIS 0X00 0X0 0 CLASS_TYPE_IRONMIND 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_IRNMND 40 0 0 0 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 220 SanctifiedMind 16790704 16822568 16822569 16822570 16822571 IR_THRALLHERD 8 CLS_ATK_1 CLS_FEAT_SNCMND CLS_SAVTHR_CLER CLS_SKILL_SNCMND CLS_BFEAT_SNCMND 4 **** **** 1 0 15 9 14 13 10 15 WIS 0X10 0X2 0 CLASS_TYPE_SANCTIFIED_MIND 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SNCMND 6 0 0 1 6 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -221 SlayerOfDomiel 16790705 16827566 16827567 16827568 16827569 IR_HEIRONEOUS 6 CLS_ATK_2 CLS_FEAT_SOD CLS_SAVTHR_ROG CLS_SKILL_SOD CLS_BFEAT_SOD 4 CLS_SPGN_SOD **** 1 1 15 9 14 13 10 15 WIS 0X15 0X3 0 CLASS_TYPE_SLAYER_OF_DOMIEL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SOD 10 0 0 0 10 2 0 **** 1 0 0 0 0 0 0 WIS Domiel 1 1 255 0 0 -222 DiscipleOfAsmodeus 16790706 16822624 16822625 16822626 16822627 IR_SOULEATER 6 CLS_ATK_2 CLS_FEAT_DOA CLS_SAVTHR_WIZ CLS_SKILL_DOA CLS_BFEAT_DOA 4 **** **** 1 0 15 9 14 13 10 15 WIS 0X09 0X2 0 CLASS_TYPE_DISCIPLE_OF_ASMODEUS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DOA 10 0 2 0 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +221 SlayerOfDomiel 16790705 16827566 16827567 16827568 16827569 IR_HEIRONEOUS 6 CLS_ATK_2 CLS_FEAT_SOD CLS_SAVTHR_ROG CLS_SKILL_SOD CLS_BFEAT_SOD 4 CLS_SPGN_SOD **** 1 1 15 9 14 13 10 15 WIS 0X15 0X3 0 CLASS_TYPE_SLAYER_OF_DOMIEL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SOD 40 0 0 0 10 2 0 **** 1 0 0 0 0 0 0 WIS Domiel 1 1 255 0 0 +222 DiscipleOfAsmodeus 16790706 16822624 16822625 16822626 16822627 IR_SOULEATER 6 CLS_ATK_2 CLS_FEAT_DOA CLS_SAVTHR_WIZ CLS_SKILL_DOA CLS_BFEAT_DOA 4 **** **** 1 0 15 9 14 13 10 15 WIS 0X09 0X2 0 CLASS_TYPE_DISCIPLE_OF_ASMODEUS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DOA 40 0 2 0 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 223 Dirgesinger 16790707 16822584 16822585 16822586 16822587 IR_PALEMA 6 CLS_ATK_2 CLS_FEAT_DIRGE CLS_SAVTHR_WIZ CLS_SKILL_DIRGE CLS_BFEAT_DIRGE 4 **** **** 1 0 15 9 14 13 10 15 WIS 0X08 0X2 0 CLASS_TYPE_DIRGESINGER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DIRGE 5 0 0 0 5 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -224 Suel_Archanamach 16790708 16822598 16822599 16822600 16822601 IR_HAVOCMAGE 8 CLS_ATK_2 CLS_FEAT_SUEL CLS_SAVTHR_BARD CLS_SKILL_SUEL CLS_BFEAT_SUEL 4 CLS_SPGN_SUEL CLS_SPKN_SUEL 0 1 14 14 14 15 10 10 WIS 0X00 0X0 0 CLASS_TYPE_SUEL_ARCHANAMACH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SUEL 10 0 0 0 10 10 131 **** **** **** **** **** **** **** **** **** Suel **** **** **** **** **** +224 Suel_Archanamach 16790708 16822598 16822599 16822600 16822601 IR_HAVOCMAGE 8 CLS_ATK_2 CLS_FEAT_SUEL CLS_SAVTHR_BARD CLS_SKILL_SUEL CLS_BFEAT_SUEL 4 CLS_SPGN_SUEL CLS_SPKN_SUEL 0 1 14 14 14 15 10 10 WIS 0X00 0X0 0 CLASS_TYPE_SUEL_ARCHANAMACH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SUEL 40 0 0 0 10 10 131 **** **** **** **** **** **** **** **** **** Suel **** **** **** **** **** 225 Favoured_Soul 16790709 16822610 16822611 16822612 16822613 IR_SPELLFIRE 8 CLS_ATK_2 CLS_FEAT_FAVSOL CLS_SAVTHR_MONK CLS_SKILL_FAVSOL CLS_BFEAT_FAVSOL 2 CLS_SPGN_FAVSOL CLS_SPKN_FAVSOL 1 1 10 14 12 14 10 16 CHA 0X00 0X0 0 CLASS_TYPE_FAVOURED_SOUL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FAVSOL 20 1 0 0 -1 2 3 **** **** **** **** **** **** **** **** **** FavoredSoul **** **** **** **** **** 226 WarWizardOfCormyr 16790710 16822644 16822645 16822646 16822647 IC_RUNE 4 CLS_ATK_3 CLS_FEAT_WWOC CLS_SAVTHR_CLER CLS_SKILL_WWOC CLS_BFEAT_WWOC 2 **** **** 0 0 12 16 14 8 14 12 INT 0X14 0X3 0 CLASS_TYPE_WAR_WIZARD_OF_CORMYR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WWOC 5 0 1 0 5 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -227 SkullclanHunter 16790711 16824867 16824868 16824869 16824870 IR_SKULLCLAN 6 CLS_ATK_2 CLS_FEAT_SKLCLN CLS_SAVTHR_BARD CLS_SKILL_SKLCLN CLS_BFEAT_SKLCLN 6 **** **** 1 0 14 14 14 15 10 10 WIS 0X11 0X2 0 CLASS_TYPE_SKULLCLAN_HUNTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SKLCLN 10 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +227 SkullclanHunter 16790711 16824867 16824868 16824869 16824870 IR_SKULLCLAN 6 CLS_ATK_2 CLS_FEAT_SKLCLN CLS_SAVTHR_BARD CLS_SKILL_SKLCLN CLS_BFEAT_SKLCLN 6 **** **** 1 0 14 14 14 15 10 10 WIS 0X11 0X2 0 CLASS_TYPE_SKULLCLAN_HUNTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SKLCLN 40 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 228 Truenamer 16790712 16828481 16828482 16828483 16828484 IR_TRUENAME 6 CLS_ATK_2 CLS_FEAT_TRUE CLS_SAVTHR_BARD CLS_SKILL_TRUE CLS_BFEAT_TRUE 4 **** **** 1 0 10 12 14 10 16 14 INT 0X00 0X0 0 CLASS_TYPE_TRUENAMER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_TRUE 20 1 0 0 -1 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -229 MasterAlchemist 16790713 16847239 16847240 16847241 16847242 IR_MSTALC 4 CLS_ATK_3 CLS_FEAT_MSTALC CLS_SAVTHR_WIZ CLS_SKILL_MSTALC CLS_BFEAT_MSTALC 2 **** **** 1 0 10 14 14 12 16 10 INT 0X00 0X0 0 CLASS_TYPE_MASTER_ALCHEMIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MSTALC 10 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +229 MasterAlchemist 16790713 16847239 16847240 16847241 16847242 IR_MSTALC 4 CLS_ATK_3 CLS_FEAT_MSTALC CLS_SAVTHR_WIZ CLS_SKILL_MSTALC CLS_BFEAT_MSTALC 2 **** **** 1 0 10 14 14 12 16 10 INT 0X00 0X0 0 CLASS_TYPE_MASTER_ALCHEMIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MSTALC 40 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 230 Bereft 16790714 16827537 16827538 16827539 16827540 IR_MAESTER 6 CLS_ATK_2 CLS_FEAT_BEREFT CLS_SAVTHR_WIZ CLS_SKILL_BEREFT CLS_BFEAT_BEREFT 2 **** **** 1 0 15 9 14 13 10 15 WIS 0X01 0X3 1 CLASS_TYPE_BEREFT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BEREFT 5 0 0 0 5 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -231 BrimstoneSpeaker 16790715 16827554 16827555 16827556 16827557 IR_BRIMSTONE 8 CLS_ATK_2 CLS_FEAT_BRIMST CLS_SAVTHR_CLER CLS_SKILL_BRIMST CLS_BFEAT_BRIMST 2 **** **** 1 0 12 16 14 8 14 12 WIS 0X11 0X2 0 CLASS_TYPE_BRIMSTONE_SPEAKER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BRIMST 10 0 0 2 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +231 BrimstoneSpeaker 16790715 16827554 16827555 16827556 16827557 IR_BRIMSTONE 8 CLS_ATK_2 CLS_FEAT_BRIMST CLS_SAVTHR_CLER CLS_SKILL_BRIMST CLS_BFEAT_BRIMST 2 **** **** 1 0 12 16 14 8 14 12 WIS 0X11 0X2 0 CLASS_TYPE_BRIMSTONE_SPEAKER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BRIMST 40 0 0 2 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 232 Shugenja **** 16825142 16825143 16825144 16825145 IR_HNSHN 6 CLS_ATK_3 CLS_FEAT_SHUGEN CLS_SAVTHR_WIZ CLS_SKILL_SHUGEN CLS_BFEAT_SHUGEN 4 **** **** 0 0 10 14 14 10 12 16 CHA 0X00 0X0 0 CLASS_TYPE_SHUGENJA 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHUGEN 0 1 0 0 -1 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 233 Sohei 16790716 16827429 16827430 16827431 16827432 IR_FIGHTER 10 CLS_ATK_2 CLS_FEAT_SOHEI CLS_SAVTHR_CLER CLS_SKILL_SOHEI CLS_BFEAT_SOHEI 2 CLS_SPGN_SOHEI **** 1 1 16 10 13 14 13 10 STR 0X05 0X1 0 CLASS_TYPE_SOHEI 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SOHEI 0 1 0 0 -1 6 0 **** 1 0 0 0 0 0 0 WIS Sohei 1 4 255 0 0 -234 Crusader 16790717 16829702 16829703 16829704 16829705 IR_CRUSADER 10 CLS_ATK_1 CLS_FEAT_CRUSDR CLS_SAVTHR_FIGHT CLS_SKILL_CRUSDR CLS_BFEAT_CRUSDR 4 **** **** 1 0 16 14 14 10 12 10 STR 0X1E 0X3 1 CLASS_TYPE_CRUSADER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_CRUSDR 20 1 0 0 -1 6 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -235 Swordsage 16790718 16829706 16829707 16829708 16829709 IR_MONK 8 CLS_ATK_2 CLS_FEAT_SWDSGE CLS_SAVTHR_BARD CLS_SKILL_SWDSGE CLS_BFEAT_SWDSGE 6 **** **** 1 0 16 14 14 10 12 10 STR 0X00 0X0 0 CLASS_TYPE_SWORDSAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SWDSGE 20 1 0 0 -1 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -236 Warblade 16790719 16829710 16829711 16829712 16829713 IR_FIGHTER 12 CLS_ATK_1 CLS_FEAT_WARBLD CLS_SAVTHR_FIGHT CLS_SKILL_WARBLD CLS_BFEAT_WARBLD 4 **** **** 1 0 16 14 14 10 12 10 STR 0X00 0X0 0 CLASS_TYPE_WARBLADE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WARBLD 20 1 0 0 -1 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +234 Crusader 16790717 16829702 16829703 16829704 16829705 IR_CRUSADER 10 CLS_ATK_1 CLS_FEAT_CRUSDR CLS_SAVTHR_FIGHT CLS_SKILL_CRUSDR CLS_BFEAT_CRUSDR 4 **** **** 1 0 16 14 14 10 12 10 STR 0X1E 0X3 1 CLASS_TYPE_CRUSADER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_CRUSDR 0 1 0 0 -1 6 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +235 Swordsage 16790718 16829706 16829707 16829708 16829709 IR_MONK 8 CLS_ATK_2 CLS_FEAT_SWDSGE CLS_SAVTHR_BARD CLS_SKILL_SWDSGE CLS_BFEAT_SWDSGE 6 **** **** 1 0 16 14 14 10 12 10 STR 0X00 0X0 0 CLASS_TYPE_SWORDSAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SWDSGE 0 1 0 0 -1 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +236 Warblade 16790719 16829710 16829711 16829712 16829713 IR_FIGHTER 12 CLS_ATK_1 CLS_FEAT_WARBLD CLS_SAVTHR_FIGHT CLS_SKILL_WARBLD CLS_BFEAT_WARBLD 4 **** **** 1 0 16 14 14 10 12 10 STR 0X00 0X0 0 CLASS_TYPE_WARBLADE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WARBLD 0 1 0 0 -1 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 237 Warmage 16790720 16827604 16827605 16827606 16827607 IR_HAVOCMAGE 6 CLS_ATK_3 CLS_FEAT_WRMAGE CLS_SAVTHR_WIZ CLS_SKILL_WRMAGE CLS_BFEAT_WRMAGE 2 CLS_SPGN_WRMAGE CLS_SPKN_WRMAGE 1 1 10 14 12 10 14 16 INT 0X00 0X0 0 CLASS_TYPE_WARMAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WRMAGE 0 1 0 0 -1 10 130 **** **** **** **** **** **** **** **** **** Warmage **** **** **** **** **** 238 Knight 16790721 16827632 16827633 16827634 16827635 IR_PALADIN 12 CLS_ATK_1 CLS_FEAT_KNIGHT CLS_SAVTHR_WIZ CLS_SKILL_KNIGHT CLS_BFEAT_KNIGHT 2 **** **** 1 0 16 10 16 10 10 12 STR 0X05 0X1 0 CLASS_TYPE_KNIGHT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_KNIGHT 20 1 0 0 -1 6 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 239 FistOfDalQuor 16790722 16827033 16827034 16827035 16827036 IR_SHOUDISC 10 CLS_ATK_2 CLS_FEAT_DALQUR CLS_SAVTHR_CLER CLS_SKILL_DALQUR CLS_BFEAT_DALQUR 2 **** **** 0 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_FIST_DAL_QUOR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DALQUR 5 0 0 0 5 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -240 HandOfTheWingedMasters 16790723 16832694 16832695 16832696 16832697 IR_HOTWM 8 CLS_ATK_2 CLS_FEAT_HOTWM CLS_SAVTHR_BARD CLS_SKILL_HOTWM CLS_BFEAT_HOTWM 6 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_HANDOTWM 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HOTWM 10 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -241 Talon_of_Tiamat 16790724 16832629 16832630 16832631 16832632 IR_TALON_TIAMAT 8 CLS_ATK_2 CLS_FEAT_TALTIA CLS_SAVTHR_FIGHT CLS_SKILL_TALTIA CLS_BFEAT_TALTIA 2 **** **** 1 0 15 9 14 13 10 15 STR 0X09 0X2 0 CLASS_TYPE_TALON_OF_TIAMAT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_TALTIA 10 0 2 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +240 HandOfTheWingedMasters 16790723 16832694 16832695 16832696 16832697 IR_HOTWM 8 CLS_ATK_2 CLS_FEAT_HOTWM CLS_SAVTHR_BARD CLS_SKILL_HOTWM CLS_BFEAT_HOTWM 6 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_HANDOTWM 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HOTWM 40 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +241 Talon_of_Tiamat 16790724 16832629 16832630 16832631 16832632 IR_TALON_TIAMAT 8 CLS_ATK_2 CLS_FEAT_TALTIA CLS_SAVTHR_FIGHT CLS_SKILL_TALTIA CLS_BFEAT_TALTIA 2 **** **** 1 0 15 9 14 13 10 15 STR 0X09 0X2 0 CLASS_TYPE_TALON_OF_TIAMAT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_TALTIA 40 0 2 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 242 Dragon_Devotee 16790725 16832633 16832634 16832635 16832636 IR_DRAGON_DEVO 6 CLS_ATK_2 CLS_FEAT_DRADEV CLS_SAVTHR_FIGHT CLS_SKILL_DRADEV CLS_BFEAT_DRADEV 4 **** **** 1 0 16 13 16 10 10 9 STR 0X00 0X0 0 CLASS_TYPE_DRAGON_DEVOTEE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DRADEV 5 0 0 0 5 10 0 cls_stat_dradev **** **** **** **** **** **** **** **** **** **** **** **** **** **** -243 FrostMage 16790726 16835103 16835104 16835105 16835106 IR_ELEMCOLD 4 CLS_ATK_3 CLS_FEAT_FROSTM CLS_SAVTHR_WIZ CLS_SKILL_FROSTM CLS_BFEAT_FROSTM 2 **** **** 1 0 12 14 14 10 12 15 CHA 0X00 0X0 0 CLASS_TYPE_FROST_MAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FROSTM 10 0 1 0 10 1 0 cls_stat_frostm **** **** **** **** **** **** **** **** **** **** **** **** **** **** +243 FrostMage 16790726 16835103 16835104 16835105 16835106 IR_ELEMCOLD 4 CLS_ATK_3 CLS_FEAT_FROSTM CLS_SAVTHR_WIZ CLS_SKILL_FROSTM CLS_BFEAT_FROSTM 2 **** **** 1 0 12 14 14 10 12 15 CHA 0X00 0X0 0 CLASS_TYPE_FROST_MAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FROSTM 40 0 1 0 10 1 0 cls_stat_frostm **** **** **** **** **** **** **** **** **** **** **** **** **** **** 244 WarforgedJuggernaut 16790727 16835083 16835084 16835085 16835086 IR_SHOUDISC 12 CLS_ATK_1 CLS_FEAT_JUGGR CLS_SAVTHR_FIGHT CLS_SKILL_JUGGR CLS_BFEAT_JUGGR 2 **** **** 0 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_WARFORGED_JUGGERNAUT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_JUGGR 5 0 0 0 5 64 130 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 245 Battlesmith 16790728 16835069 16835070 16835071 16835072 IC_LEGDREAD 10 CLS_ATK_1 CLS_FEAT_BSMITH CLS_SAVTHR_FIGHT CLS_SKILL_BSMITH CLS_BFEAT_BSMITH 2 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_BATTLESMITH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BSMITH 5 0 0 0 5 64 130 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 246 NentyarHunter 16790729 16835057 16835058 16835059 16835060 IR_RANGER 6 CLS_ATK_2 CLS_FEAT_HUNTER CLS_SAVTHR_RANG CLS_SKILL_HUNTER CLS_BFEAT_HUNTER 4 CLS_SPGN_HUNTER **** 0 1 12 16 14 8 14 12 DEX 0X10 0X2 0 CLASS_TYPE_NENTYAR_HUNTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HUNTER 5 0 0 0 5 64 130 **** 1 0 0 0 0 0 0 WIS Nentyar 1 1 255 0 0 -247 Blighter 16790730 16835035 16835036 16835037 16835038 IR_JUSTWW 8 CLS_ATK_2 CLS_FEAT_BLIGHT CLS_SAVTHR_DRU CLS_SKILL_BLIGHT CLS_BFEAT_BLIGHT 4 CLS_SPGN_BLIGHT **** 1 1 12 16 14 8 14 12 INT 0X08 0X2 0 CLASS_TYPE_BLIGHTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BLIGHT 10 0 **** 0 10 10 0 **** 1 0 0 0 0 0 0 WIS Blighter 1 1 255 0 0 -248 Rage_Mage 16790731 16789817 16789818 16789819 16789820 IR_RAGEMAGE 8 CLS_ATK_2 CLS_FEAT_RAGEM CLS_SAVTHR_BARB CLS_SKILL_RAGEM CLS_BFEAT_RAGEM 2 **** **** 1 0 12 16 14 10 14 10 INT 0X02 0X1 0 CLASS_TYPE_RAGE_MAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_RAGEM 10 0 2 0 10 15 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -249 Dragonheart_Mage 16790732 16832498 16832499 16832500 16832501 IR_DRGNHTMAGE 6 CLS_ATK_3 CLS_FEAT_DRGNHT CLS_SAVTHR_CLER CLS_SKILL_DRGNHT CLS_BFEAT_DRGNHT 2 **** **** 1 0 10 14 14 10 12 16 CHA 0X00 0X0 0 CLASS_TYPE_DRAGONHEART_MAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DRGNHT 30 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -250 Swift_Wing 16790733 16832494 16832495 16832496 16832497 DRADIS_RADIANT 8 CLS_ATK_2 CLS_FEAT_SWFTWG CLS_SAVTHR_WILD CLS_SKILL_SWFTWG CLS_BFEAT_SWFTWG 4 **** **** 1 0 14 8 14 16 10 14 WIS 0X00 0X0 0 CLASS_TYPE_SWIFT_WING 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SWFTWG 10 0 0 1 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -251 Diamond_Dragon 16790734 16832440 16832441 16832442 16832443 DRADIS_CRYSTAL 8 CLS_ATK_2 CLS_FEAT_DIADRA CLS_SAVTHR_BARD CLS_SKILL_DIADRA CLS_BFEAT_DIADRA 2 **** **** 1 0 14 14 12 10 16 10 STR 0X01 0X3 1 CLASS_TYPE_DIAMOND_DRAGON 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DIADRA 10 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +247 Blighter 16790730 16835035 16835036 16835037 16835038 IR_JUSTWW 8 CLS_ATK_2 CLS_FEAT_BLIGHT CLS_SAVTHR_DRU CLS_SKILL_BLIGHT CLS_BFEAT_BLIGHT 4 CLS_SPGN_BLIGHT **** 1 1 12 16 14 8 14 12 INT 0X08 0X2 0 CLASS_TYPE_BLIGHTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BLIGHT 40 0 **** 0 10 10 0 **** 1 0 0 0 0 0 0 WIS Blighter 1 1 255 0 0 +248 Rage_Mage 16790731 16789817 16789818 16789819 16789820 IR_RAGEMAGE 8 CLS_ATK_2 CLS_FEAT_RAGEM CLS_SAVTHR_BARB CLS_SKILL_RAGEM CLS_BFEAT_RAGEM 2 **** **** 1 0 12 16 14 10 14 10 INT 0X02 0X1 0 CLASS_TYPE_RAGE_MAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_RAGEM 40 0 2 0 10 15 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +249 Dragonheart_Mage 16790732 16832498 16832499 16832500 16832501 IR_DRGNHTMAGE 6 CLS_ATK_3 CLS_FEAT_DRGNHT CLS_SAVTHR_CLER CLS_SKILL_DRGNHT CLS_BFEAT_DRGNHT 2 **** **** 1 0 10 14 14 10 12 16 CHA 0X00 0X0 0 CLASS_TYPE_DRAGONHEART_MAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DRGNHT 40 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +250 Swift_Wing 16790733 16832494 16832495 16832496 16832497 DRADIS_RADIANT 8 CLS_ATK_2 CLS_FEAT_SWFTWG CLS_SAVTHR_WILD CLS_SKILL_SWFTWG CLS_BFEAT_SWFTWG 4 **** **** 1 0 14 8 14 16 10 14 WIS 0X00 0X0 0 CLASS_TYPE_SWIFT_WING 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SWFTWG 40 0 0 1 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +251 Diamond_Dragon 16790734 16832440 16832441 16832442 16832443 DRADIS_CRYSTAL 8 CLS_ATK_2 CLS_FEAT_DIADRA CLS_SAVTHR_BARD CLS_SKILL_DIADRA CLS_BFEAT_DIADRA 2 **** **** 1 0 14 14 12 10 16 10 STR 0X01 0X3 1 CLASS_TYPE_DIAMOND_DRAGON 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DIADRA 40 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 252 Frostrager 16790735 16834512 16834513 16834514 16834515 IR_FREBZK 12 CLS_ATK_1 CLS_FEAT_FRTRGR CLS_SAVTHR_BARB CLS_SKILL_FRTRGR CLS_BFEAT_FRTRGR 2 **** **** 1 0 16 14 14 14 10 8 STR 0X00 0X0 0 CLASS_TYPE_FROSTRAGER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FRTRGR 5 0 0 0 5 17 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 253 CrintiShadowMarauder 16790736 16823080 16823081 16823082 16823083 IR_TFSHAD 8 CLS_ATK_2 CLS_FEAT_CRINTI CLS_SAVTHR_ROG CLS_SKILL_CRINTI CLS_BFEAT_CRINTI 4 **** **** 0 0 12 14 14 10 12 15 CHA 0X08 0X2 0 CLASS_TYPE_CRINTI_SHADOW_MARAUDER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_CRINTI 5 0 0 0 5 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 254 ShadowThief 16790737 16823088 16823089 16823090 16823091 IR_X1_SHADOW 6 CLS_ATK_2 CLS_FEAT_AMN CLS_SAVTHR_ROG CLS_SKILL_AMN CLS_BFEAT_AMN 6 **** **** 0 0 16 15 14 10 10 10 STR 0X00 0X0 0 CLASS_TYPE_SHADOW_THIEF_OF_AMN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_AMN 5 0 0 0 5 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** diff --git a/src/hakpak/wog_prc8_top/2da/racialtypes.2da b/src/hakpak/wog_prc8_top/2da/racialtypes.2da index 6322a1f..3cb7c0e 100644 --- a/src/hakpak/wog_prc8_top/2da/racialtypes.2da +++ b/src/hakpak/wog_prc8_top/2da/racialtypes.2da @@ -75,7 +75,7 @@ 71 Hadrimoi Ha 16790329 16790329 16790330 16790331 16790332 **** 1 2 8 2 0 2 4 30 8 RACE_FEAT_HADRIM 8163 1 RACIAL_TYPE_HADRIMOI 15 8 1 ushemoi **** **** **** 4 30 3 1 INT 274 72 RedspawnArcaniss Ra 16790334 16790334 16790335 16790336 16790337 **** 353 0 2 0 6 0 4 40 9 RACE_FEAT_REDARC 8163 1 RACIAL_TYPE_REDSPAWN_ARCANISS 15 9 1 redspawn **** **** **** 4 30 3 1 INT 274 73 Gloura Gl 16790346 16790346 16790347 16790348 16790349 **** 6 0 10 0 6 2 4 30 1 RACE_FEAT_GLOURA 8163 1 RACIAL_TYPE_GLOURA 15 1 1 gloura **** **** **** 4 30 3 1 INT 278 -74 Muckdweller Mr 16836018 16836018 16836019 16836020 16836021 **** 206 -2 6 0 -2 -2 0 20 8 RACE_FEAT_MUCKD 8163 1 RACIAL_TYPE_MUCKDWELLER 15 8 1 muckdweller **** **** **** 4 30 3 1 INT 276 +74 Muckdweller Mr 16836018 16836018 16836019 16836020 16836021 **** 206 -6 6 0 -2 -2 0 20 8 RACE_FEAT_MUCKD 8163 1 RACIAL_TYPE_MUCKDWELLER 15 8 1 muckdweller **** **** **** 4 30 3 1 INT 276 75 Aranea Ae 16836006 16836006 16836007 16836008 16836009 **** 158 0 4 4 4 2 4 50 9 RACE_FEAT_ARANEA 8163 1 RACIAL_TYPE_ARANEA 15 9 1 aranea **** **** **** 4 30 3 1 INT 284 76 Chitine Ch 16832294 16832294 16832295 16832296 16832297 **** 2 **** 2 2 -4 **** 2 30 8 RACE_FEAT_CHIT 16832294 1 RACIAL_TYPE_CHITINE 15 8 1 chitine **** **** **** 4 30 3 1 INT 274 77 SpiretopDragon Sd 16835965 16835966 16835967 16835968 16835969 **** 375 -4 8 -4 -2 0 2 60 8 RACE_FEAT_SPDRAG 16835970 1 RACIAL_TYPE_SPIRETOPDRAGON 25 8 1 dragon **** **** **** 4 30 3 1 INT 272 @@ -246,8 +246,8 @@ 242 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 243 Spirit_Folk Sf 16828037 16828037 16828038 16828037 16828039 **** 4 0 0 0 0 0 0 30 **** RACE_FEAT_SPIRIT 16826909 0 RACIAL_TYPE_SPIRIT_FOLK 110 **** 1 human **** **** **** 4 30 3 1 INT 267 244 Killoren Kn 16835207 16835207 16835208 16835209 16835210 **** 4 0 0 0 0 0 0 30 3 RACE_FEAT_KILLOR 16826911 1 RACIAL_TYPE_KILLOREN 10 3 1 killoren **** **** **** 4 30 3 1 INT 278 -245 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -246 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +245 Korobokuru Kk 16828049 16828049 16828050 16828049 16828051 **** 2 0 0 -2 0 0 2 20 0 RACE_FEAT_KORO 16828048 0 RACIAL_TYPE_KOROBKURU 45 0 1 **** **** **** **** 4 30 3 1 INT 261 +246 Nezumi Nz 16832282 16832282 16832283 16832282 16832284 **** 170 0 0 0 -2 0 2 40 8 RACE_FEAT_NEZU 16826907 0 RACIAL_TYPE_NEZUMI 18 8 1 nezumi **** **** **** 4 30 3 1 INT 274 247 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 248 Poison_Dusk Pd 16832303 16832303 16832304 16832303 16832305 **** 304 0 2 0 -2 0 2 30 7 RACE_FEAT_PDUSK 16826908 1 RACIAL_TYPE_POISON_DUSK 20 7 1 lizardfolk **** **** **** 4 30 3 1 INT 276 249 Dromite Dq 16827668 16827668 16827669 16827670 16827671 **** 3 -2 0 0 2 -2 0 20 148 RACE_FEAT_DROM 16827688 1 RACIAL_TYPE_DROMITE 13 148 1 dromite **** **** **** 4 30 3 1 INT 274 diff --git a/src/include/inc_epicspelldef.nss b/src/include/inc_epicspelldef.nss index 78b89b4..613b0f1 100644 --- a/src/include/inc_epicspelldef.nss +++ b/src/include/inc_epicspelldef.nss @@ -47,77 +47,78 @@ const string MES_CONTINGENCIES_YES2 = "The contingencies must expire to allo */ //Primogenitors SpellID constants -const int SPELL_EPIC_A_STONE = 0;//4007; -const int SPELL_EPIC_ACHHEEL = 1;//4000; -const int SPELL_EPIC_AL_MART = 2;//4002; -const int SPELL_EPIC_ALLHOPE = 3;//4001; -const int SPELL_EPIC_ANARCHY = 4;//4003; -const int SPELL_EPIC_ANBLAST = 5;//4004; -const int SPELL_EPIC_ANBLIZZ = 6;//4005; -const int SPELL_EPIC_ARMY_UN = 7;//4006; -const int SPELL_EPIC_BATTLEB = 999;//4008; -const int SPELL_EPIC_CELCOUN = 8;//4009; -const int SPELL_EPIC_CHAMP_V = 9;//4010; -const int SPELL_EPIC_CON_RES =10;//4011; -const int SPELL_EPIC_CON_REU =11;//4012; -const int SPELL_EPIC_DEADEYE =12;//4013; -const int SPELL_EPIC_DIREWIN =13;//4015; -const int SPELL_EPIC_DREAMSC =14;//4017; -const int SPELL_EPIC_DRG_KNI =15;//4016; -const int SPELL_EPIC_DTHMARK =1000;//4014; -const int SPELL_EPIC_DULBLAD =16;//4018; -const int SPELL_EPIC_DWEO_TH =17;//4019; -const int SPELL_EPIC_ENSLAVE =18;//4020; -const int SPELL_EPIC_EP_M_AR =19;//4021; -const int SPELL_EPIC_EP_RPLS =20;//4022; -const int SPELL_EPIC_EP_SP_R =21;//4023; -const int SPELL_EPIC_EP_WARD =22;//4024; -const int SPELL_EPIC_ET_FREE =23;//4025; -const int SPELL_EPIC_FIEND_W =24;//4026; -const int SPELL_EPIC_FLEETNS =25;//4027; -const int SPELL_EPIC_GEMCAGE =26;//4028; -const int SPELL_EPIC_GODSMIT =27;//4029; -const int SPELL_EPIC_GR_RUIN =28;//4030; -const int SPELL_EPIC_GR_SP_RE=29;//4031; -const int SPELL_EPIC_GR_TIME =30;//4032; -const int SPELL_EPIC_HELBALL =31;//4034; -const int SPELL_EPIC_HELSEND =1001;//4033; -const int SPELL_EPIC_HERCALL =32;//4035; -const int SPELL_EPIC_HERCEMP =33;//4036; -const int SPELL_EPIC_IMPENET =34;//4037; -const int SPELL_EPIC_LEECH_F =35;//4038; -const int SPELL_EPIC_LEG_ART =1002;//4039; -const int SPELL_EPIC_LIFE_FT =1003;//4040; -const int SPELL_EPIC_MAGMA_B =36;//4041; -const int SPELL_EPIC_MASSPEN =37;//4042; -const int SPELL_EPIC_MORI = 38;//4043; -const int SPELL_EPIC_MUMDUST =39;//4044; -const int SPELL_EPIC_NAILSKY =40;//4045; -const int SPELL_EPIC_NIGHTSU =1004;//4046; -const int SPELL_EPIC_ORDER_R =41;//4047; -const int SPELL_EPIC_PATHS_B =42;//4048; -const int SPELL_EPIC_PEERPEN =43;//4049; -const int SPELL_EPIC_PESTIL = 44;//4050; -const int SPELL_EPIC_PIOUS_P =45;//4051; -const int SPELL_EPIC_PLANCEL =46;//4052; -const int SPELL_EPIC_PSION_S =47;//4053; -const int SPELL_EPIC_RAINFIR =48;//4054; -const int SPELL_EPIC_RISEN_R =1005;//4055; -const int SPELL_EPIC_RUINN = 49;//4056; //NON_STANDARD -const int SPELL_EPIC_SINGSUN =50;//4057; -const int SPELL_EPIC_SP_WORM =51;//4058; -const int SPELL_EPIC_STORM_M =52;//4059; -const int SPELL_EPIC_SUMABER =53;//4060; -const int SPELL_EPIC_SUP_DIS =54;//4061; -const int SPELL_EPIC_SYMRUST =1006;//4062; -const int SPELL_EPIC_THEWITH =55;//4063; -const int SPELL_EPIC_TOLO_KW =56;//4064; -const int SPELL_EPIC_TRANVIT =57;//4065; -const int SPELL_EPIC_TWINF = 58;//4066; -const int SPELL_EPIC_UNHOLYD =59;//4067; -const int SPELL_EPIC_UNIMPIN =60;//4068; -const int SPELL_EPIC_UNSEENW =61;//4069; -const int SPELL_EPIC_WHIP_SH =62;//4070; +const int SPELL_EPIC_A_STONE = 0;//4007; +const int SPELL_EPIC_ACHHEEL = 1;//4000; +const int SPELL_EPIC_AL_MART = 2;//4002; +const int SPELL_EPIC_ALLHOPE = 3;//4001; +const int SPELL_EPIC_ANARCHY = 4;//4003; +const int SPELL_EPIC_ANBLAST = 5;//4004; +const int SPELL_EPIC_ANBLIZZ = 6;//4005; +const int SPELL_EPIC_ARMY_UN = 7;//4006; +const int SPELL_EPIC_BATTLEB = 999;//4008; +const int SPELL_EPIC_CELCOUN = 8;//4009; +const int SPELL_EPIC_CHAMP_V = 9;//4010; +const int SPELL_EPIC_CON_RES = 10;//4011; +const int SPELL_EPIC_CON_REU = 11;//4012; +const int SPELL_EPIC_DEADEYE = 12;//4013; +const int SPELL_EPIC_DIREWIN = 13;//4015; +const int SPELL_EPIC_DREAMSC = 14;//4017; +const int SPELL_EPIC_DRG_KNI = 15;//4016; +const int SPELL_EPIC_DTHMARK = 1000;//4014; +const int SPELL_EPIC_DULBLAD = 16;//4018; +const int SPELL_EPIC_DWEO_TH = 17;//4019; +const int SPELL_EPIC_ENSLAVE = 18;//4020; +const int SPELL_EPIC_EP_M_AR = 19;//4021; +const int SPELL_EPIC_EP_RPLS = 20;//4022; +const int SPELL_EPIC_EP_SP_R = 21;//4023; +const int SPELL_EPIC_EP_WARD = 22;//4024; +const int SPELL_EPIC_ET_FREE = 23;//4025; +const int SPELL_EPIC_FIEND_W = 24;//4026; +const int SPELL_EPIC_FLEETNS = 25;//4027; +const int SPELL_EPIC_GEMCAGE = 26;//4028; +const int SPELL_EPIC_GODSMIT = 27;//4029; +const int SPELL_EPIC_GR_RUIN = 28;//4030; +const int SPELL_EPIC_GR_SP_RE = 29;//4031; +const int SPELL_EPIC_GR_TIME = 30;//4032; +const int SPELL_EPIC_HELBALL = 31;//4034; +const int SPELL_EPIC_HELSEND = 1001;//4033; +const int SPELL_EPIC_HERCALL = 32;//4035; +const int SPELL_EPIC_HERCEMP = 33;//4036; +const int SPELL_EPIC_IMPENET = 34;//4037; +const int SPELL_EPIC_LEECH_F = 35;//4038; +const int SPELL_EPIC_LEG_ART = 1002;//4039; +const int SPELL_EPIC_LIFE_FT = 1003;//4040; +const int SPELL_EPIC_MAGMA_B = 36;//4041; +const int SPELL_EPIC_MASSPEN = 37;//4042; +const int SPELL_EPIC_MORI = 38;//4043; +const int SPELL_EPIC_MUMDUST = 39;//4044; +const int SPELL_EPIC_NAILSKY = 40;//4045; +const int SPELL_EPIC_NIGHTSU = 1004;//4046; +const int SPELL_EPIC_ORDER_R = 41;//4047; +const int SPELL_EPIC_PATHS_B = 42;//4048; +const int SPELL_EPIC_PEERPEN = 43;//4049; +const int SPELL_EPIC_PESTIL = 44;//4050; +const int SPELL_EPIC_PIOUS_P = 45;//4051; +const int SPELL_EPIC_PLANCEL = 46;//4052; +const int SPELL_EPIC_PSION_S = 47;//4053; +const int SPELL_EPIC_RAINFIR = 48;//4054; +//const int SPELL_EPIC_RISEN_R =1005;//4055; +const int SPELL_EPIC_RISEN_R = 49;//4055; +const int SPELL_EPIC_RUINN = 50;//4056; //NON_STANDARD +const int SPELL_EPIC_SINGSUN = 51;//4057; +const int SPELL_EPIC_SP_WORM = 52;//4058; +const int SPELL_EPIC_STORM_M = 53;//4059; +const int SPELL_EPIC_SUMABER = 54;//4060; +const int SPELL_EPIC_SUP_DIS = 55;//4061; +const int SPELL_EPIC_SYMRUST = 1006;//4062; +const int SPELL_EPIC_THEWITH = 56;//4063; +const int SPELL_EPIC_TOLO_KW = 57;//4064; +const int SPELL_EPIC_TRANVIT = 58;//4065; +const int SPELL_EPIC_TWINF = 59;//4066; +const int SPELL_EPIC_UNHOLYD = 60;//4067; +const int SPELL_EPIC_UNIMPIN = 61;//4068; +const int SPELL_EPIC_UNSEENW = 62;//4069; +const int SPELL_EPIC_WHIP_SH = 63;//4070; /* diff --git a/src/include/inc_epicspellfnc.nss b/src/include/inc_epicspellfnc.nss index 59f4dd6..7fb6054 100644 --- a/src/include/inc_epicspellfnc.nss +++ b/src/include/inc_epicspellfnc.nss @@ -246,7 +246,7 @@ int GetSpellFromAbrev(string sAbrev) sAbrev = GetStringLowerCase(sAbrev); if(GetStringLeft(sAbrev, 8) == "epic_sp_") sAbrev = GetStringRight(sAbrev, GetStringLength(sAbrev)-8); - if(DEBUG) DoDebug("sAbrew to check vs: " + sAbrev); + if(DEBUG) DoDebug("sAbrev to check vs: " + sAbrev); int i = 0; string sLabel = GetStringLowerCase(Get2DACache("epicspells", "LABEL", i)); while(sLabel != "") diff --git a/src/include/inc_infusion.nss b/src/include/inc_infusion.nss new file mode 100644 index 0000000..e9c7528 --- /dev/null +++ b/src/include/inc_infusion.nss @@ -0,0 +1,481 @@ +//::////////////////////////////////////////////// +//:: ;-. ,-. ,-. ,-. +//:: | ) | ) / ( ) +//:: |-' |-< | ;-: +//:: | | \ \ ( ) +//:: ' ' ' `-' `-' +//:://///////////////////////////////////////////// +//:: +/* + Script: inc_infusion + Author: Jaysyn + Created: 2025-08-11 17:01:26 + + Description: + Contains most functions related to the Create + Infusion feat. + +*/ +//:: +//::////////////////////////////////////////////// +#include "prc_inc_spells" + +int GetMaxDivineSpellLevel(object oCaster, int nClass); +int GetCastSpellCasterLevelFromItem(object oItem, int nSpellID); +int GetIsClassSpell(object oCaster, int nSpellID, int nClass); +int GetHasSpellOnClassList(object oCaster, int nSpellID); +void InfusionSecondSave(object oUser, int nDC); + +/** + * @brief Finds the class index for which the given spell is available to the specified caster. + * + * This function iterates through all possible classes and returns the first class + * index for which the specified spell is on the caster's spell list. + * + * @param oCaster The creature object to check. + * @param nSpellID The spell ID to find the class for. + * + * @return The class index that has the spell on its class spell list for the caster, + * or -1 if no matching class is found. + */ +int FindSpellCastingClass(object oCaster, int nSpellID) +{ + int i = 0; + int nClassFound = -1; + int nClass; + + // Only loop through caster's classes + for (i = 0; i <= 8; i++) + { + nClass = GetClassByPosition(i, oCaster); + if (nClass == CLASS_TYPE_INVALID) continue; + + if (GetIsClassSpell(oCaster, nSpellID, nClass)) + { + nClassFound = nClass; + break; + } + } + + return nClassFound; +} + + +/** + * @brief Performs validation checks to determine if the caster can use a spell infusion from the specified item. + * + * This function verifies that the item is a valid infused herb, checks the caster's relevant class and ability scores, + * confirms the caster is a divine spellcaster with the necessary caster level, and ensures the spell is on the caster's class spell list. + * + * @param oCaster The creature attempting to use the infusion. + * @param oItem The infused herb item containing the spell. + * @param nSpellID The spell ID of the infusion spell being cast. + * + * @return TRUE if all infusion use checks pass and the caster can use the infusion; FALSE otherwise. + */ + int DoInfusionUseChecks(object oCaster, object oItem, int nSpellID) +{ + int bPnPHerbs = GetPRCSwitch(PRC_CREATE_INFUSION_OPTIONAL_HERBS); + + if(GetBaseItemType(oItem) != BASE_ITEM_INFUSED_HERB) + { + FloatingTextStringOnCreature("Not casting from an Infused Herb", oCaster); + return FALSE; + } + + int nItemSpellLvl = GetCastSpellCasterLevelFromItem(oItem, nSpellID); + if (bPnPHerbs && nItemSpellLvl == -1) + { + FloatingTextStringOnCreature("Item has no spellcaster level.", oCaster); + return FALSE; + } + + // **CRITICAL: Find the correct class that actually has the spell on its list** + int nClassCaster = FindSpellCastingClass(oCaster, nSpellID); + + if(DEBUG) DoDebug("nClassCaster is: " + IntToString(nClassCaster) + "."); + + // Check for valid class + if (nClassCaster == -1) + { + FloatingTextStringOnCreature("No valid class found for this spell.", oCaster); + return FALSE; + } + + if(GetMaxDivineSpellLevel(oCaster, nClassCaster) < 1 ) + { + FloatingTextStringOnCreature("You must be a divine spellcaster to activate an infusion.", oCaster); + return FALSE; + } + + // Must have spell on class list - (This will also double-check via the class) + if (!GetHasSpellOnClassList(oCaster, nSpellID)) + { + FloatingTextStringOnCreature("You must have a spell on one of your class spell lists to cast it from an infusion.", oCaster); + return FALSE; + } + + // Must meet ability requirement: Ability score >= 10 + spell level + int nSpellLevel = PRCGetSpellLevelForClass(nSpellID, nClassCaster); + int nClassAbility = GetAbilityScoreForClass(nClassCaster, oCaster); + + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nClassCaster is "+IntToString(nClassCaster)+"."); + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: Class nSpellLevel is "+IntToString(nSpellLevel)+"."); + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nClassAbility is "+IntToString(nClassAbility)+"."); + + if (nClassAbility < 10 + nSpellLevel) + { + FloatingTextStringOnCreature("You must meet ability score requirement to cast spell from infusion.", oCaster); + return FALSE; + } + + // Must have a divine caster level at least equal to infusion's caster level + int nDivineLvl = GetPrCAdjustedCasterLevelByType(TYPE_DIVINE, oCaster); + + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nDivineLvl is "+IntToString(nDivineLvl)+"."); + + if (nDivineLvl < nItemSpellLvl) + { + FloatingTextStringOnCreature("Your divine caster level is too low to cast this spell from an infusion.", oCaster); + return FALSE; + } + + return TRUE; +} + +/* int DoInfusionUseChecks(object oCaster, object oItem, int nSpellID) +{ + int bPnPHerbs = GetPRCSwitch(PRC_CREATE_INFUSION_OPTIONAL_HERBS); + + if(GetBaseItemType(oItem) != BASE_ITEM_INFUSED_HERB) + { + FloatingTextStringOnCreature("Not casting from an Infused Herb", oCaster); + return FALSE; + + } + + int nItemSpellLvl = GetCastSpellCasterLevelFromItem(oItem, nSpellID); + if (bPnPHerbs && nItemSpellLvl == -1) + { + FloatingTextStringOnCreature("Item has no spellcaster level.", oCaster); + return FALSE; + } + + // Find relevant class for the spell + int nClassCaster = FindSpellCastingClass(oCaster, nSpellID); + + if(DEBUG) DoDebug("nClassCaster is: "+IntToString(nClassCaster)+"."); + + if(GetMaxDivineSpellLevel(oCaster, nClassCaster) < 1 ) + { + FloatingTextStringOnCreature("You must be a divine spellcaster to activate an infusion.", oCaster); + return FALSE; + } + + // Must have spell on class list + if (!GetHasSpellOnClassList(oCaster, nSpellID)) + { + FloatingTextStringOnCreature("You must have a spell on one of your class spell lists to cast it from an infusion.", oCaster); + return FALSE; + } + + // Must meet ability requirement: Ability score >= 10 + spell level + int nSpellLevel = PRCGetSpellLevelForClass(nSpellID, nClassCaster); + int nClassAbility = GetAbilityScoreForClass(nClassCaster, oCaster); + + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nClassCaster is "+IntToString(nClassCaster)+"."); + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: Class nSpellLevel is "+IntToString(nSpellLevel)+"."); + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nClassAbility is "+IntToString(nClassAbility)+"."); + + if (nClassAbility < 10 + nSpellLevel) + { + FloatingTextStringOnCreature("You must meet ability score requirement to cast spell from infusion.", oCaster); + return FALSE; + } + + // Must have a divine caster level at least equal to infusion's caster level + int nDivineLvl = GetPrCAdjustedCasterLevelByType(TYPE_DIVINE, oCaster); + + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nDivineLvl is "+IntToString(nDivineLvl)+"."); + + if (nDivineLvl < nItemSpellLvl) + { + FloatingTextStringOnCreature("Your divine caster level is too low to cast this spell from an infusion.", oCaster); + return FALSE; + } + + return TRUE; +} + */ +/** + * @brief Retrieves the maximum divine spell level known by the caster for a given class. + * + * This function checks the caster's local integers named "PRC_DivSpell1" through "PRC_DivSpell9" + * in descending order to determine the highest divine spell level available. + * It returns the highest spell level for which the corresponding local int is false (zero). + * + * @param oCaster The creature whose divine spell levels are being checked. + * @param nClass The class index for which to check the divine spell level (currently unused). + * + * @return The highest divine spell level known by the caster (1 to 9). + */ +int GetMaxDivineSpellLevel(object oCaster, int nClass) +{ + int i = 9; + for (i; i > 0; i--) + { + if(!GetLocalInt(oCaster, "PRC_DivSpell"+IntToString(i))) + return i; + } + return 1; +} + +/** + * @brief Retrieves the spell school of an herb based on its resref by looking it up in the craft_infusion.2da file. + * + * This function searches the "craft_infusion" 2DA for a row matching the herb's resref. + * If found, it returns the corresponding spell school as an integer constant. + * If not found or the SpellSchool column is missing/invalid, it returns -1. + * + * @param oHerb The herb object to check. + * + * @return The spell school constant corresponding to the herb's infusion spell school, + * or -1 if the herb is invalid, not found, or the data is missing. + */ +int GetHerbsSpellSchool(object oHerb) +{ + if (!GetIsObjectValid(oHerb)) return -1; + + string sResref = GetResRef(oHerb); + int nRow = 0; + string sRowResref; + + while (nRow < 200) + { + sRowResref = Get2DACache("craft_infusion", "Resref", nRow); + if (sRowResref == "") break; + if (sRowResref == sResref) + { + string sHerbSpellSchool = Get2DAString("craft_infusion", "SpellSchool", nRow); + + if (sHerbSpellSchool == "A") return SPELL_SCHOOL_ABJURATION; + else if (sHerbSpellSchool == "C") return SPELL_SCHOOL_CONJURATION; + else if (sHerbSpellSchool == "D") return SPELL_SCHOOL_DIVINATION; + else if (sHerbSpellSchool == "E") return SPELL_SCHOOL_ENCHANTMENT; + else if (sHerbSpellSchool == "V") return SPELL_SCHOOL_EVOCATION; + else if (sHerbSpellSchool == "I") return SPELL_SCHOOL_ILLUSION; + else if (sHerbSpellSchool == "N") return SPELL_SCHOOL_NECROMANCY; + else if (sHerbSpellSchool == "T") return SPELL_SCHOOL_TRANSMUTATION; + else return SPELL_SCHOOL_GENERAL; + + return -1; + } + nRow++; + } + return -1; // Not found +} + +/** + * @brief Retrieves the infusion spell level of an herb by matching its resref in the craft_infusion.2da file. + * + * This function searches the "craft_infusion" 2DA for a row matching the herb's resref. + * If found, it returns the spell level from the SpellLevel column as an integer. + * If not found or the column is missing, it returns -1. + * + * @param oHerb The herb object whose infusion spell level is to be retrieved. + * + * @return The spell level as an integer if found, or -1 if the herb is invalid, not found, or the column is missing. + */ +int GetHerbsInfusionSpellLevel(object oHerb) +{ + if (!GetIsObjectValid(oHerb)) return -1; + + string sResref = GetResRef(oHerb); + int nRow = 0; + string sRowResref; + + // Brute-force loop — adjust limit if your 2DA has more than 500 rows + while (nRow < 200) + { + sRowResref = Get2DACache("craft_infusion", "Resref", nRow); + if (sRowResref == "") break; // End of valid rows + if (sRowResref == sResref) + { + string sSpellLevelStr = Get2DAString("craft_infusion", "SpellLevel", nRow); + return StringToInt(sSpellLevelStr); + } + nRow++; + } + return -1; // Not found +} + +/** + * @brief Retrieves the caster level of a specific cast-spell item property from an item. + * + * This function iterates through the item properties of the given item, searching for an + * ITEM_PROPERTY_CAST_SPELL_CASTER_LEVEL property that matches the specified spell ID. + * If found, it returns the caster level value stored in the item property. + * + * @param oItem The item object to check. + * @param nSpellID The spell ID to match against the item property. + * + * @return The caster level associated with the matching cast-spell item property, + * or -1 if no matching property is found. + */ +int GetCastSpellCasterLevelFromItem(object oItem, int nSpellID) +{ + int nFoundCL = -1; + + itemproperty ip = GetFirstItemProperty(oItem); + while (GetIsItemPropertyValid(ip)) + { + int nType = GetItemPropertyType(ip); + + // First preference: PRC's CASTER_LEVEL itemprop + if (nType == ITEM_PROPERTY_CAST_SPELL_CASTER_LEVEL) + { + int nSubType = GetItemPropertySubType(ip); + string sSpellIDStr = Get2DAString("iprp_spells", "SpellIndex", nSubType); + int nSubSpellID = StringToInt(sSpellIDStr); + + if (nSubSpellID == nSpellID) + { + return GetItemPropertyCostTableValue(ip); // Found exact CL + } + } + + // Fallback: vanilla CAST_SPELL property + if (nType == ITEM_PROPERTY_CAST_SPELL && nFoundCL == -1) + { + int nSubType = GetItemPropertySubType(ip); + string sSpellIDStr = Get2DAString("iprp_spells", "SpellIndex", nSubType); + int nSubSpellID = StringToInt(sSpellIDStr); + + if (nSubSpellID == nSpellID) + { + // Vanilla uses CostTableValue for *number of uses*, not CL, + // so we’ll assume default caster level = spell level * 2 - 1 + int nSpellLevel = StringToInt(Get2DAString("spells", "Innate", nSubSpellID)); + nFoundCL = nSpellLevel * 2 - 1; // default NWN caster level rule + } + } + + ip = GetNextItemProperty(oItem); + } + + return nFoundCL; // -1 if not found +} + + +/** + * @brief Checks if a given spell ID is present on the specified class's spell list for the caster. + * + * This function determines the spell level of the spell for the given class using PRCGetSpellLevelForClass. + * If the spell level is -1, the spell is not on the class's spell list. + * Otherwise, the spell is considered to be on the class spell list. + * + * @param oCaster The creature object casting or querying the spell. + * @param nSpellID The spell ID to check. + * @param nClass The class index to check the spell list against. + * + * @return TRUE if the spell is on the class's spell list; FALSE otherwise. + */ +int GetIsClassSpell(object oCaster, int nSpellID, int nClass) +{ + if(DEBUG) DoDebug("inc_infusion >> GetIsClassSpell: nSpellID is: "+IntToString(nSpellID)+"."); + if(DEBUG) DoDebug("inc_infusion >> GetIsClassSpell: nClass is: "+IntToString(nClass)+"."); + + int nSpellLevel = PRCGetSpellLevelForClass(nSpellID, nClass); + if (nSpellLevel == -1) + { + if(DEBUG) DoDebug("inc_infusion >> GetIsClassSpell: SpellLevel is "+IntToString(nSpellLevel)+"."); + if(DEBUG) DoDebug("inc_infusion >> GetIsClassSpell: Spell "+IntToString(nSpellID)+" is not in spelllist of "+IntToString(nClass)+"."); + return FALSE; + } + return TRUE; +} + +/** + * @brief Checks if the caster has the specified spell on any of their class spell lists. + * + * This function iterates through all classes the caster has (up to position 8), + * and returns TRUE if the spell is found on any class's spell list. + * + * @param oCaster The creature object to check. + * @param nSpellID The spell ID to search for. + * + * @return TRUE if the spell is present on at least one of the caster's class spell lists; + * FALSE otherwise. + */ +int GetHasSpellOnClassList(object oCaster, int nSpellID) +{ + int i; + for (i = 0; i <= 8; i++) + { + int nClass = GetClassByPosition(i, oCaster); + if (nClass == CLASS_TYPE_INVALID) continue; + + if (GetIsClassSpell(oCaster, nSpellID, nClass)) + { + if(DEBUG) DoDebug("inc_infusion >> GetHasSpellOnClassList: Class spell found."); + return TRUE; + } + } + if(DEBUG) DoDebug("inc_infusion >> GetHasSpellOnClassList: Class spell not found."); + return FALSE; +} + +/** + * @brief Applies a poison nausea effect to the user when infusion use fails. + * + * This function performs an immediate Fortitude saving throw against poison DC based on infusion caster level. + * If the user fails and is not immune to poison, an infusion nausea effect is applied, replacing any existing one. + * A second saving throw is scheduled after 1 minute to attempt to remove the effect. + * + * @param oUser The creature who used the infusion and may be poisoned. + * @param nInfusionCL The caster level of the infusion used, affecting the DC of the saving throw. + */ +void ApplyInfusionPoison(object oUser, int nInfusionCL) +{ + int nDC = 10 + (nInfusionCL / 2); + int bImmune = GetIsImmune(oUser, IMMUNITY_TYPE_POISON); + + // First save immediately + if (!bImmune && !PRCMySavingThrow(SAVING_THROW_FORT, oUser, nDC, SAVING_THROW_TYPE_POISON)) + { + // Remove existing infusion poison nausea effect before applying new + effect eOld = GetFirstEffect(oUser); + while (GetIsEffectValid(eOld)) + { + if (GetEffectTag(eOld) == "INFUSION_POISON_TAG") + { + RemoveEffect(oUser, eOld); + break; // Assuming only one effect with this tag + } + eOld = GetNextEffect(oUser); + } + + effect eNausea = EffectNausea(oUser, 60.0f); + + TagEffect(eNausea, "INFUSION_POISON_TAG"); + FloatingTextStringOnCreature("The infusion has made you nauseous.", oUser); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eNausea, oUser, RoundsToSeconds(10)); + } + + // Second save 1 minute later + if (!bImmune) + { + DelayCommand(60.0, InfusionSecondSave(oUser, nDC)); + } +} + +void InfusionSecondSave(object oUser, int nDC) +{ + if (!PRCMySavingThrow(SAVING_THROW_FORT, oUser, nDC, SAVING_THROW_TYPE_POISON)) + { + FloatingTextStringOnCreature("The infusion has made you nauseous.", oUser); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectNausea(oUser, 60.0f), oUser, RoundsToSeconds(10)); + } +} + +//:: void main (){} \ No newline at end of file diff --git a/src/include/inc_lookups.nss b/src/include/inc_lookups.nss index e5a5124..fa68b5c 100644 --- a/src/include/inc_lookups.nss +++ b/src/include/inc_lookups.nss @@ -242,25 +242,27 @@ void SetupLookupStage(object oMod, int n) case 11: SetLkupStage(n, oMod, CLASS_TYPE_DRAGON_SHAMAN, "cls_inv_drgshm"); break; case 12: SetLkupStage(n, oMod, CLASS_TYPE_WARLOCK, "cls_inv_warlok"); break; case 13: SetLkupStage(n, oMod, CLASS_TYPE_ARCHIVIST, "cls_spell_archv"); break; - case 14: SetLkupStage(n, oMod, CLASS_TYPE_ASSASSIN, "cls_spell_asasin"); break; - case 15: SetLkupStage(n, oMod, CLASS_TYPE_BARD, "cls_spell_bard"); break; - case 16: SetLkupStage(n, oMod, CLASS_TYPE_BEGUILER, "cls_spell_beguil"); break; - case 17: SetLkupStage(n, oMod, CLASS_TYPE_DREAD_NECROMANCER, "cls_spell_dnecro"); break; - case 18: SetLkupStage(n, oMod, CLASS_TYPE_DUSKBLADE, "cls_spell_duskbl"); break; - case 19: SetLkupStage(n, oMod, CLASS_TYPE_FAVOURED_SOUL, "cls_spell_favsol"); break; - case 20: SetLkupStage(n, oMod, CLASS_TYPE_HARPER, "cls_spell_harper"); break; - case 21: SetLkupStage(n, oMod, CLASS_TYPE_HEXBLADE, "cls_spell_hexbl"); break; - case 22: SetLkupStage(n, oMod, CLASS_TYPE_JUSTICEWW, "cls_spell_justww"); break; - case 23: SetLkupStage(n, oMod, CLASS_TYPE_SORCERER, "cls_spell_sorc"); break; - case 24: SetLkupStage(n, oMod, CLASS_TYPE_SUBLIME_CHORD, "cls_spell_schord"); break; - case 25: SetLkupStage(n, oMod, CLASS_TYPE_SUEL_ARCHANAMACH, "cls_spell_suel"); break; - case 26: SetLkupStage(n, oMod, CLASS_TYPE_VIGILANT, "cls_spell_vigil"); break; - case 27: SetLkupStage(n, oMod, CLASS_TYPE_WARMAGE, "cls_spell_wrmage"); break; - case 28: SetLkupStage(n, oMod, CLASS_TYPE_KNIGHT_WEAVE, "cls_spell_kngtwv"); break; - case 29: SetLkupStage(n, oMod, CLASS_TYPE_PSYCHIC_ROGUE, "cls_psipw_psyrog"); break; - case 30: SetLkupStage(n, oMod, CLASS_TYPE_SHADOWCASTER, "cls_myst_shdcst"); break; - case 31: SetLkupStage(n, oMod, CLASS_TYPE_SHADOWSMITH, "cls_myst_shdsmt"); break; - case 32: SetLkupStage(n, oMod, CLASS_TYPE_CELEBRANT_SHARESS, "cls_spell_sharss"); break; + case 14: SetLkupStage(n, oMod, CLASS_TYPE_BARD, "cls_spell_bard"); break; + case 15: SetLkupStage(n, oMod, CLASS_TYPE_BEGUILER, "cls_spell_beguil"); break; + case 16: SetLkupStage(n, oMod, CLASS_TYPE_DREAD_NECROMANCER, "cls_spell_dnecro"); break; + case 17: SetLkupStage(n, oMod, CLASS_TYPE_DUSKBLADE, "cls_spell_duskbl"); break; + case 18: SetLkupStage(n, oMod, CLASS_TYPE_FAVOURED_SOUL, "cls_spell_favsol"); break; + case 19: SetLkupStage(n, oMod, CLASS_TYPE_HARPER, "cls_spell_harper"); break; + case 20: SetLkupStage(n, oMod, CLASS_TYPE_HEXBLADE, "cls_spell_hexbl"); break; + case 21: SetLkupStage(n, oMod, CLASS_TYPE_JUSTICEWW, "cls_spell_justww"); break; + case 22: SetLkupStage(n, oMod, CLASS_TYPE_SORCERER, "cls_spell_sorc"); break; + case 23: SetLkupStage(n, oMod, CLASS_TYPE_SUBLIME_CHORD, "cls_spell_schord"); break; + case 24: SetLkupStage(n, oMod, CLASS_TYPE_SUEL_ARCHANAMACH, "cls_spell_suel"); break; + case 25: SetLkupStage(n, oMod, CLASS_TYPE_VIGILANT, "cls_spell_vigil"); break; + case 26: SetLkupStage(n, oMod, CLASS_TYPE_WARMAGE, "cls_spell_wrmage"); break; + case 27: SetLkupStage(n, oMod, CLASS_TYPE_KNIGHT_WEAVE, "cls_spell_kngtwv"); break; + case 28: SetLkupStage(n, oMod, CLASS_TYPE_PSYCHIC_ROGUE, "cls_psipw_psyrog"); break; + case 29: SetLkupStage(n, oMod, CLASS_TYPE_SHADOWCASTER, "cls_myst_shdcst"); break; + case 30: SetLkupStage(n, oMod, CLASS_TYPE_SHADOWSMITH, "cls_myst_shdsmt"); break; + case 31: SetLkupStage(n, oMod, CLASS_TYPE_CELEBRANT_SHARESS, "cls_spell_sharss"); break; + + //:: These were all moved to the Bioware spellbooks -Jaysyn + //case 14: SetLkupStage(n, oMod, CLASS_TYPE_ASSASSIN, "cls_spell_asasin"); break; //case 46: SetLkupStage(n, oMod, CLASS_TYPE_CULTIST_SHATTERED_PEAK, "cls_spell_cultst"); break; //case 40: SetLkupStage(n, oMod, CLASS_TYPE_NENTYAR_HUNTER, "cls_spell_hunter"); break; //case 28: SetLkupStage(n, oMod, CLASS_TYPE_SHADOWLORD, "cls_spell_tfshad"); break; @@ -528,7 +530,7 @@ int SpellToSpellbookID(int nSpell) int nOutSpellID = GetLocalInt(oWP, /*"PRC_GetRowFromSpellID_" + */IntToString(nSpell)); if(nOutSpellID == 0) nOutSpellID = -1; - //if(DEBUG) DoDebug("SpellToSpellbookID(" + IntToString(nSpell) + ", " + sFile + ") = " + IntToString(nOutSpellID)); + if(DEBUG) DoDebug("inc_lookup >> SpellToSpellbookID: (nSpell: " + IntToString(nSpell) + ") = nOutSpellID: " + IntToString(nOutSpellID)); return nOutSpellID; } diff --git a/src/include/inc_newspellbook.nss b/src/include/inc_newspellbook.nss index 909b93d..542e2d5 100644 --- a/src/include/inc_newspellbook.nss +++ b/src/include/inc_newspellbook.nss @@ -8,7 +8,7 @@ Make cls_spcr_*.2da Make blank cls_spell_*.2da Add cls_spgn_*.2da to classes.2da Add class entry in prc_classes.2da -Add the spellbook feat (#1999) to cls_feat_*.2da at the appropriate level +Add the spellbook feat (#1999) to cls_feat_*.2da at the appropriate level (not needed for NWN:EE) Add class to PRCGetSpellSaveDC() in prc_add_spell_dc Add class to GetSpellbookTypeForClass() below Add class to GetAbilityScoreForClass() below @@ -119,6 +119,7 @@ int GetSpellbookTypeForClass(int nClass) switch(nClass) { case CLASS_TYPE_ARCHIVIST: + case CLASS_TYPE_ASSASSIN: case CLASS_TYPE_BLACKGUARD: case CLASS_TYPE_BLIGHTER: case CLASS_TYPE_CLERIC: @@ -141,7 +142,6 @@ int GetSpellbookTypeForClass(int nClass) case CLASS_TYPE_VIGILANT: case CLASS_TYPE_WIZARD: return SPELLBOOK_TYPE_PREPARED; - case CLASS_TYPE_ASSASSIN: case CLASS_TYPE_BARD: case CLASS_TYPE_BEGUILER: case CLASS_TYPE_CELEBRANT_SHARESS: @@ -559,7 +559,7 @@ int bKnowsAllClassSpells(int nClass) { //case CLASS_TYPE_WIZARD: case CLASS_TYPE_ARCHIVIST: - case CLASS_TYPE_ASSASSIN: + //case CLASS_TYPE_ASSASSIN: case CLASS_TYPE_BARD: case CLASS_TYPE_CELEBRANT_SHARESS: case CLASS_TYPE_CULTIST_SHATTERED_PEAK: @@ -580,7 +580,79 @@ int bKnowsAllClassSpells(int nClass) return TRUE; } + int GetSpellKnownMaxCount(int nLevel, int nSpellLevel, int nClass, object oPC) +{ + // If the character doesn't have any spell slots available on for this level, it can't know any spells of that level either + if(!GetSlotCount(nLevel, nSpellLevel, GetAbilityScoreForClass(nClass, oPC), nClass)) + { + if(DEBUG) DoDebug("GetSpellKnownMaxCount: No slots available for " + IntToString(nClass) + " level " + IntToString(nLevel) + " circle " + IntToString(nSpellLevel)); + return 0; + } + + int nKnown; + string sFile = Get2DACache("classes", "SpellKnownTable", nClass); + string sKnown = Get2DACache(sFile, "SpellLevel" + IntToString(nSpellLevel), nLevel - 1); + + if(DEBUG) + { + DoDebug("GetSpellKnownMaxCount Details:"); + DoDebug("- Class: " + IntToString(nClass)); + DoDebug("- Passed Level: " + IntToString(nLevel)); + DoDebug("- Base Class Level: " + IntToString(GetLevelByClass(nClass, oPC))); + DoDebug("- Effective Level: " + IntToString(GetSpellslotLevel(nClass, oPC))); + DoDebug("- Spell Level: " + IntToString(nSpellLevel)); + DoDebug("- SpellKnownTable: " + sFile); + DoDebug("- MaxKnown from 2DA: " + sKnown); + } + + if(sKnown == "") + { + nKnown = -1; + if(DEBUG) DoDebug("GetSpellKnownMaxCount: Problem getting known numbers"); + } + else + nKnown = StringToInt(sKnown); + + if(nKnown == -1) + return 0; + + // COMPLETELY REWROTE THIS SECTION + // Bard and Sorcerer logic for prestige class advancement + if(nClass == CLASS_TYPE_SORCERER || nClass == CLASS_TYPE_BARD) + { + int baseClassLevel = GetLevelByClass(nClass, oPC); + int effectiveLevel = GetSpellslotLevel(nClass, oPC); + + // Debug the values we're checking + if(DEBUG) + { + DoDebug("Spont caster check - Base level: " + IntToString(baseClassLevel) + + ", Effective level: " + IntToString(effectiveLevel)); + } + + // If they have prestige class advancement OR special feats, they should get spells + if(effectiveLevel > baseClassLevel || + GetHasFeat(FEAT_DRACONIC_GRACE, oPC) || + GetHasFeat(FEAT_DRACONIC_BREATH, oPC)) + { + // Allow them to get spells - do nothing here, return nKnown at the end + if(DEBUG) DoDebug("Spontaneous caster eligible for new spells"); + } + else + { + // No advancement, no special feats - no new spells + if(DEBUG) DoDebug("Spontaneous caster NOT eligible for new spells"); + return 0; + } + } + + if(DEBUG) DoDebug("Final spell known count: " + IntToString(nKnown)); + return nKnown; +} + + +/* int GetSpellKnownMaxCount(int nLevel, int nSpellLevel, int nClass, object oPC) { // If the character doesn't have any spell slots available on for this level, it can't know any spells of that level either // @todo Check rules. There might be cases where this doesn't hold @@ -588,22 +660,9 @@ int GetSpellKnownMaxCount(int nLevel, int nSpellLevel, int nClass, object oPC) return 0; int nKnown; string sFile; - // Bioware casters use their classes.2da-specified tables - /*if( nClass == CLASS_TYPE_WIZARD - || nClass == CLASS_TYPE_SORCERER - || nClass == CLASS_TYPE_BARD - || nClass == CLASS_TYPE_CLERIC - || nClass == CLASS_TYPE_DRUID - || nClass == CLASS_TYPE_PALADIN - || nClass == CLASS_TYPE_RANGER) - {*/ - sFile = Get2DACache("classes", "SpellKnownTable", nClass); - /*} - else - { - sFile = Get2DACache("classes", "FeatsTable", nClass); - sFile = "cls_spkn" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061231 - }*/ + + sFile = Get2DACache("classes", "SpellKnownTable", nClass); + string sKnown = Get2DACache(sFile, "SpellLevel" + IntToString(nSpellLevel), nLevel - 1); if(DEBUG) DoDebug("GetSpellKnownMaxCount(" + IntToString(nLevel) + ", " + IntToString(nSpellLevel) + ", " + IntToString(nClass) + ", " + GetName(oPC) + ") = " + sKnown); @@ -626,6 +685,7 @@ int GetSpellKnownMaxCount(int nLevel, int nSpellLevel, int nClass, object oPC) } return nKnown; } + */ int GetSpellKnownCurrentCount(object oPC, int nSpellLevel, int nClass) { @@ -693,6 +753,44 @@ int GetSpellKnownCurrentCount(object oPC, int nSpellLevel, int nClass) } int GetSpellUnknownCurrentCount(object oPC, int nSpellLevel, int nClass) +{ + // Get the lookup token created by MakeSpellbookLevelLoop() + string sTag = "SpellLvl_" + IntToString(nClass) + "_Level_" + IntToString(nSpellLevel); + object oCache = GetObjectByTag(sTag); + if(!GetIsObjectValid(oCache)) + { + if(DEBUG) DoDebug("GetSpellUnknownCurrentCount: " + sTag + " is not valid"); + + // Add code to create the missing lookup object + if(DEBUG) DoDebug("Attempting to create missing spell lookup token"); + ExecuteScript("prc_create_spellb", oPC); + + // Try again after creating it + oCache = GetObjectByTag(sTag); + if(!GetIsObjectValid(oCache)) + { + if(DEBUG) DoDebug("Still couldn't create spell lookup token"); + return 0; + } + else + { + if(DEBUG) DoDebug("Successfully created spell lookup token"); + } + } + + // Read the total number of spells on the given level and determine how many are already known + int nTotal = array_get_size(oCache, "Lkup"); + int nKnown = GetSpellKnownCurrentCount(oPC, nSpellLevel, nClass); + int nUnknown = nTotal - nKnown; + + if(DEBUG) DoDebug("GetSpellUnknownCurrentCount(" + GetName(oPC) + ", " + IntToString(nSpellLevel) + ", " + IntToString(nClass) + ") = " + IntToString(nUnknown)); + if(DEBUG) DoDebug(" Total spells in lookup: " + IntToString(nTotal) + ", Known spells: " + IntToString(nKnown)); + + return nUnknown; +} + + +/* int GetSpellUnknownCurrentCount(object oPC, int nSpellLevel, int nClass) { // Get the lookup token created by MakeSpellbookLevelLoop() string sTag = "SpellLvl_" + IntToString(nClass) + "_Level_" + IntToString(nSpellLevel); @@ -709,7 +807,7 @@ int GetSpellUnknownCurrentCount(object oPC, int nSpellLevel, int nClass) if(DEBUG) DoDebug("GetSpellUnknownCurrentCount(" + GetName(oPC) + ", " + IntToString(nSpellLevel) + ", " + IntToString(nClass) + ") = " + IntToString(nUnknown)); return nUnknown; -} +} */ void AddSpellUse(object oPC, int nSpellbookID, int nClass, string sFile, string sArrayName, int nSpellbookType, object oSkin, int nFeatID, int nIPFeatID, string sIDX = "") { @@ -850,7 +948,7 @@ void SetupSpells(object oPC, int nClass) int nAbility = GetAbilityScoreForClass(nClass, oPC); int nSpellbookType = GetSpellbookTypeForClass(nClass); - if(DEBUG) DoDebug("SetupSpells\n" + if(DEBUG) DoDebug("SetupSpells()\n" + "nClass = " + IntToString(nClass) + "\n" + "nSpellslotLevel = " + IntToString(nLevel) + "\n" + "nAbility = " + IntToString(nAbility) + "\n" @@ -1178,7 +1276,7 @@ void CastSpontaneousSpell(int nClass, int bInstantSpell = FALSE) else if(GetLocalInt(OBJECT_SELF, "PRC_metamagic_state") == 1) SetLocalInt(OBJECT_SELF, "MetamagicFeatAdjust", 0); } - + if (DEBUG) DoDebug("CastSpontaneousSpell(): nSpellLevel is: "+IntToString(nSpellLevel)+"."); CheckSpontSlots(nClass, nSpellID, nSpellLevel); if(GetLocalInt(OBJECT_SELF, "NSB_Cast")) ActionDoCommand(CheckSpontSlots(nClass, nSpellID, nSpellLevel, TRUE)); @@ -1330,6 +1428,8 @@ void NewSpellbookSpell(int nClass, int nSpellbookType, int nMetamagic = METAMAGI string sFile = GetFileForClass(nClass); int nSpellLevel = StringToInt(Get2DACache(sFile, "Level", nSpellbookID)); + + if (DEBUG) DoDebug("inc_newspellbook >> NewSpellbookSpell(): nSpellbookType is: "+IntToString(nSpellbookType)+"."); // Make sure the caster has uses of this spell remaining // 2009-9-20: Add metamagic feat abilities. -N-S @@ -1371,13 +1471,14 @@ void NewSpellbookSpell(int nClass, int nSpellbookType, int nMetamagic = METAMAGI else if(nSpellLevel > 9)//now test the spell level { nMetamagic = METAMAGIC_NONE; - ActionDoCommand(SendMessageToPC(oPC, "Modified spell level is to high! Casting spell without metamagic")); + ActionDoCommand(SendMessageToPC(oPC, "Modified spell level is too high! Casting spell without metamagic")); nSpellLevel = nSpellSlotLevel; } else if(GetLocalInt(oPC, "PRC_metamagic_state") == 1) SetLocalInt(oPC, "MetamagicFeatAdjust", 0); } - + + if (DEBUG) DoDebug("inc_newspellbook >> NewSpellbookSpell(): nSpellLevel is: "+IntToString(nSpellLevel)+"."); CheckSpontSlots(nClass, nSpellID, nSpellLevel); if(GetLocalInt(oPC, "NSB_Cast")) ActionDoCommand(CheckSpontSlots(nClass, nSpellID, nSpellLevel, TRUE)); @@ -1460,7 +1561,7 @@ void CheckPrepSlots(int nClass, int nSpellID, int nSpellbookID, int bIsAction = { DeleteLocalInt(OBJECT_SELF, "NSB_Cast"); int nCount = persistant_array_get_int(OBJECT_SELF, "NewSpellbookMem_" + IntToString(nClass), nSpellbookID); - if(DEBUG) DoDebug("NewSpellbookSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(nSpellbookID) + "] = " + IntToString(nCount)); + if(DEBUG) DoDebug("NewSpellbookSpell >> CheckPrepSlots: NewSpellbookMem_" + IntToString(nClass) + "[SpellbookID: " + IntToString(nSpellbookID) + "] = " + IntToString(nCount)); if(nCount < 1) { string sSpellName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID))); @@ -1486,7 +1587,7 @@ void CheckSpontSlots(int nClass, int nSpellID, int nSpellSlotLevel, int bIsActio { DeleteLocalInt(OBJECT_SELF, "NSB_Cast"); int nCount = persistant_array_get_int(OBJECT_SELF, "NewSpellbookMem_" + IntToString(nClass), nSpellSlotLevel); - if(DEBUG) DoDebug("NewSpellbookSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(nSpellSlotLevel) + "] = " + IntToString(nCount)); + if(DEBUG) DoDebug("NewSpellbookSpell >> CheckSpontSlots: NewSpellbookMem_" + IntToString(nClass) + "[SpellSlotLevel: " + IntToString(nSpellSlotLevel) + "] = " + IntToString(nCount)); if(nCount < 1) { // "You have no castings of spells of level " + IntToString(nSpellLevel) + " remaining" diff --git a/src/include/inc_switch_setup.nss b/src/include/inc_switch_setup.nss index afffaae..d21b16c 100644 --- a/src/include/inc_switch_setup.nss +++ b/src/include/inc_switch_setup.nss @@ -720,7 +720,7 @@ void SetDefaultFileEnds() SetPRCSwitch("PRC_FILE_END_polymorph", 155); SetPRCSwitch("PRC_FILE_END_portraits", 1300); SetPRCSwitch("PRC_FILE_END_prc_craft_alchem", 37); - SetPRCSwitch("PRC_FILE_END_prc_craft_gen_it", 204); + SetPRCSwitch("PRC_FILE_END_prc_craft_gen_it", 253); SetPRCSwitch("PRC_FILE_END_prc_craft_poison", 62); SetPRCSwitch("PRC_FILE_END_prc_domains", 59); SetPRCSwitch("PRC_FILE_END_prc_familiar", 10); @@ -767,7 +767,7 @@ void SetDefaultFileEnds() SetPRCSwitch("PRC_FILE_END_soundset", 453); SetPRCSwitch("PRC_FILE_END_soundsettype", 4); SetPRCSwitch("PRC_FILE_END_soundtypes", 1); - SetPRCSwitch("PRC_FILE_END_spells", 19348); + SetPRCSwitch("PRC_FILE_END_spells", 19400); //SetPRCSwitch("PRC_FILE_END_spellschools", 9); SetPRCSwitch("PRC_FILE_END_statescripts", 35); SetPRCSwitch("PRC_FILE_END_stringtokens", 92); @@ -876,6 +876,8 @@ void CreateSwitchNameArray() array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_BIOWARE_HARM); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_BIOWARE_NEUTRALIZE_POISON); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_BIOWARE_REMOVE_DISEASE); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_BIO_UNLEARN); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_UNLEARN_SPELL_MAXNR); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_TIMESTOP_BIOWARE_DURATION); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_TIMESTOP_LOCAL); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_TIMESTOP_NO_HOSTILE); @@ -1067,14 +1069,16 @@ void CreateSwitchNameArray() array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_ROD_CASTER_LEVEL); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_STAFF_CASTER_LEVEL); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_BASE_ITEMS); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_BREWPOTION_MAXLEVEL); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_BREWPOTION_COSTMODIFIER); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_SCRIBESCROLL_COSTMODIFIER); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_CRAFTWAND_MAXLEVEL); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_CRAFTWAND_COSTMODIFIER); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_BREWPOTION_MAXLEVEL); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_BREWPOTION_COSTMODIFIER); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_SCRIBESCROLL_COSTMODIFIER); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_CRAFTWAND_MAXLEVEL); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_CRAFTWAND_COSTMODIFIER); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_CREATEINFUSION_COSTMODIFIER); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_ARBITRARY); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_COST_SCALE); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_TIME_SCALE); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CREATE_INFUSION_CASTER_LEVEL); //spells diff --git a/src/include/moi_inc_moifunc.nss b/src/include/moi_inc_moifunc.nss index d48a441..a2b0a3b 100644 --- a/src/include/moi_inc_moifunc.nss +++ b/src/include/moi_inc_moifunc.nss @@ -1182,7 +1182,7 @@ int GetMaxEssentiaCapacityFeat(object oMeldshaper) // Don't allow more than they have if (nMax > GetTotalUsableEssentia(oMeldshaper)) nMax = GetTotalUsableEssentia(oMeldshaper); - //if (DEBUG) DoDebug("GetMaxEssentiaCapacityFeat: nHD "+IntToString(nHD)+" nMax "+IntToString(nMax)); + if(DEBUG) DoDebug("GetMaxEssentiaCapacityFeat: nHD "+IntToString(nHD)+" nMax "+IntToString(nMax)); return nMax; } diff --git a/src/include/nw_inc_gff.nss b/src/include/nw_inc_gff.nss new file mode 100644 index 0000000..533cf21 --- /dev/null +++ b/src/include/nw_inc_gff.nss @@ -0,0 +1,623 @@ +// This is a helper library for advanced use: It allows constructing arbitrary gff data. +// You can then spawn your object via JsonToObject(). +// +// The data format is the same as https://github.com/niv/neverwinter.nim@1.4.3+. +// +// Example: +// +// json j = GffCreateObject(OBJECT_TYPE_ITEM); +// j = GffAddInt(j, "BaseItem", BASE_ITEM_BELT); +// j = GffAddInt(j, "ModelPart1", 12); +// j = GffAddLocString(j, "LocalizedName", "hi!"); +// object belt = JsonToObject(j, GetLocation(OBJECT_SELF)); + + +const string GFF_FIELD_TYPE_STRUCT = "struct"; +const string GFF_FIELD_TYPE_LIST = "list"; +const string GFF_FIELD_TYPE_BYTE = "byte"; +const string GFF_FIELD_TYPE_CHAR = "char"; +const string GFF_FIELD_TYPE_WORD = "word"; +const string GFF_FIELD_TYPE_SHORT = "short"; +const string GFF_FIELD_TYPE_DWORD = "dword"; +const string GFF_FIELD_TYPE_INT = "int"; +const string GFF_FIELD_TYPE_DWORD64 = "dword64"; +const string GFF_FIELD_TYPE_INT64 = "int64"; +const string GFF_FIELD_TYPE_FLOAT = "float"; +const string GFF_FIELD_TYPE_DOUBLE = "double"; +const string GFF_FIELD_TYPE_RESREF = "resref"; +const string GFF_FIELD_TYPE_STRING = "cexostring"; +const string GFF_FIELD_TYPE_LOC_STRING = "cexolocstring"; + + +// Create a empty object of the given type. You need to manually fill in all +// GFF data with GffAddXXX. This will require understanding of the GFF file format +// and what data fields each object type requires. +json GffCreateObject(int nObjectType); +// Create a combined area format(CAF) object. You need to manually create the ARE and GIT objects with their required data fields. +json GffCreateArea(json jARE, json jGIT); + +// Returns the OBJECT_TYPE_* of jGff. +// Note: Will return 0 for invalid object types, including areas. +int GffGetObjectType(json jGff); +// Returns TRUE if jGff is a combined area format(CAF) object. +int GffGetIsArea(json jGff); + +// Returns TRUE if a field named sLabel of sType exists in jGff. +// * sLabel: Can be a json pointer(path) without the starting /, see the documentation of JsonPointer() for details. +// * sType: An optional GFF_FIELD_TYPE_*, leave empty to check if sLabel exists regardless of type. +int GffGetFieldExists(json jGff, string sLabel, string sType = ""); + + +// Add a new field, will overwrite any existing fields with the same label even if the type is different. +// Returns a json null value on error with GetJsonError() filled in. +// +// sLabel can be a json pointer(path) without the starting /, see the documentation of JsonPointer() for details. +// For example, to add the tag of an area to an empty combined area format(CAF) object you can do the following: +// json jArea = GffCreateArea(JsonObject(), JsonObject()); +// jArea = GffAddString(jArea, "ARE/value/Tag", "AREA_TAG"); + +json GffAddStruct(json jGff, string sLabel, json jStruct, int nType = -1); +json GffAddList(json jGff, string sLabel, json jList); +json GffAddByte(json jGff, string sLabel, int v); +json GffAddChar(json jGff, string sLabel, int v); +json GffAddWord(json jGff, string sLabel, int v); +json GffAddShort(json jGff, string sLabel, int v); +// Note: Only data of type int32 will fit, because that's all that NWScript supports. +json GffAddDword(json jGff, string sLabel, int v); +json GffAddInt(json jGff, string sLabel, int v); +// Note: Only data of type int32 will fit, because that's all that NWScript supports. +json GffAddDword64(json jGff, string sLabel, int v); +// Note: Only data of type int32 will fit, because that's all that NWScript supports. +json GffAddInt64(json jGff, string sLabel, int v); +json GffAddFloat(json jGff, string sLabel, float v); +// Note: Only data of type float will fit, because that's all that NWScript supports. +json GffAddDouble(json jGff, string sLabel, float v); +json GffAddResRef(json jGff, string sLabel, string v); +json GffAddString(json jGff, string sLabel, string v); +json GffAddLocString(json jGff, string sLabel, string v, int nStrRef = -1); + + +// Replace a field, the type must match and the field must exist. +// Returns a json null value on error with GetJsonError() filled in. +// +// sLabel can be a json pointer(path) without the starting /, see the documentation of JsonPointer() for details. +// For example, to replace the name of an area in a combined area format(CAF) object you can do the following: +// json jArea = ObjectToStruct(GetFirstArea()); +// jArea = GffReplaceLocString(jArea, "ARE/value/Name", "New Area Name"); + +json GffReplaceStruct(json jGff, string sLabel, json jStruct); +json GffReplaceList(json jGff, string sLabel, json jList); +json GffReplaceByte(json jGff, string sLabel, int v); +json GffReplaceChar(json jGff, string sLabel, int v); +json GffReplaceWord(json jGff, string sLabel, int v); +json GffReplaceShort(json jGff, string sLabel, int v); +// Note: Only data of type int32 will fit, because that's all that NWScript supports. +json GffReplaceDword(json jGff, string sLabel, int v); +json GffReplaceInt(json jGff, string sLabel, int v); +// Note: Only data of type int32 will fit, because that's all that NWScript supports. +json GffReplaceDword64(json jGff, string sLabel, int v); +// Note: Only data of type int32 will fit, because that's all that NWScript supports. +json GffReplaceInt64(json jGff, string sLabel, int v); +json GffReplaceFloat(json jGff, string sLabel, float v); +// Note: Only data of type float will fit, because that's all that NWScript supports. +json GffReplaceDouble(json jGff, string sLabel, float v); +json GffReplaceResRef(json jGff, string sLabel, string v); +json GffReplaceString(json jGff, string sLabel, string v); +json GffReplaceLocString(json jGff, string sLabel, string v, int nStrRef = -1); + + +// Remove a field, the type must match and the field must exist. +// Returns a json null value on error with GetJsonError() filled in. +// +// sLabel can be a json pointer(path) without the starting /, see the documentation of JsonPointer() for details. +// For example, to remove all placeables from an area in a combined area format(CAF) object you can do the following: +// json jArea = ObjectToStruct(GetFirstArea()); +// jArea = GffRemoveList(jArea, "GIT/value/Placeable List"); + +json GffRemoveStruct(json jGff, string sLabel); +json GffRemoveList(json jGff, string sLabel); +json GffRemoveByte(json jGff, string sLabel); +json GffRemoveChar(json jGff, string sLabel); +json GffRemoveWord(json jGff, string sLabel); +json GffRemoveShort(json jGff, string sLabel); +json GffRemoveDword(json jGff, string sLabel); +json GffRemoveInt(json jGff, string sLabel); +json GffRemoveDword64(json jGff, string sLabel); +json GffRemoveInt64(json jGff, string sLabel); +json GffRemoveFloat(json jGff, string sLabel); +json GffRemoveDouble(json jGff, string sLabel); +json GffRemoveResRef(json jGff, string sLabel); +json GffRemoveString(json jGff, string sLabel); +json GffRemoveLocString(json jGff, string sLabel); + + +// Get a field's value as json object. +// Returns a json null value on error with GetJsonError() filled in. +// +// Note: Json types do not implicitly convert between types, this means you cannot convert a JsonInt to a string with JsonGetString(), etc. +// You may need to check the type with JsonGetType() and then do the appropriate cast yourself. +// For GffGet*() functions the json type returned is noted in the function description. +// +// Example: +// INCORRECT: string s = JsonGetString(GffGetInt()); +// CORRECT: string s = IntToString(JsonGetInt(GffGetInt())); +// +// sLabel can be a json pointer(path) without the starting /, see the documentation of JsonPointer() for details. +// For example, to get the resref of an area in a combined area format(CAF) object you can do the following: +// json jResRef = GffGetResRef(ObjectToStruct(GetFirstArea()), "ARE/value/ResRef"); +// if (jResRef != JsonNull()) +// { +// string sResRef = JsonGetString(jResRef); +// } +// else +// WriteTimestampedLogEntry("Failed to get area ResRef: " + JsonGetError(jResRef)); + +// Returns the struct as JsonObject() on success. +json GffGetStruct(json jGff, string sLabel); +// Returns a JsonArray() with all the list elements on success. +json GffGetList(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetByte(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetChar(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetWord(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetShort(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetDword(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetInt(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetDword64(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetInt64(json jGff, string sLabel); +// Returns a JsonFloat() on success. +json GffGetFloat(json jGff, string sLabel); +// Returns a JsonFloat() on success. +json GffGetDouble(json jGff, string sLabel); +// Returns a JsonString() on success. +json GffGetResRef(json jGff, string sLabel); +// Returns a JsonString() on success. +json GffGetString(json jGff, string sLabel); +// Returns a JsonObject() on success. +// Key "0" will have a JsonString() with the string, if set. +// Key "id" will have a JsonInt() with the strref, if set. +json GffGetLocString(json jGff, string sLabel); + + +// *** Internal Helper Functions +json AddPatchOperation(json jPatchArray, string sOp, string sPath, json jValue) +{ + json jOperation = JsonObject(); + jOperation = JsonObjectSet(jOperation, "op", JsonString(sOp)); + jOperation = JsonObjectSet(jOperation, "path", JsonString(sPath)); + jOperation = JsonObjectSet(jOperation, "value", jValue); + return JsonArrayInsert(jPatchArray, jOperation); +} + +json GffAddField(json jGff, string sLabel, string sType, json jValue, int nType = -1) +{ + json jField = JsonObject(); + jField = JsonObjectSet(jField, "type", JsonString(sType)); + jField = JsonObjectSet(jField, "value", jValue); + if (sType == GFF_FIELD_TYPE_STRUCT && nType != -1) + jField = JsonObjectSet(jField, "__struct_id", JsonInt(nType)); + + return JsonPatch(jGff, AddPatchOperation(JsonArray(), "add", "/" + sLabel, jField)); +} + +json GffReplaceField(json jGff, string sLabel, string sType, json jValue) +{ + json jPatch = JsonArray(); + jPatch = AddPatchOperation(jPatch, "test", "/" + sLabel + "/type", JsonString(sType)); + jPatch = AddPatchOperation(jPatch, "replace", "/" + sLabel + "/value", jValue); + return JsonPatch(jGff, jPatch); +} + +json GffRemoveField(json jGff, string sLabel, string sType) +{ + json jPatch = JsonArray(); + jPatch = AddPatchOperation(jPatch, "test", "/" + sLabel + "/type", JsonString(sType)); + jPatch = AddPatchOperation(jPatch, "remove", "/" + sLabel, JsonNull()); + return JsonPatch(jGff, jPatch); +} + +json GffGetFieldType(json jGff, string sLabel) +{ + return JsonPointer(jGff, "/" + sLabel + "/type"); +} + +json GffGetFieldValue(json jGff, string sLabel) +{ + return JsonPointer(jGff, "/" + sLabel + "/value"); +} + +json GffGetField(json jGff, string sLabel, string sType) +{ + json jType = GffGetFieldType(jGff, sLabel); + if (jType == JsonNull()) + return jType; + else if (jType != JsonString(sType)) + return JsonNull("field type does not match"); + else + return GffGetFieldValue(jGff, sLabel); +} + +json GffLocString(string v, int nStrRef = -1) +{ + json jLocString = JsonObject(); + if (v != "") + jLocString = JsonObjectSet(jLocString, "0", JsonString(v)); // english/any + if (nStrRef != -1) + jLocString = JsonObjectSet(jLocString, "id", JsonInt(nStrRef)); + + return jLocString; +} +//*** + +json GffCreateObject(int nObjectType) +{ + string ot; + if (nObjectType == OBJECT_TYPE_CREATURE) ot = "UTC "; + else if (nObjectType == OBJECT_TYPE_ITEM) ot = "UTI "; + else if (nObjectType == OBJECT_TYPE_TRIGGER) ot = "UTT "; + else if (nObjectType == OBJECT_TYPE_DOOR) ot = "UTD "; + else if (nObjectType == OBJECT_TYPE_WAYPOINT) ot = "UTW "; + else if (nObjectType == OBJECT_TYPE_PLACEABLE) ot = "UTP "; + else if (nObjectType == OBJECT_TYPE_STORE) ot = "UTM "; + else if (nObjectType == OBJECT_TYPE_ENCOUNTER) ot = "UTE "; + + if (ot == "") return JsonNull("invalid object type"); + + json ret = JsonObject(); + ret = JsonObjectSet(ret, "__data_type", JsonString(ot)); + return ret; +} + +json GffCreateArea(json jARE, json jGIT) +{ + json jCAF = JsonObject(); + jCAF = JsonObjectSet(jCAF, "__data_type", JsonString("CAF ")); + jCAF = GffAddStruct(jCAF, "ARE", jARE, 0); + jCAF = GffAddStruct(jCAF, "GIT", jGIT, 1); + return jCAF; +} + + +int GffGetObjectType(json jGff) +{ + json jDataType = JsonObjectGet(jGff, "__data_type"); + if (jDataType == JsonNull()) + return 0; + else + { + string sObjectType = JsonGetString(jDataType); + + if (sObjectType == "UTC ") return OBJECT_TYPE_CREATURE; + else if (sObjectType == "UTI ") return OBJECT_TYPE_ITEM; + else if (sObjectType == "UTT ") return OBJECT_TYPE_TRIGGER; + else if (sObjectType == "UTD ") return OBJECT_TYPE_DOOR; + else if (sObjectType == "UTW ") return OBJECT_TYPE_WAYPOINT; + else if (sObjectType == "UTP ") return OBJECT_TYPE_PLACEABLE; + else if (sObjectType == "UTM ") return OBJECT_TYPE_STORE; + else if (sObjectType == "UTE ") return OBJECT_TYPE_ENCOUNTER; + } + + return 0; +} + +int GffGetIsArea(json jGff) +{ + return JsonObjectGet(jGff, "__data_type") == JsonString("CAF "); +} + +int GffGetFieldExists(json jGff, string sLabel, string sType = "") +{ + json jFieldType = GffGetFieldType(jGff, sLabel); + return sType == "" ? jFieldType != JsonNull() : jFieldType == JsonString(sType); +} + + +json GffAddStruct(json jGff, string sLabel, json jStruct, int nType = -1) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_STRUCT, jStruct, nType); +} + +json GffAddList(json jGff, string sLabel, json jList) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_LIST, jList); +} + +json GffAddByte(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_BYTE, JsonInt(v)); +} + +json GffAddChar(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_CHAR, JsonInt(v)); +} + +json GffAddWord(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_WORD, JsonInt(v)); +} + +json GffAddShort(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_SHORT, JsonInt(v)); +} + +json GffAddDword(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_DWORD, JsonInt(v)); +} + +json GffAddInt(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_INT, JsonInt(v)); +} + +json GffAddDword64(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_DWORD64, JsonInt(v)); +} + +json GffAddInt64(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_INT64, JsonInt(v)); +} + +json GffAddFloat(json jGff, string sLabel, float v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_FLOAT, JsonFloat(v)); +} + +json GffAddDouble(json jGff, string sLabel, float v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_DOUBLE, JsonFloat(v)); +} + +json GffAddResRef(json jGff, string sLabel, string v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_RESREF, JsonString(v)); +} + +json GffAddString(json jGff, string sLabel, string v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_STRING, JsonString(v)); +} + +json GffAddLocString(json jGff, string sLabel, string v, int nStrRef = -1) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_LOC_STRING, GffLocString(v, nStrRef)); +} + + +json GffReplaceStruct(json jGff, string sLabel, json jStruct) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_STRUCT, jStruct); +} + +json GffReplaceList(json jGff, string sLabel, json jList) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_LIST, jList); +} + +json GffReplaceByte(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_BYTE, JsonInt(v)); +} + +json GffReplaceChar(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_CHAR, JsonInt(v)); +} + +json GffReplaceWord(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_WORD, JsonInt(v)); +} + +json GffReplaceShort(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_SHORT, JsonInt(v)); +} + +json GffReplaceDword(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_DWORD, JsonInt(v)); +} + +json GffReplaceInt(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_INT, JsonInt(v)); +} + +json GffReplaceDword64(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_DWORD64, JsonInt(v)); +} + +json GffReplaceInt64(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_INT64, JsonInt(v)); +} + +json GffReplaceFloat(json jGff, string sLabel, float v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_FLOAT, JsonFloat(v)); +} + +json GffReplaceDouble(json jGff, string sLabel, float v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_DOUBLE, JsonFloat(v)); +} + +json GffReplaceResRef(json jGff, string sLabel, string v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_RESREF, JsonString(v)); +} + +json GffReplaceString(json jGff, string sLabel, string v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_STRING, JsonString(v)); +} + +json GffReplaceLocString(json jGff, string sLabel, string v, int nStrRef = -1) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_LOC_STRING, GffLocString(v, nStrRef)); +} + + +json GffRemoveStruct(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_STRUCT); +} + +json GffRemoveList(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_LIST); +} + +json GffRemoveByte(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_BYTE); +} + +json GffRemoveChar(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_CHAR); +} + +json GffRemoveWord(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_WORD); +} + +json GffRemoveShort(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_SHORT); +} + +json GffRemoveDword(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_DWORD); +} + +json GffRemoveInt(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_INT); +} + +json GffRemoveDword64(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_DWORD64); +} + +json GffRemoveInt64(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_INT64); +} + +json GffRemoveFloat(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_FLOAT); +} + +json GffRemoveDouble(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_DOUBLE); +} + +json GffRemoveResRef(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_RESREF); +} + +json GffRemoveString(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_STRING); +} + +json GffRemoveLocString(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_LOC_STRING); +} + + +json GffGetStruct(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_STRUCT); +} + +json GffGetList(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_LIST); +} + +json GffGetByte(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_BYTE); +} + +json GffGetChar(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_CHAR); +} + +json GffGetWord(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_WORD); +} + +json GffGetShort(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_SHORT); +} + +json GffGetDword(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_DWORD); +} + +json GffGetInt(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_INT); +} + +json GffGetDword64(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_DWORD64); +} + +json GffGetInt64(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_INT64); +} + +json GffGetFloat(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_FLOAT); +} + +json GffGetDouble(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_DOUBLE); +} + +json GffGetResRef(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_RESREF); +} + +json GffGetString(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_STRING); +} + +json GffGetLocString(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_LOC_STRING); +} diff --git a/src/include/nw_inc_nui.nss b/src/include/nw_inc_nui.nss index 96fc3da..a37f13f 100644 --- a/src/include/nw_inc_nui.nss +++ b/src/include/nw_inc_nui.nss @@ -40,6 +40,24 @@ const float NUI_STYLE_TERTIARY_HEIGHT = 30.0; const float NUI_STYLE_ROW_HEIGHT = 25.0; +// ----------------------- +// Bind params + +// These currently only affect presentation and serve as a +// optimisation to let the client do the heavy lifting on this. +// In particular, this enables you to bind an array of values and +// transform them all at once on the client, instead of having to +// have the server transform them before sending. + +// NB: These must be OR-ed together into a bitmask. + +const int NUI_NUMBER_FLAG_HEX = 0x001; + +// NB: These must be OR-ed together into a bitmask. + +const int NUI_TEXT_FLAG_LOWERCASE = 0x001; +const int NUI_TEXT_FLAG_UPPERCASE = 0x002; + // ----------------------- // Window @@ -47,24 +65,41 @@ const float NUI_STYLE_ROW_HEIGHT = 25.0; // * Set the window title to JsonBool(FALSE), Collapse to JsonBool(FALSE) and bClosable to FALSE // to hide the title bar. // Note: You MUST provide a way to close the window some other way, or the user will be stuck with it. -json // Window -NuiWindow( - json jRoot, // Layout-ish (NuiRow, NuiCol, NuiGroup) - json jTitle, // Bind:String - json jGeometry, // Bind:Rect Set x and/or y to -1.0 to center the window on that axis - // Set x and/or y to -2.0 to position the window's top left at the mouse cursor's position of that axis - // Set x and/or y to -3.0 to center the window on the mouse cursor's position of that axis - json jResizable, // Bind:Bool Set to JsonBool(TRUE) or JsonNull() to let user resize without binding. - json jCollapsed, // Bind:Bool Set to a static value JsonBool(FALSE) to disable collapsing. - // Set to JsonNull() to let user collapse without binding. - // For better UX, leave collapsing on. - json jClosable, // Bind:Bool You must provide a way to close the window if you set this to FALSE. - // For better UX, handle the window "closed" event. - json jTransparent, // Bind:Bool Do not render background - json jBorder, // Bind:Bool Do not render border - json jAcceptsInput = // Bind:Bool Set JsonBool(FALSE) to disable all input. - JSON_TRUE // All hover, clicks and keypresses will fall through. -); +// * Set a minimum size constraint equal to the maximmum size constraint in the same dimension to prevent +// a window from being resized in that dimension. +// - jRoot: Layout-ish (NuiRow, NuiCol, NuiGroup) +// - jTitle: Bind:String +// - jGeometry: Bind:Rect +// Set x and/or y to -1.0 to center the window on that axis. +// Set x and/or y to -2.0 to position the window's top left at the mouse cursor's position of that axis. +// Set x and/or y to -3.0 to center the window on the mouse cursor's position of that axis. +// - jResizable: Bind:Bool +// Set to JsonBool(TRUE) or JsonNull() to let user resize without binding. +// - jCollapsed: Bind:Bool +// Set to a static value JsonBool(FALSE) to disable collapsing. +// Set to JsonNull() to let user collapse without binding. +// For better UX, leave collapsing on. +// - jCloseable: Bind:Bool +// You provide a way to close the window if you set this to FALSE. +// For better UX, handle the window "closed" event. +// - jTransparent: Bind:Bool +// Do not render background +// - jBorder: Bind:Bool +// Do not render border +// - jAcceptsInput: Bind:Bool +// Set JsonBool(FALSE) to disable all input. +// All hover, clicks and keypresses will fall through. +// - jSizeConstraint: Bind:Rect +// Constrains minimum and maximum size of window. +// Set x to minimum width, y to minimum height, w to maximum width, h to maximum height. +// Set any individual constraint to 0.0 to ignore that constraint. +// - jEdgeConstraint: Bind:Rect +// Prevents a window from being rendered within the specified margins. +// Set x to left margin, y to top margin, w to right margin, h to bottom margin. +// Set any individual constraint to 0.0 to ignore that constraint +// - jFont: Bind:String +// Override font used on window, including decorations. See NuiStyleFont() for details. +json NuiWindow(json jRoot, json jTitle, json jGeometry, json jResizable,json jCollapsed,json jClosable, json jTransparent, json jBorder, json jAcceptsInput = JSON_TRUE, json jSizeConstraint = JSON_NULL, json jEdgeConstraint = JSON_NULL, json jFont = JSON_STRING); // ----------------------- // Values @@ -74,144 +109,111 @@ NuiWindow( // NuiSetBind(.., "mybindlabel", JsonString("hi")); // To create static values, just use the json types directly: // JsonString("hi"); -json // Bind -NuiBind( - string sId -); +// +// You can parametrise this particular bind with the given flags. +// These flags only apply to that particular usage of this bind value. +// +// - sId: string +// - nNumberFlags: bitmask of NUI_NUMBER_FLAG_* +// - nNumberPrecision: Precision to print number with (int or float) +// - nTextFlags: bitmask of NUI_TEXT_FLAG_* +json NuiBind(string sId, int nNumberFlags = 0, int nNumberPrecision = 0, int nTextFlags = 0); // Tag the given element with a id. // Only tagged elements will send events to the server. -json // Element -NuiId( - json jElem, // Element - string sId // String -); +json NuiId(json jElem, string sId); // A shim/helper that can be used to render or bind a strref where otherwise // a string value would go. -json -NuiStrRef( - int nStrRef // STRREF -); +json NuiStrRef(int nStrRef); // ----------------------- // Layout // A column will auto-space all elements inside of it and advise the parent // about it's desired size. -json // Layout -NuiCol( - json jList // Layout[] or Element[] -); +// - jList: Layout[] or Element[] +json NuiCol(json jList); // A row will auto-space all elements inside of it and advise the parent // about it's desired size. -json // Layout -NuiRow( - json jList // Layout[] or Element[] -); +// - jList: Layout[] or Element[] +json NuiRow(json jList); // A group, usually with a border and some padding, holding a single element. Can scroll. // Will not advise parent of size, so you need to let it fill a span (col/row) as if it was // a element. -json // Layout -NuiGroup( - json jChild, // Layout or Element - int bBorder = TRUE, - int nScroll = NUI_SCROLLBARS_AUTO -); +// - jChild: Layout or Element +json NuiGroup(json jChild, int bBorder = TRUE, int nScroll = NUI_SCROLLBARS_AUTO); // Modifiers/Attributes: These are all static and cannot be bound, since the UI system // cannot easily reflow once the layout is set up. You need to swap the layout if you // want to change element geometry. -json // Element -NuiWidth( - json jElem, // Element - float fWidth // Float: Element width in pixels (strength=required). -); +// - jElem: Element +// - fWidth: Float: Element width in pixels (strength=required). +json NuiWidth(json jElem, float fWidth); -json // Element -NuiHeight( - json jElem, // Element - float fHeight // Float: Height in pixels (strength=required). -); +// - jElem: Element +// - fHeight: Float: Height in pixels (strength=required). +json NuiHeight(json jElem, float fHeight); -json // Element -NuiAspect( - json jElem, // Element - float fAspect // Float: Ratio of x/y. -); +// - jElem: Element +// - fAspect: Float: Ratio of x/y +json NuiAspect(json jElem, float fAspect); // Set a margin on the widget. The margin is the spacing outside of the widget. -json // Element -NuiMargin( - json jElem, // Element - float fMargin // Float -); +json NuiMargin(json jElem, float fMargin); // Set padding on the widget. The margin is the spacing inside of the widget. -json // Element -NuiPadding( - json jElem, // Element - float fPadding // Float -); +json NuiPadding(json jElem, float fPadding); // Disabled elements are non-interactive and greyed out. -json // Element -NuiEnabled( - json jElem, // Element - json jEnabler // Bind:Bool -); +// - jElem: Element +// - jEnabled: Bind:Bool +json NuiEnabled(json jElem, json jEnabler); // Invisible elements do not render at all, but still take up layout space. -json // Element -NuiVisible( - json jElem, // Element - json jVisible // Bind:Bool -); +// - jElem: Element +// - jVisible: Bind:Bool +json NuiVisible(json jElem, json jVisible); // Tooltips show on mouse hover. -json // Element -NuiTooltip( - json jElem, // Element - json jTooltip // Bind:String -); +// - jElem: Element +// - jTooltip: Bind:String +json NuiTooltip(json jElem, json jTooltip); // Tooltips for disabled elements show on mouse hover. -json // Element -NuiDisabledTooltip( - json jElem, // Element - json jTooltip // Bind:String -); +// - jElem: Element +// - jTooltip: Bind:String +json NuiDisabledTooltip(json jElem, json jTooltip); // Encouraged elements have a breathing animated glow inside of it. -json // Element -NuiEncouraged( - json jElem, // Element - json jEncouraged // Bind:Bool -); +// - jElem: Element +// - jEncouraged: Bind:Bool +json NuiEncouraged(json jElem, json jEncouraged); // ----------------------- // Props & Style -json // Vec2 -NuiVec(float x, float y); +json NuiVec(float x, float y); -json // Rect -NuiRect(float x, float y, float w, float h); +json NuiRect(float x, float y, float w, float h); -json // Color -NuiColor(int r, int g, int b, int a = 255); +json NuiColor(int r, int g, int b, int a = 255); -// Style the foreground color of the widget. This is dependent on the widget +// Style the foreground color of a widget or window title. This is dependent on the widget // in question and only supports solid/full colors right now (no texture skinning). // For example, labels would style their text color; progress bars would style the bar. -json // Element -NuiStyleForegroundColor( - json jElem, // Element - json jColor // Bind:Color -); +// - jElem: Element +// - jColor: Bind:Color +json NuiStyleForegroundColor(json jElem, json jColor); + +// Override the font used for this element. The font and it's properties needs to be listed in +// nui_skin.tml, as all fonts are pre-baked into a texture atlas at content load. +// - jElem: Element +// - jColor: Bind:String ([[fonts]].name in nui_skin.tml) +json NuiStyleFont(json jElem, json jFont); // ----------------------- // Widgets @@ -219,119 +221,87 @@ NuiStyleForegroundColor( // A special widget that just takes up layout space. // If you add multiple spacers to a span, they will try to size equally. // e.g.: [ ] will try to center the button. -json // Element -NuiSpacer(); +json NuiSpacer(); // Create a label field. Labels are single-line stylable non-editable text fields. -json // Element -NuiLabel( - json jValue, // Bind:String - json jHAlign, // Bind:Int:NUI_HALIGN_* - json jVAlign // Bind:Int:NUI_VALIGN_* -); +// - jValue: Bind:String +// - jHAlign: Bind:Int:NUI_HALIGN_* +// - jVAlign: Bind:Int:NUI_VALIGN_* +json NuiLabel(json jValue, json jHAlign, json jVAlign); // Create a non-editable text field. Note: This text field internally implies a NuiGroup wrapped // around it, which is providing the optional border and scrollbars. -json // Element -NuiText( - json jValue, // Bind:String - int bBorder = TRUE, // Bool - int nScroll = NUI_SCROLLBARS_AUTO // Int:NUI_SCROLLBARS_* -); +// - jValue: Bind:String +// - bBorder: Bool +// - nScroll: Int:NUI_SCROLLBARS_* +json NuiText(json jValue, int bBorder = TRUE, int nScroll = NUI_SCROLLBARS_AUTO); // A clickable button with text as the label. // Sends "click" events on click. -json // Element -NuiButton( - json jLabel // Bind:String -); +// - jLabel: Bind:String +json NuiButton(json jLabel); // A clickable button with an image as the label. // Sends "click" events on click. -json // Element -NuiButtonImage( - json jResRef // Bind:ResRef -); +// - jResRef: Bind:String +json NuiButtonImage(json jResRef); // A clickable button with text as the label. // Same as the normal button, but this one is a toggle. // Sends "click" events on click. -json // Element -NuiButtonSelect( - json jLabel, // Bind:String - json jValue // Bind:Bool -); +// - jLabel: Bind:String +// - jValue: Bind:Bool +json NuiButtonSelect(json jLabel, json jValue); // A checkbox with a label to the right of it. -json // Element -NuiCheck( - json jLabel, // Bind:String - json jBool // Bind:Bool -); +// - jLabel: Bind:String +// - jBool: Bind:Bool +json NuiCheck(json jLabel, json jBool); // A image, with no border or padding. -json // Element -NuiImage( - json jResRef, // Bind:ResRef - json jAspect, // Bind:Int:NUI_ASPECT_* - json jHAlign, // Bind:Int:NUI_HALIGN_* - json jVAlign // Bind:Int:NUI_VALIGN_* -); +// - jResRef: Bind:String +// - jAspect: Bind:Int:NUI_ASPECT_* +// - jHAlign: Bind:Int:NUI_HALIGN_* +// - jVAlign: Bind:Int:NUI_VALIGN_* +json NuiImage(json jResRef, json jAspect, json jHAlign, json jVAlign); -// Optionally render only subregion of jImage. +// Optionally render only subregion of jImage. This property can be set on +// NuiImage and NuiButtonImage widgets. // jRegion is a NuiRect (x, y, w, h) to indicate the render region inside the image. -json // NuiImage -NuiImageRegion( - json jImage, // NuiImage - json jRegion // Bind:NuiRect -); +json NuiImageRegion(json jImage, json jRegion); // A combobox/dropdown. -json // Element -NuiCombo( - json jElements, // Bind:ComboEntry[] - json jSelected // Bind:Int (index into jElements) -); +// - jElements: Bind:ComboEntry[] +// - jSelected: Bind:Int (index into jElements) +json NuiCombo(json jElements, json jSelected); -json // ComboEntry -NuiComboEntry( - string sLabel, - int nValue -); +json NuiComboEntry(string sLabel, int nValue); // A floating-point slider. A good step size for normal-sized sliders is 0.01. -json // Element -NuiSliderFloat( - json jValue, // Bind:Float - json jMin, // Bind:Float - json jMax, // Bind:Float - json jStepSize // Bind:Float -); +// - jValue: Bind:Float +// - jMin: Bind:Float +// - jMax: Bind:Float +// - jStepSize: Bind:Float +json NuiSliderFloat(json jValue, json jMin, json jMax, json jStepSize); // A integer/discrete slider. -json // Element -NuiSlider( - json jValue, // Bind:Int - json jMin, // Bind:Int - json jMax, // Bind:Int - json jStepSize // Bind:Int -); +// - jValue: Bind:Int +// - jMin: Bind:Int +// - jMax: Bind:Int +// - jStepSize: Bind:Int +json NuiSlider(json jValue, json jMin, json jMax, json jStepSize); // A progress bar. Progress is always from 0.0 to 1.0. -json // Element -NuiProgress( - json jValue // Bind:Float (0.0->1.0) -); +// - jValue: Bind:Float (0.0->1.0 +json NuiProgress(json jValue); // A editable text field. -json // Element -NuiTextEdit( - json jPlaceholder, // Bind:String - json jValue, // Bind:String - int nMaxLength, // UInt >= 1, <= 65535 - int bMultiline, // Bool - int bWordWrap = TRUE // Bool -); +// - jPlaceholder: Bind:String +// - jValue: Bind:String +// - nMaxLength: UInt >= 1, <= 65535 +// - bMultiLine: Bool +// - bWordWrap: Bool +json NuiTextEdit(json jPlaceholder, json jValue, int nMaxLength, int bMultiline, int bWordWrap = TRUE); // Creates a list view of elements. // jTemplate needs to be an array of NuiListTemplateCell instances. @@ -339,67 +309,52 @@ NuiTextEdit( // e.g. when rendering a NuiLabel(), the bound label String should be an array of strings. // You can pass in one of the template jRowCount into jSize as a convenience. The array // size will be uses as the Int bind. -// jRowHeight defines the height of the rendered rows. -json // Element -NuiList( - json jTemplate, // NuiListTemplateCell[] (max: 16) - json jRowCount, // Bind:Int - float fRowHeight = NUI_STYLE_ROW_HEIGHT, - int bBorder = TRUE, - int nScroll = NUI_SCROLLBARS_Y // Note: Cannot be AUTO. -); +// fRowHeight defines the height of the rendered rows. +// - jTemplate: NuiListTemplateCell[] (max: 16) +// - jRowCount: Bind:Int +// - bBorder: Bool +// - nScroll: Int:NUI_SCROLLBARS_*, Note: Cannot be AUTO +json NuiList(json jTemplate, json jRowCount, float fRowHeight = NUI_STYLE_ROW_HEIGHT, int bBorder = TRUE, int nScroll = NUI_SCROLLBARS_Y); -json // NuiListTemplateCell -NuiListTemplateCell( - json jElem, // Element - float fWidth, // Float:0 = auto, >1 = pixel width - int bVariable // Bool:Cell can grow if space is available; otherwise static -); +// - jElem: Element +// - fWidth: Float:0 = auto, >1 = pixel width +// - bVariable: Bool:Cell can grow if space is available; otherwise static +json NuiListTemplateCell(json jElem, float fWidth, int bVariable); // A simple color picker, with no border or spacing. -json // Element -NuiColorPicker( - json jColor // Bind:Color -); +// - jColor: Bind:Color +json NuiColorPicker(json jColor); // A list of options (radio buttons). Only one can be selected // at a time. jValue is updated every time a different element is // selected. The special value -1 means "nothing". -json // Element -NuiOptions( - int nDirection, // NUI_DIRECTION_* - json jElements, // JsonArray of string labels - json jValue // Bind:Int -); +// - nDirection: NUI_DIRECTION_* +// - jElements: JsonArray of string labels +// - jValue: Bind:UInt +json NuiOptions(int nDirection, json jElements, json jValue); -// A group of buttons. Only one can be selected at a time. jValue -// is updated every time a different button is selected. The special +// A group of buttons. Only one can be selected at a time. jValue +// is updated every time a different button is selected. The special // value -1 means "nothing". -json // Element -NuiToggles( - int nDirection, // NUI_DIRECTION_* - json jElements, // JsonArray of string labels - json jValue // Bind:Int -); +// - nDirection: NUI_DIRECTION_* +// - jElements: JsonArray of string labels +// - jValue: Bind:Int +json NuiToggles(int nDirection, json jElements, json jValue); const int NUI_CHART_TYPE_LINES = 0; const int NUI_CHART_TYPE_COLUMN = 1; -json // NuiChartSlot -NuiChartSlot( - int nType, // Int:NUI_CHART_TYPE_* - json jLegend, // Bind:String - json jColor, // Bind:NuiColor - json jData // Bind:Float[] -); +// - nType: Int:NUI_CHART_TYPE_* +// - jLegend: Bind:String +// - jColor: Bind:NuiColor +// - jData: Bind:Float[] +json NuiChartSlot(int nType, json jLegend, json jColor, json jData); // Renders a chart. // Currently, min and max values are determined automatically and // cannot be influenced. -json // Element -NuiChart( - json jSlots // NuiChartSlot[] -); +// - jSlots: NuiChartSlot[] +json NuiChart( json jSlots); // ----------------------- // Draw Lists @@ -417,6 +372,7 @@ const int NUI_DRAW_LIST_ITEM_TYPE_ARC = 3; const int NUI_DRAW_LIST_ITEM_TYPE_TEXT = 4; const int NUI_DRAW_LIST_ITEM_TYPE_IMAGE = 5; const int NUI_DRAW_LIST_ITEM_TYPE_LINE = 6; +const int NUI_DRAW_LIST_ITEM_TYPE_RECT = 7; // You can order draw list items to be painted either before, or after the // builtin render of the widget in question. This enables you to paint "behind" @@ -438,100 +394,100 @@ const int NUI_DRAW_LIST_ITEM_RENDER_MOUSE_RIGHT = 4; // Only render while MMB is held down. const int NUI_DRAW_LIST_ITEM_RENDER_MOUSE_MIDDLE = 5; -json // DrawListItem -NuiDrawListPolyLine( - json jEnabled, // Bind:Bool - json jColor, // Bind:Color - json jFill, // Bind:Bool - json jLineThickness, // Bind:Float - json jPoints, // Bind:Float[] Always provide points in pairs - int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, // Int:NUI_DRAW_LIST_ITEM_ORDER_* - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS // Int:NUI_DRAW_LIST_ITEM_RENDER_* -); +// - jEnabled: Bind:Bool +// - jColor: Bind:Color +// - jFill: Bind:Bool +// - jLineThickness: Bind:Float +// - jPoints: Bind:Float[] Always provide points in pairs +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +json NuiDrawListPolyLine(json jEnabled, json jColor, json jFill, json jLineThickness, json jPoints, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE); -json // DrawListItem -NuiDrawListCurve( - json jEnabled, // Bind:Bool - json jColor, // Bind:Color - json jLineThickness, // Bind:Float - json jA, // Bind:Vec2 - json jB, // Bind:Vec2 - json jCtrl0, // Bind:Vec2 - json jCtrl1, // Bind:Vec2 - int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, // Int:NUI_DRAW_LIST_ITEM_ORDER_* - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS // Int:NUI_DRAW_LIST_ITEM_RENDER_* -); +// - jEnabled: Bind:Bool +// - jColor: Bind:Color +// - jLineThickness: Bind:Float +// - jA: Bind:Vec2 +// - jB: Bind:Vec2 +// - jCtrl0: Bind:Vec2 +// - jCtrl1: Bind:Vec2 +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +json NuiDrawListCurve(json jEnabled, json jColor, json jLineThickness, json jA, json jB, json jCtrl0, json jCtrl1, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE); -json // DrawListItem -NuiDrawListCircle( - json jEnabled, // Bind:Bool - json jColor, // Bind:Color - json jFill, // Bind:Bool - json jLineThickness, // Bind:Float - json jRect, // Bind:Rect - int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, // Int:NUI_DRAW_LIST_ITEM_ORDER_* - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS // Int:NUI_DRAW_LIST_ITEM_RENDER_* -); +// - jEnabled: Bind:Bool +// - jColor: Bind:Color +// - jFill: Bind:Bool +// - jLineThickness: Bind:Float +// - jRect: Bind:Rect +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +json NuiDrawListCircle(json jEnabled, json jColor, json jFill, json jLineThickness, json jRect, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE); -json // DrawListItem -NuiDrawListArc( - json jEnabled, // Bind:Bool - json jColor, // Bind:Color - json jFill, // Bind:Bool - json jLineThickness, // Bind:Float - json jCenter, // Bind:Vec2 - json jRadius, // Bind:Float - json jAMin, // Bind:Float - json jAMax, // Bind:Float - int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, // Int:NUI_DRAW_LIST_ITEM_ORDER_* - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS // Int:NUI_DRAW_LIST_ITEM_RENDER_* -); +// - jEnabled: Bind:Bool +// - jColor: Bind:Color +// - jFill: Bind:Bool +// - jLineThickness: Bind:Float +// - jCenter: Bind:Rect +// - jRadius: Bind:Float +// - jAMin: Bind:Float +// - jAMax: Bind:Float +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +json NuiDrawListArc(json jEnabled, json jColor, json jFill, json jLineThickness, json jCenter, json jRadius, json jAMin, json jAMax, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE); -json // DrawListItem -NuiDrawListText( - json jEnabled, // Bind:Bool - json jColor, // Bind:Color - json jRect, // Bind:Rect - json jText, // Bind:String - int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, // Int:NUI_DRAW_LIST_ITEM_ORDER_* - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS // Int:NUI_DRAW_LIST_ITEM_RENDER_* -); +// - jEnabled: Bind:Bool +// - jColor: Bind:Color +// - jRect: Bind:Rect +// - jText: Bind:String +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +// - jFont: Bind:String +json NuiDrawListText(json jEnabled, json jColor, json jRect, json jText, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE, json jFont = JSON_STRING); -json // DrawListItem -NuiDrawListImage( - json jEnabled, // Bind:Bool - json jResRef, // Bind:ResRef - json jPos, // Bind:Rect - json jAspect, // Bind:Int:NUI_ASPECT_* - json jHAlign, // Bind:Int:NUI_HALIGN_* - json jVAlign, // Bind:Int:NUI_VALIGN_* - int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, // Int:NUI_DRAW_LIST_ITEM_ORDER_* - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS // Int:NUI_DRAW_LIST_ITEM_RENDER_* -); +// - jEnabled: Bind:Bool +// - jResRef: Bind:String +// - jPos: Bind:Rect +// - jAspect: Bind:Int:NUI_ASPECT_* +// - jHAlign: Bind:Int:NUI_HALIGN_* +// - jVAlign: Bind:Int:NUI_VALIGN_* +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +json NuiDrawListImage(json jEnabled, json jResRef, json jPos, json jAspect, json jHAlign, json jVAlign, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE); -json // DrawListItemImage -NuiDrawListImageRegion( - json jDrawListImage, // DrawListItemImage - json jRegion // Bind:NuiRect -); +// - jDrawListImage: DrawListItemImage +// - jRegion: Bind:NuiRect +json NuiDrawListImageRegion(json jDrawListImage, json jRegion); -json // DrawListItem -NuiDrawListLine( - json jEnabled, // Bind:Bool - json jColor, // Bind:Color - json jLineThickness, // Bind:Float - json jA, // Bind:Vec2 - json jB, // Bind:Vec2 - int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, // Int:NUI_DRAW_LIST_ITEM_ORDER_* - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS // Int:NUI_DRAW_LIST_ITEM_RENDER_* -); +// - jEnabled: Bind:Bool +// - jColor: Bind:Color +// - jLineThickness: Bind:Float +// - jA: Bind:Vec2 +// - jB: Bind:Vec2 +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +json NuiDrawListLine(json jEnabled, json jColor, json jLineThickness, json jA, json jB, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE); -json // Element -NuiDrawList( - json jElem, // Element - json jScissor, // Bind:Bool Constrain painted elements to widget bounds. - json jList // DrawListItem[] -); +// - jEnabled: Bind:Bool +// - jColor: Bind:Color +// - jFill: Bind:Bool +// - jLineThickness: Bind:Float +// - jRext: Bind:Rect +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +json NuiDrawListRect(json jEnabled, json jColor, json jFill, json jLineThickness, json jRect, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE); + +// - jElem: Element +// - jScissor: Bind:Bool, Constrain painted elements to widget bounds. +// - jList: DrawListItem[] +json NuiDrawList(json jElem, json jScissor, json jList); // ----------------------- // Implementation @@ -546,21 +502,27 @@ NuiWindow( json jClosable, json jTransparent, json jBorder, - json jAcceptsInput + json jAcceptsInput = JSON_TRUE, + json jWindowConstraint = JSON_NULL, + json jEdgeConstraint = JSON_NULL, + json jFont = JSON_STRING ) { json ret = JsonObject(); // Currently hardcoded and here to catch backwards-incompatible data in the future. - ret = JsonObjectSet(ret, "version", JsonInt(1)); - ret = JsonObjectSet(ret, "title", jTitle); - ret = JsonObjectSet(ret, "root", jRoot); - ret = JsonObjectSet(ret, "geometry", jGeometry); - ret = JsonObjectSet(ret, "resizable", jResizable); - ret = JsonObjectSet(ret, "collapsed", jCollapsed); - ret = JsonObjectSet(ret, "closable", jClosable); - ret = JsonObjectSet(ret, "transparent", jTransparent); - ret = JsonObjectSet(ret, "border", jBorder); - ret = JsonObjectSet(ret, "accepts_input", jAcceptsInput); + JsonObjectSetInplace(ret, "version", JsonInt(1)); + JsonObjectSetInplace(ret, "title", jTitle); + JsonObjectSetInplace(ret, "root", jRoot); + JsonObjectSetInplace(ret, "geometry", jGeometry); + JsonObjectSetInplace(ret, "resizable", jResizable); + JsonObjectSetInplace(ret, "collapsed", jCollapsed); + JsonObjectSetInplace(ret, "closable", jClosable); + JsonObjectSetInplace(ret, "transparent", jTransparent); + JsonObjectSetInplace(ret, "border", jBorder); + JsonObjectSetInplace(ret, "accepts_input", jAcceptsInput); + JsonObjectSetInplace(ret, "size_constraint", jWindowConstraint); + JsonObjectSetInplace(ret, "edge_constraint", jEdgeConstraint); + JsonObjectSetInplace(ret, "font", jFont); return ret; } @@ -572,18 +534,26 @@ NuiElement( ) { json ret = JsonObject(); - ret = JsonObjectSet(ret, "type", JsonString(sType)); - ret = JsonObjectSet(ret, "label", jLabel); - ret = JsonObjectSet(ret, "value", jValue); + JsonObjectSetInplace(ret, "type", JsonString(sType)); + JsonObjectSetInplace(ret, "label", jLabel); + JsonObjectSetInplace(ret, "value", jValue); return ret; } json NuiBind( - string sId + string sId, + int nNumberFlags = 0, + int nNumberPrecision = 0, + int nTextFlags = 0 ) { - return JsonObjectSet(JsonObject(), "bind", JsonString(sId)); + json ret = JsonObject(); + JsonObjectSetInplace(ret, "bind", JsonString(sId)); + JsonObjectSetInplace(ret, "number_flags", JsonInt(nNumberFlags)); + JsonObjectSetInplace(ret, "number_precision", JsonInt(nNumberPrecision)); + JsonObjectSetInplace(ret, "text_flags", JsonInt(nTextFlags)); + return ret; } json @@ -601,7 +571,7 @@ NuiStrRef( ) { json ret = JsonObject(); - ret = JsonObjectSet(ret, "strref", JsonInt(nStrRef)); + JsonObjectSetInplace(ret, "strref", JsonInt(nStrRef)); return ret; } @@ -629,9 +599,9 @@ NuiGroup( ) { json ret = NuiElement("group", JsonNull(), JsonNull()); - ret = JsonObjectSet(ret, "children", JsonArrayInsert(JsonArray(), jChild)); - ret = JsonObjectSet(ret, "border", JsonBool(bBorder)); - ret = JsonObjectSet(ret, "scrollbars", JsonInt(nScroll)); + JsonObjectSetInplace(ret, "children", JsonArrayInsert(JsonArray(), jChild)); + JsonObjectSetInplace(ret, "border", JsonBool(bBorder)); + JsonObjectSetInplace(ret, "scrollbars", JsonInt(nScroll)); return ret; } @@ -720,8 +690,8 @@ json NuiVec(float x, float y) { json ret = JsonObject(); - ret = JsonObjectSet(ret, "x", JsonFloat(x)); - ret = JsonObjectSet(ret, "y", JsonFloat(y)); + JsonObjectSetInplace(ret, "x", JsonFloat(x)); + JsonObjectSetInplace(ret, "y", JsonFloat(y)); return ret; } @@ -729,10 +699,10 @@ json NuiRect(float x, float y, float w, float h) { json ret = JsonObject(); - ret = JsonObjectSet(ret, "x", JsonFloat(x)); - ret = JsonObjectSet(ret, "y", JsonFloat(y)); - ret = JsonObjectSet(ret, "w", JsonFloat(w)); - ret = JsonObjectSet(ret, "h", JsonFloat(h)); + JsonObjectSetInplace(ret, "x", JsonFloat(x)); + JsonObjectSetInplace(ret, "y", JsonFloat(y)); + JsonObjectSetInplace(ret, "w", JsonFloat(w)); + JsonObjectSetInplace(ret, "h", JsonFloat(h)); return ret; } @@ -740,10 +710,10 @@ json NuiColor(int r, int g, int b, int a = 255) { json ret = JsonObject(); - ret = JsonObjectSet(ret, "r", JsonInt(r)); - ret = JsonObjectSet(ret, "g", JsonInt(g)); - ret = JsonObjectSet(ret, "b", JsonInt(b)); - ret = JsonObjectSet(ret, "a", JsonInt(a)); + JsonObjectSetInplace(ret, "r", JsonInt(r)); + JsonObjectSetInplace(ret, "g", JsonInt(g)); + JsonObjectSetInplace(ret, "b", JsonInt(b)); + JsonObjectSetInplace(ret, "a", JsonInt(a)); return ret; } @@ -756,6 +726,15 @@ NuiStyleForegroundColor( return JsonObjectSet(jElem, "foreground_color", jColor); } +json +NuiStyleFont( + json jElem, + json jFont +) +{ + return JsonObjectSet(jElem, "font", jFont); +} + json NuiSpacer() { @@ -770,8 +749,8 @@ NuiLabel( ) { json ret = NuiElement("label", JsonNull(), jValue); - ret = JsonObjectSet(ret, "text_halign", jHAlign); - ret = JsonObjectSet(ret, "text_valign", jVAlign); + JsonObjectSetInplace(ret, "text_halign", jHAlign); + JsonObjectSetInplace(ret, "text_valign", jVAlign); return ret; } @@ -783,8 +762,8 @@ NuiText( ) { json ret = NuiElement("text", JsonNull(), jValue); - ret = JsonObjectSet(ret, "border", JsonBool(bBorder)); - ret = JsonObjectSet(ret, "scrollbars", JsonInt(nScroll)); + JsonObjectSetInplace(ret, "border", JsonBool(bBorder)); + JsonObjectSetInplace(ret, "scrollbars", JsonInt(nScroll)); return ret; } @@ -831,9 +810,9 @@ NuiImage( ) { json img = NuiElement("image", JsonNull(), jResRef); - img = JsonObjectSet(img, "image_aspect", jAspect); - img = JsonObjectSet(img, "image_halign", jHAlign); - img = JsonObjectSet(img, "image_valign", jVAlign); + JsonObjectSetInplace(img, "image_aspect", jAspect); + JsonObjectSetInplace(img, "image_halign", jHAlign); + JsonObjectSetInplace(img, "image_valign", jVAlign); return img; } @@ -873,9 +852,9 @@ NuiSliderFloat( ) { json ret = NuiElement("sliderf", JsonNull(), jValue); - ret = JsonObjectSet(ret, "min", jMin); - ret = JsonObjectSet(ret, "max", jMax); - ret = JsonObjectSet(ret, "step", jStepSize); + JsonObjectSetInplace(ret, "min", jMin); + JsonObjectSetInplace(ret, "max", jMax); + JsonObjectSetInplace(ret, "step", jStepSize); return ret; } @@ -888,9 +867,9 @@ NuiSlider( ) { json ret = NuiElement("slider", JsonNull(), jValue); - ret = JsonObjectSet(ret, "min", jMin); - ret = JsonObjectSet(ret, "max", jMax); - ret = JsonObjectSet(ret, "step", jStepSize); + JsonObjectSetInplace(ret, "min", jMin); + JsonObjectSetInplace(ret, "max", jMax); + JsonObjectSetInplace(ret, "step", jStepSize); return ret; } @@ -912,9 +891,9 @@ NuiTextEdit( ) { json ret = NuiElement("textedit", jPlaceholder, jValue); - ret = JsonObjectSet(ret, "max", JsonInt(nMaxLength)); - ret = JsonObjectSet(ret, "multiline", JsonBool(bMultiline)); - ret = JsonObjectSet(ret, "wordwrap", JsonBool(bWordWrap)); + JsonObjectSetInplace(ret, "max", JsonInt(nMaxLength)); + JsonObjectSetInplace(ret, "multiline", JsonBool(bMultiline)); + JsonObjectSetInplace(ret, "wordwrap", JsonBool(bWordWrap)); return ret; } @@ -928,11 +907,11 @@ NuiList( ) { json ret = NuiElement("list", JsonNull(), JsonNull()); - ret = JsonObjectSet(ret, "row_template", jTemplate); - ret = JsonObjectSet(ret, "row_count", jRowCount); - ret = JsonObjectSet(ret, "row_height", JsonFloat(fRowHeight)); - ret = JsonObjectSet(ret, "border", JsonBool(bBorder)); - ret = JsonObjectSet(ret, "scrollbars", JsonInt(nScroll)); + JsonObjectSetInplace(ret, "row_template", jTemplate); + JsonObjectSetInplace(ret, "row_count", jRowCount); + JsonObjectSetInplace(ret, "row_height", JsonFloat(fRowHeight)); + JsonObjectSetInplace(ret, "border", JsonBool(bBorder)); + JsonObjectSetInplace(ret, "scrollbars", JsonInt(nScroll)); return ret; } @@ -944,9 +923,9 @@ NuiListTemplateCell( ) { json ret = JsonArray(); - ret = JsonArrayInsert(ret, jElem); - ret = JsonArrayInsert(ret, JsonFloat(fWidth)); - ret = JsonArrayInsert(ret, JsonBool(bVariable)); + JsonArrayInsertInplace(ret, jElem); + JsonArrayInsertInplace(ret, JsonFloat(fWidth)); + JsonArrayInsertInplace(ret, JsonBool(bVariable)); return ret; } @@ -967,8 +946,8 @@ NuiOptions( ) { json ret = NuiElement("options", JsonNull(), jValue); - ret = JsonObjectSet(ret, "direction", JsonInt(nDirection)); - ret = JsonObjectSet(ret, "elements", jElements); + JsonObjectSetInplace(ret, "direction", JsonInt(nDirection)); + JsonObjectSetInplace(ret, "elements", jElements); return ret; } @@ -980,8 +959,8 @@ NuiToggles( ) { json ret = NuiElement("tabbar", JsonNull(), jValue); - ret = JsonObjectSet(ret, "direction", JsonInt(nDirection)); - ret = JsonObjectSet(ret, "elements", jElements); + JsonObjectSetInplace(ret, "direction", JsonInt(nDirection)); + JsonObjectSetInplace(ret, "elements", jElements); return ret; } @@ -994,10 +973,10 @@ NuiChartSlot( ) { json ret = JsonObject(); - ret = JsonObjectSet(ret, "type", JsonInt(nType)); - ret = JsonObjectSet(ret, "legend", jLegend); - ret = JsonObjectSet(ret, "color", jColor); - ret = JsonObjectSet(ret, "data", jData); + JsonObjectSetInplace(ret, "type", JsonInt(nType)); + JsonObjectSetInplace(ret, "legend", jLegend); + JsonObjectSetInplace(ret, "color", jColor); + JsonObjectSetInplace(ret, "data", jData); return ret; } @@ -1018,17 +997,19 @@ NuiDrawListItem( json jFill, json jLineThickness, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE ) { json ret = JsonObject(); - ret = JsonObjectSet(ret, "type", JsonInt(nType)); - ret = JsonObjectSet(ret, "enabled", jEnabled); - ret = JsonObjectSet(ret, "color", jColor); - ret = JsonObjectSet(ret, "fill", jFill); - ret = JsonObjectSet(ret, "line_thickness", jLineThickness); - ret = JsonObjectSet(ret, "order", JsonInt(nOrder)); - ret = JsonObjectSet(ret, "render", JsonInt(nRender)); + JsonObjectSetInplace(ret, "type", JsonInt(nType)); + JsonObjectSetInplace(ret, "enabled", jEnabled); + JsonObjectSetInplace(ret, "color", jColor); + JsonObjectSetInplace(ret, "fill", jFill); + JsonObjectSetInplace(ret, "line_thickness", jLineThickness); + JsonObjectSetInplace(ret, "order", JsonInt(nOrder)); + JsonObjectSetInplace(ret, "render", JsonInt(nRender)); + JsonObjectSetInplace(ret, "arrayBinds", JsonBool(nBindArrays)); return ret; } @@ -1040,11 +1021,12 @@ NuiDrawListPolyLine( json jLineThickness, json jPoints, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE ) { - json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_POLYLINE, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender); - ret = JsonObjectSet(ret, "points", jPoints); + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_POLYLINE, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "points", jPoints); return ret; } @@ -1058,14 +1040,15 @@ NuiDrawListCurve( json jCtrl0, json jCtrl1, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE ) { - json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_CURVE, jEnabled, jColor, JsonBool(0), jLineThickness, nOrder, nRender); - ret = JsonObjectSet(ret, "a", jA); - ret = JsonObjectSet(ret, "b", jB); - ret = JsonObjectSet(ret, "ctrl0", jCtrl0); - ret = JsonObjectSet(ret, "ctrl1", jCtrl1); + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_CURVE, jEnabled, jColor, JsonBool(0), jLineThickness, nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "a", jA); + JsonObjectSetInplace(ret, "b", jB); + JsonObjectSetInplace(ret, "ctrl0", jCtrl0); + JsonObjectSetInplace(ret, "ctrl1", jCtrl1); return ret; } @@ -1077,11 +1060,12 @@ NuiDrawListCircle( json jLineThickness, json jRect, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE ) { - json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_CIRCLE, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender); - ret = JsonObjectSet(ret, "rect", jRect); + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_CIRCLE, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "rect", jRect); return ret; } @@ -1096,14 +1080,15 @@ NuiDrawListArc( json jAMin, json jAMax, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE ) { - json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_ARC, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender); - ret = JsonObjectSet(ret, "c", jCenter); - ret = JsonObjectSet(ret, "radius", jRadius); - ret = JsonObjectSet(ret, "amin", jAMin); - ret = JsonObjectSet(ret, "amax", jAMax); + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_ARC, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "c", jCenter); + JsonObjectSetInplace(ret, "radius", jRadius); + JsonObjectSetInplace(ret, "amin", jAMin); + JsonObjectSetInplace(ret, "amax", jAMax); return ret; } @@ -1114,12 +1099,15 @@ NuiDrawListText( json jRect, json jText, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE, + json jFont = JSON_STRING ) { - json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_TEXT, jEnabled, jColor, JsonNull(), JsonNull(), nOrder, nRender); - ret = JsonObjectSet(ret, "rect", jRect); - ret = JsonObjectSet(ret, "text", jText); + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_TEXT, jEnabled, jColor, JsonNull(), JsonNull(), nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "rect", jRect); + JsonObjectSetInplace(ret, "text", jText); + ret = NuiStyleFont(ret, jFont); return ret; } @@ -1132,15 +1120,16 @@ NuiDrawListImage( json jHAlign, json jVAlign, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE ) { - json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_IMAGE, jEnabled, JsonNull(), JsonNull(), JsonNull(), nOrder, nRender); - ret = JsonObjectSet(ret, "image", jResRef); - ret = JsonObjectSet(ret, "rect", jRect); - ret = JsonObjectSet(ret, "image_aspect", jAspect); - ret = JsonObjectSet(ret, "image_halign", jHAlign); - ret = JsonObjectSet(ret, "image_valign", jVAlign); + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_IMAGE, jEnabled, JsonNull(), JsonNull(), JsonNull(), nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "image", jResRef); + JsonObjectSetInplace(ret, "rect", jRect); + JsonObjectSetInplace(ret, "image_aspect", jAspect); + JsonObjectSetInplace(ret, "image_halign", jHAlign); + JsonObjectSetInplace(ret, "image_valign", jVAlign); return ret; } @@ -1161,12 +1150,30 @@ NuiDrawListLine( json jA, json jB, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE ) { - json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_LINE, jEnabled, jColor, JsonNull(), jLineThickness, nOrder, nRender); - ret = JsonObjectSet(ret, "a", jA); - ret = JsonObjectSet(ret, "b", jB); + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_LINE, jEnabled, jColor, JsonNull(), jLineThickness, nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "a", jA); + JsonObjectSetInplace(ret, "b", jB); + return ret; +} + +json +NuiDrawListRect( + json jEnabled, + json jColor, + json jFill, + json jLineThickness, + json jRect, + int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE +) +{ + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_RECT, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "rect", jRect); return ret; } @@ -1178,7 +1185,7 @@ NuiDrawList( ) { json ret = JsonObjectSet(jElem, "draw_list", jList); - ret = JsonObjectSet(ret, "draw_list_scissor", jScissor); + JsonObjectSetInplace(ret, "draw_list_scissor", jScissor); return ret; } @@ -1190,4 +1197,3 @@ NuiDrawList( // json ret = NuiElement("canvas", JsonNull(), jList); // return ret; // } - diff --git a/src/include/prc_add_spell_dc.nss b/src/include/prc_add_spell_dc.nss index 4cde6de..f2a0e2f 100644 --- a/src/include/prc_add_spell_dc.nss +++ b/src/include/prc_add_spell_dc.nss @@ -513,6 +513,8 @@ int PRCGetSpellSaveDC(int nSpellID = -1, int nSchool = -1, object oCaster = OBJE if(nClass == CLASS_TYPE_BARD) nDC += StringToInt(Get2DACache("Spells", "Bard", nSpellID)); + else if(nClass == CLASS_TYPE_ASSASSIN) + nDC += StringToInt(Get2DACache("Spells", "Assassin", nSpellID)); else if(nClass == CLASS_TYPE_CLERIC || nClass == CLASS_TYPE_UR_PRIEST || nClass == CLASS_TYPE_OCULAR) nDC += StringToInt(Get2DACache("Spells", "Cleric", nSpellID)); else if(nClass == CLASS_TYPE_DRUID) diff --git a/src/include/prc_class_const.nss b/src/include/prc_class_const.nss index 286b574..04e96f1 100644 --- a/src/include/prc_class_const.nss +++ b/src/include/prc_class_const.nss @@ -143,7 +143,7 @@ const int CLASS_TYPE_MASTER_HARPER = 176; const int CLASS_TYPE_FRE_BERSERKER = 177; const int CLASS_TYPE_TEMPEST = 178; const int CLASS_TYPE_FOE_HUNTER = 179; -//:: Free = 180 +const int CLASS_TYPE_VERDANT_LORD = 180; const int CLASS_TYPE_ORC_WARLORD = 181; const int CLASS_TYPE_THRALL_OF_GRAZZT_A = 182; const int CLASS_TYPE_NECROCARNATE = 183; @@ -162,7 +162,7 @@ const int CLASS_TYPE_MASTER_OF_NINE = 195; const int CLASS_TYPE_ETERNAL_BLADE = 196; const int CLASS_TYPE_SHADOW_SUN_NINJA = 197; const int CLASS_TYPE_WITCHBORN_BINDER = 198; -const int CLASS_TYPE_BAELNORN = 199; +const int CLASS_TYPE_LION_OF_TALISID = 199; const int CLASS_TYPE_DISCIPLE_OF_MEPH = 200; const int CLASS_TYPE_SOUL_EATER = 201; const int CLASS_TYPE_HENSHIN_MYSTIC = 202; @@ -236,6 +236,7 @@ const int CLASS_TYPE_WITCH = -1; const int CLASS_TYPE_TEMPLAR = -1; const int CLASS_TYPE_MYSTIC = -1; const int CLASS_TYPE_NOBLE = -1; +const int CLASS_TYPE_BAELNORN = -2; //void main (){} \ No newline at end of file diff --git a/src/include/prc_effect_inc.nss b/src/include/prc_effect_inc.nss index 6186f71..4552481 100644 --- a/src/include/prc_effect_inc.nss +++ b/src/include/prc_effect_inc.nss @@ -75,6 +75,13 @@ void DeathlessFrenzyCheck(object oTarget); // * PRC Version of a Bioware function to disable include loops void PRCRemoveSpellEffects(int nSpell_ID, object oCaster, object oTarget); +/** + * Target is immune to gaze attacks + * + * @return the Dazzle effect + */ +effect EffectGazeImmune(); + /** * Dazzles the target: -1 Attack, Search, Spot, and VFX * @@ -583,7 +590,8 @@ effect PRCEffectHeal(int nHP, object oTarget) return EffectHeal(nHP); } -effect EffectAbilityBasedSkillIncrease(int iAbility, int iIncrease = 1){ +effect EffectAbilityBasedSkillIncrease(int iAbility, int iIncrease = 1) +{ effect eReturn; switch(iAbility) { @@ -639,7 +647,8 @@ effect EffectAbilityBasedSkillIncrease(int iAbility, int iIncrease = 1){ return eReturn; } -effect EffectAbilityBasedSkillDecrease(int iAbility, int iDecrease = 1){ +effect EffectAbilityBasedSkillDecrease(int iAbility, int iDecrease = 1) +{ effect eReturn; switch(iAbility) { @@ -695,7 +704,8 @@ effect EffectAbilityBasedSkillDecrease(int iAbility, int iDecrease = 1){ return eReturn; } -effect EffectDamageImmunityAll(){ +effect EffectDamageImmunityAll() +{ effect eReturn = EffectDamageImmunityIncrease(DAMAGE_TYPE_ACID, 100); eReturn = EffectLinkEffects(eReturn, EffectDamageImmunityIncrease(DAMAGE_TYPE_BLUDGEONING, 100)); eReturn = EffectLinkEffects(eReturn, EffectDamageImmunityIncrease(DAMAGE_TYPE_COLD, 100)); @@ -712,7 +722,8 @@ effect EffectDamageImmunityAll(){ return eReturn; } -effect EffectImmunityMiscAll(){ +effect EffectImmunityMiscAll() +{ effect eReturn = EffectImmunity(IMMUNITY_TYPE_ABILITY_DECREASE); eReturn = EffectLinkEffects(eReturn, EffectImmunity(IMMUNITY_TYPE_BLINDNESS)); eReturn = EffectLinkEffects(eReturn, EffectImmunity(IMMUNITY_TYPE_DEAFNESS)); @@ -732,6 +743,31 @@ effect EffectImmunityMiscAll(){ return eReturn; } +//:: Immunity to all gaze attacks +effect EffectGazeImmune() +{ + effect eBlank; + + effect eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_CHARM); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_CONFUSION); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DAZE); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DEATH); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DESTROY_CHAOS); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DESTROY_EVIL); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DESTROY_GOOD); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DESTROY_LAW); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DOMINATE); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DOOM); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_FEAR); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_PARALYSIS); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_PETRIFY); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_STUNNED); + + eReturn = TagEffect(eReturn, "PRCGazeImmune"); + + return eReturn; +} + int GetIsShaken(object oTarget) { effect eEffect = GetFirstEffect(oTarget); @@ -747,4 +783,7 @@ int GetIsShaken(object oTarget) eEffect = GetNextEffect(oTarget); } return FALSE; -} \ No newline at end of file +} + +//:: Test void +//:: void main() {} \ No newline at end of file diff --git a/src/include/prc_feat_const.nss b/src/include/prc_feat_const.nss index c961dab..8035960 100644 --- a/src/include/prc_feat_const.nss +++ b/src/include/prc_feat_const.nss @@ -152,6 +152,9 @@ const int FEAT_EPIC_DIAMOND_DRAGON = 25115; const int FEAT_EPIC_CRUSADER = 25116; const int FEAT_EPIC_SWORDSAGE = 25117; const int FEAT_EPIC_WARBLADE = 25118; +const int FEAT_EPIC_LION_OF_TALISID = 25600; +const int FEAT_EPIC_VERDANT_LORD = 25618; + //:: Vile Martial Strike Expansion const int FEAT_VILE_MARTIAL_EAGLE_CLAW = 24800; @@ -195,6 +198,28 @@ const int FEAT_CHARMING_THE_ARROW = 25998; //:: Skill Based Feats const int FEAT_JUMP = 2884; +//:: Lion of Talisid +const int FEAT_LOT_LIONS_COURAGE = 25614; +const int FEAT_LOT_LIONS_POUNCE = 25615; +const int FEAT_LOT_LIONS_SWIFTNESS = 25616; +const int FEAT_LOT_LEONALS_ROAR = 25617; + +//::: Verdant Lord +const int FEAT_VL_EXPERT_INFUSION = 25634; +const int FEAT_VL_SUN_SUSTENANCE = 25635; +const int FEAT_VL_SPONTANEITY = 25636; +const int FEAT_VL_PLANT_FACILITY = 25637; +const int FEAT_VL_WILD_SHAPE_TREANT = 25638; +const int FEAT_VL_ANIMATE_TREE = 25639; +const int FEAT_VL_GAEAS_EMBRACE = 25640; + +//:: Masters of the Wild feats +const int FEAT_CREATE_INFUSION = 25960; +const int FEAT_MAGICAL_ARTISAN_CREATE_INFUSION = 25961; +const int FEAT_PLANT_DEFIANCE = 25992; +const int FEAT_PLANT_CONTROL = 25993; + + //:: Racial Feats const int FEAT_WEMIC_JUMP_8 = 4518; const int FEAT_URDINNIR_STONESKIN = 4644; @@ -782,6 +807,9 @@ const int FEAT_SUEL_IGNORE_SPELL_FAILURE = 2398; const int FEAT_SUEL_EXTENDED_SPELL = 2399; const int FEAT_SUEL_DISPELLING_STRIKE = 2400; +//:: Druid +const int FEAT_SPONT_SUMMON = 2372; + //Passive Feats const int FEAT_ETERNAL_FREEDOM = 4298; const int FEAT_INTUITIVE_ATTACK = 3166; @@ -1538,18 +1566,19 @@ const int FEAT_SELVETARMS_BLESSING = 2447; const int FEAT_RANGER_DUAL = 374; const int FEAT_CAMOUFLAGE = 4486; -//Exalted Feat -const int FEAT_SAC_VOW = 3388; -const int FEAT_VOW_OBED = 3389; -const int FEAT_EXALTED_TURNING = 3168; -const int FEAT_HAND_HEALER = 3167; -const int FEAT_NIMBUSLIGHT = 3165; -const int FEAT_HOLYRADIANCE = 3164; -const int FEAT_STIGMATA = 3163; -const int FEAT_SERVHEAVEN = 3355; -const int FEAT_RANGED_SMITE = 3356; -const int FEAT_VOW_PURITY = 5360; -const int FEAT_VOWOFPOVERTY = 26001; +//:: Exalted Feats +const int FEAT_SAC_VOW = 3388; +const int FEAT_VOW_OBED = 3389; +const int FEAT_EXALTED_TURNING = 3168; +const int FEAT_HAND_HEALER = 3167; +const int FEAT_NIMBUSLIGHT = 3165; +const int FEAT_HOLYRADIANCE = 3164; +const int FEAT_STIGMATA = 3163; +const int FEAT_SERVHEAVEN = 3355; +const int FEAT_RANGED_SMITE = 3356; +const int FEAT_VOW_PURITY = 5360; +const int FEAT_VOWOFPOVERTY = 26002; +const int FEAT_FAV_COMPANIONS = 25994; //Vile Feat const int FEAT_LICHLOVED = 3395; @@ -1868,12 +1897,12 @@ const int FEAT_SANCTIFY_MARTIAL_SICKLE = 3169; const int FEAT_SANCTIFY_MARTIAL_MINDBLADE = 3623; const int FEAT_SANCTIFY_MARTIAL_WHIP = 3596; const int FEAT_SANCTIFY_MARTIAL_TRIDENT = 3597; -const int FEAT_SANCTIFYKISTRIKE = 26002; -const int FEAT_HOLYKISTRIKE = 26003; -const int FEAT_FISTOFHEAVENS = 26004; -const int FEAT_VOWABSTINENCE = 26005; -const int FEAT_VOWCHASTITY = 26006; -const int FEAT_GIFTOFFAITH = 26007; +const int FEAT_SANCTIFYKISTRIKE = 26003; +const int FEAT_HOLYKISTRIKE = 26004; +const int FEAT_FISTOFHEAVENS = 26005; +const int FEAT_VOWABSTINENCE = 26006; +const int FEAT_VOWCHASTITY = 26007; +const int FEAT_GIFTOFFAITH = 26008; //heartwarder const int FEAT_CHARISMA_INC1 = 3230; @@ -3189,6 +3218,8 @@ const int FEAT_ETHEREAL = 4167; const int FEAT_TEMPLATE_ARCHLICH_MARKER = 22700; const int FEAT_TEMPLATE_ARCHLICH_TURN_UNDEAD = 22701; +const int FEAT_TEMPLATE_BAELNORN_MARKER = 22708; + const int FEAT_TEMPLATE_CELESTIAL_SMITE_EVIL = 22601; const int FEAT_TEMPLATE_CELESTIAL_MARKER = 22602; const int FEAT_TEMPLATE_FIENDISH_SMITE_GOOD = 22603; @@ -3933,6 +3964,8 @@ const int FEAT_OPPORTUNISTIC_PIETY_HEAL = 5358; const int FEAT_OPPORTUNISTIC_PIETY_TURN = 5359; // Combat Maneuver Feats +const int FEAT_CM_CHARGE = 2823; +const int FEAT_CM_GRAPPLE = 3414; const int FEAT_CURLING_WAVE_STRIKE = 2809; const int FEAT_SIDESTEP_CHARGE = 3505; const int FEAT_POWERFUL_CHARGE = 3506; @@ -6203,6 +6236,38 @@ const int FEAT_SHINING_BLADE_SPELLCASTING_VASSAL = 19587; const int FEAT_SWIFT_WING_SPELLCASTING_VASSAL = 19588; const int FEAT_WARPRIEST_SPELLCASTING_VASSAL = 19589; +//:: Lion of Talisid marker feats +const int FEAT_LION_OF_TALISID_SPELLCASTING_ARCHIVIST = 25601; +const int FEAT_LION_OF_TALISID_SPELLCASTING_CLERIC = 25602; +const int FEAT_LION_OF_TALISID_SPELLCASTING_DRUID = 25603; +const int FEAT_LION_OF_TALISID_SPELLCASTING_FAVOURED_SOUL = 25604; +const int FEAT_LION_OF_TALISID_SPELLCASTING_HEALER = 25605; +const int FEAT_LION_OF_TALISID_SPELLCASTING_JOWAW = 25606; +const int FEAT_LION_OF_TALISID_SPELLCASTING_KOTMC = 25607; +const int FEAT_LION_OF_TALISID_SPELLCASTING_NENTYAR_HUNTER = 25608; +const int FEAT_LION_OF_TALISID_SPELLCASTING_RANGER = 25609; +const int FEAT_LION_OF_TALISID_SPELLCASTING_OASHAMAN = 25610; +const int FEAT_LION_OF_TALISID_SPELLCASTING_SOHEI = 25611; +const int FEAT_LION_OF_TALISID_SPELLCASTING_SOL = 25612; +const int FEAT_LION_OF_TALISID_SPELLCASTING_SPSHAMAN = 25613; + +//:: Verdant Lord marker feats +const int FEAT_VERDANT_LORD_SPELLCASTING_ARCHIVIST = 25619; +const int FEAT_VERDANT_LORD_SPELLCASTING_CLERIC = 25620; +const int FEAT_VERDANT_LORD_SPELLCASTING_DRUID = 25621; +const int FEAT_VERDANT_LORD_SPELLCASTING_FAVOURED_SOUL = 25622; +const int FEAT_VERDANT_LORD_SPELLCASTING_HEALER = 25623; +const int FEAT_VERDANT_LORD_SPELLCASTING_JOWAW = 25624; +const int FEAT_VERDANT_LORD_SPELLCASTING_KOTC = 25625; +const int FEAT_VERDANT_LORD_SPELLCASTING_KOTMC = 25626; +const int FEAT_VERDANT_LORD_SPELLCASTING_NENTYAR_HUNTER = 25627; +const int FEAT_VERDANT_LORD_SPELLCASTING_PALADIN = 25628; +const int FEAT_VERDANT_LORD_SPELLCASTING_RANGER = 25629; +const int FEAT_VERDANT_LORD_SPELLCASTING_OASHAMAN = 25630; +const int FEAT_VERDANT_LORD_SPELLCASTING_SOHEI = 25631; +const int FEAT_VERDANT_LORD_SPELLCASTING_SOL = 25632; +const int FEAT_VERDANT_LORD_SPELLCASTING_SPSHAMAN = 25633; + //:: No spellcasting or invoking marker feats const int FEAT_ASMODEUS_SPELLCASTING_NONE = 19590; const int FEAT_TIAMAT_SPELLCASTING_NONE = 19591; diff --git a/src/include/prc_inc_castlvl.nss b/src/include/prc_inc_castlvl.nss index 876ac84..8336a62 100644 --- a/src/include/prc_inc_castlvl.nss +++ b/src/include/prc_inc_castlvl.nss @@ -575,8 +575,8 @@ int PRCGetCasterLevel(object oCaster = OBJECT_SELF) iReturnLevel = GetLevelByClass(CLASS_TYPE_SHAPECHANGER); } - // Casting as a bard but don't have any levels in the class - if(iCastingClass == CLASS_TYPE_BARD && !GetLevelByClass(CLASS_TYPE_BARD, oCaster)) + // Casting as a bard but don't have any levels in the class //:: Double-dipping? +/* if(iCastingClass == CLASS_TYPE_BARD && !GetLevelByClass(CLASS_TYPE_BARD, oCaster)) { int nRace = GetRacialType(oCaster); @@ -584,7 +584,7 @@ int PRCGetCasterLevel(object oCaster = OBJECT_SELF) //otherwise use RHD instead of bard levels if(nRace == RACIAL_TYPE_GLOURA) iReturnLevel = GetLevelByClass(CLASS_TYPE_FEY); - } + } */ //Spell Rage ability if(GetHasSpellEffect(SPELL_SPELL_RAGE, oCaster) @@ -960,8 +960,10 @@ int GetArcanePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) } //:: End Bard Arcane PrC casting calculations - if(nCastingClass == CLASS_TYPE_BARD && nRace == RACIAL_TYPE_GLOURA && !GetLevelByClass(CLASS_TYPE_BARD, oCaster)) + if(nCastingClass == CLASS_TYPE_BARD || nCastingClass == CLASS_TYPE_BARD && nRace == RACIAL_TYPE_GLOURA && !GetLevelByClass(CLASS_TYPE_BARD, oCaster)) { + if(DEBUG) DoDebug("prc_inc_castlvl >> Found Fey RHD caster (not bard)"); + if(GetHasFeat(FEAT_ABCHAMP_SPELLCASTING_FEY, oCaster)) nArcane += GetLevelByClass(CLASS_TYPE_ABJURANT_CHAMPION, oCaster); @@ -1065,7 +1067,10 @@ int GetArcanePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nArcane += GetLevelByClass(CLASS_TYPE_UNSEEN_SEER, oCaster); if(GetHasFeat(FEAT_VIRTUOSO_SPELLCASTING_FEY, oCaster)) + { nArcane += GetLevelByClass(CLASS_TYPE_VIRTUOSO, oCaster); + if(DEBUG) DoDebug("prc_inc_castlvl >> Found Fey + Virtuoso PrC. Arcane caster level is "+IntToString(nArcane)+"."); + } if(GetHasFeat(FEAT_WWOC_SPELLCASTING_FEY, oCaster)) nArcane += GetLevelByClass(CLASS_TYPE_WAR_WIZARD_OF_CORMYR, oCaster); @@ -1143,8 +1148,8 @@ int GetArcanePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_DIABOLIST_SPELLCASTING_ASSASSIN, oCaster)) nArcane += GetLevelByClass(CLASS_TYPE_DIABOLIST, oCaster); - if(GetHasFeat(FEAT_DHEART_SPELLCASTING_ASSASSIN, oCaster)) - nArcane += GetLevelByClass(CLASS_TYPE_DRAGONHEART_MAGE, oCaster); + //if(GetHasFeat(FEAT_DHEART_SPELLCASTING_ASSASSIN, oCaster)) + //nArcane += GetLevelByClass(CLASS_TYPE_DRAGONHEART_MAGE, oCaster); if(GetHasFeat(FEAT_EKNIGHT_SPELLCASTING_ASSASSIN, oCaster)) nArcane += GetLevelByClass(CLASS_TYPE_ELDRITCH_KNIGHT, oCaster); @@ -3817,6 +3822,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_ARCHIVIST, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_ARCHIVIST, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); + /* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_ARCHIVIST, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */ @@ -4143,7 +4151,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster); if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_CLERIC, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_CLERIC, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_CLERIC, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); @@ -4253,7 +4264,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster); if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_DRUID, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_DRUID, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); // if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_DRUID, oCaster)) // nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); @@ -4365,10 +4379,13 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster); if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_FAVOURED_SOUL, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_FAVOURED_SOUL, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); - // if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_FAVOURED_SOUL, oCaster)) - // nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); + if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_FAVOURED_SOUL, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); if(GetHasFeat(FEAT_MORNINGLORD_SPELLCASTING_FAVOURED_SOUL, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MORNINGLORD, oCaster); @@ -4474,6 +4491,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_HEALER, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_HEALER, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); + /* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_HEALER, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */ @@ -4581,6 +4601,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_JUSTICEWW, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_JOWAW, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); + // if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_JUSTICEWW, oCaster)) // nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); @@ -4791,6 +4814,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_KNIGHT_MIDDLECIRCLE, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_KOTMC, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); + /* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_KNIGHT_MIDDLECIRCLE, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */ @@ -4896,7 +4922,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster); */ if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_NENTYAR_HUNTER, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_NENTYAR_HUNTER, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); /* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_NENTYAR_HUNTER, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */ @@ -5207,7 +5236,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster); */ if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_RANGER, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_RANGER, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); if(GetHasFeat(FEAT_MORNINGLORD_SPELLCASTING_RANGER, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MORNINGLORD, oCaster); @@ -5311,7 +5343,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster); if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_OASHAMAN, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_OASHAMAN, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_SHAMAN, oCaster); if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_OASHAMAN, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); @@ -5524,6 +5559,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_SOHEI, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_SOHEI, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); + // if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_SOHEI, oCaster)) // nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); @@ -5631,6 +5669,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_SOL, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_SOL, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); + /* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_SOL, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */ diff --git a/src/include/prc_inc_combat.nss b/src/include/prc_inc_combat.nss index 3cdbab5..df4a5b7 100644 --- a/src/include/prc_inc_combat.nss +++ b/src/include/prc_inc_combat.nss @@ -1206,6 +1206,7 @@ int GetIsDoubleSidedWeaponType(int iWeaponType) return ( iWeaponType == BASE_ITEM_DIREMACE || iWeaponType == BASE_ITEM_DOUBLEAXE || iWeaponType == BASE_ITEM_TWOBLADEDSWORD + || iWeaponType == BASE_ITEM_DOUBLE_SCIMITAR ); } diff --git a/src/include/prc_inc_combmove.nss b/src/include/prc_inc_combmove.nss index b81aab4..d280dd1 100644 --- a/src/include/prc_inc_combmove.nss +++ b/src/include/prc_inc_combmove.nss @@ -1140,6 +1140,9 @@ void DoCharge(object oPC, object oTarget, int nDoAttack = TRUE, int nGenerateAoO nPounce = TRUE; if (GetHasSpellEffect(VESTIGE_CHUPOCLOPS, oPC) && GetLocalInt(oPC, "ExploitVestige") != VESTIGE_CHUPOCLOPS_POUNCE) nPounce = TRUE; + //:: Lion of Talisid + if(GetHasFeat(FEAT_LOT_LIONS_POUNCE, oPC)) + nPounce = TRUE; // Checks for a White Raven Stance // If it exists, +1 damage/initiator level @@ -2312,7 +2315,10 @@ void DoShieldCharge(object oPC, object oTarget, int nSlam = FALSE) if(GetLevelByClass(CLASS_TYPE_CELEBRANT_SHARESS, oPC) >= 5) nPounce = TRUE; if(GetRacialType(oPC) == RACIAL_TYPE_MARRUSAULT) - nPounce = TRUE; + nPounce = TRUE; + //:: Lion of Talisid + if(GetHasFeat(FEAT_LOT_LIONS_POUNCE, oPC)) + nPounce = TRUE; // Checks for a White Raven Stance // If it exists, +1 damage/initiator level diff --git a/src/include/prc_inc_core.nss b/src/include/prc_inc_core.nss index 30af518..099c3ac 100644 --- a/src/include/prc_inc_core.nss +++ b/src/include/prc_inc_core.nss @@ -462,7 +462,7 @@ int PRCGetSpellLevelForClass(int nSpell, int nClass) return nSpellLevel; } -// returns the spelllevel of nSpell as it can be cast by oCreature +// returns the spell circle level of nSpell as it can be cast by oCreature int PRCGetSpellLevel(object oCreature, int nSpell) { /*if (!PRCGetHasSpell(nSpell, oCreature)) @@ -605,7 +605,7 @@ int PRCGetHasSpell(int nRealSpellID, object oCreature = OBJECT_SELF) if(nSpellbookType == SPELLBOOK_TYPE_PREPARED) { nCount = persistant_array_get_int(oCreature, "NewSpellbookMem_" + IntToString(nClass), j); - if(DEBUG) DoDebug("PRCGetHasSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(j) + "] = " + IntToString(nCount)); + if(DEBUG) DoDebug("prc_inc_core >> PRCGetHasSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(j) + "] = " + IntToString(nCount)); if(nCount > 0) { nUses += nCount; @@ -615,7 +615,7 @@ int PRCGetHasSpell(int nRealSpellID, object oCreature = OBJECT_SELF) { nSpellLevel = StringToInt(Get2DACache(sFile, "Level", j)); nCount = persistant_array_get_int(oCreature, "NewSpellbookMem_" + IntToString(nClass), nSpellLevel); - if(DEBUG) DoDebug("PRCGetHasSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(j) + "] = " + IntToString(nCount)); + if(DEBUG) DoDebug("prc_inc_core >> PRCGetHasSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(j) + "] = " + IntToString(nCount)); if(nCount > 0) { nUses += nCount; diff --git a/src/include/prc_inc_fork.nss b/src/include/prc_inc_fork.nss index b6b672e..2b19f97 100644 --- a/src/include/prc_inc_fork.nss +++ b/src/include/prc_inc_fork.nss @@ -795,7 +795,7 @@ int GetWeaponSize(object oWeapon) case BASE_ITEM_GREATAXE: case BASE_ITEM_HEAVYFLAIL: case BASE_ITEM_QUARTERSTAFF: - case BASE_ITEM_MAGICSTAFF: + //case BASE_ITEM_MAGICSTAFF: case BASE_ITEM_SCYTHE: case BASE_ITEM_SHORTSPEAR: case BASE_ITEM_ELVEN_COURTBLADE: @@ -832,7 +832,7 @@ int PRCLargeWeaponCheck(int iBaseType, int nSize) case BASE_ITEM_GREATAXE: case BASE_ITEM_HEAVYFLAIL: case BASE_ITEM_QUARTERSTAFF: - case BASE_ITEM_MAGICSTAFF: + //case BASE_ITEM_MAGICSTAFF: case BASE_ITEM_SCYTHE: case BASE_ITEM_SHORTSPEAR: case BASE_ITEM_ELVEN_COURTBLADE: diff --git a/src/include/prc_inc_function.nss b/src/include/prc_inc_function.nss index 93f7aa1..aa47614 100644 --- a/src/include/prc_inc_function.nss +++ b/src/include/prc_inc_function.nss @@ -108,8 +108,8 @@ void SetupCharacterData(object oPC) case CLASS_TYPE_ALIENIST: sScript = "prc_alienist"; break; case CLASS_TYPE_ARCANE_DUELIST: sScript = "prc_arcduel"; break; case CLASS_TYPE_ARCHIVIST: sScript = "prc_archivist"; iData |= 0x01; break; - case CLASS_TYPE_ASSASSIN: iData |= 0x03; break; - case CLASS_TYPE_BAELNORN: sScript = "prc_baelnorn"; break; + case CLASS_TYPE_ASSASSIN: break; + //case CLASS_TYPE_BAELNORN: sScript = "prc_baelnorn"; break; case CLASS_TYPE_BARD: iData |= 0x07; break; case CLASS_TYPE_BATTLESMITH: sScript = "prc_battlesmith"; break; case CLASS_TYPE_BEGUILER: iData |= 0x03; break; @@ -121,7 +121,7 @@ void SetupCharacterData(object oPC) case CLASS_TYPE_BLIGHTLORD: sScript = "prc_blightlord"; break; case CLASS_TYPE_BLOODCLAW_MASTER: sScript = "tob_bloodclaw"; break; case CLASS_TYPE_BONDED_SUMMONNER: sScript = "prc_bondedsumm"; break; - case CLASS_TYPE_CELEBRANT_SHARESS: iData |= 0x03; break; + case CLASS_TYPE_CELEBRANT_SHARESS: iData |= 0x07; break; case CLASS_TYPE_CHILD_OF_NIGHT: sScript = "shd_childnight"; break; case CLASS_TYPE_COC: sScript = "prc_coc"; break; case CLASS_TYPE_COMBAT_MEDIC: sScript = "prc_cbtmed"; break; @@ -180,6 +180,7 @@ void SetupCharacterData(object oPC) case CLASS_TYPE_LASHER: sScript = "prc_lasher"; break; case CLASS_TYPE_LEGENDARY_DREADNOUGHT: sScript = "prc_legendread"; break; case CLASS_TYPE_LICH: sScript = "pnp_lich_level"; break; + case CLASS_TYPE_LION_OF_TALISID: sScript = "prc_lot"; break; case CLASS_TYPE_MAGEKILLER: sScript = "prc_magekill"; break; case CLASS_TYPE_MASTER_HARPER: sScript = "prc_masterh"; break; case CLASS_TYPE_MASTER_OF_NINE: sScript = "tob_masterofnine"; break; @@ -245,6 +246,7 @@ void SetupCharacterData(object oPC) case CLASS_TYPE_TOTEM_RAGER: sScript = "moi_totemrager"; break; case CLASS_TYPE_TRUENAMER: sScript = "true_truenamer"; iData |= 0x01; break; case CLASS_TYPE_VASSAL: sScript = "prc_vassal"; break; + case CLASS_TYPE_VERDANT_LORD: sScript = "prc_verdantlord"; break; case CLASS_TYPE_VIGILANT: sScript = "prc_vigilant"; break; case CLASS_TYPE_WARBLADE: sScript = "tob_warblade"; iData |= 0x01; break; case CLASS_TYPE_WARCHIEF: sScript = "prc_warchief"; break; @@ -2264,6 +2266,8 @@ void FeatSpecialUsePerDay(object oPC) FeatUsePerDay(oPC, FEAT_FM_FOREST_DOMINION, ABILITY_CHARISMA, 3); FeatUsePerDay(oPC, FEAT_SOD_DEATH_TOUCH, -1, (GetLevelByClass(CLASS_TYPE_SLAYER_OF_DOMIEL, oPC)+4)/4); FeatUsePerDay(oPC, FEAT_SUEL_DISPELLING_STRIKE, -1, (GetLevelByClass(CLASS_TYPE_SUEL_ARCHANAMACH, oPC) + 2) / 4); + FeatUsePerDay(oPC, FEAT_PLANT_CONTROL, ABILITY_CHARISMA, 3); + FeatUsePerDay(oPC, FEAT_PLANT_DEFIANCE, ABILITY_CHARISMA, 3); FeatDiabolist(oPC); FeatAlaghar(oPC); ShadowShieldUses(oPC); diff --git a/src/include/prc_inc_json.nss b/src/include/prc_inc_json.nss new file mode 100644 index 0000000..749c551 --- /dev/null +++ b/src/include/prc_inc_json.nss @@ -0,0 +1,750 @@ +//::////////////////////////////////////////////// +//:: ;-. ,-. ,-. ,-. +//:: | ) | ) / ( ) +//:: |-' |-< | ;-: +//:: | | \ \ ( ) +//:: ' ' ' `-' `-' +//::////////////////////////////////////////////// +//:: +/* + Library for json related functions. + +*/ +//:: +//::////////////////////////////////////////////// +//:: Script: prc_inc_json.nss +//:: Author: Jaysyn +//:: Created: 2025-08-14 12:52:32 +//::////////////////////////////////////////////// +#include "nw_inc_gff" +#include "inc_debug" + + +//::---------------------------------------------| +//:: Helper functions | +//::---------------------------------------------| + +//:: Function to calculate the maximum possible hitpoints for oCreature +int GetMaxPossibleHP(object oCreature) +{ + int nMaxHP = 0; // Stores the total maximum hitpoints + int i = 1; // Initialize position for class index + int nConb = GetAbilityModifier(ABILITY_CONSTITUTION, oCreature); + + // Loop through each class position the creature may have, checking each class in turn + while (TRUE) + { + // Get the class ID at position i + int nClassID = GetClassByPosition(i, oCreature); + + // If class is invalid (no more classes to check), break out of loop + if (nClassID == CLASS_TYPE_INVALID) + break; + + // Get the number of levels in this class + int nClassLevels = GetLevelByClass(nClassID, oCreature); + + // Get the row index of the class in classes.2da by using class ID as the row index + int nHitDie = StringToInt(Get2DAString("classes", "HitDie", nClassID)); + + // Add maximum HP for this class (Hit Die * number of levels in this class) + nMaxHP += nClassLevels * nHitDie; + + // Move to the next class position + i++; + } + + nMaxHP += nConb * GetHitDice(oCreature); + + return nMaxHP; +} + +// Returns how many feats a creature should gain when its HD increases +int CalculateFeatsFromHD(int nOriginalHD, int nNewHD) +{ + // HD increase + int nHDIncrease = nNewHD - nOriginalHD; + + if (nHDIncrease <= 0) + return 0; // No new feats if HD did not increase + + // D&D 3E: 1 feat per 3 HD + int nBonusFeats = nHDIncrease / 3; + + return nBonusFeats; +} + +// Returns how many stat boosts a creature needs based on its HD +int GetStatBoostsFromHD(int nCreatureHD, int nModiferCap) +{ + // Make sure we don't get negative boosts + int nBoosts = (40 - nCreatureHD) / 4; + if (nBoosts < 0) + { + nBoosts = 0; + } + return nBoosts; +} + +// Struct to hold size modifiers +struct SizeModifiers +{ + int strMod; + int dexMod; + int conMod; + int naturalAC; + int attackBonus; + int dexSkillMod; +}; + +//::---------------------------------------------| +//:: JSON functions | +//::---------------------------------------------| + +//:: Returns the integer value of a VarTable entry named sVarName, or 0 if not found. +int json_GetLocalIntFromVarTable(json jCreature, string sVarName) +{ + json jVarTable = GffGetList(jCreature, "VarTable"); + if (jVarTable == JsonNull()) + return 0; + + int nCount = JsonGetLength(jVarTable); + int i; + for (i = 0; i < nCount; i++) + { + json jEntry = JsonArrayGet(jVarTable, i); + if (jEntry == JsonNull()) continue; + + // Get the Name field using GFF functions + json jName = GffGetString(jEntry, "Name"); + if (jName == JsonNull()) continue; + string sName = JsonGetString(jName); + + if (sName == sVarName) + { + // Get the Type field to verify it's an integer + json jType = GffGetDword(jEntry, "Type"); + if (jType != JsonNull()) + { + int nType = JsonGetInt(jType); + if (nType == 1) // Type 1 = integer + { + // Get the Value field using GFF functions + json jValue = GffGetInt(jEntry, "Value"); + if (jValue == JsonNull()) return 0; + return JsonGetInt(jValue); + } + } + } + } + + return 0; +} + +//:: Returns the total Hit Dice from a JSON creature GFF. +int json_GetCreatureHD(json jGff) +{ + int nHD = 0; + + json jClasses = GffGetList(jGff, "ClassList"); + if (jClasses == JsonNull()) + return 0; + + int nCount = JsonGetLength(jClasses); + int i; + for (i = 0; i < nCount; i = i + 1) + { + json jClass = JsonArrayGet(jClasses, i); + if (jClass == JsonNull()) + continue; + + json jLevel = GffGetShort(jClass, "ClassLevel"); // Use GffGetShort, not GffGetField + if (jLevel != JsonNull()) + { + int nLevel = JsonGetInt(jLevel); + nHD += nLevel; + } + } + + if (nHD <= 0) nHD = 1; + return nHD; +} + +//:: Reads ABILITY_TO_INCREASE from creature's VarTable and applies stat boosts based on increased HD +json json_ApplyAbilityBoostFromHD(json jCreature, int nOriginalHD, int nModifierCap) +{ + if (jCreature == JsonNull()) + return jCreature; + + // Get the ability to increase from VarTable + int nAbilityToIncrease = json_GetLocalIntFromVarTable(jCreature, "ABILITY_TO_INCREASE"); + if (nAbilityToIncrease < 0 || nAbilityToIncrease > 5) + { + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Invalid ABILITY_TO_INCREASE value: " + IntToString(nAbilityToIncrease)); + return jCreature; // Invalid ability index + } + + // Calculate total current HD from ClassList + json jClassList = GffGetList(jCreature, "ClassList"); + if (jClassList == JsonNull()) + { + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Failed to get ClassList"); + return jCreature; + } + + int nCurrentTotalHD = 0; + int nClassCount = JsonGetLength(jClassList); + int i; + + for (i = 0; i < nClassCount; i++) + { + json jClass = JsonArrayGet(jClassList, i); + if (jClass != JsonNull()) + { + json jClassLevel = GffGetShort(jClass, "ClassLevel"); + if (jClassLevel != JsonNull()) + { + nCurrentTotalHD += JsonGetInt(jClassLevel); + } + } + } + + if (nCurrentTotalHD <= 0) + { + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: No valid Hit Dice found"); + return jCreature; + } + + // Calculate stat boosts based on crossing level thresholds + // Characters get stat boosts at levels 4, 8, 12, 16, 20, etc. + int nOriginalBoosts = nOriginalHD / 4; // How many boosts they already had + int nCurrentBoosts = nCurrentTotalHD / 4; // How many they should have now + int nBoosts = nCurrentBoosts - nOriginalBoosts; // Additional boosts to apply + + if (nBoosts <= 0) + { + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: No boosts needed (Original boosts: " + IntToString(nOriginalBoosts) + ", Current boosts: " + IntToString(nCurrentBoosts) + ")"); + return jCreature; + } + + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Applying " + IntToString(nBoosts) + " boosts to ability " + IntToString(nAbilityToIncrease) + " for HD increase from " + IntToString(nOriginalHD) + " to " + IntToString(nCurrentTotalHD)); + + // Determine which ability to boost and apply the increases + string sAbilityField; + switch (nAbilityToIncrease) + { + case 0: sAbilityField = "Str"; break; + case 1: sAbilityField = "Dex"; break; + case 2: sAbilityField = "Con"; break; + case 3: sAbilityField = "Int"; break; + case 4: sAbilityField = "Wis"; break; + case 5: sAbilityField = "Cha"; break; + default: + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Unknown ability index: " + IntToString(nAbilityToIncrease)); + return jCreature; + } + + // Get current ability score + json jCurrentAbility = GffGetByte(jCreature, sAbilityField); + if (jCurrentAbility == JsonNull()) + { + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Failed to get " + sAbilityField + " score"); + return jCreature; + } + + int nCurrentScore = JsonGetInt(jCurrentAbility); + int nNewScore = nCurrentScore + nBoosts; + + // Clamp to valid byte range + if (nNewScore < 1) nNewScore = 1; + if (nNewScore > 255) nNewScore = 255; + + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Increasing " + sAbilityField + " from " + IntToString(nCurrentScore) + " to " + IntToString(nNewScore)); + + // Apply the ability score increase + jCreature = GffReplaceByte(jCreature, sAbilityField, nNewScore); + if (jCreature == JsonNull()) + { + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Failed to update " + sAbilityField); + return JsonNull(); + } + + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Successfully applied ability boosts"); + return jCreature; +} + +//:: Adjust a skill by its ID (more efficient than name lookup) +json json_AdjustCreatureSkillByID(json jCreature, int nSkillID, int nMod) +{ + // Get the SkillList + json jSkillList = GffGetList(jCreature, "SkillList"); + if (jSkillList == JsonNull()) + { + if(DEBUG) DoDebug("json_AdjustCreatureSkillByID: Failed to get SkillList"); + return jCreature; + } + + // Check if we have enough skills in the list + int nSkillCount = JsonGetLength(jSkillList); + if (nSkillID >= nSkillCount) + { + if(DEBUG) DoDebug("json_AdjustCreatureSkillByID: Skill ID " + IntToString(nSkillID) + " exceeds skill list length " + IntToString(nSkillCount)); + return jCreature; + } + + // Get the skill struct at the correct index + json jSkill = JsonArrayGet(jSkillList, nSkillID); + if (jSkill == JsonNull()) + { + if(DEBUG) DoDebug("json_AdjustCreatureSkillByID: Failed to get skill at index " + IntToString(nSkillID)); + return jCreature; + } + + // Get current rank + json jRank = GffGetByte(jSkill, "Rank"); + if (jRank == JsonNull()) + { + if(DEBUG) DoDebug("json_AdjustCreatureSkillByID: Failed to get Rank for skill ID " + IntToString(nSkillID)); + return jCreature; + } + + int nCurrentRank = JsonGetInt(jRank); + int nNewRank = nCurrentRank + nMod; + + // Clamp to valid range + if (nNewRank < 0) nNewRank = 0; + if (nNewRank > 255) nNewRank = 255; + + // Update the rank in the skill struct + jSkill = GffReplaceByte(jSkill, "Rank", nNewRank); + if (jSkill == JsonNull()) + { + if(DEBUG) DoDebug("json_AdjustCreatureSkillByID: Failed to replace Rank for skill ID " + IntToString(nSkillID)); + return JsonNull(); + } + + // Replace the skill in the array + jSkillList = JsonArraySet(jSkillList, nSkillID, jSkill); + + // Replace the SkillList in the creature + jCreature = GffReplaceList(jCreature, "SkillList", jSkillList); + + return jCreature; +} + +//:: Reads FutureFeat1..FutureFeatN from the template's VarTable and appends them to FeatList if missing. +json json_AddFeatsFromCreatureVars(json jCreature, int nOriginalHD) +{ + if (jCreature == JsonNull()) + return jCreature; + + // Calculate current total HD + int nCurrentHD = json_GetCreatureHD(jCreature); + int nAddedHD = nCurrentHD - nOriginalHD; + + if (nAddedHD <= 0) + { + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: No additional HD to process (Current: " + IntToString(nCurrentHD) + ", Original: " + IntToString(nOriginalHD) + ")"); + return jCreature; + } + + // Calculate how many feats the creature should get based on added HD + // Characters get a feat at levels 1, 3, 6, 9, 12, 15, 18, etc. + // For added levels, we need to check what feat levels they cross + int nOriginalFeats = (nOriginalHD + 2) / 3; // Feats from original HD + int nCurrentFeats = (nCurrentHD + 2) / 3; // Feats from current HD + int nNumFeats = nCurrentFeats - nOriginalFeats; // Additional feats earned + + if (nNumFeats <= 0) + { + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: No additional feats earned from " + IntToString(nAddedHD) + " added HD"); + return jCreature; + } + + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Processing " + IntToString(nNumFeats) + " feats for " + IntToString(nAddedHD) + " added HD (Original: " + IntToString(nOriginalHD) + ", Current: " + IntToString(nCurrentHD) + ")"); + + // Get or create FeatList + json jFeatArray = GffGetList(jCreature, "FeatList"); + if (jFeatArray == JsonNull()) + jFeatArray = JsonArray(); + + int nOriginalFeatCount = JsonGetLength(jFeatArray); + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Original feat count: " + IntToString(nOriginalFeatCount)); + + int nAdded = 0; + int i = 1; + int nMaxIterations = 100; // Safety valve + int nIterations = 0; + + while (nAdded < nNumFeats && nIterations < nMaxIterations) + { + nIterations++; + string sVarName = "FutureFeat" + IntToString(i); + + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Checking " + sVarName); + + int nFeat = json_GetLocalIntFromVarTable(jCreature, sVarName); + + if (nFeat <= 0) + { + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: " + sVarName + " not found or invalid"); + i++; + continue; + } + + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Found " + sVarName + " = " + IntToString(nFeat)); + + // Check if feat already exists + int bHasFeat = FALSE; + int nFeatCount = JsonGetLength(jFeatArray); + int j; + + for (j = 0; j < nFeatCount; j++) + { + json jFeatStruct = JsonArrayGet(jFeatArray, j); + if (jFeatStruct != JsonNull()) + { + json jFeatValue = GffGetWord(jFeatStruct, "Feat"); + if (jFeatValue != JsonNull() && JsonGetInt(jFeatValue) == nFeat) + { + bHasFeat = TRUE; + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Feat " + IntToString(nFeat) + " already exists"); + break; + } + } + } + + // Insert if missing + if (!bHasFeat) + { + json jNewFeat = JsonObject(); + jNewFeat = JsonObjectSet(jNewFeat, "__struct_id", JsonInt(1)); + jNewFeat = GffAddWord(jNewFeat, "Feat", nFeat); + + if (jNewFeat == JsonNull()) + { + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Failed to create feat struct for feat " + IntToString(nFeat)); + break; + } + + jFeatArray = JsonArrayInsert(jFeatArray, jNewFeat); + nAdded++; + + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Added feat " + IntToString(nFeat) + " (" + IntToString(nAdded) + "/" + IntToString(nNumFeats) + ")"); + } + + i++; + + // Safety break if we've checked too many variables + if (i > 100) + { + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Safety break - checked too many FutureFeat variables"); + break; + } + } + + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Completed. Added " + IntToString(nAdded) + " feats in " + IntToString(nIterations) + " iterations"); + + // Save back the modified FeatList only if we added something + if (nAdded > 0) + { + jCreature = GffReplaceList(jCreature, "FeatList", jFeatArray); + if (jCreature == JsonNull()) + { + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Failed to replace FeatList"); + return JsonNull(); + } + } + + return jCreature; +} + +//:: Get the size of a JSON array +int json_GetArraySize(json jArray) +{ + int iSize = 0; + while (JsonArrayGet(jArray, iSize) != JsonNull()) + { + iSize++; + } + return iSize; +} + +//:: Directly modifies oCreature's Base Natural AC if iNewAC is higher. +//:: +json json_UpdateBaseAC(json jCreature, int iNewAC) +{ + //json jBaseAC = GffGetByte(jCreature, "Creature/value/NaturalAC/value"); + json jBaseAC = GffGetByte(jCreature, "NaturalAC"); + + if (jBaseAC == JsonNull()) + { + return JsonNull(); + } + else if (JsonGetInt(jBaseAC) > iNewAC) + { + return jCreature; + } + else + { + jCreature = GffReplaceByte(jCreature, "NaturalAC", iNewAC); + + return jCreature; + } +} + +//:: Directly modifies jCreature's Challenge Rating. +//:: This is useful for most XP calculations. +json json_UpdateCR(json jCreature, int nBaseCR, int nCRMod) +{ + int nNewCR; + +//:: Add CRMod to current CR + nNewCR = nBaseCR + nCRMod; + +//:: Modify Challenge Rating + jCreature = GffReplaceFloat(jCreature, "ChallengeRating", IntToFloat(nNewCR)); + + return jCreature; +} + +//:: Directly modifies ability scores in a creature's JSON GFF. +//:: +json json_UpdateTemplateStats(json jCreature, int iModStr = 0, int iModDex = 0, int iModCon = 0, + int iModInt = 0, int iModWis = 0, int iModCha = 0) +{ + int iCurrent; + + // STR + if (!GffGetFieldExists(jCreature, "Str", GFF_FIELD_TYPE_BYTE)) + jCreature = GffAddByte(jCreature, "Str", 10); + iCurrent = JsonGetInt(GffGetByte(jCreature, "Str")); + jCreature = GffReplaceByte(jCreature, "Str", iCurrent + iModStr); + + // DEX + if (!GffGetFieldExists(jCreature, "Dex", GFF_FIELD_TYPE_BYTE)) + jCreature = GffAddByte(jCreature, "Dex", 10); + iCurrent = JsonGetInt(GffGetByte(jCreature, "Dex")); + jCreature = GffReplaceByte(jCreature, "Dex", iCurrent + iModDex); + + // CON + if (!GffGetFieldExists(jCreature, "Con", GFF_FIELD_TYPE_BYTE)) + jCreature = GffAddByte(jCreature, "Con", 10); + iCurrent = JsonGetInt(GffGetByte(jCreature, "Con")); + jCreature = GffReplaceByte(jCreature, "Con", iCurrent + iModCon); + + // INT + if (!GffGetFieldExists(jCreature, "Int", GFF_FIELD_TYPE_BYTE)) + jCreature = GffAddByte(jCreature, "Int", 10); + iCurrent = JsonGetInt(GffGetByte(jCreature, "Int")); + jCreature = GffReplaceByte(jCreature, "Int", iCurrent + iModInt); + + // WIS + if (!GffGetFieldExists(jCreature, "Wis", GFF_FIELD_TYPE_BYTE)) + jCreature = GffAddByte(jCreature, "Wis", 10); + iCurrent = JsonGetInt(GffGetByte(jCreature, "Wis")); + jCreature = GffReplaceByte(jCreature, "Wis", iCurrent + iModWis); + + // CHA + if (!GffGetFieldExists(jCreature, "Cha", GFF_FIELD_TYPE_BYTE)) + jCreature = GffAddByte(jCreature, "Cha", 10); + iCurrent = JsonGetInt(GffGetByte(jCreature, "Cha")); + jCreature = GffReplaceByte(jCreature, "Cha", iCurrent + iModCha); + + return jCreature; +} + +//:: Directly modifies oCreature's ability scores. +//:: +json json_UpdateCreatureStats(json jCreature, object oBaseCreature, int iModStr = 0, int iModDex = 0, int iModCon = 0, int iModInt = 0, int iModWis = 0, int iModCha = 0) +{ +//:: Retrieve and modify ability scores + int iCurrentStr = GetAbilityScore(oBaseCreature, ABILITY_STRENGTH); + int iCurrentDex = GetAbilityScore(oBaseCreature, ABILITY_DEXTERITY); + int iCurrentCon = GetAbilityScore(oBaseCreature, ABILITY_CONSTITUTION); + int iCurrentInt = GetAbilityScore(oBaseCreature, ABILITY_INTELLIGENCE); + int iCurrentWis = GetAbilityScore(oBaseCreature, ABILITY_WISDOM); + int iCurrentCha = GetAbilityScore(oBaseCreature, ABILITY_CHARISMA); + + jCreature = GffReplaceByte(jCreature, "Str", iCurrentStr + iModStr); + jCreature = GffReplaceByte(jCreature, "Dex", iCurrentDex + iModDex); + jCreature = GffReplaceByte(jCreature, "Con", iCurrentCon + iModCon); + jCreature = GffReplaceByte(jCreature, "Int", iCurrentInt + iModInt); + jCreature = GffReplaceByte(jCreature, "Wis", iCurrentWis + iModWis); + jCreature = GffReplaceByte(jCreature, "Cha", iCurrentCha + iModCha); + + return jCreature; +} + +//:: Increases a creature's Hit Dice in its JSON GFF data by nAmount +json json_AddHitDice(json jCreature, int nAmount) +{ + if (jCreature == JsonNull() || nAmount <= 0) + return jCreature; + + // Get the ClassList + json jClasses = GffGetList(jCreature, "ClassList"); + if (jClasses == JsonNull() || JsonGetLength(jClasses) == 0) + return jCreature; + + // Grab the first class entry + json jFirstClass = JsonArrayGet(jClasses, 0); + + // Only touch ClassLevel; do NOT modify Class type + json jCurrentLevel = GffGetShort(jFirstClass, "ClassLevel"); + int nCurrentLevel = JsonGetInt(jCurrentLevel); + int nNewLevel = nCurrentLevel + nAmount; + + // Replace ClassLevel only + jFirstClass = GffReplaceShort(jFirstClass, "ClassLevel", nNewLevel); + + // Put modified class back into the array + jClasses = JsonArraySet(jClasses, 0, jFirstClass); + + // Replace ClassList in the creature JSON + jCreature = GffReplaceList(jCreature, "ClassList", jClasses); + + return jCreature; +} + +//:: Adjusts a creature's size by nSizeChange (-4 to +4) and updates ability scores accordingly. +json json_AdjustCreatureSize(json jCreature, int nSizeDelta) +{ + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Entering function. nSizeDelta=" + IntToString(nSizeDelta)); + + if (jCreature == JsonNull() || nSizeDelta == 0) + { + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Exiting: jCreature is null or nSizeDelta is 0"); + return jCreature; + } + + // Get Appearance_Type using GFF functions + json jAppearanceType = GffGetWord(jCreature, "Appearance_Type"); + if (jAppearanceType == JsonNull()) + { + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed to get Appearance_Type"); + return jCreature; + } + + int nAppearance = JsonGetInt(jAppearanceType); + int nCurrentSize = StringToInt(Get2DAString("appearances", "Size", nAppearance)); + + // Default to Medium (4) if invalid + if (nCurrentSize < 0 || nCurrentSize > 8) nCurrentSize = 4; + + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Appearance_Type =" + IntToString(nAppearance) + ", Size =" + IntToString(nCurrentSize)); + + int nSteps = nSizeDelta; + + // Calculate modifiers based on size change + int strMod = nSteps * 4; + int dexMod = nSteps * -1; + int conMod = nSteps * 2; + int naturalAC = nSteps * 1; + int dexSkillMod = nSteps * -2; + + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Applying stat modifiers: STR=" + IntToString(strMod) + + " DEX=" + IntToString(dexMod) + + " CON=" + IntToString(conMod)); + + // Update ability scores using GFF functions with error checking + json jStr = GffGetByte(jCreature, "Str"); + if (jStr != JsonNull()) + { + int nNewStr = JsonGetInt(jStr) + strMod; + if (nNewStr < 1) nNewStr = 1; + if (nNewStr > 255) nNewStr = 255; + + jCreature = GffReplaceByte(jCreature, "Str", nNewStr); + if (jCreature == JsonNull()) + { + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed to update Str"); + return JsonNull(); + } + } + + json jDex = GffGetByte(jCreature, "Dex"); + if (jDex != JsonNull()) + { + int nNewDex = JsonGetInt(jDex) + dexMod; + if (nNewDex < 1) nNewDex = 1; + if (nNewDex > 255) nNewDex = 255; + + jCreature = GffReplaceByte(jCreature, "Dex", nNewDex); + if (jCreature == JsonNull()) + { + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed to update Dex"); + return JsonNull(); + } + } + + json jCon = GffGetByte(jCreature, "Con"); + if (jCon != JsonNull()) + { + int nNewCon = JsonGetInt(jCon) + conMod; + if (nNewCon < 1) nNewCon = 1; + if (nNewCon > 255) nNewCon = 255; + + jCreature = GffReplaceByte(jCreature, "Con", nNewCon); + if (jCreature == JsonNull()) + { + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed to update Con"); + return JsonNull(); + } + } + + // Update Natural AC + json jNaturalAC = GffGetByte(jCreature, "NaturalAC"); + if (jNaturalAC != JsonNull()) + { + int nCurrentNA = JsonGetInt(jNaturalAC); + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Current NaturalAC: " + IntToString(nCurrentNA)); + + int nNewNA = nCurrentNA + naturalAC; + if (nNewNA < 0) nNewNA = 0; + if (nNewNA > 255) nNewNA = 255; + + jCreature = GffReplaceByte(jCreature, "NaturalAC", nNewNA); + if (jCreature == JsonNull()) + { + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed to update NaturalAC"); + return JsonNull(); + } + } + + // Adjust all Dexterity-based skills by finding them in skills.2da + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Adjusting DEX-based skills"); + + int nSkillID = 0; + while (TRUE) + { + string sKeyAbility = Get2DAString("skills", "KeyAbility", nSkillID); + + // Break when we've reached the end of skills + if (sKeyAbility == "") + break; + + // If this skill uses Dexterity, adjust it + if (sKeyAbility == "DEX") + { + string sSkillLabel = Get2DAString("skills", "Label", nSkillID); + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Adjusting DEX skill: " + sSkillLabel + " (ID: " + IntToString(nSkillID) + ")"); + + jCreature = json_AdjustCreatureSkillByID(jCreature, nSkillID, dexSkillMod); + if (jCreature == JsonNull()) + { + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed adjusting skill ID " + IntToString(nSkillID)); + return JsonNull(); + } + } + + nSkillID++; + } + + if(DEBUG) DoDebug("json_AdjustCreatureSize completed successfully"); + return jCreature; +} + + +//:: Test void +//:: void main (){} \ No newline at end of file diff --git a/src/include/prc_inc_material.nss b/src/include/prc_inc_material.nss index f69e26d..dc050aa 100644 --- a/src/include/prc_inc_material.nss +++ b/src/include/prc_inc_material.nss @@ -16,26 +16,28 @@ const int MATERIAL_TYPE_UNKNOWN = 0; const int MATERIAL_TYPE_BONE = 1; const int MATERIAL_TYPE_CERAMIC = 2; const int MATERIAL_TYPE_CRYSTAL = 3; -const int MATERIAL_TYPE_FABRIC = 4; +const int MATERIAL_TYPE_FIBER = 4; const int MATERIAL_TYPE_LEATHER = 5; const int MATERIAL_TYPE_METAL = 6; const int MATERIAL_TYPE_PAPER = 7; const int MATERIAL_TYPE_ROPE = 8; const int MATERIAL_TYPE_STONE = 9; const int MATERIAL_TYPE_WOOD = 10; +const int MATERIAL_TYPE_BOTANICAL = 11; const string MATERIAL_TYPE_NAME_INVALID = ""; const string MATERIAL_TYPE_NAME_UNKNOWN = "Unknown"; const string MATERIAL_TYPE_NAME_BONE = "Bone"; const string MATERIAL_TYPE_NAME_CERAMIC = "Ceramic"; const string MATERIAL_TYPE_NAME_CRYSTAL = "Crystal"; -const string MATERIAL_TYPE_NAME_FABRIC = "Fabric"; +const string MATERIAL_TYPE_NAME_FIBER = "Fiber"; const string MATERIAL_TYPE_NAME_LEATHER = "Leather"; const string MATERIAL_TYPE_NAME_METAL = "Metal"; const string MATERIAL_TYPE_NAME_PAPER = "Paper"; const string MATERIAL_TYPE_NAME_ROPE = "Rope"; const string MATERIAL_TYPE_NAME_STONE = "Stone"; const string MATERIAL_TYPE_NAME_WOOD = "Wood"; +const string MATERIAL_TYPE_NAME_BOTANICAL = "Bontanical"; //:: Material Itemproperty Constants //:://////////////////////////////////////////////////////////////////////////////// @@ -163,7 +165,8 @@ const int IP_MATERIAL_OBSIDIAN = 140; const int IP_MATERIAL_BAMBOO = 141; const int IP_MATERIAL_POTTERY = 142; const int IP_MATERIAL_GLASSTEEL = 143; -const int IP_NUM_MATERIALS = 143; +const int IP_MATERIAL_HERB = 144; +const int IP_NUM_MATERIALS = 144; const string IP_MATERIAL_NAME_INVALID = ""; const string IP_MATERIAL_NAME_UNKNOWN = "Unknown"; @@ -288,6 +291,7 @@ const string IP_MATERIAL_NAME_OBSIDIAN = "Obsidian"; const string IP_MATERIAL_NAME_BAMBOO = "Bamboo"; const string IP_MATERIAL_NAME_POTTERY = "Pottery"; const string IP_MATERIAL_NAME_GLASSTEEL = "Glassteel"; +const string IP_MATERIAL_NAME_HERB = "Herbs"; //:://///////////////////////////////////////////////////////////// // GetMaterialName( int iMaterialType, int bLowerCase = FALSE) @@ -428,6 +432,7 @@ string GetMaterialName( int iMaterialType, int bLowerCase = FALSE) case IP_MATERIAL_BAMBOO: sName = IP_MATERIAL_NAME_BAMBOO; break; case IP_MATERIAL_POTTERY: sName = IP_MATERIAL_NAME_POTTERY; break; case IP_MATERIAL_GLASSTEEL: sName = IP_MATERIAL_NAME_GLASSTEEL; break; + case IP_MATERIAL_HERB: sName = IP_MATERIAL_NAME_HERB; break; default: return ""; } @@ -573,6 +578,7 @@ int GetIPMaterial( string sMaterialName) else if( sMaterialName == GetStringUpperCase(IP_MATERIAL_NAME_BAMBOO)) return IP_MATERIAL_BAMBOO; else if( sMaterialName == GetStringUpperCase(IP_MATERIAL_NAME_POTTERY)) return IP_MATERIAL_POTTERY; else if( sMaterialName == GetStringUpperCase(IP_MATERIAL_NAME_GLASSTEEL)) return IP_MATERIAL_GLASSTEEL; + else if( sMaterialName == GetStringUpperCase(IP_MATERIAL_NAME_HERB)) return IP_MATERIAL_HERB; return IP_MATERIAL_INVALID; } @@ -806,6 +812,9 @@ int GetMaterialType(int nMaterial) || nMaterial == IP_MATERIAL_DRAKE_IVORY ) return MATERIAL_TYPE_BONE; + else if ( nMaterial == IP_MATERIAL_HERB ) + return MATERIAL_TYPE_BOTANICAL; + else if ( nMaterial == IP_MATERIAL_ELUKIAN_CLAY || nMaterial == IP_MATERIAL_POTTERY ) return MATERIAL_TYPE_CERAMIC; @@ -814,7 +823,7 @@ int GetMaterialType(int nMaterial) || nMaterial == IP_MATERIAL_COTTON || nMaterial == IP_MATERIAL_SILK || nMaterial == IP_MATERIAL_WOOL ) - return MATERIAL_TYPE_FABRIC; + return MATERIAL_TYPE_FIBER; else if ( nMaterial == IP_MATERIAL_GEM || nMaterial == IP_MATERIAL_GEM_ALEXANDRITE diff --git a/src/include/prc_inc_skills.nss b/src/include/prc_inc_skills.nss index bbca299..0674604 100644 --- a/src/include/prc_inc_skills.nss +++ b/src/include/prc_inc_skills.nss @@ -115,11 +115,11 @@ int PerformJump(object oPC, location lLoc, int bDoKnockDown = TRUE) iBonus = 4; } } - /*if (GetHasSpellEffect(MOVE_TC_LEAPING_DRAGON, oPC)) + if (GetHasSpellEffect(MOVE_TC_LEAPING_DRAGON, oPC)) { bIsRunningJump = TRUE; - iBonus = 10; - } */ + //iBonus = 10; //:: This is granted in the stance. + } // PnP rules are height * 6 for run and height * 2 for jump. // I can't get height so that is assumed to be 6. // Changed maxed jump distance because the NwN distance is rather short @@ -374,6 +374,12 @@ int PRCIsFlying(object oCreature) if(GetRacialType(oCreature) == RACIAL_TYPE_GLOURA) bFlying = TRUE; + + if(GetRacialType(oCreature) == RACIAL_TYPE_AVARIEL) + bFlying = TRUE; + + if(GetRacialType(oCreature) == RACIAL_TYPE_FEYRI) + bFlying = TRUE; if(GetRacialType(oCreature) == RACIAL_TYPE_SPIRETOPDRAGON) bFlying = TRUE; diff --git a/src/include/prc_inc_spells.nss b/src/include/prc_inc_spells.nss index 19e73d7..18c0efa 100644 --- a/src/include/prc_inc_spells.nss +++ b/src/include/prc_inc_spells.nss @@ -20,6 +20,11 @@ /* Function prototypes */ ////////////////////////////////////////////////// + + +//:: Calculates total Shield AC bonuses from all sources +int GetTotalShieldACBonus(object oCreature); + //:: Handles psuedo-Foritifcation void DoFortification(object oPC = OBJECT_SELF, int nFortification = 25); @@ -376,23 +381,53 @@ const int TYPE_DIVINE = -2; /* Function definitions */ ////////////////////////////////////////////////// + +// Returns TRUE if nSpellID is a subradial spell, FALSE otherwise +int GetIsSubradialSpell(int nSpellID) +{ + string sMaster = Get2DACache("spells", "Master", nSpellID); + + // If the Master column is numeric, this spell is a subradial of that master + if (sMaster != "" && sMaster != "****") + { + return TRUE; + } + + return FALSE; +} + +// Returns the masterspell SpellID for a subradial spell. +int GetMasterSpellFromSubradial(int nSpellID) +{ + string sMaster = Get2DAString("spells", "Master", nSpellID); + + if (sMaster != "****") + { + return StringToInt(sMaster); + } + + return -1; // No master +} + + + int GetPrCAdjustedClassLevel(int nClass, object oCaster = OBJECT_SELF) { int iTemp; // is it arcane, divine or neither? if(GetIsArcaneClass(nClass, oCaster) && nClass != CLASS_TYPE_SUBLIME_CHORD) { - if (GetPrimaryArcaneClass(oCaster) == nClass) // adjust for any PrCs + if (GetPrimaryArcaneClass(oCaster) == nClass) // adjust for any PrCs iTemp = GetArcanePRCLevels(oCaster, nClass); } else if(GetIsDivineClass(nClass, oCaster)) { - if (GetPrimaryDivineClass(oCaster) == nClass) // adjust for any PrCs - iTemp = GetDivinePRCLevels(oCaster, nClass); + if (GetPrimaryDivineClass(oCaster) == nClass) // adjust for any PrCs + iTemp = GetDivinePRCLevels(oCaster, nClass); } else // a non-caster class or a PrC { - return 0; + return 0; } // add the caster class levels return iTemp += GetLevelByClass(nClass, oCaster); @@ -412,7 +447,9 @@ int GetPrCAdjustedCasterLevelByType(int nClassType, object oCaster = OBJECT_SELF { int nClassLvl; int nClass1, nClass2, nClass3, nClass4, nClass5, nClass6, nClass7, nClass8; - int nClass1Lvl, nClass2Lvl, nClass3Lvl, nClass4Lvl, nClass5Lvl, nClass6Lvl, nClass7Lvl, nClass8Lvl; + int nClass1Lvl = 0, nClass2Lvl = 0, nClass3Lvl = 0, nClass4Lvl = 0, + nClass5Lvl = 0, nClass6Lvl = 0, nClass7Lvl = 0, nClass8Lvl = 0; + nClass1 = GetClassByPosition(1, oCaster); nClass2 = GetClassByPosition(2, oCaster); @@ -2223,6 +2260,78 @@ int GetControlledCelestialTotalHD(object oPC = OBJECT_SELF) return nTotalHD; } +//:: Calculates total Shield AC bonuses from all sources +int GetTotalShieldACBonus(object oCreature) +{ + int nShieldBonus = 0; + object oItem; + + // Check left hand for shield + oItem = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oCreature); + if (GetIsObjectValid(oItem)) + { + int nBaseItem = GetBaseItemType(oItem); + if (nBaseItem == BASE_ITEM_SMALLSHIELD || + nBaseItem == BASE_ITEM_LARGESHIELD || + nBaseItem == BASE_ITEM_TOWERSHIELD) + { + nShieldBonus += GetItemACValue(oItem); + if(DEBUG) DoDebug("prc_inc_spells >> GetTotalShieldACBonus: Found Shield AC, bonus = " + IntToString(nShieldBonus)+"."); + } + } + + // Check creature weapon slots for shield AC bonus + oItem = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oCreature); + if (GetIsObjectValid(oItem)) + nShieldBonus += GetItemACValue(oItem); + + oItem = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oCreature); + if (GetIsObjectValid(oItem)) + nShieldBonus += GetItemACValue(oItem); + + oItem = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oCreature); + if (GetIsObjectValid(oItem)) + nShieldBonus += GetItemACValue(oItem); + + // Add shield AC bonuses from magical effects + effect eEffect = GetFirstEffect(oCreature); + while (GetIsEffectValid(eEffect)) + { + int nACType = GetEffectInteger(eEffect, 0); + int nACAmount = GetEffectInteger(eEffect, 1); + + if(GetEffectType(eEffect) == EFFECT_TYPE_AC_INCREASE && nACType == AC_SHIELD_ENCHANTMENT_BONUS) + { + if(DEBUG) DoDebug("prc_inc_spells >> GetTotalShieldACBonus: Found Shield AC effect, bonus = " + IntToString(nACAmount)+"."); + nShieldBonus += nACAmount; + } + + eEffect = GetNextEffect(oCreature); + } + return nShieldBonus; +} + + + + // Add shield AC bonuses from magical effects +/* effect eEffect = GetFirstEffect(oCreature); + while (GetIsEffectValid(eEffect)) + { + if (GetEffectType(eEffect) == EFFECT_TYPE_AC_INCREASE && + GetEffectInteger(eEffect, 1) == AC_SHIELD_ENCHANTMENT_BONUS) + { + int nMod = GetEffectInteger(eEffect, 0); + int nType = GetEffectInteger(eEffect, 1); + nShieldBonus += GetEffectInteger(eEffect, 0); + string s = "Found AC effect: bonus = " + IntToString(nMod) + ", type = " + IntToString(nType); + SendMessageToPC(GetFirstPC(), s); + } + eEffect = GetNextEffect(oCreature); + } + + return nShieldBonus; +}*/ +// //:: Handles psuedo-Foritifcation void DoFortification(object oPC = OBJECT_SELF, int nFortification = 25) { @@ -2275,7 +2384,7 @@ void DoFortification(object oPC = OBJECT_SELF, int nFortification = 25) IPSafeAddItemProperty(oHide, ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_BACKSTAB)); } } - +// // wrapper for DecrementRemainingSpellUses, works for newspellbook 'fake' spells too // should also find and decrement metamagics for newspellbooks diff --git a/src/include/prc_inc_switch.nss b/src/include/prc_inc_switch.nss index 4913e3d..b2c7160 100644 --- a/src/include/prc_inc_switch.nss +++ b/src/include/prc_inc_switch.nss @@ -70,6 +70,8 @@ 43 PRC_CRAFTING_BASE_ITEMS int 1 44 PRC_XP_USE_SIMPLE_LA int 1 45 PRC_XP_USE_SIMPLE_RACIAL_HD int 1 +46 PRC_CREATE_INFUSION_CASTER_LEVEL int 1 +47 PRC_CREATE_INFUSION_OPTIONAL_HERBS int 0 */ /* This variable MUST be updated with every new version of the PRC!!! */ @@ -1952,6 +1954,18 @@ const string PRC_CRAFT_ROD_CASTER_LEVEL = "PRC_CRAFT_ROD_CASTER_LEVE */ const string PRC_CRAFT_STAFF_CASTER_LEVEL = "PRC_CRAFT_STAFF_CASTER_LEVEL"; +/* + * As above, except it applies to herbal infusions + */ +const string PRC_CREATE_INFUSION_CASTER_LEVEL = "PRC_CREATE_INFUSION_CASTER_LEVEL"; + +/* + * Builder's Option: Enables the optional PnP herbs for creating infusions. + * Each herb is keyed to a spell circle level & spell school as shown on pg. 33 + * of the Master's of the Wild sourcebook. + */ +const string PRC_CREATE_INFUSION_OPTIONAL_HERBS = "PRC_CREATE_INFUSION_OPTIONAL_HERBS"; + /* * Characters with a crafting feat always have the appropriate base item in their inventory */ @@ -1961,45 +1975,52 @@ const string PRC_CRAFTING_BASE_ITEMS = "PRC_CRAFTING_BASE_ITEMS"; * Max level of spells brewed into potions * defaults to 3 */ -const string X2_CI_BREWPOTION_MAXLEVEL = "X2_CI_BREWPOTION_MAXLEVEL"; +//const string X2_CI_BREWPOTION_MAXLEVEL = "X2_CI_BREWPOTION_MAXLEVEL"; +const string PRC_X2_BREWPOTION_MAXLEVEL = "PRC_X2_BREWPOTION_MAXLEVEL"; /* * cost modifier of spells brewed into poitions * defaults to 50 */ -const string X2_CI_BREWPOTION_COSTMODIFIER = "X2_CI_BREWPOTION_COSTMODIFIER"; +const string PRC_X2_BREWPOTION_COSTMODIFIER = "PRC_X2_BREWPOTION_COSTMODIFIER"; /* * cost modifier of spells scribed into scrolls * defaults to 25 */ -const string X2_CI_SCRIBESCROLL_COSTMODIFIER = "X2_CI_SCRIBESCROLL_COSTMODIFIER"; +const string PRC_X2_SCRIBESCROLL_COSTMODIFIER = "PRC_X2_SCRIBESCROLL_COSTMODIFIER"; + +/* + * cost modifier of spells infused into herbs + * defaults to 25 + */ +const string PRC_X2_CREATEINFUSION_COSTMODIFIER = "PRC_X2_CREATEINFUSION_COSTMODIFIER"; /* * Max level of spells crafted into wands * defaults to 4 */ -const string X2_CI_CRAFTWAND_MAXLEVEL = "X2_CI_CRAFTWAND_MAXLEVEL"; +const string PRC_X2_CRAFTWAND_MAXLEVEL = "PRC_X2_CRAFTWAND_MAXLEVEL"; /* * cost modifier of spells crafted into wands * defaults to 750 */ -const string X2_CI_CRAFTWAND_COSTMODIFIER = "X2_CI_CRAFTWAND_COSTMODIFIER"; +const string PRC_X2_CRAFTWAND_COSTMODIFIER = "PRC_X2_CRAFTWAND_COSTMODIFIER"; /* * cost modifier of spells crafted into rods * note that adding a second spell costs 75% and 3 or more costs 50% * defaults to 750 */ -const string X2_CI_CRAFTROD_COSTMODIFIER = "X2_CI_CRAFTROD_COSTMODIFIER"; +const string PRC_X2_CRAFTROD_COSTMODIFIER = "PRC_X2_CRAFTROD_COSTMODIFIER"; /* * cost modifier of spells crafted into staffs * note that adding a second spell costs 75% and 3 or more costs 50% * defaults to 750 */ -const string X2_CI_CRAFTSTAFF_COSTMODIFIER = "X2_CI_CRAFTSTAFF_COSTMODIFIER"; +const string PRC_X2_CRAFTSTAFF_COSTMODIFIER = "PRC_X2_CRAFTSTAFF_COSTMODIFIER"; /** * Allows the use of arbitrary itemproperties and uses NWN item costs diff --git a/src/include/prc_inc_turning.nss b/src/include/prc_inc_turning.nss index 5504819..6c819d4 100644 --- a/src/include/prc_inc_turning.nss +++ b/src/include/prc_inc_turning.nss @@ -14,17 +14,6 @@ /* Function prototypes */ ////////////////////////////////////////////////// - - - - - - - - - - - //gets the number of class levels that count for turning int GetTurningClassLevel(object oCaster = OBJECT_SELF, int nTurnType = SPELL_TURN_UNDEAD); @@ -191,6 +180,20 @@ int GetIsTurnOrRebuke(object oTarget, int nTurnType, int nTargetRace) break; } + case SPELL_PLANT_DEFIANCE: + { + if(nTargetRace == RACIAL_TYPE_PLANT) + nReturn = ACTION_TURN; + + break; + } + case SPELL_PLANT_CONTROL: + { + if(nTargetRace == RACIAL_TYPE_PLANT) + nReturn = ACTION_REBUKE; + + break; + } case SPELL_TURN_PLANT: { // Plant domain rebukes or commands plants @@ -383,6 +386,13 @@ int GetTurningClassLevel(object oCaster = OBJECT_SELF, int nTurnType = SPELL_TUR if (nTurnType == SPELL_OPPORTUNISTIC_PIETY_TURN) return GetLevelByClass(CLASS_TYPE_FACTOTUM, oCaster); + + if (nTurnType == SPELL_PLANT_DEFIANCE || nTurnType == SPELL_PLANT_CONTROL) + { + int nDivineLvl = GetPrCAdjustedCasterLevelByType(TYPE_DIVINE, oCaster); + + return nDivineLvl; + } //Baelnorn & Archlich adds all class levels. if(GetLevelByClass(CLASS_TYPE_BAELNORN, oCaster) || GetHasFeat(FEAT_TEMPLATE_ARCHLICH_MARKER, oCaster)) //:: Archlich diff --git a/src/include/prc_inc_wpnrest.nss b/src/include/prc_inc_wpnrest.nss index c101e78..9dcf65a 100644 --- a/src/include/prc_inc_wpnrest.nss +++ b/src/include/prc_inc_wpnrest.nss @@ -40,13 +40,31 @@ int IsProficient(object oPC, int nBaseItem) case BASE_ITEM_CLUB: return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC) - || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC) - || GetHasFeat(FEAT_WEAPON_PROFICIENCY_CLUB, oPC); + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_CLUB, oPC); + + case BASE_ITEM_HEAVYCROSSBOW: + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_HEAVY_XBOW, oPC); + + case BASE_ITEM_LIGHTCROSSBOW: + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_LIGHT_XBOW, oPC); case BASE_ITEM_DAGGER: return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC) - || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC) - || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DAGGER, oPC); + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DAGGER, oPC); case BASE_ITEM_LONGSWORD: return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oPC) @@ -152,12 +170,14 @@ int IsProficient(object oPC, int nBaseItem) || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC); case BASE_ITEM_QUARTERSTAFF: - return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC) + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_QUARTERSTAFF, oPC) + ||GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC) || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC) - || GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC); + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC); case BASE_ITEM_MAGICSTAFF: - return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC) + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_QUARTERSTAFF, oPC) + ||GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC) || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC) || GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC); @@ -300,167 +320,185 @@ int GetWeaponProfFeatByType(int nBaseType) { switch(nBaseType) { - case BASE_ITEM_SHORTSWORD: - return FEAT_WEAPON_PROFICIENCY_SHORTSWORD; + case BASE_ITEM_CLUB: + return FEAT_WEAPON_PROFICIENCY_CLUB; + + case BASE_ITEM_QUARTERSTAFF: + return FEAT_WEAPON_PROFICIENCY_QUARTERSTAFF; - case BASE_ITEM_LONGSWORD: - return FEAT_WEAPON_PROFICIENCY_LONGSWORD; + case BASE_ITEM_MAGICSTAFF: + return FEAT_WEAPON_PROFICIENCY_QUARTERSTAFF; + + case BASE_ITEM_DAGGER: + return FEAT_WEAPON_PROFICIENCY_DAGGER; - case BASE_ITEM_BATTLEAXE: - return FEAT_WEAPON_PROFICIENCY_BATTLEAXE; + case BASE_ITEM_HEAVYCROSSBOW: + return FEAT_WEAPON_PROFICIENCY_HEAVY_XBOW; - case BASE_ITEM_BASTARDSWORD: - return FEAT_WEAPON_PROFICIENCY_BASTARD_SWORD; + case BASE_ITEM_LIGHTCROSSBOW: + return FEAT_WEAPON_PROFICIENCY_LIGHT_XBOW; + + case BASE_ITEM_SHORTSWORD: + return FEAT_WEAPON_PROFICIENCY_SHORTSWORD; - case BASE_ITEM_LIGHTFLAIL: - return FEAT_WEAPON_PROFICIENCY_LIGHT_FLAIL; + case BASE_ITEM_LONGSWORD: + return FEAT_WEAPON_PROFICIENCY_LONGSWORD; - case BASE_ITEM_WARHAMMER: - return FEAT_WEAPON_PROFICIENCY_WARHAMMER; + case BASE_ITEM_BATTLEAXE: + return FEAT_WEAPON_PROFICIENCY_BATTLEAXE; - case BASE_ITEM_LONGBOW: - return FEAT_WEAPON_PROFICIENCY_LONGBOW; + case BASE_ITEM_BASTARDSWORD: + return FEAT_WEAPON_PROFICIENCY_BASTARD_SWORD; - case BASE_ITEM_LIGHTMACE: - return FEAT_WEAPON_PROFICIENCY_LIGHT_MACE; + case BASE_ITEM_LIGHTFLAIL: + return FEAT_WEAPON_PROFICIENCY_LIGHT_FLAIL; - case BASE_ITEM_HALBERD: - return FEAT_WEAPON_PROFICIENCY_HALBERD; + case BASE_ITEM_WARHAMMER: + return FEAT_WEAPON_PROFICIENCY_WARHAMMER; - case BASE_ITEM_SHORTBOW: + case BASE_ITEM_LONGBOW: + return FEAT_WEAPON_PROFICIENCY_LONGBOW; + + case BASE_ITEM_LIGHTMACE: + return FEAT_WEAPON_PROFICIENCY_LIGHT_MACE; + + case BASE_ITEM_HALBERD: + return FEAT_WEAPON_PROFICIENCY_HALBERD; + + case BASE_ITEM_SHORTBOW: return FEAT_WEAPON_PROFICIENCY_SHORTBOW; - case BASE_ITEM_TWOBLADEDSWORD: + case BASE_ITEM_TWOBLADEDSWORD: return FEAT_WEAPON_PROFICIENCY_TWO_BLADED_SWORD; - case BASE_ITEM_GREATSWORD: + case BASE_ITEM_GREATSWORD: return FEAT_WEAPON_PROFICIENCY_GREATSWORD; - case BASE_ITEM_GREATAXE: + case BASE_ITEM_GREATAXE: return FEAT_WEAPON_PROFICIENCY_GREATAXE; - case BASE_ITEM_DART: + case BASE_ITEM_DART: return FEAT_WEAPON_PROFICIENCY_DART; - case BASE_ITEM_DIREMACE: + case BASE_ITEM_DIREMACE: return FEAT_WEAPON_PROFICIENCY_DIRE_MACE; - case BASE_ITEM_DOUBLEAXE: + case BASE_ITEM_DOUBLEAXE: return FEAT_WEAPON_PROFICIENCY_DOUBLE_AXE; - case BASE_ITEM_HEAVYFLAIL: + case BASE_ITEM_HEAVYFLAIL: return FEAT_WEAPON_PROFICIENCY_HEAVY_FLAIL; - case BASE_ITEM_LIGHTHAMMER: + case BASE_ITEM_LIGHTHAMMER: return FEAT_WEAPON_PROFICIENCY_LIGHT_HAMMER; - case BASE_ITEM_HANDAXE: + case BASE_ITEM_HANDAXE: return FEAT_WEAPON_PROFICIENCY_HANDAXE; - case BASE_ITEM_KAMA: + case BASE_ITEM_KAMA: return FEAT_WEAPON_PROFICIENCY_KAMA; - case BASE_ITEM_KATANA: + case BASE_ITEM_KATANA: return FEAT_WEAPON_PROFICIENCY_KATANA; - case BASE_ITEM_KUKRI: + case BASE_ITEM_KUKRI: return FEAT_WEAPON_PROFICIENCY_KUKRI; - case BASE_ITEM_MORNINGSTAR: + case BASE_ITEM_MORNINGSTAR: return FEAT_WEAPON_PROFICIENCY_MORNINGSTAR; - case BASE_ITEM_RAPIER: + case BASE_ITEM_RAPIER: return FEAT_WEAPON_PROFICIENCY_RAPIER; - case BASE_ITEM_SCIMITAR: + case BASE_ITEM_SCIMITAR: return FEAT_WEAPON_PROFICIENCY_SCIMITAR; - case BASE_ITEM_SCYTHE: + case BASE_ITEM_SCYTHE: return FEAT_WEAPON_PROFICIENCY_SCYTHE; - case BASE_ITEM_SHORTSPEAR: + case BASE_ITEM_SHORTSPEAR: return FEAT_WEAPON_PROFICIENCY_SHORTSPEAR; - case BASE_ITEM_SHURIKEN: + case BASE_ITEM_SHURIKEN: return FEAT_WEAPON_PROFICIENCY_SHURIKEN; - case BASE_ITEM_SICKLE: + case BASE_ITEM_SICKLE: return FEAT_WEAPON_PROFICIENCY_SICKLE; - case BASE_ITEM_SLING: + case BASE_ITEM_SLING: return FEAT_WEAPON_PROFICIENCY_SLING; - case BASE_ITEM_THROWINGAXE: + case BASE_ITEM_THROWINGAXE: return FEAT_WEAPON_PROFICIENCY_THROWING_AXE; - case BASE_ITEM_CSLASHWEAPON: + case BASE_ITEM_CSLASHWEAPON: return FEAT_WEAPON_PROFICIENCY_CREATURE; - case BASE_ITEM_CPIERCWEAPON: + case BASE_ITEM_CPIERCWEAPON: return FEAT_WEAPON_PROFICIENCY_CREATURE; - case BASE_ITEM_CBLUDGWEAPON: + case BASE_ITEM_CBLUDGWEAPON: return FEAT_WEAPON_PROFICIENCY_CREATURE; - case BASE_ITEM_CSLSHPRCWEAP: + case BASE_ITEM_CSLSHPRCWEAP: return FEAT_WEAPON_PROFICIENCY_CREATURE; - case BASE_ITEM_TRIDENT: + case BASE_ITEM_TRIDENT: return FEAT_WEAPON_PROFICIENCY_TRIDENT; - case BASE_ITEM_DWARVENWARAXE: + case BASE_ITEM_DWARVENWARAXE: return FEAT_WEAPON_PROFICIENCY_DWARVEN_WARAXE; - case BASE_ITEM_WHIP: + case BASE_ITEM_WHIP: return FEAT_WEAPON_PROFICIENCY_WHIP; - case BASE_ITEM_ELVEN_LIGHTBLADE: + case BASE_ITEM_ELVEN_LIGHTBLADE: return FEAT_WEAPON_PROFICIENCY_ELVEN_LIGHTBLADE; - case BASE_ITEM_ELVEN_THINBLADE: + case BASE_ITEM_ELVEN_THINBLADE: return FEAT_WEAPON_PROFICIENCY_ELVEN_THINBLADE; - case BASE_ITEM_ELVEN_COURTBLADE: + case BASE_ITEM_ELVEN_COURTBLADE: return FEAT_WEAPON_PROFICIENCY_ELVEN_COURTBLADE; - case BASE_ITEM_HEAVY_PICK: + case BASE_ITEM_HEAVY_PICK: return FEAT_WEAPON_PROFICIENCY_HEAVY_PICK; - case BASE_ITEM_LIGHT_PICK: + case BASE_ITEM_LIGHT_PICK: return FEAT_WEAPON_PROFICIENCY_LIGHT_PICK; - case BASE_ITEM_SAI: + case BASE_ITEM_SAI: return FEAT_WEAPON_PROFICIENCY_SAI; - case BASE_ITEM_NUNCHAKU: + case BASE_ITEM_NUNCHAKU: return FEAT_WEAPON_PROFICIENCY_NUNCHAKU; - case BASE_ITEM_FALCHION: + case BASE_ITEM_FALCHION: return FEAT_WEAPON_PROFICIENCY_FALCHION; - case BASE_ITEM_SAP: + case BASE_ITEM_SAP: return FEAT_WEAPON_PROFICIENCY_SAP; - case BASE_ITEM_KATAR: + case BASE_ITEM_KATAR: return FEAT_WEAPON_PROFICIENCY_KATAR; - case BASE_ITEM_HEAVY_MACE: + case BASE_ITEM_HEAVY_MACE: return FEAT_WEAPON_PROFICIENCY_HEAVY_MACE; - case BASE_ITEM_MAUL: + case BASE_ITEM_MAUL: return FEAT_WEAPON_PROFICIENCY_MAUL; - case BASE_ITEM_DOUBLE_SCIMITAR: + case BASE_ITEM_DOUBLE_SCIMITAR: return FEAT_WEAPON_PROFICIENCY_DOUBLE_SCIMITAR; - case BASE_ITEM_GOAD: + case BASE_ITEM_GOAD: return FEAT_WEAPON_PROFICIENCY_GOAD; - case BASE_ITEM_EAGLE_CLAW: + case BASE_ITEM_EAGLE_CLAW: return FEAT_WEAPON_PROFICIENCY_EAGLE_CLAW; - default: - return FEAT_WEAPON_PROFICIENCY_SIMPLE; + default: + return FEAT_WEAPON_PROFICIENCY_SIMPLE; } return 0; diff --git a/src/include/prc_ipfeat_const.nss b/src/include/prc_ipfeat_const.nss index a1829be..d419f0b 100644 --- a/src/include/prc_ipfeat_const.nss +++ b/src/include/prc_ipfeat_const.nss @@ -1206,11 +1206,12 @@ const int IP_CONST_FEAT_REGENERATION_5 = 24820; const int IP_CONST_FEAT_SCENT = 24821; const int IP_CONST_FEAT_GIANT_RACIAL_TYPE = 24822; -const int IP_CONST_FEAT_TEMPLATE_ARCHLICH_MARKER = 16401; //:: Archlich -const int IP_CONST_FEAT_TEMPLATE_TURN_UNDEAD = 16402; -const int IP_CONST_FEAT_TEMPLATE_PROJECTION = 24823; -const int IP_CONST_FEAT_TEMPLATE_END_PROJECTION = 24824; -const int IP_CONST_FEAT_TEMPLATE_ANIMATE_DEAD = 24825; +const int IP_CONST_FEAT_TEMPLATE_ARCHLICH_MARKER = 16401; //:: Archlich +const int IP_CONST_FEAT_TEMPLATE_TURN_UNDEAD = 16402; +const int IP_CONST_FEAT_TEMPLATE_BAELNORN_MARKER = 16409; //:: Baelnorn +const int IP_CONST_FEAT_TEMPLATE_PROJECTION = 24823; +const int IP_CONST_FEAT_TEMPLATE_END_PROJECTION = 24824; +const int IP_CONST_FEAT_TEMPLATE_ANIMATE_DEAD = 24825; const int IP_CONST_FEAT_TEMPLATE_SAINT_SLA_BLESS = 16403; //:: Saint //const int IP_CONST_FEAT_TEMPLATE_SAINT_SLA_GUIDANCE = 16404; const int IP_CONST_FEAT_TEMPLATE_SAINT_SLA_RESISTANCE = 16405; diff --git a/src/include/prc_misc_const.nss b/src/include/prc_misc_const.nss index 0575811..b083a8e 100644 --- a/src/include/prc_misc_const.nss +++ b/src/include/prc_misc_const.nss @@ -29,6 +29,10 @@ const int BASE_ITEM_CRAFTED_STAFF = 201; const int BASE_ITEM_ELVEN_LIGHTBLADE = 202; const int BASE_ITEM_ELVEN_THINBLADE = 203; const int BASE_ITEM_ELVEN_COURTBLADE = 204; +const int BASE_ITEM_CRAFT_SCEPTER = 249; +const int BASE_ITEM_MAGIC_SCEPTER = 250; +const int BASE_ITEM_MUNDANE_HERB = 252; +const int BASE_ITEM_INFUSED_HERB = 253; //::////////////////////////////////////////////// //:: Player Health Const diff --git a/src/include/prc_nui_com_inc.nss b/src/include/prc_nui_com_inc.nss new file mode 100644 index 0000000..bf9bc51 --- /dev/null +++ b/src/include/prc_nui_com_inc.nss @@ -0,0 +1,530 @@ +#include "prc_nui_consts" +#include "inc_newspellbook" +#include "psi_inc_psifunc" +#include "inc_lookups" +#include "nw_inc_nui" + +// +// GetCurrentSpellLevel +// Gets the current spell level the class can achieve at the current +// caster level (ranging from 0-9) +// +// Arguments: +// nClass:int the ClassID +// nLevel:int the caster level +// +// Returns: +// int the circle the class can achieve currently +// +int GetCurrentSpellLevel(int nClass, int nLevel); + +// +// GetMaxSpellLevel +// Gets the highest possible circle the class can achieve (from 0-9) +// +// Arguments: +// nClass:int the ClassID +// +// Returns: +// int the highest circle that can be achieved +// +int GetMaxSpellLevel(int nClass); + +// +// GetMinSpellLevel +// Gets the lowest possible circle the class can achieve (from 0-9) +// +// Arguments: +// nClass:int the ClassID +// +// Returns: +// int the lowest circle that can be achieved +// +int GetMinSpellLevel(int nClass); + +// +// GetHighestLevelPossibleInClass +// Given a class Id this will determine what the max level of a class can be +// achieved +// +// Arguments: +// nClass:int the ClassID +// +// Returns: +// int the highest possible level the class can achieve +// +int GetHighestLevelPossibleInClass(int nClass); + +// +// GetClassSpellbookFile +// Gets the class 2da spellbook/ability for the given class Id +// +// Arguments: +// nClass:int the classID +// +// Returns: +// string the 2da file name for the spell/abilities of the ClassID +// +string GetClassSpellbookFile(int nClass); + +// +// GetBinderSpellToFeatDictionary +// Sets up the Binder Spell Dictionary that is used to match a binder's vestige +// to their feat. This is constructed based off the binder's known location of +// their feat and spell ranges in the base 2das respectivly. After constructing +// this it will be saved to the player locally as a cached result since we do +// not need to call this again. +// +// Argument: +// oPlayer:object the player +// +// Returns: +// json:Dictionary a dictionary of mapping between the SpellID +// and the FeatID of a vestige ability +// +json GetBinderSpellToFeatDictionary(object oPlayer=OBJECT_SELF); + +// +// GetSpellLevelIcon +// Takes the spell circle int and gets the icon appropriate for it (i.e. 0 turns +// into "ir_cantrips" +// +// Arguments: +// spellLevel:int the spell level we want the icon for +// +// Returns: +// string the spell level icon +// +string GetSpellLevelIcon(int spellLevel); + +// +// GetSpellLevelToolTip +// Gets the spell level tool tip text based on the int spell level provided (i.e. +// 0 turns into "Cantrips") +// +// Arguments: +// spellLevel:int the spell level we want the tooltip for +// +// Returns: +// string the spell level toop tip +// +string GetSpellLevelToolTip(int spellLevel); + +// +// GetSpellIcon +// Gets the spell icon based off the spellId, or featId supplied +// +// Arguments: +// nClass:int the class Id +// featId:int the featId we can use the icon for +// spellId:int the spell Id we want the icon for +// +// Returns: +// json:String the string of the icon we want. +// +json GetSpellIcon(int spellId, int featId=0, int nClass=0); +string GetSpellName(int spellId, int realSpellID=0, int featId=0, int nClass=0); + +// +// GreyOutButton +// Takes NUI Button along with it's width and height and greys it out it with a drawn +// colored rectangle to represent it's not been selected or not valid. +// +// Arguments: +// jButton:json the NUI Button +// w:float the width of the button +// h:float the height of the button +// +// Returns: +// json the NUI button greyed out +// +json GreyOutButton(json jButton, float w, float h); + +// +// CreateGreyOutRectangle +// Creates a grey out rectangle for buttons +// +// Arguments: +// w:float the width of the button +// h:float the height of the button +// +// Returns: +// json the transparant black rectangle +// +json CreateGreyOutRectangle(float w, float h); + +void CreateSpellDescriptionNUI(object oPlayer, int featID, int spellId=0, int realSpellId=0, int nClass=0); +void ClearSpellDescriptionNUI(object oPlayer=OBJECT_SELF); + +int GetCurrentSpellLevel(int nClass, int nLevel) +{ + int currentLevel = nLevel; + + // ToB doesn't have a concept of spell levels, but still match up to it + if(nClass == CLASS_TYPE_WARBLADE + || nClass == CLASS_TYPE_SWORDSAGE + || nClass == CLASS_TYPE_CRUSADER + || nClass == CLASS_TYPE_SHADOWCASTER) + { + return 9; + } + + + // Binders don't really have a concept of spell level + if (nClass == CLASS_TYPE_BINDER + || nClass == CLASS_TYPE_DRAGON_SHAMAN) // they can only reach 1st circle + return 1; + + //Shadowsmith has no concept of spell levels + if (nClass == CLASS_TYPE_SHADOWSMITH) + return 2; + + if (nClass == CLASS_TYPE_WARLOCK + || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT) + return 4; + + // Spont casters have their own function + if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS + || nClass == CLASS_TYPE_ARCHIVIST) + { + + int maxLevel = GetMaxSpellLevelForCasterLevel(nClass, currentLevel); + return maxLevel; + } + else + { + // everyone else uses this + string spellLevel2da = GetAMSKnownFileName(nClass); + + currentLevel = nLevel - 1; // Level is 1 off of the row in the 2da + + if (nClass == CLASS_TYPE_FIST_OF_ZUOKEN + || nClass == CLASS_TYPE_PSION + || nClass == CLASS_TYPE_PSYWAR + || nClass == CLASS_TYPE_WILDER + || nClass == CLASS_TYPE_PSYCHIC_ROGUE + || nClass == CLASS_TYPE_WARMIND) + currentLevel = GetManifesterLevel(OBJECT_SELF, nClass, TRUE) - 1; + + int totalLevel = Get2DARowCount(spellLevel2da); + + // in case we somehow go over bounds just don't :) + if (currentLevel >= totalLevel) + currentLevel = totalLevel - 1; + + //Psionics have MaxPowerLevel as their column name + string columnName = "MaxPowerLevel"; + + //Invokers have MaxInvocationLevel + if (nClass == CLASS_TYPE_WARLOCK + || nClass == CLASS_TYPE_DRAGON_SHAMAN + || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT) + columnName = "MaxInvocationLevel"; + + // Truenamers have 3 sets of utterances, ranging from 1-6, EvolvingMind covers the entire range + if (nClass == CLASS_TYPE_TRUENAMER) + { + columnName = "EvolvingMind"; + spellLevel2da = "cls_true_maxlvl"; //has a different 2da we want to look at + } + + if (nClass == CLASS_TYPE_BINDER) + { + columnName = "VestigeLvl"; + spellLevel2da = "cls_bind_binder"; + } + + // ToB doesn't have a concept of this, but we don't care. + + int maxLevel = StringToInt(Get2DACache(spellLevel2da, columnName, currentLevel)); + return maxLevel; + } +} + +int GetMinSpellLevel(int nClass) +{ + // again sponts have their own function + if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS + || nClass == CLASS_TYPE_ARCHIVIST) + { + return GetMinSpellLevelForCasterLevel(nClass, GetHighestLevelPossibleInClass(nClass)); + } + else + { + if (nClass == CLASS_TYPE_FIST_OF_ZUOKEN + || nClass == CLASS_TYPE_PSION + || nClass == CLASS_TYPE_PSYWAR + || nClass == CLASS_TYPE_WILDER + || nClass == CLASS_TYPE_PSYCHIC_ROGUE + || nClass == CLASS_TYPE_WARMIND + || nClass == CLASS_TYPE_WARBLADE + || nClass == CLASS_TYPE_SWORDSAGE + || nClass == CLASS_TYPE_CRUSADER + || nClass == CLASS_TYPE_WARLOCK + || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT + || nClass == CLASS_TYPE_DRAGON_SHAMAN + || nClass == CLASS_TYPE_SHADOWCASTER + || nClass == CLASS_TYPE_SHADOWSMITH + || nClass == CLASS_TYPE_BINDER) + return 1; + + return GetCurrentSpellLevel(nClass, 1); + } + +} + +int GetMaxSpellLevel(int nClass) +{ + if (nClass == CLASS_TYPE_WILDER + || nClass == CLASS_TYPE_PSION) + return 9; + if (nClass == CLASS_TYPE_PSYCHIC_ROGUE + || nClass == CLASS_TYPE_FIST_OF_ZUOKEN + || nClass == CLASS_TYPE_WARMIND) + return 5; + if (nClass == CLASS_TYPE_PSYWAR) + return 6; + + return GetCurrentSpellLevel(nClass, GetHighestLevelPossibleInClass(nClass)); +} + +int GetHighestLevelPossibleInClass(int nClass) +{ + string sFile; + + //sponts have their spells in the classes.2da + if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS + || nClass == CLASS_TYPE_ARCHIVIST) + { + sFile = Get2DACache("classes", "SpellGainTable", nClass); + } + else + { + // everyone else uses this + sFile = GetAMSKnownFileName(nClass); + + if (nClass == CLASS_TYPE_TRUENAMER) + { + sFile = "cls_true_maxlvl"; //has a different 2da we want to look at + } + + if (nClass == CLASS_TYPE_BINDER) + { + sFile = "cls_bind_binder"; + } + } + + return Get2DARowCount(sFile); +} + +string GetClassSpellbookFile(int nClass) +{ + string sFile; + // Spontaneous casters use a specific file name structure + if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS + || nClass == CLASS_TYPE_ARCHIVIST) + { + sFile = GetFileForClass(nClass); + } + // everyone else uses this structure + else + { + sFile = GetAMSDefinitionFileName(nClass); + + if (nClass == CLASS_TYPE_BINDER) + { + sFile = "vestiges"; + } + } + + return sFile; +} + +string GetSpellLevelIcon(int spellLevel) +{ + switch (spellLevel) + { + case 0: return "ir_cantrips"; + case 1: return "ir_level1"; + case 2: return "ir_level2"; + case 3: return "ir_level3"; + case 4: return "ir_level4"; + case 5: return "ir_level5"; + case 6: return "ir_level6"; + case 7: return "ir_level789"; + case 8: return "ir_level789"; + case 9: return "ir_level789"; + } + + return ""; +} + +string GetSpellLevelToolTip(int spellLevel) +{ + switch (spellLevel) + { + case 0: return "Cantrips"; + case 1: return "Level 1"; + case 2: return "Level 2"; + case 3: return "Level 3"; + case 4: return "Level 4"; + case 5: return "Level 5"; + case 6: return "Level 6"; + case 7: return "Level 7"; + case 8: return "Level 8"; + case 9: return "Level 9"; + } + + return ""; +} + + +json GetSpellIcon(int spellId,int featId=0,int nClass=0) +{ + // Binder's spells don't have the FeatID on the spells.2da, so we have to use + // the mapping we constructed to get it. + if (nClass == CLASS_TYPE_BINDER) + { + json binderDict = GetBinderSpellToFeatDictionary(); + int nFeatID = JsonGetInt(JsonObjectGet(binderDict, IntToString(spellId))); + return JsonString(Get2DACache("feat", "Icon", featId)); + } + + if (featId) + return JsonString(Get2DACache("feat", "Icon", featId)); + + int masterSpellID = StringToInt(Get2DACache("spells", "Master", spellId)); + + // if this is a sub radial spell, then we use spell's icon instead + if (masterSpellID) + return JsonString(Get2DACache("spells", "IconResRef", spellId)); + + // the FeatID holds the accurate spell icon, not the SpellID + int nFeatID = StringToInt(Get2DACache("spells", "FeatID", spellId)); + + return JsonString(Get2DACache("feat", "Icon", nFeatID)); +} + +string GetSpellName(int spellId, int realSpellID=0, int featId=0, int nClass=0) +{ + if ((nClass == CLASS_TYPE_SHADOWSMITH + || nClass == CLASS_TYPE_SHADOWCASTER) && spellId) + return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", spellId))); + if (nClass == CLASS_TYPE_TRUENAMER && featId) + return GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT", featId))); + if (realSpellID) + return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", realSpellID))); + if (spellId) + return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", spellId))); + if (featId) + return GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT", featId))); + + return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", spellId))); +} + +json GetBinderSpellToFeatDictionary(object oPlayer=OBJECT_SELF) +{ + // a dictionary of + json binderDict = GetLocalJson(oPlayer, NUI_SPELLBOOK_BINDER_DICTIONARY_CACHE_VAR); + // if this hasn't been created, create it now. + if (binderDict == JsonNull()) + binderDict = JsonObject(); + else + return binderDict; + + // the starting row for binder spells + int spellIndex = 19070; + // the starting row for binder feats + int featIndex = 9030; + //the end of the binder spells/feats + while (spellIndex <= 19156 && featIndex <= 9104) + { + // get the SpellID tied to the feat + int spellID = StringToInt(Get2DACache("feat", "SPELLID", featIndex)); + // if the spellID matches the current index, then this is the spell + // attached to the feat + if (spellID == spellIndex) + { + binderDict = JsonObjectSet(binderDict, IntToString(spellID), JsonInt(featIndex)); + + // move to next spell/feat + featIndex++; + spellIndex++; + } + // else we have reached a subdial spell + else + { + // loop through until we reach back at spellID + while (spellIndex < spellID) + { + int masterSpell = StringToInt(Get2DACache("spells", "Master", spellIndex)); + + // add the sub radial to the dict, tied to the master's FeatID + int featId = JsonGetInt(JsonObjectGet(binderDict, IntToString(masterSpell))); + binderDict = JsonObjectSet(binderDict, IntToString(spellIndex), JsonInt(featId)); + + spellIndex++; + } + + + // some feats overlap the same FeatID, can cause this to get stuck. + // if it happens then move on + if (spellIndex > spellID) + featIndex++; + } + } + + // cache the result + SetLocalJson(oPlayer, NUI_SPELLBOOK_BINDER_DICTIONARY_CACHE_VAR, binderDict); + return binderDict; +} + +json GreyOutButton(json jButton, float w, float h) +{ + json retValue = jButton; + + json jBorders = JsonArray(); + jBorders = JsonArrayInsert(jBorders, CreateGreyOutRectangle(w, h)); + + return NuiDrawList(jButton, JsonBool(FALSE), jBorders); +} + +json CreateGreyOutRectangle(float w, float h) +{ + // set the points of the button shape + json jPoints = JsonArray(); + jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0)); + jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0)); + + jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0)); + jPoints = JsonArrayInsert(jPoints, JsonFloat(h)); + + jPoints = JsonArrayInsert(jPoints, JsonFloat(w)); + jPoints = JsonArrayInsert(jPoints, JsonFloat(h)); + + jPoints = JsonArrayInsert(jPoints, JsonFloat(w)); + jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0)); + + jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0)); + jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0)); + + return NuiDrawListPolyLine(JsonBool(TRUE), NuiColor(0, 0, 0, 127), JsonBool(TRUE), JsonFloat(2.0), jPoints); +} + +void CreateSpellDescriptionNUI(object oPlayer, int featID, int spellId=0, int realSpellId=0, int nClass=0) +{ + SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_FEATID_VAR, featID); + SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_SPELLID_VAR, spellId); + SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_REAL_SPELLID_VAR, realSpellId); + SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_CLASSID_VAR, nClass); + ExecuteScript("prc_nui_dsc_view", oPlayer); +} + +void ClearSpellDescriptionNUI(object oPlayer=OBJECT_SELF) +{ + DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_FEATID_VAR); + DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_SPELLID_VAR); + DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_REAL_SPELLID_VAR); + DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_CLASSID_VAR); +} + diff --git a/src/include/prc_nui_consts.nss b/src/include/prc_nui_consts.nss index 0cb0efa..e1e9c5c 100644 --- a/src/include/prc_nui_consts.nss +++ b/src/include/prc_nui_consts.nss @@ -110,4 +110,49 @@ const string NUI_PRC_PA_TEXT_BIND = "nui_prc_pa_text_bind"; // Left Button Enabled Bind for Power Attack NUI const string NUI_PRC_PA_LEFT_BUTTON_ENABLED_BIND = "leftButtonEnabled"; // Right Button Enabled Bind for Power Attack NUI -const string NUI_PRC_PA_RIGHT_BUTTON_ENABLED_BIND = "rightButtonEnabled"; \ No newline at end of file +const string NUI_PRC_PA_RIGHT_BUTTON_ENABLED_BIND = "rightButtonEnabled"; + +////////////////////////////////////////////////// +// // +// NUI Level Up // +// // +////////////////////////////////////////////////// + +const string NUI_LEVEL_UP_WINDOW_ID = "prcLevelUpNui"; + +const string NUI_LEVEL_UP_SPELL_CIRCLE_BUTTON_BASEID = "NuiLevelUpCircleButton_"; +const string NUI_LEVEL_UP_SPELL_BUTTON_BASEID = "NuiLevelUpSpellButton_"; +const string NUI_LEVEL_UP_SPELL_DISABLED_BUTTON_BASEID = "NuiLevelUpDisabledSpellButton_"; +const string NUI_LEVEL_UP_SPELL_CHOSEN_BUTTON_BASEID = "NuiLevelUpChosenSpellButton_"; +const string NUI_LEVEL_UP_SPELL_CHOSEN_DISABLED_BUTTON_BASEID = "NuiLevelUpDisabledChosenSpellButton_"; +const string NUI_LEVEL_UP_DONE_BUTTON = "NuiLevelUpDoneButton"; +const string NUI_LEVEL_UP_RESET_BUTTON = "NuiLevelUpResetButton"; + +const string NUI_LEVEL_UP_SELECTED_CLASS_VAR = "NUILevelUpSelectedClass"; +const string NUI_LEVEL_UP_SELECTED_CIRCLE_VAR = "NUILevelUpSelectedCircle"; +const string NUI_LEVEL_UP_KNOWN_SPELLS_VAR = "NUILevelUpKnownSpells"; +const string NUI_LEVEL_UP_CHOSEN_SPELLS_VAR = "NUILevelUpChosenSpells"; +const string NUI_LEVEL_UP_EXPANDED_KNOW_LIST_VAR = "NUILevelUpExpKnowList"; +const string NUI_LEVEL_UP_POWER_LIST_VAR = "NUILevelUpPowerList"; +const string NUI_LEVEL_UP_DISCIPLINE_INFO_VAR = "GetDisciplineInfoObjectCache_"; +const string NUI_LEVEL_UP_SPELLID_LIST_VAR = "NUILevelUpSpellIDList_"; +const string NUI_LEVEL_UP_REMAINING_CHOICES_CACHE_VAR = "NUIRemainingChoicesCache"; +const string NUI_LEVEL_UP_RELEARN_LIST_VAR = "NUILevelUpRelearnList"; +const string NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR = "NUILevelUpArchivistNewSpellsList"; + +const string NUI_LEVEL_UP_EXPANDED_CHOICES_VAR = "NUIExpandedChoices"; +const string NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR = "NUIEpicExpandedChoices"; + +const int NUI_LEVEL_UP_MANEUVER_PREREQ_LIMIT = 6; + +const string NUI_LEVEL_UP_MANEUVER_TOTAL = "ManeuverTotal"; +const string NUI_LEVEL_UP_STANCE_TOTAL = "StanceTotal"; + +const string NUI_LEVEL_UP_SPELLBOOK_OBJECT_CACHE_VAR = "GetSpellListObjectCache_"; +const string NUI_LEVEL_UP_KNOWN_INVOCATIONS_CACHE_VAR = "GetInvokerKnownListObjectCache_"; + +const string NUI_SPELL_DESCRIPTION_FEATID_VAR = "NUISpellDescriptionFeatID"; +const string NUI_SPELL_DESCRIPTION_CLASSID_VAR = "NUISpellDescriptionClassID"; +const string NUI_SPELL_DESCRIPTION_SPELLID_VAR = "NUISpellDescriptionSpellID"; +const string NUI_SPELL_DESCRIPTION_REAL_SPELLID_VAR = "NUISpellDescriptionRealSpellID"; + diff --git a/src/include/prc_nui_lv_inc.nss b/src/include/prc_nui_lv_inc.nss new file mode 100644 index 0000000..bc10b28 --- /dev/null +++ b/src/include/prc_nui_lv_inc.nss @@ -0,0 +1,3339 @@ +//:://///////////////////////////////////////////// +//:: PRC Level Up NUI +//:: prc_nui_lv_inc +//::////////////////////////////////////////////// +/* + This is the logic for the Level Up NUI, holding all the functions needed for + the NUI to operate properly and allow leveling up in different classes. +*/ +//::////////////////////////////////////////////// +//:: Created By: Rakiov +//:: Created On: 20.06.2005 +//::////////////////////////////////////////////// + +#include "prc_nui_com_inc" +#include "tob_inc_tobfunc" +#include "tob_inc_moveknwn" +#include "inv_inc_invfunc" +#include "shd_inc_mystknwn" +#include "shd_inc_shdfunc" +#include "true_inc_truknwn" +#include "true_inc_trufunc" + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Spont Casters / Base /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +// +// GetSpellListObject +// Gets the JSON Object representation of a class's spellbook 2da. This function +// will cache it's result to the object given to it to avoid further calculations +// and will not clear itself since it does not change. +// +// Arguments: +// nClass:int the ClassID +// oPC:Object the player +// +// Returns: +// Json:Dictionary a dictionary of each circle's spellbook Ids. +// +json GetSpellListObject(int nClass, object oPC=OBJECT_SELF); + +// +// GetKnownSpellListObject +// Gets the JSON Object representation of a player's known spell list. This function +// will temporarily cache it's result to the object given to avoid further calculations. +// However this should be cleared after done using the level up screen or reset. +// +// Arguments: +// nClass:int the ClassID +// oPC:Object the player +// +// Returns: +// Json:Dictionary a dictionary of each circle's known spellbook Ids. +// +json GetKnownSpellListObject(int nClass, object oPC=OBJECT_SELF); + +// +// GetKnownSpellListObject +// Gets the JSON Object representation of a player's chosen spell list. This function +// will temporarily cache it's result to the object given to avoid further calculations. +// However this should be cleared after done using the level up screen or reset. +// +// Arguments: +// nClass:int the ClassID +// oPC:Object the player +// +// Returns: +// Json:Dictionary a dictionary of each circle's chosen spellbook Ids. +// +json GetChosenSpellListObject(int nClass, object oPC=OBJECT_SELF); + +// +// ShouldAddSpellToSpellButtons +// Given a classId and a spellbookId, if the player knows the spell already we +// should not add the spell, otherwise we should +// +// Arguments: +// nClass:int Class ID +// spellbookId:int the spell book ID +// oPC:object the player +// +// Returns: +// int:Boolean TRUE if spell should be added, FALSE otherwise +// +int ShouldAddSpellToSpellButtons(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +// +// OpenNUILevelUpWindow +// Opens the Level Up NUI window for the provided class +// +// Arguments: +// nClass:int the ClassID +// +void OpenNUILevelUpWindow(int nClass, object oPC=OBJECT_SELF); + +// +// CloseNUILevelUpWindow +// Closes the NUI Level Up Window if its open +// +void CloseNUILevelUpWindow(object oPC=OBJECT_SELF); + +// +// GetTrueClassType +// Gets the true class Id for a provided class Id, mostly for RHD and for +// ToB prestige classes +// +// Arguments: +// nClass:int classId +// +// Returns: +// int the true classId based off nClass +// +int GetTrueClassType(int nClass, object oPC=OBJECT_SELF); + +// +// GetRemainingSpellChoices +// Gets the remaining spell choices for a class at the given circle by checking its +// chosen spells and comparing it against the total spells allowed. This value +// is cached on the player and cleared everytime the window is refreshed/closed +// +// Arguments: +// nClass:int the class id +// circleLevel:int the circle being checked +// +// Returns: +// int the amount of choices left at the circle +// +int GetRemainingSpellChoices(int nClass, int circleLevel, object oPC=OBJECT_SELF); + +// +// ShouldSpellButtonBeEnabled +// Checks whether a spell button should be enabled either because all choices have +// been made, replacing spells isn't allowed, or for various other reasons +// +// Arguments: +// nClass:int class id +// circleLevel:int the chosen circle +// spellbookId:int the chosen spell +// +// Returns: +// int:Boolean TRUE if spell button should be enabled, FALSE otherwise +// +int ShouldSpellButtonBeEnabled(int nClass, int circleLevel, int spellbookId, object oPC=OBJECT_SELF); + +// +// AddSpellToChosenList +// Adds spell to the chosen spells list +// +// Arguments: +// nClass:int the classId +// spellbookId:int the spellbook Id +// spellCircle:int the current circle of the spell +// +void AddSpellToChosenList(int nClass, int spellbookId, int spellCircle, object oPC=OBJECT_SELF); + +// +// RemoveSpellFromChosenList +// Removes a spell from the chosen spell list +// +// Arguments: +// nClass:int the class id +// spellbookId:int the spellbook Id +// spellCircle:int the circle of the spell +// +void RemoveSpellFromChosenList(int nClass, int spellbookId, int spellCircle, object oPC=OBJECT_SELF); + +// +// LearnSpells +// gives the player the spells they want to learn based off of the chosen spell +// list in a stored variable +// +// Arguments: +// nClass:int the classId +// +void LearnSpells(int nClass, object oPC=OBJECT_SELF); + +// +// RemoveSpells +// removes spells from the player that they may know currently but aren't selected +// based off lists in stored variables +// +// Arguments: +// nClass:int the classId +// +void RemoveSpells(int nClass, object oPC=OBJECT_SELF); + +// +// FinishLevelUp +// Finishes level up NUI by removing spells, learning spells, clearing cache, then closing the NUI +// +// Arguments: +// nClass:int the class id +// +void FinishLevelUp(int nClass, object oPC=OBJECT_SELF); + +// +// ClearLevelUpNUICaches +// Clears the cache (stored local variables) for the level up NUI so it is +// ready to be used for a new level up +// +// Arguments: +// nClass:int class id +// oPC:object the player object this is stored under +// +void ClearLevelUpNUICaches(int nClass, object oPC=OBJECT_SELF); + +// +// SpellIsWithinObject +// checks whether a spell is within a JSON Object structure used by the remaining +// spells object and known spells object, following this structure +// { +// "circleLevel:int": [ 1,2,3...,spellId], +// ... +// } +// +// Arguments +// nClass:int classId +// spellbookId:int the spellbook Id +// circleLevel:int the chosen circle of the spell +// spellList;JsonObject the spell list object being checked +// +// Returns: +// int:Boolean TRUE if it is in the object, FALSE otherwise +// +int SpellIsWithinObject(int nClass, int spellbookId, int circleLevel, json spellList, object oPC=OBJECT_SELF); + +// +// IsLevelUpNUIOpen +// Checks if the Level Up NUI is open for the player or not +// +// Arguments: +// oPC:object the player object +// +// Returns: +// int:Boolean TRUE if it is, FALSE otherwise +// +int IsLevelUpNUIOpen(object oPC=OBJECT_SELF); + +// +// IsClassAllowedToUseLevelUpNUI +// Is the provided class allowed to use the level up NUI +// +// Arguments: +// nClass:int class id +// +// Returns: +// int:Boolean TRUE if it can, FALSE otherwise +// +int IsClassAllowedToUseLevelUpNUI(int nClass); + +// +// EnabledChosenButton +// determines if a chosen spell button should be enabled or not. It may not due to +// class restrictions, replacing is not enabled, or other reason +// +// Arguments: +// nClass:int the class id +// spellbookId: the spellbook Id +// circleLevel: the spell's circle +// +// Returns: +// int:Boolean TRUE if it should be enabled, FALSE otherwise +// +int EnableChosenButton(int nClass, int spellbookId, int circleLevel, object oPC=OBJECT_SELF); + +// +// ResetChoices +// Action for the Level Up NUI's 'Reset' button, resets choices by clearing the cache of +// the user so their choices are forgotten and they can start over. +// +// Arguments: +// oPC:object the player object +// +void ResetChoices(object oPC=OBJECT_SELF); + +// +// RemoveSpellKnown +// Removes a spell from a player based off class id. This is for classes that +// aren't spont casters where we have to go in and adjust persistant arrays +// to say if a spell is known or not. +// +// Arguments: +// nClass:int class id +// spellbookId:int the spellbook Id +// oPC:object the player object +// nList:int the list we are removing the spell from (extra invocations or expanded knowledge) +// +void RemoveSpellKnown(int nClass, int spellbookId, object oPC=OBJECT_SELF, int nList=0); + +// +// GetSpellIDsKnown +// Gets the SpellIDs list of the given class and list and returns it as a JsonObject following this structure +// { +// "spellId:int": TRUE, +// ... +// } +// +// This is to keep lookups at O(1) processing time. This value is cached and is +// cleared when the player finishes level up +// +// Arguments: +// nClass:int class id +// oPC:object the player object +// nList:int the list we are checking if provided (extra invocations or expanded knowledge) +// +// Returns: +// JsonObject the list of spell ids the class knows in JsonObject format +// +json GetSpellIDsKnown(int nClass, object oPC=OBJECT_SELF, int nList=0); + +// +// ReasonForDisabledSpell +// Provides the reason for why a spell choice is disabled +// +// Arguments: +// nClass:int the class id +// spellbookId:int the spellbook Id +// +// Returns: +// string the reason for the disabled button, empty string otherwise +// +string ReasonForDisabledSpell(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +// +// ReasonForDisabledChosen +// Provides the reason for why a chosen spell button is disabled +// +// Arguments: +// nClass:int the class id +// spellbookId:int the spellbook Id +// +// Returns: +// string the reason for the disabled button, empty string otherwise +// +string ReasonForDisabledChosen(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +// +// GetExpandedChoicesList +// Gets the expanded choices list for a class (the list of expanded knowledge or +// extra invocations). It follows this structure +// +// { +// "spellId:int": TRUE, +// ... +// } +// This is cached to reduce process times and is cleared everytime the window is refreshed/closed +// +// Arguments: +// nClass:int the class id +// +// Returns: +// JsonObject the object representation of the expanded choices +// +json GetExpandedChoicesList(int nClass, object oPC=OBJECT_SELF); + +// +// GetExpandedChoicesList +// Gets the epic expanded choices list for a class (the list of expanded knowledge or +// extra invocations). It follows this structure +// +// { +// "spellId:int": TRUE, +// ... +// } +// This is cached to reduce process times and is cleared everytime the window is refreshed/closed +// +// Arguments: +// nClass:int the class id +// +// Returns: +// JsonObject the object representation of the expanded choices +// +json GetEpicExpandedChoicesList(int nClass, object oPC=OBJECT_SELF); + +// +// GetRemainingExpandedChoices +// Gets the remaining expanded choices for a class based off list, comparing the +// total number of choices allowed and the total number chosen +// +// Arguments: +// nClass: class id +// nList: the list we are checking (extra invocations/expanded knowledge) +// +// Returns: +// int the amount of choices left +// +int GetRemainingExpandedChoices(int nClass, int nList, object oPC=OBJECT_SELF); +// +// IsSpellInExpandedChoices +// tells if a spell is in the expanded choices list or not +// +// Arguments: +// nClass:int class id +// nList:int the list we are checking (extra invocations/expanded knowledge) +// spellId:int the spell id (not the spellbook id) +// +// Returns +// int:Boolean TRUE if it is a expanded choice, FALSE otherwise +// +int IsSpellInExpandedChoices(int nClass, int nList, int spellId, object oPC=OBJECT_SELF); + +// +// GetChosenReplaceListObject +// The chosen list of spells we wish to replace for PnP replacing if Bioware replacing +// is disabled. This is cached and is cleared when the player is finished leveling +// or resets their choices +// +// Arguments: +// oPC:object the player +// +// Returns: +// json the list of spells chosen to replace +// +json GetChosenReplaceListObject(object oPC=OBJECT_SELF); + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Psionics /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +// +// IsExpKnowledgePower +// checks if a spell is a expanded knowledge spell +// +// Arguments: +// nClass:int class id +// spellbookId:int the spellbook Id +// +// Returns: +// int:Boolean TRUE if the spell is a expanded knowledge spell, FALSE otherwise +// +int IsExpKnowledgePower(int nClass, int spellbookId); + +// +// GetExpKnowledgePowerListRequired +// Tells what list the spell should be added to based on if it was added to the +// expanded choices or epic expanded choices list +// +// Arguments: +// nClass:int the class id +// spellbookId:int the spellbook Id +// +// Returns: +// int -1 for the expanded knowledge list, -2 for the epic expanded knowledge +// list, 0 if just add it to the normal class list +// +int GetExpKnowledgePowerListRequired(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +// +// GetCurrentPowerList +// Gets the current chosen powers list. This is cached and is cleared when the +// player either finishs leveling up or resets. +// +// Arguments: +// oPC:object the player object +// +// Returns: +// JsonArray the list of chosen powers wanting to learn +// +json GetCurrentPowerList(object oPC=OBJECT_SELF); + +// +// ShouldAddPower +// Tells if the power should be added to the list of choices or not. It may not +// be added because its an expanded knowledge choice and you have no more expanded +// knowledge slots, or it may be a restricted spell like psions list +// +// Arguments: +// nClass:int the class id +// spellbookId:int the spellbook id +// +// Returns: +// int:Boolean TRUE if it should be added, FALSE otherwise +// +int ShouldAddPower(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +// +// LearnPowers +// learns the list of chosen powers for the player based off their chosen power list +// +// Arguments: +// nClass:int class id +// oPC:object the player object where stored variables are +// +void LearnPowers(int nClass, object oPC=OBJECT_SELF); + +// +// GetMaxPowerLevelForClass +// gets the max power level for the player based off their level and the class's +// known 2da +// +// Arguments: +// nClass:int the class id +// oPC:object the player +// +// Returns: +// int the max power level (circle) the player can achieve on that class +// +int GetMaxPowerLevelForClass(int nClass, object oPC=OBJECT_SELF); + +// +// GetRemainingPowerChoices +// Gets the remaining power choices the character has at the given chosen circle/power level +// +// Arguments: +// nClass:int class id +// chosenCircle:int the chosen circle/power level +// oPC:object the player +// extra:int should we add the expanded knowledge choices or not +// +// Returns: +// int the number of choices left at the given circle +// +int GetRemainingPowerChoices(int nClass, int chosenCircle, object oPC=OBJECT_SELF, int extra=TRUE); + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Initiators /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +// +// GetDisciplineInfoObject +// Gets the disciplien info for the given class, telling what the chosen spells +// disicpline is, what type of maneuever it is, the different totals, and prerequisites. +// This is cached and is cleared when the window is refreshed/closed +// +// Argument: +// nClass:int class id +// +// Returns: +// JsonObject the object representation of the chosen spells discipline info +// +json GetDisciplineInfoObject(int nClass, object oPC=OBJECT_SELF); + +// +// HasPreRequisitesForManeuver +// Does the player have the prerequisites for the given spell based off their chosen +// spell list +// +// Arguments: +// nClass:int the class id +// spellbookId:int the spellbook id +// oPC:object the player object with stored variables +// +// Returns: +// int:Boolean, TRUE if you have the prerequisites, FALSE otherwise +// +int HasPreRequisitesForManeuver(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +// +// GetMaxInitiatorCircle +// gets the max circle/level a player can obtain with the given class +// +// Arguments: +// nClass:int the class id +// oPC:object the player +// +// Returns: +// int the highest circle the player can achieve with the class +// +int GetMaxInitiatorCircle(int nClass, object oPC=OBJECT_SELF); + +// +// GetRemainingManeuverChoices +// Gets remaining maneuever choices for the player +// +// Arguments: +// nClass:int class id +// oPC:object the player +// +// Returns: +// int the remaining maneuevers choices +// +int GetRemainingManeuverChoices(int nClass, object oPC=OBJECT_SELF); + +// +// GetRemainingStanceChoices +// Gets remaining stance choices for the player +// +// Arguments: +// nClass:int class id +// oPC:object the player +// +// Returns: +// int the remaining stance choices +// +int GetRemainingStanceChoices(int nClass, object oPC=OBJECT_SELF); + +// +// IsRequiredForOtherManeuvers +// Checks the given prerequisite number and the chosen spells to see if removing it +// will cause it to fail the requirement for other maneuevers +// +// Arguments: +// nClass:int the class id +// prereq:int the chosen spells prerequisite number of maneuevers needed +// discipline:string the chosen spells discipline +// +// Returns: +// int:Boolean TRUE if it is required, FALSE otherwise +// +int IsRequiredForOtherManeuvers(int nClass, int prereq, string discipline, object oPC=OBJECT_SELF); + +// +// IsAllowedDiscipline +// checks to see if the given spell is a allowed discipline for a class +// +// Arguments: +// nClass:int class id +// spellbookId:int the spellbook id +// +// Returns: +// int:boolean TRUE if it is allowed, FALSE otherwise +// +int IsAllowedDiscipline(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +// +// AddSpellDisciplineInfo +// Adds the maneuver's discipline info to the class's discpline object +// +// Arguments: +// sFile:string the class's spell 2da +// spellbookId:int the spellbook Id +// classDisc:JsonObject the class discipline object we are adding to +// +// Returns: +// json:Object the classDisc with the given spells information added +// +json AddSpellDisciplineInfo(string sFile, int spellbookId, json classDisc); + +// +// IsRequiredForToBPRCClass +// tells if a given maneuver is needed to satisfy a PRC's prerequsitie +// +// Arguments: +// nClass:int class id +// spellbookId:int the spellbook id +// +// Returns: +// int:Boolean TRUE if the maneuver is required for a PRC, FALSE otherwise. +// +int IsRequiredForToBPRCClass(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Invokers /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +// +// GetInvokerKnownListObject +// gets the invokers known invocations list in object format, needed to tell how many +// of each invocation level does a person know at a given level. This is cached on the +// player and not cleared since it never changes. +// +// Arguments: +// nClass:int class id +// +// Returns: +// json:Object the list of invocations known in json format +// +json GetInvokerKnownListObject(int nClass, object oPC=OBJECT_SELF); + +// +// GetRemainingInvocationChoices +// Gets the remaining invocation choices left +// +// Arguments: +// nClass:int class id +// chosenCircle:int the chosen circle we are checking +// oPC:Object the player +// extra:int should we count the number of extra invocations we have left +// +// Returns: +// int the amount of choices left at the given circle +// +int GetRemainingInvocationChoices(int nClass, int chosenCircle, object oPC=OBJECT_SELF, int extra=TRUE); + +// +// IsExtraChoiceInvocation +// tells if a given spell is a extra invocation choice +// +// Arguments: +// nClass:int class id +// spellbookId:int the spellbook id +// +// Returns: +// int;Boolean TRUE if it is a extra choice, FALSE otherwise +// +int IsExtraChoiceInvocation(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Truenamer /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +// +// GetRemainingTruenameChoices +// gets the remaining truename choices left at the given lexicon type +// +// Arguments: +// nClass:int class id +// nType:int the lexicon +// +// Returns: +// int the amount of truename choices left for the given lexicon +// +int GetRemainingTruenameChoices(int nClass, int nType, object oPC=OBJECT_SELF); + +// +// GetLexiconCircleKnownAtLevel +// gets the known circle level for a given lexicon +// +// Arguments: +// nLevel:int the level to check +// nType:int the lexicon we are checking +// +// Returns: +// int the highest circle we can achieve +// +int GetLexiconCircleKnownAtLevel(int nLevel, int nType); + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Archivist /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +json GetArchivistNewSpellsList(object oPC=OBJECT_SELF); + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Spont Casters / Base /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +int IsLevelUpNUIOpen(object oPC=OBJECT_SELF) +{ + int nPreviousToken = NuiFindWindow(oPC, NUI_LEVEL_UP_WINDOW_ID); + if (nPreviousToken != 0) + { + return TRUE; + } + + return FALSE; +} + +int IsClassAllowedToUseLevelUpNUI(int nClass) +{ + + if (GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS) + return TRUE; + + if (nClass == CLASS_TYPE_PSYWAR + || nClass == CLASS_TYPE_PSYCHIC_ROGUE + || nClass == CLASS_TYPE_PSION + || nClass == CLASS_TYPE_FIST_OF_ZUOKEN + || nClass == CLASS_TYPE_WILDER + || nClass == CLASS_TYPE_WARMIND) + return TRUE; + + if (nClass == CLASS_TYPE_WARBLADE + || nClass == CLASS_TYPE_SWORDSAGE + || nClass == CLASS_TYPE_CRUSADER) + return TRUE; + + if (nClass == CLASS_TYPE_WARLOCK + || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT + || nClass == CLASS_TYPE_DRAGON_SHAMAN) + return TRUE; + + if (nClass == CLASS_TYPE_SHADOWCASTER + || nClass == CLASS_TYPE_SHADOWSMITH) + return TRUE; + + if (nClass == CLASS_TYPE_TRUENAMER) + return TRUE; + + if (nClass == CLASS_TYPE_ARCHIVIST) + return TRUE; + + return FALSE; +} + +int SpellIsWithinObject(int nClass, int spellbookId, int circleLevel, json spellList, object oPC=OBJECT_SELF) +{ + // check to see if the spell circle isn't empty + json currentList = JsonObjectGet(spellList, IntToString(circleLevel)); + if (currentList == JsonNull()) + return FALSE; + + int totalSpells = JsonGetLength(currentList); + + // then loop through the spell list and find the spell. + int i; + for (i = 0; i < totalSpells; i++) + { + int currentSpell = JsonGetInt(JsonArrayGet(currentList, i)); + if (currentSpell == spellbookId) + return TRUE; + } + + return FALSE; +} + +int AllSpellsAreChosen(int nClass, object oPC=OBJECT_SELF) +{ + // we need the max number of circles a class has. + json spellList = GetSpellListObject(nClass, oPC); + json spellCircles = JsonObjectKeys(spellList); + int totalCircles = JsonGetLength(spellCircles); + + int i; + for (i = 0; i < totalCircles; i++) + { + // loop through each circle and check if you have any remaining choices left + // if you do or you have a deficit then you need to remove or add something + // until you get 0 + int spellCircle = StringToInt(JsonGetString(JsonArrayGet(spellCircles, i))); + int remainingChoices = GetRemainingSpellChoices(nClass, spellCircle, oPC); + if (remainingChoices < 0 || remainingChoices > 0) + return FALSE; + } + + return TRUE; +} + +void AddSpellToChosenList(int nClass, int spellbookId, int spellCircle, object oPC=OBJECT_SELF) +{ + if (GetIsInvocationClass(nClass)) + { + // get the remaining invocation choices left without extra feats + // if it is 0 then we are adding the chosen invocation to the extra lists + int totalInvocations = GetRemainingInvocationChoices(nClass, spellCircle, oPC, FALSE); + if (totalInvocations == 0) + { + string sFile = GetClassSpellbookFile(nClass); + if (GetRemainingExpandedChoices(nClass, INVOCATION_LIST_EXTRA, oPC)) + { + json expList = GetExpandedChoicesList(nClass, oPC); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + expList = JsonObjectSet(expList, spellId, JsonBool(TRUE)); + SetLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR, expList); + } + else if (GetRemainingExpandedChoices(nClass, INVOCATION_LIST_EXTRA_EPIC, oPC)) + { + json expList = GetEpicExpandedChoicesList(nClass, oPC); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + expList = JsonObjectSet(expList, spellId, JsonBool(TRUE)); + SetLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR, expList); + } + } + } + if (GetIsPsionicClass(nClass)) + { + // if the power is a expanded knowledge than we immediatly add it to the + // extra list, otherwise check to make sure we have made all choices in our + // base list first before adding it to the extra list. + if (IsExpKnowledgePower(nClass, spellbookId) + || GetRemainingPowerChoices(nClass, spellCircle, oPC, FALSE) == 0) + { + string sFile = GetClassSpellbookFile(nClass); + if (GetRemainingExpandedChoices(nClass, POWER_LIST_EXP_KNOWLEDGE, oPC)) + { + json expList = GetExpandedChoicesList(nClass, oPC); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + expList = JsonObjectSet(expList, spellId, JsonBool(TRUE)); + SetLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR, expList); + } + else if (GetRemainingExpandedChoices(nClass, POWER_LIST_EPIC_EXP_KNOWLEDGE, oPC)) + { + json expList = GetEpicExpandedChoicesList(nClass, oPC); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + expList = JsonObjectSet(expList, spellId, JsonBool(TRUE)); + SetLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR, expList); + } + } + + // add the power to the current power list. + json currPowerList = GetCurrentPowerList(oPC); + currPowerList = JsonArrayInsert(currPowerList, JsonInt(spellbookId)); + SetLocalJson(oPC, NUI_LEVEL_UP_POWER_LIST_VAR, currPowerList); + } + + if (nClass == CLASS_TYPE_ARCHIVIST) + { + json newSpells = GetArchivistNewSpellsList(oPC); + newSpells = JsonArrayInsert(newSpells, JsonInt(spellbookId)); + SetLocalJson(oPC, NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR, newSpells); + } + + // base logic for spont casters, add the spell to the ChosenSpells JSON object + // by adding it to it's appropriate circle. + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + json spellsAtCircle = JsonObjectGet(chosenSpells, IntToString(spellCircle)); + if (spellsAtCircle == JsonNull()) + spellsAtCircle = JsonArray(); + spellsAtCircle = JsonArrayInsert(spellsAtCircle, JsonInt(spellbookId)); + chosenSpells = JsonObjectSet(chosenSpells, IntToString(spellCircle), spellsAtCircle); + SetLocalJson(oPC, NUI_LEVEL_UP_CHOSEN_SPELLS_VAR, chosenSpells); + + // if we are not using bioware unlearning logic, then we need to limit the + // amount of spells we can replace. + if (!GetPRCSwitch(PRC_BIO_UNLEARN)) + { + json unlearnList = GetChosenReplaceListObject(oPC); + // if the spell belongs to the unlearn list, then remove it to make room + // for a new spell. + if (JsonObjectGet(unlearnList, IntToString(spellbookId)) != JsonNull()) + { + unlearnList = JsonObjectDel(unlearnList, IntToString(spellbookId)); + SetLocalJson(oPC, NUI_LEVEL_UP_RELEARN_LIST_VAR, unlearnList); + } + } +} + +void RemoveSpellFromChosenList(int nClass, int spellbookId, int spellCircle, object oPC=OBJECT_SELF) +{ + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + json spellsAtCircle = JsonObjectGet(chosenSpells, IntToString(spellCircle)); + if (spellsAtCircle == JsonNull()) + spellsAtCircle = JsonArray(); + + int totalSpells = JsonGetLength(spellsAtCircle); + + // find the spell at the circle in the chosen list and remove it. + int i; + for (i = 0; i < totalSpells; i++) + { + if (spellbookId == JsonGetInt(JsonArrayGet(spellsAtCircle, i))) + { + spellsAtCircle = JsonArrayDel(spellsAtCircle, i); + break; + } + } + + chosenSpells = JsonObjectSet(chosenSpells, IntToString(spellCircle), spellsAtCircle); + SetLocalJson(oPC, NUI_LEVEL_UP_CHOSEN_SPELLS_VAR, chosenSpells); + + // if we re not using bioware unlearn logic we need to limit how many spells + // can be replaced + if (!GetPRCSwitch(PRC_BIO_UNLEARN)) + { + json knownSpells = GetKnownSpellListObject(nClass, oPC); + json spellListAtCircle = JsonObjectGet(knownSpells, IntToString(spellCircle)); + int totalSpells = JsonGetLength(spellListAtCircle); + + // with the list of known spells, check the selected circle and see if the + // current spell belongs in the already known spell list. + for (i = 0; i < totalSpells; i++) + { + int chosenSpell = JsonGetInt(JsonArrayGet(spellListAtCircle, i)); + if (chosenSpell == spellbookId) + { + // if it does we need to add the spell to the unlearn JSON object to track what spells + // are being replaced. + json unlearnList = GetChosenReplaceListObject(oPC); + unlearnList = JsonObjectSet(unlearnList, IntToString(spellbookId), JsonBool(TRUE)); + SetLocalJson(oPC, NUI_LEVEL_UP_RELEARN_LIST_VAR, unlearnList); + break; + } + } + } + + if (GetIsPsionicClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + + // for psionics we need to check if the removed spell was a expanded knowledge choice + // or not. The id of the list is -1 or -2. + int i; + for (i == -1; i >= -2; i--) + { + json expList = (i == -1) ? GetExpandedChoicesList(nClass, oPC) : + GetEpicExpandedChoicesList(nClass, oPC); + + //if the spell belongs in the expanded knowledge list, then we need + // to remove it. + if (JsonObjectGet(expList, spellId) != JsonNull()) + { + expList = JsonObjectDel(expList, spellId); + if (i == POWER_LIST_EXP_KNOWLEDGE) + SetLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR, expList); + else + SetLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR, expList); + } + } + + // then we need to remove the power from the selected powers list. + json currPowerChoices = GetCurrentPowerList(oPC); + int totalPowers = JsonGetLength(currPowerChoices); + + for (i = 0; i < totalPowers; i++) + { + if (spellbookId == JsonGetInt(JsonArrayGet(currPowerChoices, i))) + { + currPowerChoices = JsonArrayDel(currPowerChoices, i); + break; + } + } + + SetLocalJson(oPC, NUI_LEVEL_UP_POWER_LIST_VAR, currPowerChoices); + } + if (GetIsInvocationClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + + // for invocations we need to check if the spell was added to the extra + // invocations list, the list ids are the invalid class id, and -2 + int i; + for (i = 0; i <= 1; i++) + { + json expList = (i == 0) ? GetExpandedChoicesList(nClass, oPC) : + GetEpicExpandedChoicesList(nClass, oPC); + + // if the spell was found, remove it. + if (JsonObjectGet(expList, spellId) != JsonNull()) + { + expList = JsonObjectDel(expList, spellId); + if (i == 0) + SetLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR, expList); + else + SetLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR, expList); + } + } + } + if (nClass == CLASS_TYPE_ARCHIVIST) + { + json newSpells = GetArchivistNewSpellsList(oPC); + int totalNew = JsonGetLength(newSpells); + + int i; + for (i = 0; i < totalNew; i++) + { + int newSpellbookId = JsonGetInt(JsonArrayGet(newSpells, i)); + if (newSpellbookId == spellbookId) + { + newSpells = JsonArrayDel(newSpells, i); + SetLocalJson(oPC, NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR, newSpells); + break; + } + } + } +} + +void OpenNUILevelUpWindow(int nClass, object oPC=OBJECT_SELF) +{ + CloseNUILevelUpWindow(oPC); + // set the NUI to the given classId + int currentClass = GetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CLASS_VAR); + // we need to clear the cache if it was used before to avoid weird behaviors + ClearLevelUpNUICaches(currentClass, oPC); + // sometimes we are given a different classId instead of the base, we need to + // figure out what the true base class is (mostly true for RHD) + int chosenClass = GetTrueClassType(nClass, oPC); + SetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CLASS_VAR, chosenClass); + + ExecuteScript("prc_nui_lv_view", oPC); +} + +int GetTrueClassType(int nClass, object oPC=OBJECT_SELF) +{ + if (nClass == CLASS_TYPE_JADE_PHOENIX_MAGE + || nClass == CLASS_TYPE_MASTER_OF_NINE + || nClass == CLASS_TYPE_DEEPSTONE_SENTINEL + || nClass == CLASS_TYPE_BLOODCLAW_MASTER + || nClass == CLASS_TYPE_RUBY_VINDICATOR + || nClass == CLASS_TYPE_ETERNAL_BLADE + || nClass == CLASS_TYPE_SHADOW_SUN_NINJA) + { + int trueClass = GetPrimaryBladeMagicClass(oPC); + return trueClass; + } + + if ((nClass == CLASS_TYPE_SHAPECHANGER + && GetRacialType(oPC) == RACIAL_TYPE_ARANEA) + || (nClass == CLASS_TYPE_OUTSIDER + && GetRacialType(oPC) == RACIAL_TYPE_RAKSHASA) + || (nClass == CLASS_TYPE_ABERRATION + && GetRacialType(oPC) == RACIAL_TYPE_DRIDER) + || (nClass == CLASS_TYPE_MONSTROUS + && GetRacialType(oPC) == RACIAL_TYPE_ARKAMOI) + || (nClass == CLASS_TYPE_MONSTROUS + && GetRacialType(oPC) == RACIAL_TYPE_HOBGOBLIN_WARSOUL) + || (nClass == CLASS_TYPE_MONSTROUS + && GetRacialType(oPC) == RACIAL_TYPE_REDSPAWN_ARCANISS) + || (nClass == CLASS_TYPE_MONSTROUS + && GetRacialType(oPC) == RACIAL_TYPE_MARRUTACT)) + return CLASS_TYPE_SORCERER; + if (nClass == CLASS_TYPE_FEY + && GetRacialType(oPC) == RACIAL_TYPE_GLOURA) + return CLASS_TYPE_BARD; + + return nClass; +} + +void CloseNUILevelUpWindow(object oPC=OBJECT_SELF) +{ + int currentClass = GetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CLASS_VAR); + // if we are refreshing the NUI but not finished we need to clear some caching done + // to save computation time as they will need to be reprocessed. + DeleteLocalJson(oPC, NUI_LEVEL_UP_DISCIPLINE_INFO_VAR + IntToString(currentClass)); + SetLocalInt(oPC, NUI_LEVEL_UP_REMAINING_CHOICES_CACHE_VAR, -20); + int nPreviousToken = NuiFindWindow(oPC, NUI_LEVEL_UP_WINDOW_ID); + if (nPreviousToken != 0) + { + NuiDestroy(oPC, nPreviousToken); + } +} + +int ShouldSpellButtonBeEnabled(int nClass, int circleLevel, int spellbookId, object oPC=OBJECT_SELF) +{ + // logic for psionics + if (GetIsPsionicClass(nClass)) + { + int maxLevel = GetMaxPowerLevelForClass(nClass, oPC); + if (circleLevel > maxLevel) + return FALSE; + + // if its an expanded knowledge choice and we have already made all our + // exp knowledge choices then it needs to be disabled. + if (IsExpKnowledgePower(nClass, spellbookId)) + { + int remainingExp = GetRemainingExpandedChoices(nClass, POWER_LIST_EXP_KNOWLEDGE, oPC) + + GetRemainingExpandedChoices(nClass, POWER_LIST_EPIC_EXP_KNOWLEDGE, oPC); + if (!remainingExp) + return FALSE; + } + } + + if (GetIsShadowMagicClass(nClass)) + { + // mysteries are weird, the circles are sectioned by 1-3, 4-6, 7-9 + // if you do not have at least 2 choices from a circle you can't progress up + // so you can have access to circles 1,2,4,7,8 + int nType = 1; + if (circleLevel >= 4 && circleLevel <= 6) + nType = 2; + if (circleLevel >= 7 && circleLevel <= 9) + nType = 3; + int maxPossibleCircle = GetMaxMysteryLevelLearnable(oPC, nClass, nType); + if (circleLevel > maxPossibleCircle) + return FALSE; + } + + if (GetIsTruenamingClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + int lexicon = StringToInt(Get2DACache(sFile, "Lexicon", spellbookId)); + // each lexicon learns at different rates + int maxCircle = GetLexiconCircleKnownAtLevel(GetLevelByClass(nClass, oPC), lexicon); + if (circleLevel > maxCircle) + return FALSE; + + if (GetRemainingTruenameChoices(nClass, lexicon, oPC)) + return TRUE; + return FALSE; + } + + // logic for ToB + if (GetIsBladeMagicClass(nClass)) + { + if (circleLevel > GetMaxInitiatorCircle(nClass, oPC)) + return FALSE; + + // if you do not have the prerequisite amount of maneuevers to learn + // the maneuever, then you can't learn it. + if (!HasPreRequisitesForManeuver(nClass, spellbookId, oPC)) + return FALSE; + + // maneuvers and stances have their own seperate limits + string sFile = GetClassSpellbookFile(nClass); + int type = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + if (type == MANEUVER_TYPE_BOOST + || type == MANEUVER_TYPE_COUNTER + || type == MANEUVER_TYPE_STRIKE + || type == MANEUVER_TYPE_MANEUVER) + { + int remainingMan = GetRemainingManeuverChoices(nClass, oPC); + if (remainingMan) + return TRUE; + return FALSE; + } + if (type == MANEUVER_TYPE_STANCE) + { + int remainingStance = GetRemainingStanceChoices(nClass, oPC); + if (remainingStance) + return TRUE; + return FALSE; + } + } + + if (nClass == CLASS_TYPE_ARCHIVIST) + { + int maxLevel = GetMaxSpellLevelForCasterLevel(nClass, GetCasterLevelByClass(nClass, oPC)); + if (circleLevel > maxLevel) + return FALSE; + } + + // default logic + // determine remaining Spell/Power choices left for player, if there is any + // remaining, enable the buttons. + if (GetRemainingSpellChoices(nClass, circleLevel, oPC)) + return TRUE; + + return FALSE; +} + +int ShouldAddSpellToSpellButtons(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + string sFile = GetClassSpellbookFile(nClass); + + string spellLevel = Get2DACache(sFile, "Level", spellbookId); + json chosenSpellsAtCircle = JsonObjectGet(chosenSpells, spellLevel); + + int chosenSpellCount = JsonGetLength(chosenSpellsAtCircle); + + // if the spell is in the chosen list, then don't add it to the available list + int i; + for (i = 0; i < chosenSpellCount; i++) + { + int chosenSpellId = JsonGetInt(JsonArrayGet(chosenSpellsAtCircle, i)); + if (chosenSpellId == spellbookId) + return FALSE; + } + + if (GetIsBladeMagicClass(nClass)) + return IsAllowedDiscipline(nClass, spellbookId, oPC); + + // if a psionic class we need to see if the power is a expanded knowledge + // choice and if we should show it or not + if (GetIsPsionicClass(nClass)) + return ShouldAddPower(nClass, spellbookId, oPC); + + // for these set of classes we need to only allow 'advanced learning' + // spells to be added + if (nClass == CLASS_TYPE_BEGUILER + || nClass == CLASS_TYPE_DREAD_NECROMANCER + || nClass == CLASS_TYPE_WARMAGE) + { + int advancedLearning = StringToInt(Get2DACache(sFile, "AL", spellbookId)); + if (advancedLearning) + return TRUE; + return FALSE; + } + + if (nClass == CLASS_TYPE_ARCHIVIST) + { + int nLevel = GetLevelByClass(nClass, oPC); + if ((StringToInt(spellLevel) == 0) && (nLevel == 1)) + return FALSE; + int advancedLearning = StringToInt(Get2DACache(sFile, "AL", spellbookId)); + if (advancedLearning) + return FALSE; + } + + return TRUE; +} + +json GetChosenSpellListObject(int nClass, object oPC=OBJECT_SELF) +{ + json retValue = GetLocalJson(oPC, NUI_LEVEL_UP_CHOSEN_SPELLS_VAR); + // if this isn't set yet then we the chosen currently is the known spells + if (retValue == JsonNull()) + { + retValue = GetKnownSpellListObject(nClass, oPC); + SetLocalJson(oPC, NUI_LEVEL_UP_CHOSEN_SPELLS_VAR, retValue); + } + + return retValue; +} + +json GetKnownSpellListObject(int nClass, object oPC=OBJECT_SELF) +{ + json retValue = GetLocalJson(oPC, NUI_LEVEL_UP_KNOWN_SPELLS_VAR); + if (retValue == JsonNull()) + retValue = JsonObject(); + else + return retValue; + + string sFile = GetClassSpellbookFile(nClass); + int totalSpells = Get2DARowCount(sFile); + + if (nClass == CLASS_TYPE_ARCHIVIST) + { + int i; + for (i = 0; i < 10; i++) + { + string sSpellbook = GetSpellsKnown_Array(nClass, i); + + int nSize = persistant_array_get_size(oPC, sSpellbook); + + int j; + for (j = 0; j < nSize; j++) + { + int knownSpellbookID = persistant_array_get_int(oPC, sSpellbook, j); + // we store things in a JSON Object where the spell circle + // is the key to a JsonArray of spellbookIds. + json spellList = JsonObjectGet(retValue, IntToString(i)); + if (spellList == JsonNull()) + spellList = JsonArray(); + spellList = JsonArrayInsert(spellList, JsonInt(knownSpellbookID)); + retValue = JsonObjectSet(retValue, IntToString(i), spellList); + } + } + } + else + { + // loop through all the spells in the class's 2da + int i; + for (i = 0; i < totalSpells; i++) + { + int featId = StringToInt(Get2DACache(sFile, "FeatID", i)); + // if you have the feat, you know the spell + if (featId && GetHasFeat(featId, oPC, TRUE)) + { + string spellLevel = Get2DACache(sFile, "Level", i); + int nSpellLevel = StringToInt(spellLevel); + // some spells have **** as their level, so make sure we have + // parsed it correctly + if (IntToString(nSpellLevel) == spellLevel) + { + // we store things in a JSON Object where the spell circle + // is the key to a JsonArray of spellbookIds. + json spellList = JsonObjectGet(retValue, spellLevel); + if (spellList == JsonNull()) + spellList = JsonArray(); + spellList = JsonArrayInsert(spellList, JsonInt(i)); + retValue = JsonObjectSet(retValue, spellLevel, spellList); + } + } + } + } + + SetLocalJson(oPC, NUI_LEVEL_UP_KNOWN_SPELLS_VAR, retValue); + return retValue; +} + +json GetSpellListObject(int nClass, object oPC=OBJECT_SELF) +{ + json retValue = GetLocalJson(oPC, NUI_LEVEL_UP_SPELLBOOK_OBJECT_CACHE_VAR + IntToString(nClass)); + if (retValue == JsonNull()) + retValue = JsonObject(); + else + return retValue; + + string sFile = GetClassSpellbookFile(nClass); + int totalSpells = Get2DARowCount(sFile); + + // loop through all the spells in the 2da and convert it to a JSON Object representation + int i; + for (i = 0; i < totalSpells; i++) + { + string spellLevel = Get2DACache(sFile, "Level", i); + int nSpellLevel = StringToInt(spellLevel); + // some spells in the list have **** as spell level. We need to ignore them + if (IntToString(nSpellLevel) == spellLevel) + { + if (nClass == CLASS_TYPE_ARCHIVIST) + { + int reqFeat = StringToInt(Get2DACache(sFile, "ReqFeat", i)); + if (!reqFeat) + { + json spellList = JsonObjectGet(retValue, spellLevel); + if (spellList == JsonNull()) + spellList = JsonArray(); + spellList = JsonArrayInsert(spellList, JsonInt(i)); + retValue = JsonObjectSet(retValue, spellLevel, spellList); + } + } + else + { + json spellList = JsonObjectGet(retValue, spellLevel); + if (spellList == JsonNull()) + spellList = JsonArray(); + spellList = JsonArrayInsert(spellList, JsonInt(i)); + retValue = JsonObjectSet(retValue, spellLevel, spellList); + } + } + } + + SetLocalJson(oPC, NUI_LEVEL_UP_SPELLBOOK_OBJECT_CACHE_VAR + IntToString(nClass), retValue); + return retValue; +} + +int GetRemainingSpellChoices(int nClass, int circleLevel, object oPC=OBJECT_SELF) +{ + int chosenCircle = GetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CIRCLE_VAR); + int remainingChoices = 0; + + // we only want to cache on the current circle. + if (chosenCircle == circleLevel) + { + remainingChoices = GetLocalInt(oPC, NUI_LEVEL_UP_REMAINING_CHOICES_CACHE_VAR); + // -20 is the chosen number to say there is no cache set since 0 is + // a valid option + if (remainingChoices != -20) + return remainingChoices; + } + + // logic for psionics + if (GetIsPsionicClass(nClass)) + remainingChoices = GetRemainingPowerChoices(nClass, circleLevel, oPC); + + // logic for ToB + if (GetIsBladeMagicClass(nClass)) + remainingChoices = (GetRemainingManeuverChoices(nClass, oPC) + + GetRemainingStanceChoices(nClass, oPC)); + + // logic for Invokers + if (GetIsInvocationClass(nClass)) + remainingChoices = GetRemainingInvocationChoices(nClass, circleLevel, oPC); + + // logic for mysteries + if (GetIsShadowMagicClass(nClass)) + { + int totalChosen = 0; + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + json circles = JsonObjectKeys(chosenSpells); + int totalCircles = JsonGetLength(circles); + + int i; + for (i = 0; i < totalCircles; i++) + { + // loop through each circle and add its total spells together since + // we don't care about where you spend your spells, only the amount + string currentCircle = JsonGetString(JsonArrayGet(circles, i)); + json spellList = JsonObjectGet(chosenSpells, currentCircle); + if (spellList != JsonNull()) + totalChosen += JsonGetLength(spellList); + } + + int maxKnown = GetMaxMysteryCount(oPC, nClass); + remainingChoices = (maxKnown - totalChosen); + } + + if (GetIsTruenamingClass(nClass)) + remainingChoices = GetRemainingTruenameChoices(nClass, -1, oPC); + + if (nClass == CLASS_TYPE_ARCHIVIST) + { + int nLevel = GetLevelByClass(CLASS_TYPE_ARCHIVIST, oPC); + int spellsAvailable; + if (nLevel == 1) + spellsAvailable = (3 + GetAbilityModifier(ABILITY_INTELLIGENCE, oPC)); + else + spellsAvailable = 2; + + json newSpells = GetArchivistNewSpellsList(oPC); + int totalNewSpells = JsonGetLength(newSpells); + remainingChoices = (spellsAvailable - totalNewSpells); + } + if (GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS) + { + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + int totalSpellsKnown = 0; + int casterLevel = GetCasterLevelByClass(nClass, oPC); + + // these specific classes only learn at specific rates + int advancedLearning = 0; + // beguiler learns every 4th level starting on 3 + if (nClass == CLASS_TYPE_BEGUILER) + advancedLearning = ((casterLevel+1)/4); + // dread learns every 4th level + if (nClass == CLASS_TYPE_DREAD_NECROMANCER) + advancedLearning = (casterLevel/4); + // warmage is a bastard child that choses when it learns a spell whenever + // it decides it feels like it wants to + if (nClass == CLASS_TYPE_WARMAGE) + { + if (casterLevel >= 3) // 1 choice + advancedLearning++; + if (casterLevel >= 6) // 2 choice + advancedLearning++; + if (casterLevel >= 11) // 3 choice + advancedLearning++; + if (casterLevel >= 16) // 4 choice + advancedLearning++; + if (casterLevel >= 24) // 5 choice + advancedLearning++; + if (casterLevel >= 28) // 6 choice + advancedLearning++; + if (casterLevel >= 32) // 7 choice + advancedLearning++; + if (casterLevel >= 36) // 8 choice + advancedLearning++; + if (casterLevel >= 40) // 9 choice + advancedLearning++; + } + + if (advancedLearning) + { + int maxSpellLevel = GetMaxSpellLevelForCasterLevel(nClass, casterLevel); + // can't learn what you can't achieve + if (circleLevel > maxSpellLevel) + remainingChoices = 0; + else + { + int chosenSpellsAmount = 0; + + json circles = JsonObjectKeys(chosenSpells); + int totalCircles = JsonGetLength(circles); + string sFile = GetClassSpellbookFile(nClass); + + int i; + for (i = 0; i <= totalCircles; i++) + { + string currentCircle = JsonGetString(JsonArrayGet(circles, i)); + json spellList = JsonObjectGet(chosenSpells, currentCircle); + if ((spellList != JsonNull())) + { + // loop through the spells of a given circle and count how + // many advanced learning spells you know + int numOfSpells = JsonGetLength(spellList); + int j; + for (j = 0; j < numOfSpells; j++) + { + int nSpellbookID = JsonGetInt(JsonArrayGet(spellList, j)); + int isAL = StringToInt(Get2DACache(sFile, "AL", nSpellbookID)); + if (isAL) + chosenSpellsAmount++; + } + } + } + + remainingChoices = (advancedLearning - chosenSpellsAmount); + } + } + else + { + // default logic for spont casters + totalSpellsKnown = GetSpellKnownMaxCount(casterLevel, circleLevel, nClass, oPC); + // Favoured Soul has more 0 choices than there are spells for some reason + if (nClass == CLASS_TYPE_FAVOURED_SOUL && circleLevel == 0 && totalSpellsKnown > 6) + totalSpellsKnown = 6; + + // logic for spont casters + json selectedCircle = JsonObjectGet(chosenSpells, IntToString(circleLevel)); + if (selectedCircle == JsonNull()) + return totalSpellsKnown; + + int selectedSpellCount = JsonGetLength(selectedCircle); + remainingChoices = (totalSpellsKnown - selectedSpellCount); + } + } + + if (chosenCircle == circleLevel) + SetLocalInt(oPC, NUI_LEVEL_UP_REMAINING_CHOICES_CACHE_VAR, remainingChoices); + return remainingChoices; +} + +void FinishLevelUp(int nClass, object oPC=OBJECT_SELF) +{ + RemoveSpells(nClass, oPC); + LearnSpells(nClass, oPC); + if (nClass == CLASS_TYPE_ARCHIVIST) + { + int nLevel = GetLevelByClass(nClass, oPC); + SetPersistantLocalInt(oPC, "LastSpellGainLevel", nLevel); + } + ClearLevelUpNUICaches(nClass, oPC); +} + +void ClearLevelUpNUICaches(int nClass, object oPC=OBJECT_SELF) +{ + // clear the chosen spells you made + DeleteLocalJson(oPC, NUI_LEVEL_UP_CHOSEN_SPELLS_VAR); + // clear the known spells you have + DeleteLocalJson(oPC, NUI_LEVEL_UP_KNOWN_SPELLS_VAR); + SetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CIRCLE_VAR, -1); + DeleteLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CLASS_VAR); + // clear the psionics selected choices + DeleteLocalJson(oPC, NUI_LEVEL_UP_POWER_LIST_VAR); + // clear the expanded choices for psionics and invokers + DeleteLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR); + DeleteLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR); + // clear the PnP replace list + DeleteLocalJson(oPC, NUI_LEVEL_UP_RELEARN_LIST_VAR); + DeleteLocalJson(oPC, NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR); + // for invocation and psionics we grab the list of known extra spells and cache it + // so we need to clear those caches + if (GetIsInvocationClass(nClass)) + { + DeleteLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_0"); + DeleteLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_" + IntToString(INVOCATION_LIST_EXTRA)); + DeleteLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_" + IntToString(INVOCATION_LIST_EXTRA_EPIC)); + } + if (GetIsPsionicClass(nClass)) + { + DeleteLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_0"); + DeleteLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_" + IntToString(POWER_LIST_EXP_KNOWLEDGE)); + DeleteLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_" + IntToString(POWER_LIST_EPIC_EXP_KNOWLEDGE)); + } + // for ToB we need to clear all the discipline info for determining PrC choice validity + if (GetIsBladeMagicClass(nClass)) + { + DeleteLocalJson(oPC, NUI_LEVEL_UP_DISCIPLINE_INFO_VAR + IntToString(CLASS_TYPE_SWORDSAGE)); + DeleteLocalJson(oPC, NUI_LEVEL_UP_DISCIPLINE_INFO_VAR + IntToString(CLASS_TYPE_WARBLADE)); + DeleteLocalJson(oPC, NUI_LEVEL_UP_DISCIPLINE_INFO_VAR + IntToString(CLASS_TYPE_CRUSADER)); + } +} + +void RemoveSpells(int nClass, object oPC=OBJECT_SELF) +{ + // we don't remove on psionic classes and archivist + if (GetIsPsionicClass(nClass) || nClass == CLASS_TYPE_ARCHIVIST) + return; + + json knownSpells = GetKnownSpellListObject(nClass, oPC); + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + json spellCircles = JsonObjectKeys(knownSpells); + int totalCircles = JsonGetLength(spellCircles); + + // loop through all the known spells circles + int i; + for (i = 0; i < totalCircles; i++) + { + string sSpellLevel = JsonGetString(JsonArrayGet(spellCircles, i)); + int nSpellLevel = StringToInt(sSpellLevel); + + json chosenCircle = JsonObjectGet(knownSpells, sSpellLevel); + int totalSpells = JsonGetLength(chosenCircle); + + // loop through the spell list at the given circle + int y; + for (y = 0; y < totalSpells; y++) + { + int nSpellbookID = JsonGetInt(JsonArrayGet(chosenCircle, y)); + // if the spell is not a chosen spell, then it was removed + if (!SpellIsWithinObject(nClass, nSpellbookID, nSpellLevel, chosenSpells, oPC)) + { + if (GetIsInvocationClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + string spellId = Get2DACache(sFile, "SpellID", nSpellbookID); + int chosenList = 0; + // check to see if its a extra invocation choice and set it's chosen list + if (GetHasFeat(FEAT_EXTRA_INVOCATION_I, oPC)) + { + json expList = GetSpellIDsKnown(nClass, oPC, INVOCATION_LIST_EXTRA); + if (JsonObjectGet(expList, spellId) != JsonNull()) + chosenList = INVOCATION_LIST_EXTRA; + } + if (GetHasFeat(FEAT_EPIC_EXTRA_INVOCATION_I, oPC)) + { + json expList = GetSpellIDsKnown(nClass, oPC, INVOCATION_LIST_EXTRA_EPIC); + if (JsonObjectGet(expList, spellId) != JsonNull()) + chosenList = INVOCATION_LIST_EXTRA_EPIC; + } + RemoveSpellKnown(nClass, nSpellbookID, oPC, chosenList); + } + if (GetIsBladeMagicClass(nClass) || GetIsShadowMagicClass(nClass)) + RemoveSpellKnown(nClass, nSpellbookID, oPC); + + if (GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS) + { + string sFile = GetClassSpellbookFile(nClass); + string sSpellBook = GetSpellsKnown_Array(nClass); + // remove the spell from the spellbook + array_extract_int(oPC, sSpellBook, nSpellbookID); + // wipe the spell from the player + int ipFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", nSpellbookID)); + WipeSpellFromHide(ipFeatID, oPC); + } + } + } + } +} + +void LearnSpells(int nClass, object oPC=OBJECT_SELF) +{ + if (GetIsPsionicClass(nClass)) + { + LearnPowers(nClass, oPC); + return; + } + + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + json knownSpells = GetKnownSpellListObject(nClass, oPC); + json spellCircles = JsonObjectKeys(chosenSpells); + int totalCircles = JsonGetLength(spellCircles); + + // loop through chosen spells circles + int i; + for (i = 0; i < totalCircles; i++) + { + string sSpellLevel = JsonGetString(JsonArrayGet(spellCircles, i)); + int nSpellLevel = StringToInt(sSpellLevel); + + json chosenCircle = JsonObjectGet(chosenSpells, sSpellLevel); + int totalSpells = JsonGetLength(chosenCircle); + + // loop through the spell list at the circle + int y; + for (y = 0; y < totalSpells; y++) + { + int nSpellbookID = JsonGetInt(JsonArrayGet(chosenCircle, y)); + // if the spell is not in the known spell list then it was newly added + if (!SpellIsWithinObject(nClass, nSpellbookID, nSpellLevel, knownSpells, oPC)) + { + if (GetIsTruenamingClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + // find out what lexicon it belongs to and add it to that + int lexicon = StringToInt(Get2DACache(sFile, "Lexicon", nSpellbookID)); + AddUtteranceKnown(oPC, nClass, nSpellbookID, lexicon, TRUE, GetHitDice(oPC)); + } + + if (GetIsShadowMagicClass(nClass)) + AddMysteryKnown(oPC, nClass, nSpellbookID, TRUE, GetHitDice(oPC)); + + if (GetIsInvocationClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + string spellId = Get2DACache(sFile, "SpellID", nSpellbookID); + int chosenList = nClass; + json expList = GetExpandedChoicesList(nClass, oPC); + // if the invocation belongs to the extra or epic extra list + // then we need to provide those list ids instead. + if (JsonObjectGet(expList, spellId) != JsonNull()) + chosenList = INVOCATION_LIST_EXTRA; + expList = GetEpicExpandedChoicesList(nClass, oPC); + if (JsonObjectGet(expList, spellId) != JsonNull()) + chosenList = INVOCATION_LIST_EXTRA_EPIC; + AddInvocationKnown(oPC, chosenList, nSpellbookID, TRUE, GetHitDice(oPC)); + } + + if (GetIsBladeMagicClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + int maneuverType = StringToInt(Get2DACache(sFile, "Type", nSpellbookID)); + // we save our moves either to stance or maneuever + if (maneuverType != MANEUVER_TYPE_STANCE) + maneuverType = MANEUVER_TYPE_MANEUVER; + + AddManeuverKnown(oPC, nClass, nSpellbookID, maneuverType, TRUE, GetHitDice(oPC)); + } + int nSpellbookType = GetSpellbookTypeForClass(nClass); + if (nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS + || nClass == CLASS_TYPE_ARCHIVIST) + { + // these classes have their own syste, + if (nClass == CLASS_TYPE_BEGUILER + || nClass == CLASS_TYPE_DREAD_NECROMANCER + || nClass == CLASS_TYPE_WARMAGE) + { + int casterLevel = GetCasterLevelByClass(nClass, oPC); + // this is taken from prc_s_spellgain as it is coupled with the + // dynamic dialogue system + int advancedLearning = 0; + // beguilers learn every 4th level starting on 3rd + if (nClass == CLASS_TYPE_BEGUILER) + advancedLearning = ((casterLevel+1)/4); + // dread learns every 4th level + if (nClass == CLASS_TYPE_DREAD_NECROMANCER) + advancedLearning = (casterLevel/4); + if (nClass == CLASS_TYPE_WARMAGE) + { + if (casterLevel >= 3) + advancedLearning++; + } + + if (advancedLearning) + { + // incremenet the total advanced learning known + int nAdvLearn = GetPersistantLocalInt(oPC, "AdvancedLearning_"+IntToString(nClass)); + nAdvLearn++; + SetPersistantLocalInt(oPC, "AdvancedLearning_"+IntToString(nClass), nAdvLearn); + } + } + + // get location of persistant storage on the hide + string sSpellbook = GetSpellsKnown_Array(nClass, nSpellLevel); + //object oToken = GetHideToken(oPC); + + // Create spells known persistant array if it is missing + int nSize = persistant_array_get_size(oPC, sSpellbook); + if (nSize < 0) + { + persistant_array_create(oPC, sSpellbook); + nSize = 0; + } + + // Mark the spell as known (e.g. add it to the end of oPCs spellbook) + persistant_array_set_int(oPC, sSpellbook, nSize, nSpellbookID); + + if (nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS) + { + // add spell + string sFile = GetClassSpellbookFile(nClass); + string sArrayName = "NewSpellbookMem_" + IntToString(nClass); + int featId = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookID)); + int ipFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", nSpellbookID)); + AddSpellUse(oPC, nSpellbookID, nClass, sFile, sArrayName, nSpellbookType, GetPCSkin(oPC), featId, ipFeatID); + } + } + } + } + } +} + +int EnableChosenButton(int nClass, int spellbookId, int circleLevel, object oPC=OBJECT_SELF) +{ + if (GetIsPsionicClass(nClass) + || GetIsShadowMagicClass(nClass) + || GetIsTruenamingClass(nClass) + || nClass == CLASS_TYPE_DREAD_NECROMANCER + || nClass == CLASS_TYPE_BEGUILER + || nClass == CLASS_TYPE_WARMAGE + || nClass == CLASS_TYPE_ARCHIVIST) + { + json knownSpells = GetKnownSpellListObject(nClass, oPC); + json currentCircle = JsonObjectGet(knownSpells, IntToString(circleLevel)); + int totalSpells = JsonGetLength(currentCircle); + int i; + for (i = 0; i < totalSpells; i++) + { + // if spell belongs to known spells, then disable, we don't allow + // replacing for these classes. + int currentSpellbookId = JsonGetInt(JsonArrayGet(currentCircle, i)); + if (currentSpellbookId == spellbookId) + return FALSE; + } + + } + + if (GetIsBladeMagicClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + int prereqs = StringToInt(Get2DACache(sFile, "Prereqs", spellbookId)); + string discipline = Get2DACache(sFile, "Discipline", spellbookId); + // if the maneuver is required for others to exist, t hen disable it + if (IsRequiredForOtherManeuvers(nClass, prereqs, discipline, oPC)) + return FALSE; + // if it is required for a PRC to exist, then disable it. + if (IsRequiredForToBPRCClass(nClass, spellbookId, oPC)) + return FALSE; + } + + if (GetIsInvocationClass(nClass)) + { + // dragon Shamans can't replace + if (nClass == CLASS_TYPE_DRAGON_SHAMAN) + { + json invokKnown = GetSpellIDsKnown(nClass, oPC); + string sFile = GetClassSpellbookFile(nClass); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + json chosenSpell = JsonObjectGet(invokKnown, spellId); + if (chosenSpell != JsonNull()) + return FALSE; + } + } + + // If we do not use the bioware unlearn system, we follow PnP + if (!GetPRCSwitch(PRC_BIO_UNLEARN)) + { + json knownSpells = GetKnownSpellListObject(nClass, oPC); + json currentCircle = JsonObjectGet(knownSpells, IntToString(circleLevel)); + int totalSpells = JsonGetLength(currentCircle); + int i; + for (i = 0; i < totalSpells; i++) + { + int currentSpellbookId = JsonGetInt(JsonArrayGet(currentCircle, i)); + // if the spell belongs to the known spell list, then we need to determine + if (currentSpellbookId == spellbookId) + { + json unlearnList = GetChosenReplaceListObject(oPC); + int totalUnlearned = JsonGetLength(unlearnList); + int totalAllowed = GetPRCSwitch(PRC_UNLEARN_SPELL_MAXNR); + // we default to 1 if no max number of unlearns is set + if (!totalAllowed) + totalAllowed = 1; + // we cannot replace a spell if we have more than or equal to the + // amount of relearns allowed, therefore disable. + return totalUnlearned < totalAllowed; + } + } + + } + + return TRUE; +} + +void ResetChoices(object oPC=OBJECT_SELF) +{ + // reset choices made so far + DeleteLocalJson(oPC, NUI_LEVEL_UP_CHOSEN_SPELLS_VAR); + DeleteLocalJson(oPC, NUI_LEVEL_UP_POWER_LIST_VAR); + DeleteLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR); + DeleteLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR); + DeleteLocalJson(oPC, NUI_LEVEL_UP_RELEARN_LIST_VAR); + DeleteLocalJson(oPC, NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR); +} + +void RemoveSpellKnown(int nClass, int spellbookId, object oPC=OBJECT_SELF, int nList=0) +{ + string sBase; + string levelArrayBaseId; + string generalArrayBaseId; + string totalCountId; + + string sFile = GetClassSpellbookFile(nClass); + int chosenList = (nList != 0) ? nList : nClass; + int spellID = StringToInt(Get2DACache(sFile, "SpellID", spellbookId)); + + // if statements are to change the location of the spellbook we are grabbing + if (GetIsShadowMagicClass(nClass)) + { + sBase = _MYSTERY_LIST_NAME_BASE + IntToString(chosenList); + levelArrayBaseId = _MYSTERY_LIST_LEVEL_ARRAY; + generalArrayBaseId = _MYSTERY_LIST_GENERAL_ARRAY; + totalCountId = _MYSTERY_LIST_TOTAL_KNOWN; + } + + if (GetIsInvocationClass(nClass)) + { + sBase = _INVOCATION_LIST_NAME_BASE + IntToString(chosenList); + levelArrayBaseId = _INVOCATION_LIST_LEVEL_ARRAY; + generalArrayBaseId = _INVOCATION_LIST_GENERAL_ARRAY; + totalCountId = _INVOCATION_LIST_TOTAL_KNOWN; + } + + if (GetIsBladeMagicClass(nClass)) + { + int maneuverType = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + if (maneuverType != MANEUVER_TYPE_STANCE) maneuverType = MANEUVER_TYPE_MANEUVER; + sBase = _MANEUVER_LIST_NAME_BASE + IntToString(chosenList) + IntToString(maneuverType); + levelArrayBaseId = _MANEUVER_LIST_LEVEL_ARRAY; + generalArrayBaseId = _MANEUVER_LIST_GENERAL_ARRAY; + totalCountId = _MANEUVER_LIST_TOTAL_KNOWN; + } + + if (GetIsTruenamingClass(nClass)) + { + string lexicon = Get2DACache(sFile, "Lexicon", spellbookId); + sBase = _UTTERANCE_LIST_NAME_BASE + IntToString(chosenList) + lexicon; + levelArrayBaseId = _UTTERANCE_LIST_LEVEL_ARRAY; + generalArrayBaseId = _UTTERANCE_LIST_GENERAL_ARRAY; + totalCountId = _UTTERANCE_LIST_TOTAL_KNOWN; + } + + string sTestArray; + + int found = FALSE; + + int i; + for (i = 1; i <= GetHitDice(oPC); i++) + { + sTestArray = sBase + levelArrayBaseId + IntToString(i); + if (persistant_array_exists(oPC, sTestArray)) + { + // if we found the spell, then we remove it. + if (persistant_array_extract_int(oPC, sTestArray, spellID) >= 0) + { + found = TRUE; + break; + } + } + } + + if (!found) + { + // if not found we check the general list where spells aren't set to a level. + sTestArray = sBase + generalArrayBaseId; + if (persistant_array_exists(oPC, sTestArray)) + { + //if we could not find the spell here, something went wrong + if (persistant_array_extract_int(oPC, sTestArray, spellID) < 0) + { + SendMessageToPC(oPC, "Could not find spellID " + IntToString(spellID) + " in the class's spellbook!"); + return; + } + } + } + + // decrement the amount of spells known. + SetPersistantLocalInt(oPC, sBase + totalCountId, + GetPersistantLocalInt(oPC, sBase + totalCountId) - 1 + ); + + // if ToB we need to decrement the specific discipline as well. + if (GetIsBladeMagicClass(nClass)) + { + int maneuverType = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + if (maneuverType == MANEUVER_TYPE_BOOST + || maneuverType == MANEUVER_TYPE_COUNTER + || maneuverType == MANEUVER_TYPE_STRIKE + || maneuverType == MANEUVER_TYPE_MANEUVER) + maneuverType = MANEUVER_TYPE_MANEUVER; + string sDisciplineArray = _MANEUVER_LIST_DISCIPLINE + IntToString(maneuverType) + "_" + Get2DACache(sFile, "Discipline", spellbookId); + SetPersistantLocalInt(oPC, sDisciplineArray, + GetPersistantLocalInt(oPC, sDisciplineArray) - 1); + } + + // remove spell from player + int ipFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", spellbookId)); + itemproperty ipFeat = PRCItemPropertyBonusFeat(ipFeatID); + object oSkin = GetPCSkin(oPC); + RemoveItemProperty(oSkin, ipFeat); + CheckAndRemoveFeat(oSkin, ipFeat); +} + +json GetSpellIDsKnown(int nClass, object oPC=OBJECT_SELF, int nList=0) +{ + json spellIds = GetLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_" + IntToString(nList)); + if (spellIds == JsonNull()) + spellIds = JsonObject(); + else + return spellIds; + + string sBase; + string levelArrayBaseId; + string generalArrayBaseId; + // if we are given a listId then use that instead, used for extra choices and + // expanded knowledge + int chosenList = (nList != 0) ? nList : nClass; + // these if checks are for setting class specific ids + if (nClass == CLASS_TYPE_DRAGON_SHAMAN + || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT + || nClass == CLASS_TYPE_WARLOCK) + { + sBase = _INVOCATION_LIST_NAME_BASE + IntToString(chosenList); + levelArrayBaseId = _INVOCATION_LIST_LEVEL_ARRAY; + generalArrayBaseId = _INVOCATION_LIST_GENERAL_ARRAY; + } + if (GetIsPsionicClass(nClass)) + { + sBase = _POWER_LIST_NAME_BASE + IntToString(chosenList); + levelArrayBaseId = _POWER_LIST_LEVEL_ARRAY; + generalArrayBaseId = _POWER_LIST_GENERAL_ARRAY; + } + + // go through the level list and translate the spellIds into a JSON Object + // structure for easier access. + int i; + for (i = 1; i <= GetHitDice(oPC); i++) + { + string sTestArray = sBase + levelArrayBaseId + IntToString(i); + if (persistant_array_exists(oPC, sTestArray)) + { + int nSize = persistant_array_get_size(oPC, sTestArray); + + int j; + for (j = 0; j < nSize; j++) + { + spellIds = JsonObjectSet(spellIds, IntToString(persistant_array_get_int(oPC, sTestArray, j)), JsonBool(TRUE)); + } + } + } + + // go through the general list and translate the spellIds into a JSON Object + // structure for easier access. + string sTestArray = sBase + generalArrayBaseId; + if (persistant_array_exists(oPC, sTestArray)) + { + int nSize = persistant_array_get_size(oPC, sTestArray); + + int j; + for (j = 0; j < nSize; j++) + { + spellIds = JsonObjectSet(spellIds, IntToString(persistant_array_get_int(oPC, sTestArray, j)), JsonBool(TRUE)); + } + } + + SetLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_" + IntToString(nList), spellIds); + return spellIds; +} + +string ReasonForDisabledSpell(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + int circleLevel = StringToInt(Get2DACache(sFile, "Level", spellbookId)); + + // logic for psionics + if (GetIsPsionicClass(nClass)) + { + int maxLevel = GetMaxPowerLevelForClass(nClass, oPC); + if (circleLevel > maxLevel) + return "You are unable to learn at this level currently."; + + // if its an expanded knowledge choice and we have already made all our + // exp knowledge choices then it needs to be disabled. + if (IsExpKnowledgePower(nClass, spellbookId)) + { + int remainingExp = GetRemainingExpandedChoices(nClass, POWER_LIST_EXP_KNOWLEDGE, oPC) + + GetRemainingExpandedChoices(nClass, POWER_LIST_EPIC_EXP_KNOWLEDGE, oPC); + if (!remainingExp) + return "You have no more expanded knowledge choices left."; + } + } + + if (GetIsShadowMagicClass(nClass)) + { + // mysteries are weird, the circles are sectioned by 1-3, 4-6, 7-9 + // if you do not have at least 2 choices from a circle you can't progress up + // so you can have access to circles 1,2,4,7,8 + int nType = 1; + if (circleLevel >= 4 && circleLevel <= 6) + nType = 2; + if (circleLevel >= 7 && circleLevel <= 9) + nType = 3; + int maxPossibleCircle = GetMaxMysteryLevelLearnable(oPC, nClass, nType); + if (circleLevel > maxPossibleCircle) + return "You are unable to learn at this level currently."; + } + + if (GetIsTruenamingClass(nClass)) + { + int lexicon = StringToInt(Get2DACache(sFile, "Lexicon", spellbookId)); + // each lexicon learns at different rates + int maxCircle = GetLexiconCircleKnownAtLevel(GetLevelByClass(nClass, oPC), lexicon); + if (circleLevel > maxCircle) + return "You are unable to learn at this level currently."; + + if (GetRemainingTruenameChoices(nClass, lexicon, oPC)) + return ""; + return "You have made all your truenaming choices."; + } + + // logic for ToB + if (GetIsBladeMagicClass(nClass)) + { + if (circleLevel > GetMaxInitiatorCircle(nClass, oPC)) + return "You are unable to learn at this level currently."; + + // if you do not have the prerequisite amount of maneuevers to learn + // the maneuever, then you can't learn it. + if (!HasPreRequisitesForManeuver(nClass, spellbookId, oPC)) + return "You do not have the prerequisites for this maneuver."; + + // maneuvers and stances have their own seperate limits + int type = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + if (type == MANEUVER_TYPE_BOOST + || type == MANEUVER_TYPE_COUNTER + || type == MANEUVER_TYPE_STRIKE + || type == MANEUVER_TYPE_MANEUVER) + { + int remainingMan = GetRemainingManeuverChoices(nClass, oPC); + if (remainingMan) + return ""; + return "You have made all your maneuver choices."; + } + if (type == MANEUVER_TYPE_STANCE) + { + int remainingStance = GetRemainingStanceChoices(nClass, oPC); + if (remainingStance) + return ""; + return "You have made all your stance choices."; + } + } + + // default logic + // determine remaining Spell/Power choices left for player, if there is any + // remaining, enable the buttons. + if (GetRemainingSpellChoices(nClass, circleLevel, oPC)) + return ""; + + return "You have made all your spell choices."; +} + +string ReasonForDisabledChosen(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + int circleLevel = StringToInt(Get2DACache(sFile, "Level", spellbookId)); + + + if (GetIsPsionicClass(nClass) + || GetIsShadowMagicClass(nClass) + || GetIsTruenamingClass(nClass) + || nClass == CLASS_TYPE_DREAD_NECROMANCER + || nClass == CLASS_TYPE_BEGUILER + || nClass == CLASS_TYPE_WARMAGE) + { + json knownSpells = GetKnownSpellListObject(nClass, oPC); + json currentCircle = JsonObjectGet(knownSpells, IntToString(circleLevel)); + int totalSpells = JsonGetLength(currentCircle); + int i; + for (i = 0; i < totalSpells; i++) + { + // if spell belongs to known spells, then disable, we don't allow + // replacing for these classes. + int currentSpellbookId = JsonGetInt(JsonArrayGet(currentCircle, i)); + if (currentSpellbookId == spellbookId) + return "You cannot replace spells as this class."; + } + + } + + if (GetIsBladeMagicClass(nClass)) + { + int prereqs = StringToInt(Get2DACache(sFile, "Prereqs", spellbookId)); + string discipline = Get2DACache(sFile, "Discipline", spellbookId); + // if the maneuver is required for others to exist, t hen disable it + if (IsRequiredForOtherManeuvers(nClass, prereqs, discipline, oPC)) + return "This maneuver is required for another maneuver."; + // if it is required for a PRC to exist, then disable it. + if (IsRequiredForToBPRCClass(nClass, spellbookId, oPC)) + return "This maneuver is reuquired for a PRC class."; + } + + if (GetIsInvocationClass(nClass)) + { + // dragon Shamans can't replace + if (nClass == CLASS_TYPE_DRAGON_SHAMAN) + { + json invokKnown = GetSpellIDsKnown(nClass, oPC); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + json chosenSpell = JsonObjectGet(invokKnown, spellId); + if (chosenSpell != JsonNull()) + return "You cannot replace invocations as this class."; + } + } + + // If we do not use the bioware unlearn system, we follow PnP + if (!GetPRCSwitch(PRC_BIO_UNLEARN)) + { + json knownSpells = GetKnownSpellListObject(nClass, oPC); + json currentCircle = JsonObjectGet(knownSpells, IntToString(circleLevel)); + int totalSpells = JsonGetLength(currentCircle); + int i; + for (i = 0; i < totalSpells; i++) + { + int currentSpellbookId = JsonGetInt(JsonArrayGet(currentCircle, i)); + // if the spell belongs to the known spell list, then we need to determine + if (currentSpellbookId == spellbookId) + { + json unlearnList = GetChosenReplaceListObject(oPC); + int totalUnlearned = JsonGetLength(unlearnList); + int totalAllowed = GetPRCSwitch(PRC_UNLEARN_SPELL_MAXNR); + // we default to 1 if no max number of unlearns is set + if (!totalAllowed) + totalAllowed = 1; + // we cannot replace a spell if we have more than or equal to the + // amount of relearns allowed, therefore disable. + if (totalUnlearned < totalAllowed) + return ""; + return "You can only replace " + IntToString(totalAllowed) + " spells during level up."; + } + } + + } + + return ""; +} + +json GetExpandedChoicesList(int nClass, object oPC=OBJECT_SELF) +{ + json expandedChoices = GetLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR); + if (expandedChoices != JsonNull()) + return expandedChoices; + + if (GetIsPsionicClass(nClass)) + expandedChoices = GetSpellIDsKnown(nClass, oPC, POWER_LIST_EXP_KNOWLEDGE); + else + expandedChoices = GetSpellIDsKnown(nClass, oPC, INVOCATION_LIST_EXTRA); + + SetLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR, expandedChoices); + return expandedChoices; +} + +int GetRemainingExpandedChoices(int nClass, int nList, object oPC=OBJECT_SELF) +{ + int remainingChoices = 0; + + json expandedList = (nList == INVOCATION_LIST_EXTRA || nList == POWER_LIST_EXP_KNOWLEDGE ) ? GetExpandedChoicesList(nClass, oPC) + : GetEpicExpandedChoicesList(nClass, oPC); + int expChoicesCount = JsonGetLength(JsonObjectKeys(expandedList)); + int maxExpChoices = (GetIsPsionicClass(nClass)) ? GetMaxPowerCount(oPC, nList) + : GetMaxInvocationCount(oPC, nList); + remainingChoices += (maxExpChoices - expChoicesCount); + + return remainingChoices; +} + +json GetEpicExpandedChoicesList(int nClass, object oPC=OBJECT_SELF) +{ + json expandedChoices = GetLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR); + if (expandedChoices != JsonNull()) + return expandedChoices; + + if (GetIsPsionicClass(nClass)) + expandedChoices = GetSpellIDsKnown(nClass, oPC, POWER_LIST_EPIC_EXP_KNOWLEDGE); + else + expandedChoices = GetSpellIDsKnown(nClass, oPC, INVOCATION_LIST_EXTRA_EPIC); + + SetLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR, expandedChoices); + return expandedChoices; +} + +int IsSpellInExpandedChoices(int nClass, int nList, int spellId, object oPC=OBJECT_SELF) +{ + json expList = (nList == POWER_LIST_EXP_KNOWLEDGE || nList == INVOCATION_LIST_EXTRA) ? GetExpandedChoicesList(nClass, oPC) + : GetEpicExpandedChoicesList(nClass, oPC); + + return (JsonObjectGet(expList, IntToString(spellId)) != JsonNull()); +} + +json GetChosenReplaceListObject(object oPC=OBJECT_SELF) +{ + json replaceList = GetLocalJson(oPC, NUI_LEVEL_UP_RELEARN_LIST_VAR); + if (replaceList == JsonNull()) + replaceList = JsonObject(); + else + return replaceList; + + SetLocalJson(oPC, NUI_LEVEL_UP_RELEARN_LIST_VAR, replaceList); + return replaceList; +} + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Psionics /// +/// /// +//////////////////////////////////////////////////////////////////////////// + + +int IsExpKnowledgePower(int nClass, int spellbookId) +{ + string sFile = GetClassSpellbookFile(nClass); + int isExp = StringToInt(Get2DACache(sFile, "Exp", spellbookId)); + return isExp; +} + +json GetCurrentPowerList(object oPC=OBJECT_SELF) +{ + json retValue = GetLocalJson(oPC, NUI_LEVEL_UP_POWER_LIST_VAR); + if (retValue == JsonNull()) + retValue = JsonArray(); + else + return retValue; + + SetLocalJson(oPC, NUI_LEVEL_UP_POWER_LIST_VAR, retValue); + return retValue; +} + +int ShouldAddPower(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + int featId = StringToInt(Get2DACache(sFile, "FeatID", spellbookId)); + int isExp = StringToInt(Get2DACache(sFile, "Exp", spellbookId)); + // if you don't have the prereqs for a power then don't add it. Specific for + // psions + if (!CheckPowerPrereqs(featId, oPC)) + return FALSE; + // if the power is a expanded knowledge power + if (isExp) + { + // and we have a expanded knowledge choice left to make then show + // the button + int addPower = FALSE; + int maxLevel = GetMaxPowerLevelForClass(nClass, oPC); + int currentCircle = GetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CIRCLE_VAR); + + int choicesLeft = GetRemainingExpandedChoices(nClass, POWER_LIST_EXP_KNOWLEDGE, oPC); + if (choicesLeft && (currentCircle <= (maxLevel-1))) + addPower = TRUE; + choicesLeft = GetRemainingExpandedChoices(nClass, POWER_LIST_EPIC_EXP_KNOWLEDGE, oPC); + if (choicesLeft) + addPower = TRUE; + // otherwise don't show the button. + return addPower; + } + + return TRUE; +} + +void LearnPowers(int nClass, object oPC=OBJECT_SELF) +{ + // add normal powers + json powerList = GetCurrentPowerList(oPC); + int totalPowers = JsonGetLength(powerList); + int i; + for (i = 0; i < totalPowers; i++) + { + int nSpellbookID = JsonGetInt(JsonArrayGet(powerList, i)); + // get the expanded knowledge list we are adding to if any + int expKnow = GetExpKnowledgePowerListRequired(nClass, nSpellbookID, oPC); + AddPowerKnown(oPC, nClass, nSpellbookID, TRUE, GetManifesterLevel(oPC, nClass, TRUE), expKnow); + } +} + +int GetExpKnowledgePowerListRequired(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + + int i; + // expanded knowledge is -1, epic epxanded knowledge is -2 + for (i = -1; i >= -2; i--) + { + int spellId = StringToInt(Get2DACache(sFile, "SpellID", spellbookId)); + if (IsSpellInExpandedChoices(nClass, i, spellId, oPC)) + return i; + } + + return 0; +} + +int GetMaxPowerLevelForClass(int nClass, object oPC=OBJECT_SELF) +{ + string sFile = GetAMSKnownFileName(nClass); + int nLevel = GetManifesterLevel(oPC, nClass, TRUE); + // index is level - 1 since it starts at 0. + int maxLevel = StringToInt(Get2DACache(sFile, "MaxPowerLevel", nLevel-1)); + return maxLevel; +} + +int GetRemainingPowerChoices(int nClass, int chosenCircle, object oPC=OBJECT_SELF, int extra=TRUE) +{ + int remaining = 0; + + int maxLevel = GetMaxPowerLevelForClass(nClass, oPC); + if (chosenCircle > maxLevel) + return 0; + + json choices = GetCurrentPowerList(oPC); + int totalChoices = JsonGetLength(choices); + int allowedChoices = GetMaxPowerCount(oPC, nClass); + int alreadyChosen = GetPowerCount(oPC, nClass); + string sFile = GetClassSpellbookFile(nClass); + + int i = 0; + for (i = 0; i < totalChoices; i++) + { + int spellbookId = JsonGetInt(JsonArrayGet(choices, i)); + int spellId = StringToInt(Get2DACache(sFile, "SpellID", spellbookId)); + //if the power is a expanded knowledge choice, don't count it + if (!IsSpellInExpandedChoices(nClass, POWER_LIST_EXP_KNOWLEDGE, spellId, oPC) + && !IsSpellInExpandedChoices(nClass, POWER_LIST_EPIC_EXP_KNOWLEDGE, spellId, oPC)) + remaining++; + } + remaining = (allowedChoices - remaining - alreadyChosen); + + // if this is true we count expanded knowledge choices + if (extra) + { + if (GetHasFeat(FEAT_EXPANDED_KNOWLEDGE_1, oPC) && (chosenCircle <= (maxLevel-1))) + { + int totalExp = GetMaxPowerCount(oPC, POWER_LIST_EXP_KNOWLEDGE); + json expChoices = GetExpandedChoicesList(nClass, oPC); + int choicesCount = JsonGetLength(JsonObjectKeys(expChoices)); + remaining += (totalExp - choicesCount); + } + if (GetHasFeat(FEAT_EPIC_EXPANDED_KNOWLEDGE_1, oPC)) + { + int totalExp = GetMaxPowerCount(oPC, POWER_LIST_EPIC_EXP_KNOWLEDGE); + json expChoices = GetEpicExpandedChoicesList(nClass, oPC); + int choicesCount = JsonGetLength(JsonObjectKeys(expChoices)); + remaining += (totalExp - choicesCount); + } + } + + return remaining; +} + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Initiators /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +json GetDisciplineInfoObject(int nClass, object oPC=OBJECT_SELF) +{ + json disciplineInfo = GetLocalJson(oPC, NUI_LEVEL_UP_DISCIPLINE_INFO_VAR + IntToString(nClass)); + if (disciplineInfo == JsonNull()) + disciplineInfo = JsonObject(); + else + return disciplineInfo; + + int chosenClass = GetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CLASS_VAR); + string sFile = GetClassSpellbookFile(nClass); + + //if this is not the chosen class then we do not have a chosen spell list + // need to go through the class's 2da and check if you know the spell or not. + if (nClass != chosenClass) + { + int totalSpells = Get2DARowCount(sFile); + + int i; + for (i = 0; i < totalSpells; i++) + { + int featId = StringToInt(Get2DACache(sFile, "FeatID", i)); + if (featId && GetHasFeat(featId, oPC, TRUE)) + disciplineInfo = AddSpellDisciplineInfo(sFile, i, disciplineInfo); + } + } + else + { + json chosenMans = GetChosenSpellListObject(nClass, oPC); + + json circles = JsonObjectKeys(chosenMans); + int totalCircles = JsonGetLength(circles); + + int i; + for (i = 0; i < totalCircles; i++) + { + string currentCircle = JsonGetString(JsonArrayGet(circles, i)); + json currentList = JsonObjectGet(chosenMans, currentCircle); + int totalSpells = JsonGetLength(currentList); + + int y; + for (y = 0; y < totalSpells; y++) + { + int spellbookId = JsonGetInt(JsonArrayGet(currentList, y)); + disciplineInfo = AddSpellDisciplineInfo(sFile, spellbookId, disciplineInfo); + } + } + } + + SetLocalJson(oPC, NUI_LEVEL_UP_DISCIPLINE_INFO_VAR + IntToString(nClass), disciplineInfo); + return disciplineInfo; +} + +int IsRequiredForOtherManeuvers(int nClass, int prereq, string discipline, object oPC=OBJECT_SELF) +{ + json discInfo = GetDisciplineInfoObject(nClass, oPC); + + int total = 0; + + // loop through each prereq level and add up it's totals (ie how many maneuevrs + // do we know with 0,1,2...,n prereqs. + int i; + for (i = 0; i <= prereq; i++) + { + + json currDisc = JsonObjectGet(discInfo, discipline); + string discKey = ("Prereq_" + IntToString(i)); + int currentDiscPrereq = JsonGetInt(JsonObjectGet(currDisc, discKey)); + total += currentDiscPrereq; + } + + // then from above the given prereq check if we have any prereq maneuevers taken + for (i = (prereq+1); i < NUI_LEVEL_UP_MANEUVER_PREREQ_LIMIT; i++) + { + json currDisc = JsonObjectGet(discInfo, discipline); + string discKey = ("Prereq_" + IntToString(i)); + json discPrereq = JsonObjectGet(currDisc, discKey); + if (discPrereq != JsonNull()) + { + // if we do take the total and subtract by one, if it is lower than + // than the prereq needed, it is required + if (total - 1 < i) + return TRUE; + + // otherwise add how many we have and move up and keep trying. + int currentDiscPrereq = JsonGetInt(discPrereq); + total += currentDiscPrereq; + } + } + + return FALSE; +} + +int HasPreRequisitesForManeuver(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + int prereqs = StringToInt(Get2DACache(sFile, "Prereqs", spellbookId)); + if (!prereqs) + return TRUE; + string discipline = Get2DACache(sFile, "Discipline", spellbookId); + json discInfo = GetDisciplineInfoObject(nClass, oPC); + json chosenDisc = JsonObjectGet(discInfo, discipline); + if (chosenDisc != JsonNull()) + { + int nManCount = (JsonGetInt(JsonObjectGet(chosenDisc, IntToString(MANEUVER_TYPE_MANEUVER))) + + JsonGetInt(JsonObjectGet(chosenDisc, IntToString(MANEUVER_TYPE_STANCE)))); + if (nManCount >= prereqs) + return TRUE; + } + + return FALSE; +} + +int GetMaxInitiatorCircle(int nClass, object oPC=OBJECT_SELF) +{ + int initiatorLevel = GetInitiatorLevel(oPC, nClass); + // initiators learn by ceiling(classLevel) + int highestCircle = (initiatorLevel + 1) / 2; + if (highestCircle > 9) + return 9; + return highestCircle; +} + +int GetRemainingManeuverChoices(int nClass, object oPC=OBJECT_SELF) +{ + json discInfo = GetDisciplineInfoObject(nClass, oPC); + + json jManAmount = JsonObjectGet(discInfo, NUI_LEVEL_UP_MANEUVER_TOTAL); + int nManAmount = 0; + if (jManAmount != JsonNull()) + nManAmount = JsonGetInt(jManAmount); + + int maxAmount = GetMaxManeuverCount(oPC, nClass, MANEUVER_TYPE_MANEUVER); + + return maxAmount - nManAmount; +} + +int GetRemainingStanceChoices(int nClass, object oPC=OBJECT_SELF) +{ + json discInfo = GetDisciplineInfoObject(nClass, oPC); + + json jStanceAmount = JsonObjectGet(discInfo, NUI_LEVEL_UP_STANCE_TOTAL); + int nStanceAmount = 0; + if (jStanceAmount != JsonNull()) + nStanceAmount = JsonGetInt(jStanceAmount); + + int maxAmount = GetMaxManeuverCount(oPC, nClass, MANEUVER_TYPE_STANCE); + + return maxAmount - nStanceAmount; +} + +int IsAllowedDiscipline(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + // logic carried over from private function in discipline inc functions + // uses bitwise matching to tell if the discipline is allowed or not + string sFile = GetClassSpellbookFile(nClass); + int discipline = StringToInt(Get2DACache(sFile, "Discipline", spellbookId)); + + int nOverride = GetPersistantLocalInt(oPC, "AllowedDisciplines"); + if(nOverride == 0) + { + switch(nClass) + { + case CLASS_TYPE_CRUSADER: nOverride = 322; break;//DISCIPLINE_DEVOTED_SPIRIT + DISCIPLINE_STONE_DRAGON + DISCIPLINE_WHITE_RAVEN + case CLASS_TYPE_SWORDSAGE: nOverride = 245; break;//DISCIPLINE_DESERT_WIND + DISCIPLINE_DIAMOND_MIND + DISCIPLINE_SETTING_SUN + DISCIPLINE_SHADOW_HAND + DISCIPLINE_STONE_DRAGON + DISCIPLINE_TIGER_CLAW + case CLASS_TYPE_WARBLADE: nOverride = 460; break;//DISCIPLINE_DIAMOND_MIND + DISCIPLINE_IRON_HEART + DISCIPLINE_STONE_DRAGON + DISCIPLINE_TIGER_CLAW + DISCIPLINE_WHITE_RAVEN + } + } + return nOverride & discipline; +} + +int IsRequiredForToBPRCClass(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + int currentClassPos = 1; + // loop through all the classes and look for a PRC + while (currentClassPos) + { + int currentClass = GetClassByPosition(currentClassPos, oPC); + // if we reached a non existant class, we reached the end. + if (currentClass != CLASS_TYPE_INVALID) + { + string sFile = GetClassSpellbookFile(nClass); + int discipline = StringToInt(Get2DACache(sFile, "Discipline", spellbookId)); + + // check if the class is a ToB PRC Class and if the current spell's + // discipline is used for it. + int isUsed = FALSE; + if (currentClass == CLASS_TYPE_DEEPSTONE_SENTINEL + && (discipline == DISCIPLINE_STONE_DRAGON)) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_BLOODCLAW_MASTER + && (discipline == DISCIPLINE_TIGER_CLAW)) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_RUBY_VINDICATOR + && (discipline == DISCIPLINE_DEVOTED_SPIRIT)) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_JADE_PHOENIX_MAGE) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_MASTER_OF_NINE) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_ETERNAL_BLADE + && (discipline == DISCIPLINE_DEVOTED_SPIRIT + || discipline == DISCIPLINE_DIAMOND_MIND)) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_SHADOW_SUN_NINJA + && (discipline == DISCIPLINE_SETTING_SUN + || discipline == DISCIPLINE_SHADOW_HAND)) + isUsed = TRUE; + + // if any of the above was true than we need to check if this spell + // is required for a PRC + if (isUsed) + { + // get the discipline info for all BladeMagic classes if we have them. + json discInfo = GetDisciplineInfoObject(nClass, oPC); + json classDisc2Info = JsonObject(); + json classDisc3Info = JsonObject(); + if (nClass == CLASS_TYPE_SWORDSAGE) + { + if (GetLevelByClass(CLASS_TYPE_WARBLADE, oPC)) + classDisc2Info = GetDisciplineInfoObject(CLASS_TYPE_WARBLADE, oPC); + if (GetLevelByClass(CLASS_TYPE_CRUSADER, oPC)) + classDisc3Info = GetDisciplineInfoObject(CLASS_TYPE_CRUSADER, oPC); + } + if (nClass == CLASS_TYPE_CRUSADER) + { + if (GetLevelByClass(CLASS_TYPE_WARBLADE, oPC)) + classDisc2Info = GetDisciplineInfoObject(CLASS_TYPE_WARBLADE, oPC); + if (GetLevelByClass(CLASS_TYPE_SWORDSAGE, oPC)) + classDisc3Info = GetDisciplineInfoObject(CLASS_TYPE_SWORDSAGE, oPC); + } + if (nClass == CLASS_TYPE_WARBLADE) + { + if (GetLevelByClass(CLASS_TYPE_CRUSADER, oPC)) + classDisc2Info = GetDisciplineInfoObject(CLASS_TYPE_CRUSADER, oPC); + if (GetLevelByClass(CLASS_TYPE_SWORDSAGE, oPC)) + classDisc3Info = GetDisciplineInfoObject(CLASS_TYPE_SWORDSAGE, oPC); + } + + // Time to begin checking the PRCs + // this should follow the same logic as here + // https://gitea.raptio.us/Jaysyn/PRC8/src/commit/797442d3da7c9c8e1fcf585b97e2ff1cbe56045b/nwn/nwnprc/trunk/scripts/prc_prereq.nss#L991 + + // Check Deepstone Sentinel + if (currentClass == CLASS_TYPE_DEEPSTONE_SENTINEL) + { + // we need to look for 2 Stone Dragon Maneuvers and 1 Stone Dragon + // Stance. So add up the other MagicBlade classes and see if it is satisfied. + int stoneDMan, stoneDStance = 0; + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stoneDMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + stoneDStance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + if (stoneDMan >= 2 && stoneDStance >= 1) + return FALSE; + } + + currentDisc = JsonObjectGet(classDisc3Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stoneDMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + stoneDStance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + if (stoneDMan >= 2 && stoneDStance >= 1) + return FALSE; + } + // if it still isn't satisfied than the current class is required + // for it to exist. Check to see if it is safe to remove the maneuever + currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stoneDMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + stoneDStance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + int type = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + //if the current maneuver is a stance, check to see if it is safe to remove + if (type == MANEUVER_TYPE_STANCE) + { + if (stoneDStance - 1 >= 1) + return FALSE; + } + else + { + // if it is not a stance we can just check the maneuevers in general + if (stoneDMan - 1 >= 2) + return FALSE; + } + + // this maneuver is required and should not be removed. + return TRUE; + } + } + + // Check Bloodclaw Master + if (currentClass == CLASS_TYPE_BLOODCLAW_MASTER) + { + // bloodclaw needs 3 Tiger Claw maneuevers + int tigerCMan = 0; + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + if (tigerCMan >= 3) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + if (tigerCMan >= 3) + return FALSE; + } + currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + if (tigerCMan-1 >= 3) + return FALSE; + return TRUE; + } + } + + if (currentClass == CLASS_TYPE_RUBY_VINDICATOR) + { + // Ruby Vindicator needs 1 stance and 1 maneuever from Devoted Spirit + int stance = 0; + int maneuver = 0; + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + if (stance >= 1 && maneuver >= 1) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + if (stance >= 1 && maneuver >= 1) + return FALSE; + } + currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + int type = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + if (type == MANEUVER_TYPE_STANCE) + { + if (stance - 1 >= 1) + return FALSE; + return TRUE; + } + if (maneuver - 1 >= 1) + return FALSE; + return TRUE; + } + } + + if (currentClass == CLASS_TYPE_JADE_PHOENIX_MAGE) + { + // Jade Phoenix needs 1 stance and 2 maneuvers of any type + int stance = 0; + int maneuver = 0; + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + if (stance >= 1 && maneuver >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + if (stance >= 1 && maneuver >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + int type = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + if (type == MANEUVER_TYPE_STANCE) + { + if ((stance - 1 >= 1) && (maneuver -1 >= 2)) + return FALSE; + return TRUE; + } + if (maneuver - 1 >= 2) + return FALSE; + return TRUE; + } + } + + if (currentClass == CLASS_TYPE_MASTER_OF_NINE) + { + // master of nine needs 1 maneuever from 6 different disciplines + + int totalDiscCount = 0; + int currentClassAndDiscUsed = 0; + int i; + // loop through each possible discipline + for (i = 0; i <= 256; i++) + { + int found = 0; + // only disciplines that exist are stored, and only those + // that are used are stored, so we can loop through and + // find what disciplines we do or don't know. + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(i)); + if (currentDisc != JsonNull()) + found = 1; + + if (!found) + { + json currentDisc = JsonObjectGet(classDisc3Info, IntToString(i)); + if (currentDisc != JsonNull()) + found = 1; + } + + if (!found) + { + json currentDisc = JsonObjectGet(discInfo, IntToString(i)); + if (currentDisc != JsonNull()) + { + if (i == discipline) + currentClassAndDiscUsed = 1; + found = 1; + } + } + + totalDiscCount += found; + } + // if we have more maneuevers than 6, it is not required + if (totalDiscCount > 6) + return FALSE; + // however if we have 6 and this discipline was grabbed we need to make sure it is safe to remove + if (currentClassAndDiscUsed) + { + // if we were to remove this discipline and it is 5 or less total disciplines we have now + // it is important + if (totalDiscCount - 1 >= 6) + return FALSE; + json currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + int stance = JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + int maneuver = JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + // if we were to remove this discipline and are left with no more than + // this was important and it can't be removed + if ((stance + maneuver - 1) >= 1) + return FALSE; + return TRUE; + } + return FALSE; + } + + if (currentClass == CLASS_TYPE_ETERNAL_BLADE) + { + //Eternal blade 2 Devoted Spirits OR 2 Diamond Mind + int nTotal = 0; + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(DISCIPLINE_DEVOTED_SPIRIT)); + if (currentDisc != JsonNull()) + { + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nTotal >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc2Info, IntToString(DISCIPLINE_DIAMOND_MIND)); + if (currentDisc != JsonNull()) + { + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nTotal >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(DISCIPLINE_DEVOTED_SPIRIT)); + if (currentDisc != JsonNull()) + { + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nTotal >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(DISCIPLINE_DIAMOND_MIND)); + if (currentDisc != JsonNull()) + { + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nTotal >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + if ((nTotal - 1) >= 2) + return FALSE; + return TRUE; + } + } + + if (currentClass == CLASS_TYPE_SHADOW_SUN_NINJA) + { + // Shadow Sun Ninja needs 1 lvl2 Setting Sun OR Shadow Hand maneuever + // 1 Setting Sun maneuver AND 1 Shadow Hand maneuver + int nLvl2 = 0; + int shadowHTotal; + int settingSTotal; + + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(DISCIPLINE_SHADOW_HAND)); + if (currentDisc != JsonNull()) + { + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nLvl2 && shadowHTotal && settingSTotal && (shadowHTotal >= 2 || settingSTotal >= 2)) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc2Info, IntToString(DISCIPLINE_SETTING_SUN)); + if (currentDisc != JsonNull()) + { + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nLvl2 && shadowHTotal && settingSTotal && (shadowHTotal >= 2 || settingSTotal >= 2)) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(DISCIPLINE_SHADOW_HAND)); + if (currentDisc != JsonNull()) + { + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nLvl2 && shadowHTotal && settingSTotal && (shadowHTotal >= 2 || settingSTotal >= 2)) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc2Info, IntToString(DISCIPLINE_SETTING_SUN)); + if (currentDisc != JsonNull()) + { + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nLvl2 && shadowHTotal && settingSTotal && (shadowHTotal >= 2 || settingSTotal >= 2)) + return FALSE; + } + currentDisc = JsonObjectGet(discInfo, IntToString(DISCIPLINE_SHADOW_HAND)); + if (currentDisc != JsonNull()) + { + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + } + currentDisc = JsonObjectGet(discInfo, IntToString(DISCIPLINE_SETTING_SUN)); + if (currentDisc != JsonNull()) + { + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + } + int level = StringToInt(Get2DACache(sFile, "Level", spellbookId)); + if (level == 2) + nLvl2 -= 1; + if (discipline == DISCIPLINE_SHADOW_HAND) + shadowHTotal -= 1; + else + settingSTotal -= 1; + + return !(nLvl2 && shadowHTotal && settingSTotal && (shadowHTotal >= 2 || settingSTotal >= 2)); + } + } + + currentClassPos += 1; + } + else + currentClassPos = 0; + } + + return FALSE; +} + +json AddSpellDisciplineInfo(string sFile, int spellbookId, json classDisc) +{ + json classDiscCopy = classDisc; + int discipline = StringToInt(Get2DACache(sFile, "Discipline", spellbookId)); + int type = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + int level = StringToInt(Get2DACache(sFile, "Level", spellbookId)); + int prereq = StringToInt(Get2DACache(sFile, "Prereqs", spellbookId)); + + json jDisc = JsonObjectGet(classDisc, IntToString(discipline)); + if (jDisc == JsonNull()) + jDisc = JsonObject(); + + string levelKey = "Level" + IntToString(level) + "_" + IntToString(type); + int nTypeTotal = (JsonGetInt(JsonObjectGet(jDisc, levelKey)) + 1); + jDisc = JsonObjectSet(jDisc, levelKey, JsonInt(nTypeTotal)); + + nTypeTotal = (JsonGetInt(JsonObjectGet(jDisc, IntToString(type))) + 1); + jDisc = JsonObjectSet(jDisc, IntToString(type), JsonInt(nTypeTotal)); + + if (type != MANEUVER_TYPE_MANEUVER + && type != MANEUVER_TYPE_STANCE) + { + levelKey = "Level" + IntToString(level) + "_" + IntToString(MANEUVER_TYPE_MANEUVER); + nTypeTotal = (JsonGetInt(JsonObjectGet(jDisc, levelKey)) + 1); + jDisc = JsonObjectSet(jDisc, levelKey, JsonInt(nTypeTotal)); + + nTypeTotal = (JsonGetInt(JsonObjectGet(jDisc, IntToString(MANEUVER_TYPE_MANEUVER))) + 1); + jDisc = JsonObjectSet(jDisc, IntToString(MANEUVER_TYPE_MANEUVER), JsonInt(nTypeTotal)); + } + + string prereqKey = "Prereq_" + IntToString(prereq); + int nPrereqTotal = (JsonGetInt(JsonObjectGet(jDisc, prereqKey)) + 1); + jDisc = JsonObjectSet(jDisc, prereqKey, JsonInt(nPrereqTotal)); + + if (type == MANEUVER_TYPE_STANCE) + { + nTypeTotal = (JsonGetInt(JsonObjectGet(classDisc, NUI_LEVEL_UP_STANCE_TOTAL)) + 1); + classDiscCopy = JsonObjectSet(classDiscCopy, NUI_LEVEL_UP_STANCE_TOTAL, JsonInt(nTypeTotal)); + } + else + { + nTypeTotal = (JsonGetInt(JsonObjectGet(classDisc, NUI_LEVEL_UP_MANEUVER_TOTAL)) + 1); + classDiscCopy = JsonObjectSet(classDiscCopy, NUI_LEVEL_UP_MANEUVER_TOTAL, JsonInt(nTypeTotal)); + } + + return JsonObjectSet(classDiscCopy, IntToString(discipline), jDisc); +} + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Invokers /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +json GetInvokerKnownListObject(int nClass, object oPC=OBJECT_SELF) +{ + json knownObject = GetLocalJson(oPC, NUI_LEVEL_UP_KNOWN_INVOCATIONS_CACHE_VAR + IntToString(nClass)); + if (knownObject == JsonNull()) + knownObject = JsonObject(); + else + return knownObject; + + string sFile = GetAMSKnownFileName(nClass); + int totalRows = Get2DARowCount(sFile); + int maxInvocLevel = StringToInt(Get2DACache(sFile, "MaxInvocationLevel", totalRows-1)); + json previousInvocList = JsonObject(); + + int i; + for (i = 1; i <= maxInvocLevel; i++) + { + previousInvocList = JsonObjectSet(previousInvocList, IntToString(i), JsonInt(0)); + } + + for (i = 0; i < totalRows; i++) + { + int maxInvocation = StringToInt(Get2DACache(sFile, "MaxInvocationLevel", i)); + int invocationKnown = StringToInt(Get2DACache(sFile, "InvocationKnown", i)); + json invocList = previousInvocList; + + int previousInvocTotal = 0; + if (i > 0) + previousInvocTotal = StringToInt(Get2DACache(sFile, "InvocationKnown", i-1)); + int previousInvocAmount = JsonGetInt(JsonObjectGet(previousInvocList, IntToString(maxInvocation))); + int currentInvocationAmount = (invocationKnown - previousInvocTotal + previousInvocAmount); + + invocList = JsonObjectSet(invocList, IntToString(maxInvocation), JsonInt(currentInvocationAmount)); + knownObject = JsonObjectSet(knownObject, IntToString(i+1), invocList); + previousInvocList = invocList; + } + + SetLocalJson(oPC, NUI_LEVEL_UP_KNOWN_INVOCATIONS_CACHE_VAR + IntToString(nClass), knownObject); + return knownObject; +} + +int GetRemainingInvocationChoices(int nClass, int chosenCircle, object oPC=OBJECT_SELF, int extra=TRUE) +{ + int remaining = 0; + int nLevel = GetInvokerLevel(oPC, nClass); + + json knownObject = GetInvokerKnownListObject(nClass, oPC); + json chosenInv = GetChosenSpellListObject(nClass, oPC); + json currentLevelKnown = JsonObjectGet(knownObject, IntToString(nLevel)); + + int totalCircles = JsonGetLength(JsonObjectKeys(currentLevelKnown)); + + // logic goes we are given a set amount of invocations at each circle. We can + // take from a circle above us, but not below us. So we need to make sure + // we have a legal amount of choices + int i; + for (i = 1; i <= totalCircles; i++) + { + int currentChosen = 0; + json chosenSpells = JsonObjectGet(chosenInv, IntToString(i)); + if (chosenSpells != JsonNull()) + { + int totalChosen = JsonGetLength(chosenSpells); + int j; + for (j = 0; j < totalChosen; j++) + { + int spellbookId = JsonGetInt(JsonArrayGet(chosenSpells, j)); + // only count non extra invocation choices + if (!IsExtraChoiceInvocation(nClass, spellbookId, oPC)) + currentChosen += 1; + } + } + + int allowedAtCircle = JsonGetInt(JsonObjectGet(currentLevelKnown, IntToString(i))); + + remaining = (allowedAtCircle - currentChosen + remaining); + // if the circle is below the chosen circle and we have a positive remaining, + // we set it to 0 because we cannot use lower circle spells on higher circle. + // however if thge value is negative then we carry it over because we + // have a deficit and need to account for it by using the spells of the + // next circle. + if (i < chosenCircle && remaining > 0) + remaining = 0; + } + + + // count extra and epic invocation choices + if (extra) + { + string sFile = GetAMSKnownFileName(nClass); + int maxCircle = StringToInt(Get2DACache(sFile, "MaxInvocationLevel", nLevel-1)); + + if (GetHasFeat(FEAT_EXTRA_INVOCATION_I, oPC) && (chosenCircle <= (maxCircle-1))) + { + int totalExp = GetMaxInvocationCount(oPC, INVOCATION_LIST_EXTRA); + json expChoices = GetExpandedChoicesList(nClass, oPC); + int choicesCount = JsonGetLength(JsonObjectKeys(expChoices)); + remaining += (totalExp - choicesCount); + } + if (GetHasFeat(FEAT_EPIC_EXTRA_INVOCATION_I, oPC)) + { + int totalExp = GetMaxInvocationCount(oPC, INVOCATION_LIST_EXTRA_EPIC); + json expChoices = GetEpicExpandedChoicesList(nClass, oPC); + int choicesCount = JsonGetLength(JsonObjectKeys(expChoices)); + remaining += (totalExp - choicesCount); + } + } + + return remaining; +} + +int IsExtraChoiceInvocation(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + json extraChoices = GetExpandedChoicesList(nClass, oPC); + json chosenSpell = JsonObjectGet(extraChoices, spellId); + if (chosenSpell != JsonNull()) + return TRUE; + + extraChoices = GetEpicExpandedChoicesList(nClass, oPC); + chosenSpell = JsonObjectGet(extraChoices, spellId); + if (chosenSpell != JsonNull()) + return TRUE; + + return FALSE; +} + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Truenamer /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +int GetRemainingTruenameChoices(int nClass, int nType, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + json circles = JsonObjectKeys(chosenSpells); + int totalCircles = JsonGetLength(circles); + + int remainingChoices = 0; + + int i; + for (i = 0; i < totalCircles; i++) + { + json spellList = JsonObjectGet(chosenSpells, JsonGetString(JsonArrayGet(circles, i))); + if (spellList != JsonNull()) + { + int totalChoices = JsonGetLength(spellList); + + int j; + for (j = 0; j < totalChoices; j++) + { + int spellbookId = JsonGetInt(JsonArrayGet(spellList, j)); + int lexicon = StringToInt(Get2DACache(sFile, "Lexicon", spellbookId)); + // -1 means count all lexicons + if (nType == -1 || lexicon == nType) + remainingChoices += 1; + } + } + } + + int maxChoices; + // if -1 we count all lexicons to get total remaining + if (nType == -1) + maxChoices = (GetMaxUtteranceCount(oPC, nClass, LEXICON_CRAFTED_TOOL) + + GetMaxUtteranceCount(oPC, nClass, LEXICON_EVOLVING_MIND) + + GetMaxUtteranceCount(oPC, nClass, LEXICON_PERFECTED_MAP)); + else + maxChoices = GetMaxUtteranceCount(oPC, nClass, nType); + return (maxChoices - remainingChoices); +} + +int GetLexiconCircleKnownAtLevel(int nLevel, int nType) +{ + + string sFile = "cls_true_maxlvl"; + + string columnName; + if (nType == LEXICON_EVOLVING_MIND) + columnName = "EvolvingMind"; + else if (nType == LEXICON_CRAFTED_TOOL) + columnName = "CraftedTool"; + else + columnName = "PerfectedMap"; + + return StringToInt(Get2DACache(sFile, columnName, nLevel-1)); +} + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Archivist /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +json GetArchivistNewSpellsList(object oPC=OBJECT_SELF) +{ + json retValue = GetLocalJson(oPC, NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR); + if (retValue == JsonNull()) + retValue = JsonArray(); + else + return retValue; + + SetLocalJson(oPC, NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR, retValue); + return retValue; +} + +//:: void main(){} \ No newline at end of file diff --git a/src/include/prc_nui_sb_inc.nss b/src/include/prc_nui_sb_inc.nss index a1a768e..7148413 100644 --- a/src/include/prc_nui_sb_inc.nss +++ b/src/include/prc_nui_sb_inc.nss @@ -10,10 +10,8 @@ //:: Created By: Rakiov //:: Created On: 24.05.2005 //::////////////////////////////////////////////// -#include "inc_newspellbook" -#include "psi_inc_psifunc" -#include "inc_lookups" -#include "prc_nui_consts" + +#include "prc_nui_com_inc" // // GetSpellListForCircle @@ -43,69 +41,6 @@ json GetSpellListForCircle(object oPlayer, int nClass, int circle); // json GetSupportedNUISpellbookClasses(object oPlayer); -// -// GetCurrentSpellLevel -// Gets the current spell level the class can achieve at the current -// caster level (ranging from 0-9) -// -// Arguments: -// nClass:int the ClassID -// nLevel:int the caster level -// -// Returns: -// int the circle the class can achieve currently -// -int GetCurrentSpellLevel(int nClass, int nLevel); - -// -// GetMaxSpellLevel -// Gets the highest possible circle the class can achieve (from 0-9) -// -// Arguments: -// nClass:int the ClassID -// -// Returns: -// int the highest circle that can be achieved -// -int GetMaxSpellLevel(int nClass); - -// -// GetMinSpellLevel -// Gets the lowest possible circle the class can achieve (from 0-9) -// -// Arguments: -// nClass:int the ClassID -// -// Returns: -// int the lowest circle that can be achieved -// -int GetMinSpellLevel(int nClass); - -// -// GetHighestLevelPossibleInClass -// Given a class Id this will determine what the max level of a class can be -// achieved -// -// Arguments: -// nClass:int the ClassID -// -// Returns: -// int the highest possible level the class can achieve -// -int GetHighestLevelPossibleInClass(int nClass); - -// -// GetClassSpellbookFile -// Gets the class 2da spellbook/ability for the given class Id -// -// Arguments: -// nClass:int the classID -// -// Returns: -// string the 2da file name for the spell/abilities of the ClassID -// -string GetClassSpellbookFile(int nClass); - // // IsSpellKnown // Returns whether the player with the given class, spell file, and spellbook id @@ -234,23 +169,6 @@ json GetMetaMysteryFeatList(); // int GetTrueClassIfRHD(object oPlayer, int nClass); -// -// GetBinderSpellToFeatDictionary -// Sets up the Binder Spell Dictionary that is used to match a binder's vestige -// to their feat. This is constructed based off the binder's known location of -// their feat and spell ranges in the base 2das respectivly. After constructing -// this it will be saved to the player locally as a cached result since we do -// not need to call this again. -// -// Argument: -// oPlayer:object the player -// -// Returns: -// json:Dictionary a dictionary of mapping between the SpellID -// and the FeatID of a vestige ability -// -json GetBinderSpellToFeatDictionary(object oPlayer=OBJECT_SELF); - // // ShouldAddSpell // Given a spellId and a class, determines if the spell should be added to the @@ -318,6 +236,18 @@ json GetInvokerEssenceSpellList(int nClass, object oPlayer=OBJECT_SELF); // int JsonArrayContainsInt(json list, int item); +// +// IsSpellbookNUIOpen +// Checks to see if the Spellbook NUI is open on a given player. +// +// Arguments: +// oPC:object the player +// +// Returns: +// int:Boolean TRUE if window is open, FALSE otherwise +// +int IsSpellbookNUIOpen(object oPC); + json GetSpellListForCircle(object oPlayer, int nClass, int circle) { json retValue = JsonArray(); @@ -397,86 +327,6 @@ int ShouldAddSpell(int nClass, int spellId, object oPlayer=OBJECT_SELF) return TRUE; } -json GetBinderSpellToFeatDictionary(object oPlayer=OBJECT_SELF) -{ - // a dictionary of - json binderDict = GetLocalJson(oPlayer, NUI_SPELLBOOK_BINDER_DICTIONARY_CACHE_VAR); - // if this hasn't been created, create it now. - if (binderDict == JsonNull()) - binderDict = JsonObject(); - else - return binderDict; - - // the starting row for binder spells - int spellIndex = 19070; - // the starting row for binder feats - int featIndex = 9030; - //the end of the binder spells/feats - while (spellIndex <= 19156 && featIndex <= 9104) - { - // get the SpellID tied to the feat - int spellID = StringToInt(Get2DACache("feat", "SPELLID", featIndex)); - // if the spellID matches the current index, then this is the spell - // attached to the feat - if (spellID == spellIndex) - { - binderDict = JsonObjectSet(binderDict, IntToString(spellID), JsonInt(featIndex)); - - // move to next spell/feat - featIndex++; - spellIndex++; - } - // else we have reached a subdial spell - else - { - // loop through until we reach back at spellID - while (spellIndex < spellID) - { - int masterSpell = StringToInt(Get2DACache("spells", "Master", spellIndex)); - - // add the sub radial to the dict, tied to the master's FeatID - int featId = JsonGetInt(JsonObjectGet(binderDict, IntToString(masterSpell))); - binderDict = JsonObjectSet(binderDict, IntToString(spellIndex), JsonInt(featId)); - - spellIndex++; - } - - - // some feats overlap the same FeatID, can cause this to get stuck. - // if it happens then move on - if (spellIndex > spellID) - featIndex++; - } - } - - // cache the result - SetLocalJson(oPlayer, NUI_SPELLBOOK_BINDER_DICTIONARY_CACHE_VAR, binderDict); - return binderDict; -} - -string GetClassSpellbookFile(int nClass) -{ - string sFile; - // Spontaneous casters use a specific file name structure - if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS - || nClass == CLASS_TYPE_ARCHIVIST) - { - sFile = GetFileForClass(nClass); - } - // everyone else uses this structure - else - { - sFile = GetAMSDefinitionFileName(nClass); - - if (nClass == CLASS_TYPE_BINDER) - { - sFile = "vestiges"; - } - } - - return sFile; -} - json GetSupportedNUISpellbookClasses(object oPlayer) { json retValue = JsonArray(); @@ -526,167 +376,6 @@ int IsSpellKnown(object oPlayer, int nClass, int spellId) return FALSE; } -int GetCurrentSpellLevel(int nClass, int nLevel) -{ - int currentLevel = nLevel; - - // ToB doesn't have a concept of spell levels, but still match up to it - if(nClass == CLASS_TYPE_WARBLADE - || nClass == CLASS_TYPE_SWORDSAGE - || nClass == CLASS_TYPE_CRUSADER - || nClass == CLASS_TYPE_SHADOWCASTER) - { - return 9; - } - - - // Binders don't really have a concept of spell level - if (nClass == CLASS_TYPE_BINDER - || nClass == CLASS_TYPE_DRAGON_SHAMAN) // they can only reach 1st circle - return 1; - - //Shadowsmith has no concept of spell levels - if (nClass == CLASS_TYPE_SHADOWSMITH) - return 2; - - if (nClass == CLASS_TYPE_WARLOCK - || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT) - return 4; - - // Spont casters have their own function - if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS - || nClass == CLASS_TYPE_ARCHIVIST) - { - - int maxLevel = GetMaxSpellLevelForCasterLevel(nClass, currentLevel); - return maxLevel; - } - else - { - // everyone else uses this - string spellLevel2da = GetAMSKnownFileName(nClass); - - currentLevel = nLevel - 1; // Level is 1 off of the row in the 2da - - if (nClass == CLASS_TYPE_FIST_OF_ZUOKEN - || nClass == CLASS_TYPE_PSION - || nClass == CLASS_TYPE_PSYWAR - || nClass == CLASS_TYPE_WILDER - || nClass == CLASS_TYPE_PSYCHIC_ROGUE - || nClass == CLASS_TYPE_WARMIND) - currentLevel = GetManifesterLevel(OBJECT_SELF, nClass, TRUE) - 1; - - int totalLevel = Get2DARowCount(spellLevel2da); - - // in case we somehow go over bounds just don't :) - if (currentLevel >= totalLevel) - currentLevel = totalLevel - 1; - - //Psionics have MaxPowerLevel as their column name - string columnName = "MaxPowerLevel"; - - //Invokers have MaxInvocationLevel - if (nClass == CLASS_TYPE_WARLOCK - || nClass == CLASS_TYPE_DRAGON_SHAMAN - || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT) - columnName = "MaxInvocationLevel"; - - // Truenamers have 3 sets of utterances, ranging from 1-6, EvolvingMind covers the entire range - if (nClass == CLASS_TYPE_TRUENAMER) - { - columnName = "EvolvingMind"; - spellLevel2da = "cls_true_maxlvl"; //has a different 2da we want to look at - } - - if (nClass == CLASS_TYPE_BINDER) - { - columnName = "VestigeLvl"; - spellLevel2da = "cls_bind_binder"; - } - - // ToB doesn't have a concept of this, but we don't care. - - int maxLevel = StringToInt(Get2DACache(spellLevel2da, columnName, currentLevel)); - return maxLevel; - } -} - -int GetMinSpellLevel(int nClass) -{ - // again sponts have their own function - if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS - || nClass == CLASS_TYPE_ARCHIVIST) - { - return GetMinSpellLevelForCasterLevel(nClass, GetHighestLevelPossibleInClass(nClass)); - } - else - { - if (nClass == CLASS_TYPE_FIST_OF_ZUOKEN - || nClass == CLASS_TYPE_PSION - || nClass == CLASS_TYPE_PSYWAR - || nClass == CLASS_TYPE_WILDER - || nClass == CLASS_TYPE_PSYCHIC_ROGUE - || nClass == CLASS_TYPE_WARMIND - || nClass == CLASS_TYPE_WARBLADE - || nClass == CLASS_TYPE_SWORDSAGE - || nClass == CLASS_TYPE_CRUSADER - || nClass == CLASS_TYPE_WARLOCK - || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT - || nClass == CLASS_TYPE_DRAGON_SHAMAN - || nClass == CLASS_TYPE_SHADOWCASTER - || nClass == CLASS_TYPE_SHADOWSMITH - || nClass == CLASS_TYPE_BINDER) - return 1; - - return GetCurrentSpellLevel(nClass, 1); - } - -} - -int GetMaxSpellLevel(int nClass) -{ - if (nClass == CLASS_TYPE_WILDER - || nClass == CLASS_TYPE_PSION) - return 9; - if (nClass == CLASS_TYPE_PSYCHIC_ROGUE - || nClass == CLASS_TYPE_FIST_OF_ZUOKEN - || nClass == CLASS_TYPE_WARMIND) - return 5; - if (nClass == CLASS_TYPE_PSYWAR) - return 6; - - return GetCurrentSpellLevel(nClass, GetHighestLevelPossibleInClass(nClass)); -} - -int GetHighestLevelPossibleInClass(int nClass) -{ - string sFile; - - //sponts have their spells in the classes.2da - if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS - || nClass == CLASS_TYPE_ARCHIVIST) - { - sFile = Get2DACache("classes", "SpellGainTable", nClass); - } - else - { - // everyone else uses this - sFile = GetAMSKnownFileName(nClass); - - if (nClass == CLASS_TYPE_TRUENAMER) - { - sFile = "cls_true_maxlvl"; //has a different 2da we want to look at - } - - if (nClass == CLASS_TYPE_BINDER) - { - sFile = "cls_bind_binder"; - } - } - - return Get2DARowCount(sFile); -} - int IsClassAllowedToUseNUISpellbook(object oPlayer, int nClass) { // This controls who can use the Spellbook NUI, if for some reason you don't @@ -698,8 +387,7 @@ int IsClassAllowedToUseNUISpellbook(object oPlayer, int nClass) return TRUE; // Arcane Spont - if (nClass == CLASS_TYPE_ASSASSIN - || nClass == CLASS_TYPE_BEGUILER + if (nClass == CLASS_TYPE_BEGUILER || nClass == CLASS_TYPE_CELEBRANT_SHARESS || nClass == CLASS_TYPE_DREAD_NECROMANCER || nClass == CLASS_TYPE_DUSKBLADE @@ -817,8 +505,7 @@ int CanClassUseMetamagicFeats(int nClass) // I don't want to spend the time looping through each class's // feat 2da so this is the list of all classes that are allowed to use the // Spellbook NUI and can use Metamagic - return (nClass == CLASS_TYPE_ASSASSIN - || nClass == CLASS_TYPE_BARD + return (nClass == CLASS_TYPE_BARD || nClass == CLASS_TYPE_SORCERER || nClass == CLASS_TYPE_BEGUILER || nClass == CLASS_TYPE_DREAD_NECROMANCER @@ -838,7 +525,6 @@ int CanClassUseSuddenMetamagicFeats(int nClass) // Spellbook NUI and can use Sudden Metamagic return (nClass == CLASS_TYPE_SHADOWLORD || nClass == CLASS_TYPE_ARCHIVIST - || nClass == CLASS_TYPE_ASSASSIN || nClass == CLASS_TYPE_BARD || nClass == CLASS_TYPE_BEGUILER || nClass == CLASS_TYPE_DREAD_NECROMANCER @@ -1144,5 +830,16 @@ int JsonArrayContainsInt(json list, int item) return TRUE; } + return FALSE; +} + +int IsSpellbookNUIOpen(object oPC) +{ + int nPreviousToken = NuiFindWindow(oPC, PRC_SPELLBOOK_NUI_WINDOW_ID); + if (nPreviousToken != 0) + { + return TRUE; + } + return FALSE; } \ No newline at end of file diff --git a/src/include/prc_spell_const.nss b/src/include/prc_spell_const.nss index bb8b1cd..02a3a2f 100644 --- a/src/include/prc_spell_const.nss +++ b/src/include/prc_spell_const.nss @@ -22,6 +22,9 @@ const int SPELL_BCM_RENDING_CLAWS = 17997; //:: Complete Warrior const int SPELL_RANGED_DISARM = 3493; +//:: Tome of Battle +const int SPELL_TOB_SNAP_KICK = 3794; + //marshal const int SPELL_MINAUR_DEMFORT = 3500; const int SPELL_MINAUR_FORCEWILL = 3501; @@ -1289,6 +1292,69 @@ const int SPELL_SUMMON_CREATURE_IX_WATER = 3200; //:: Player's Handbook Spells const int SPELL_SPIRITUAL_WEAPON = 17249; +const int SPELL_SUMMON_NATURES_ALLY_1 = 17000; +const int SPELL_SUMMON_NATURES_ALLY_1_DIREBADGER = 17001; +const int SPELL_SUMMON_NATURES_ALLY_1_DIRERAT = 17002; +const int SPELL_SUMMON_NATURES_ALLY_1_DOG = 17003; +const int SPELL_SUMMON_NATURES_ALLY_1_HAWK = 17004; +const int SPELL_SUMMON_NATURES_ALLY_1_TINY_VIPER = 17005; + +const int SPELL_SUMMON_NATURES_ALLY_2 = 17010; +const int SPELL_SUMMON_NATURES_ALLY_2_DIREBOAR = 17011; +const int SPELL_SUMMON_NATURES_ALLY_2_COOSHEE = 17012; +const int SPELL_SUMMON_NATURES_ALLY_2_WOLF = 17013; +const int SPELL_SUMMON_NATURES_ALLY_2_SMALL_VIPER = 17014; +const int SPELL_SUMMON_NATURES_ALLY_2_BLACKBEAR = 17015; + +const int SPELL_SUMMON_NATURES_ALLY_3 = 17020; +const int SPELL_SUMMON_NATURES_ALLY_3_BROWNBEAR = 17021; +const int SPELL_SUMMON_NATURES_ALLY_3_DIREWOLK = 17022; +const int SPELL_SUMMON_NATURES_ALLY_3_LARGE_VIPER = 17023; +const int SPELL_SUMMON_NATURES_ALLY_3_LEOPARD = 17024; +const int SPELL_SUMMON_NATURES_ALLY_3_SATYR = 17025; + +const int SPELL_SUMMON_NATURES_ALLY_4 = 17030; +const int SPELL_SUMMON_NATURES_ALLY_4_LION = 17031; +const int SPELL_SUMMON_NATURES_ALLY_4_POLAR_BEAR = 17032; +const int SPELL_SUMMON_NATURES_ALLY_4_DIRE_SPIDER = 17033; +const int SPELL_SUMMON_NATURES_ALLY_4_HUGE_VIPER = 17034; +const int SPELL_SUMMON_NATURES_ALLY_4_WEREBOAR = 17035; + +const int SPELL_SUMMON_NATURES_ALLY_5 = 17040; +const int SPELL_SUMMON_NATURES_ALLY_5_MED_AIR = 17041; +const int SPELL_SUMMON_NATURES_ALLY_5_MED_EARTH = 17042; +const int SPELL_SUMMON_NATURES_ALLY_5_MED_FIRE = 17043; +const int SPELL_SUMMON_NATURES_ALLY_5_MED_WATER = 17044; +const int SPELL_SUMMON_NATURES_ALLY_5_DIRE_BEAR = 17045; + +const int SPELL_SUMMON_NATURES_ALLY_6 = 17050; +const int SPELL_SUMMON_NATURES_ALLY_6_LG_AIR = 17051; +const int SPELL_SUMMON_NATURES_ALLY_6_LG_EARTH = 17052; +const int SPELL_SUMMON_NATURES_ALLY_6_LG_FIRE = 17053; +const int SPELL_SUMMON_NATURES_ALLY_6_LG_WATER = 17054; +const int SPELL_SUMMON_NATURES_ALLY_6_DIRETIGER = 17055; + +const int SPELL_SUMMON_NATURES_ALLY_7 = 17060; +const int SPELL_SUMMON_NATURES_ALLY_7_BULETTE = 17061; +const int SPELL_SUMMON_NATURES_ALLY_7_INVSTALKER = 17062; +const int SPELL_SUMMON_NATURES_ALLY_7_PIXIE = 17063; +const int SPELL_SUMMON_NATURES_ALLY_7_GORGON = 17064; +const int SPELL_SUMMON_NATURES_ALLY_7_MANTICORE = 17065; + +const int SPELL_SUMMON_NATURES_ALLY_8 = 17070; +const int SPELL_SUMMON_NATURES_ALLY_8_GR_AIR = 17071; +const int SPELL_SUMMON_NATURES_ALLY_8_GR_EARTH = 17072; +const int SPELL_SUMMON_NATURES_ALLY_8_GR_FIRE = 17073; +const int SPELL_SUMMON_NATURES_ALLY_8_GR_WATER = 17074; +const int SPELL_SUMMON_NATURES_ALLY_8_NYMPH = 17075; + +const int SPELL_SUMMON_NATURES_ALLY_9 = 17080; +const int SPELL_SUMMON_NATURES_ALLY_9_ELD_AIR = 17081; +const int SPELL_SUMMON_NATURES_ALLY_9_ELD_EARTH = 17082; +const int SPELL_SUMMON_NATURES_ALLY_9_ELD_FIRE = 17083; +const int SPELL_SUMMON_NATURES_ALLY_9_ELD_WATER = 17084; +const int SPELL_SUMMON_NATURES_ALLY_9_ARANEA = 17085; + //:: Player's Handbook II Spells const int SPELL_CHASING_PERFECTION = 2479; @@ -1297,12 +1363,34 @@ const int SPELL_SPIRIT_WORM = 17248; const int SPELL_FORCE_MISSILES = 2480; //:: Masters of the Wild Spells +const int SPELL_FORESTFOLD = 17090; +const int SPELL_CREEPING_COLD = 17091; +const int SPELL_GREATER_CREEPING_COLD = 17092; +const int SPELL_CONTROL_PLANTS = 17237; +const int SPELL_ADRENALINE_SURGE = 17238; +const int SPELL_INVULNERABILITY_TO_ELEMENTS = 17239; +const int SPELL_REGEN_RING = 17241; +const int SPELL_REGEN_CIRCLE = 17242; const int SPELL_REGEN_LIGHT_WOUNDS = 17243; const int SPELL_REGEN_MODERATE_WOUNDS = 17244; const int SPELL_REGEN_SERIOUS_WOUNDS = 17245; const int SPELL_REGEN_CRITICAL_WOUNDS = 17246; const int SPELL_SPEED_WIND = 17247; -const int SPELL_TORTISE_SHELL = 17250; +const int SPELL_TORTISE_SHELL = 17250; + +//:: Book of Exalted Deeds Spells +const int SPELL_LEONALS_ROAR = 17240; + +//:: Master of the Wild Feats +const int SPELL_VL_WILD_SHAPE_TREANT = 17989; +const int SPELL_VL_ANIMATE_TREE = 17990; +const int SPELL_PLANT_DEFIANCE = 17991; +const int SPELL_PLANT_CONTROL = 17992; + +//:: Book of Exalted Deeds Feats +const int SPELL_FOT_LEONALS_ROAR = 17993; +const int SPELL_FOT_LIONS_SWIFTNESS = 17994; +const int SPELL_FAVORED_OF_THE_COMPANIONS = 17995; //x const int SPELL_TENSERS_FLOATING_DISK = 3849; diff --git a/src/include/prc_spellf_inc.nss b/src/include/prc_spellf_inc.nss index 753680f..1b6042f 100644 --- a/src/include/prc_spellf_inc.nss +++ b/src/include/prc_spellf_inc.nss @@ -299,6 +299,7 @@ int SpellfireDrainItem(object oPC, object oItem, int bCharged = TRUE, int bSingl { if((nBase == BASE_ITEM_POTIONS) || + (nBase == BASE_ITEM_INFUSED_HERB) || (nBase == BASE_ITEM_SCROLL) || (nBase == BASE_ITEM_SPELLSCROLL) || (nBase == BASE_ITEM_BLANK_POTION) || @@ -382,6 +383,7 @@ void SpellfireDrain(object oPC, object oTarget, int bCharged = TRUE, int bExempt if(GetPRCSwitch(PRC_SPELLFIRE_DISALLOW_DRAIN_SCROLL_POTION) && ((nBase == BASE_ITEM_POTIONS) || (nBase == BASE_ITEM_SCROLL) || + (nBase == BASE_ITEM_INFUSED_HERB) || (nBase == BASE_ITEM_BLANK_POTION) || (nBase == BASE_ITEM_BLANK_SCROLL) ) @@ -525,3 +527,4 @@ void SpellfireCrown(object oPC) } } +//:: void main() {} \ No newline at end of file diff --git a/src/include/prc_template_con.nss b/src/include/prc_template_con.nss index fc15544..2955524 100644 --- a/src/include/prc_template_con.nss +++ b/src/include/prc_template_con.nss @@ -18,6 +18,7 @@ const int TEMPLATE_CURST = 26; const int TEMPLATE_GRAVETOUCHED_GHOUL = 29; const int TEMPLATE_CRYPTSPAWN = 30; const int TEMPLATE_ARCHLICH = 99; +const int TEMPLATE_BAELNORN = 100; const int TEMPLATE_LICH = 101; const int TEMPLATE_DEMILICH = 102; const int TEMPLATE_NECROPOLITAN = 105; diff --git a/src/include/prc_x2_craft.nss b/src/include/prc_x2_craft.nss index 5834f63..ac1d795 100644 --- a/src/include/prc_x2_craft.nss +++ b/src/include/prc_x2_craft.nss @@ -13,7 +13,7 @@ //:: Created On: 2003-05-09 //:: Last Updated On: 2003-10-14 //::////////////////////////////////////////////// - +#include "prc_x2_itemprop" struct craft_struct { @@ -44,22 +44,24 @@ const string X2_CI_CRAFTSKILL_CONV ="x2_p_craftskills"; /* moved to be code switches const int X2_CI_BREWPOTION_MAXLEVEL = 3; // Max Level for potions -const int X2_CI_BREWPOTION_COSTMODIFIER = 50; // gp Brew Potion XPCost Modifier +const int PRC_X2_BREWPOTION_COSTMODIFIER = 50; // gp Brew Potion XPCost Modifier // Scribe Scroll related constants -const int X2_CI_SCRIBESCROLL_COSTMODIFIER = 25; // Scribescroll Cost Modifier +const int PRC_X2_SCRIBESCROLL_COSTMODIFIER = 25; // Scribescroll Cost Modifier // Craft Wand related constants -const int X2_CI_CRAFTWAND_MAXLEVEL = 4; -const int X2_CI_CRAFTWAND_COSTMODIFIER = 750; +const int PRC_X2_CRAFTWAND_MAXLEVEL = 4; +const int PRC_X2_CRAFTWAND_COSTMODIFIER = 750; */ -const int X2_CI_BREWPOTION_FEAT_ID = 944; // Brew Potion feat simulation -const int X2_CI_SCRIBESCROLL_FEAT_ID = 945; -const int X2_CI_CRAFTWAND_FEAT_ID = 946; -const int X2_CI_CRAFTROD_FEAT_ID = 2927; -const int X2_CI_CRAFTROD_EPIC_FEAT_ID = 3490; -const int X2_CI_CRAFTSTAFF_FEAT_ID = 2928; -const int X2_CI_CRAFTSTAFF_EPIC_FEAT_ID = 3491; +const int X2_CI_BREWPOTION_FEAT_ID = 944; // Brew Potion feat simulation +const int X2_CI_SCRIBESCROLL_FEAT_ID = 945; +const int X2_CI_CRAFTWAND_FEAT_ID = 946; +const int X2_CI_CRAFTROD_FEAT_ID = 2927; +const int X2_CI_CRAFTROD_EPIC_FEAT_ID = 3490; +const int X2_CI_CRAFTSTAFF_FEAT_ID = 2928; +const int X2_CI_CRAFTSTAFF_EPIC_FEAT_ID = 3491; +const int X2_CI_CREATEINFUSION_FEAT_ID = 25960; + const string X2_CI_BREWPOTION_NEWITEM_RESREF = "x2_it_pcpotion"; // ResRef for new potion item const string X2_CI_SCRIBESCROLL_NEWITEM_RESREF = "x2_it_pcscroll"; // ResRef for new scroll item const string X2_CI_CRAFTWAND_NEWITEM_RESREF = "x2_it_pcwand"; @@ -185,6 +187,17 @@ int CheckAlternativeCrafting(object oPC, int nSpell, struct craft_cost_struct co // Returns the maximum of caster level used and other effective levels from emulating spells int GetAlternativeCasterLevel(object oPC, int nLevel); +// ----------------------------------------------------------------------------- +// Create and Return an herbal infusion with an item property +// matching nSpellID. +// ----------------------------------------------------------------------------- +object CICreateInfusion(object oCreator, int nSpellID); + +// ----------------------------------------------------------------------------- +// Returns TRUE if the player successfully performed Create Infusion +// ----------------------------------------------------------------------------- +int CICraftCheckCreateInfusion(object oSpellTarget, object oCaster, int nID = 0); + ////////////////////////////////////////////////// /* Include section */ ////////////////////////////////////////////////// @@ -194,6 +207,7 @@ int GetAlternativeCasterLevel(object oPC, int nLevel); #include "prc_inc_newip" #include "prc_inc_spells" #include "prc_add_spell_dc" +#include "inc_infusion" ////////////////////////////////////////////////// /* Function definitions */ @@ -261,7 +275,8 @@ int CIGetIsCraftFeatBaseItem(object oItem) nBt == BASE_ITEM_BLANK_SCROLL || nBt == BASE_ITEM_BLANK_WAND || nBt == BASE_ITEM_CRAFTED_ROD || - nBt == BASE_ITEM_CRAFTED_STAFF) + nBt == BASE_ITEM_CRAFTED_STAFF || + nBt == BASE_ITEM_MUNDANE_HERB) return TRUE; else return FALSE; @@ -453,11 +468,158 @@ object CICraftCraftWand(object oCreator, int nSpellID ) // ----------------------------------------------------------------------------- // Georg, 2003-06-12 -// Create and Return a magic wand with an item property -// matching nSpellID. Charges are set to d20 + casterlevel -// capped at 50 max +// Create and Return a magic scroll with an item property +// matching nSpellID. // ----------------------------------------------------------------------------- object CICraftScribeScroll(object oCreator, int nSpellID) +{ + if (DEBUG) DoDebug("CICraftScribeScroll: Enter (nSpellID=" + IntToString(nSpellID) + ")"); + + // Keep original and compute one-step master (if subradial) + int nSpellOriginal = nSpellID; + int nSpellMaster = nSpellOriginal; + if (GetIsSubradialSpell(nSpellOriginal)) + { + nSpellMaster = GetMasterSpellFromSubradial(nSpellOriginal); + if (DEBUG) DoDebug("CICraftScribeScroll: subradial detected original=" + IntToString(nSpellOriginal) + " master=" + IntToString(nSpellMaster)); + } + + // Prefer iprp mapping for the original, fallback to master + int nPropID = IPGetIPConstCastSpellFromSpellID(nSpellOriginal); + int nSpellUsedForIP = nSpellOriginal; + if (nPropID < 0) + { + if (DEBUG) DoDebug("CICraftScribeScroll: no iprp for original " + IntToString(nSpellOriginal) + ", trying master " + IntToString(nSpellMaster)); + nPropID = IPGetIPConstCastSpellFromSpellID(nSpellMaster); + nSpellUsedForIP = nSpellMaster; + } + + // If neither original nor master has an iprp row, we can still try templates, + // but most templates expect a matching iprp. Bail out now if nothing found. + if (nPropID < 0) + { + if (DEBUG) DoDebug("CICraftScribeScroll: no iprp_spells entry for original/master -> aborting"); + FloatingTextStringOnCreature("This spell cannot be scribed (no item property mapping).", oCreator, FALSE); + return OBJECT_INVALID; + } + + if (DEBUG) DoDebug("CICraftScribeScroll: using spell " + IntToString(nSpellUsedForIP) + " (iprp row " + IntToString(nPropID) + ") for item property"); + + // Material component check (based on resolved iprp row) + string sMat = GetMaterialComponentTag(nPropID); + if (sMat != "") + { + object oMat = GetItemPossessedBy(oCreator, sMat); + if (oMat == OBJECT_INVALID) + { + FloatingTextStrRefOnCreature(83374, oCreator); // Missing material component + return OBJECT_INVALID; + } + else + { + DestroyObject(oMat); + } + } + + // Resolve class and scroll template + int nClass = PRCGetLastSpellCastClass(); + string sClass = ""; + switch (nClass) + { + case CLASS_TYPE_WIZARD: + case CLASS_TYPE_SORCERER: sClass = "Wiz_Sorc"; break; + case CLASS_TYPE_CLERIC: + case CLASS_TYPE_UR_PRIEST: sClass = "Cleric"; break; + case CLASS_TYPE_PALADIN: sClass = "Paladin"; break; + case CLASS_TYPE_DRUID: + case CLASS_TYPE_BLIGHTER: sClass = "Druid"; break; + case CLASS_TYPE_RANGER: sClass = "Ranger"; break; + case CLASS_TYPE_BARD: sClass = "Bard"; break; + case CLASS_TYPE_ASSASSIN: sClass = "Assassin"; break; + } + + object oTarget = OBJECT_INVALID; + string sResRef = ""; + + // Try to find a class-specific scroll template. + if (sClass != "") + { + // Try original first (so if you made a subradial-specific template it will be used) + sResRef = Get2DACache(X2_CI_2DA_SCROLLS, sClass, nSpellOriginal); + if (sResRef == "") + { + // fallback to the spell that matched an iprp row (master or original) + sResRef = Get2DACache(X2_CI_2DA_SCROLLS, sClass, nSpellUsedForIP); + } + if (sResRef != "") + { + oTarget = CreateItemOnObject(sResRef, oCreator); + if (DEBUG) DoDebug("CICraftScribeScroll: created template " + sResRef + " for class " + sClass); + // Ensure template uses the correct cast-spell property: replace the template's cast-spell IP with ours + if (oTarget != OBJECT_INVALID) + { + itemproperty ipIter = GetFirstItemProperty(oTarget); + while (GetIsItemPropertyValid(ipIter)) + { + if (GetItemPropertyType(ipIter) == ITEM_PROPERTY_CAST_SPELL) + { + RemoveItemProperty(oTarget, ipIter); + break; + } + ipIter = GetNextItemProperty(oTarget); + } + itemproperty ipSpell = ItemPropertyCastSpell(nPropID, IP_CONST_CASTSPELL_NUMUSES_SINGLE_USE); + AddItemProperty(DURATION_TYPE_PERMANENT, ipSpell, oTarget); + } + } + } + + // If no template or sClass was empty, create generic scroll and add itemprop. + if (oTarget == OBJECT_INVALID) + { + sResRef = "craft_scroll"; + oTarget = CreateItemOnObject(sResRef, oCreator); + if (oTarget == OBJECT_INVALID) + { + WriteTimestampedLogEntry("CICraftScribeScroll: failed to create craft_scroll template."); + return OBJECT_INVALID; + } + // Remove existing default IP and add correct one + itemproperty ipFirst = GetFirstItemProperty(oTarget); + if (GetIsItemPropertyValid(ipFirst)) + RemoveItemProperty(oTarget, ipFirst); + + itemproperty ipSpell = ItemPropertyCastSpell(nPropID, IP_CONST_CASTSPELL_NUMUSES_SINGLE_USE); + AddItemProperty(DURATION_TYPE_PERMANENT, ipSpell, oTarget); + } + + // Add PRC metadata (use the same spell that matched the iprp row so metadata and IP line up) + if (GetPRCSwitch(PRC_SCRIBE_SCROLL_CASTER_LEVEL)) + { + int nCasterLevel = GetAlternativeCasterLevel(oCreator, PRCGetCasterLevel(oCreator)); + itemproperty ipLevel = ItemPropertyCastSpellCasterLevel(nSpellUsedForIP, nCasterLevel); + AddItemProperty(DURATION_TYPE_PERMANENT, ipLevel, oTarget); + + itemproperty ipMeta = ItemPropertyCastSpellMetamagic(nSpellUsedForIP, PRCGetMetaMagicFeat()); + AddItemProperty(DURATION_TYPE_PERMANENT, ipMeta, oTarget); + + int nDC = PRCGetSpellSaveDC(nSpellUsedForIP, GetSpellSchool(nSpellUsedForIP), OBJECT_SELF); + itemproperty ipDC = ItemPropertyCastSpellDC(nSpellUsedForIP, nDC); + AddItemProperty(DURATION_TYPE_PERMANENT, ipDC, oTarget); + } + + if (oTarget == OBJECT_INVALID) + { + WriteTimestampedLogEntry("prc_x2_craft::CICraftScribeScroll failed - Resref: " + sResRef + " Class: " + sClass + "(" + IntToString(nClass) + ") " + " SpellID " + IntToString(nSpellID)); + return OBJECT_INVALID; + } + + if (DEBUG) DoDebug("CICraftScribeScroll: Success - created scroll " + sResRef + " for spell " + IntToString(nSpellUsedForIP)); + return oTarget; +} + + +/* object CICraftScribeScroll(object oCreator, int nSpellID) { int nPropID = IPGetIPConstCastSpellFromSpellID(nSpellID); object oTarget; @@ -491,6 +653,7 @@ object CICraftScribeScroll(object oCreator, int nSpellID) break; case CLASS_TYPE_CLERIC: case CLASS_TYPE_UR_PRIEST: + case CLASS_TYPE_OCULAR: sClass = "Cleric"; break; case CLASS_TYPE_PALADIN: @@ -506,6 +669,9 @@ object CICraftScribeScroll(object oCreator, int nSpellID) case CLASS_TYPE_BARD: sClass = "Bard"; break; + case CLASS_TYPE_ASSASSIN: + sClass = "Assassin"; + break; } string sResRef; if (sClass != "") @@ -542,7 +708,7 @@ object CICraftScribeScroll(object oCreator, int nSpellID) } return oTarget; } - + */ // ----------------------------------------------------------------------------- // Returns TRUE if the player used the last spell to brew a potion // ----------------------------------------------------------------------------- @@ -593,7 +759,7 @@ These dont work as IPs since they are hardcoded */ // ------------------------------------------------------------------------- // check if spell is below maxlevel for brew potions // ------------------------------------------------------------------------- - int nPotionMaxLevel = GetPRCSwitch(X2_CI_BREWPOTION_MAXLEVEL); + int nPotionMaxLevel = GetPRCSwitch(PRC_X2_BREWPOTION_MAXLEVEL); if(nPotionMaxLevel == 0) nPotionMaxLevel = 3; @@ -624,7 +790,7 @@ These dont work as IPs since they are hardcoded */ // ------------------------------------------------------------------------- // XP/GP Cost Calculation // ------------------------------------------------------------------------- - int nCostModifier = GetPRCSwitch(X2_CI_BREWPOTION_COSTMODIFIER); + int nCostModifier = GetPRCSwitch(PRC_X2_BREWPOTION_COSTMODIFIER); if(nCostModifier == 0) nCostModifier = 50; int nCost = CIGetCraftGPCost(nLevel, nCostModifier, PRC_BREW_POTION_CASTER_LEVEL); @@ -728,7 +894,7 @@ int CICraftCheckScribeScroll(object oSpellTarget, object oCaster, int nID = 0) // XP/GP Cost Calculation // ------------------------------------------------------------------------- int nLevel = CIGetSpellInnateLevel(nID,TRUE); - int nCostModifier = GetPRCSwitch(X2_CI_SCRIBESCROLL_COSTMODIFIER); + int nCostModifier = GetPRCSwitch(PRC_X2_SCRIBESCROLL_COSTMODIFIER); if(nCostModifier == 0) nCostModifier = 25; int nCost = CIGetCraftGPCost(nLevel, nCostModifier, PRC_SCRIBE_SCROLL_CASTER_LEVEL); @@ -884,7 +1050,7 @@ These dont work as IPs since they are hardcoded */ // ------------------------------------------------------------------------- // check if spell is below maxlevel for craft want // ------------------------------------------------------------------------- - int nMaxLevel = GetPRCSwitch(X2_CI_CRAFTWAND_MAXLEVEL); + int nMaxLevel = GetPRCSwitch(PRC_X2_CRAFTWAND_MAXLEVEL); if(nMaxLevel == 0) nMaxLevel = 4; if (nLevel > nMaxLevel) @@ -896,7 +1062,7 @@ These dont work as IPs since they are hardcoded */ // ------------------------------------------------------------------------- // XP/GP Cost Calculation // ------------------------------------------------------------------------- - int nCostMod = GetPRCSwitch(X2_CI_CRAFTWAND_COSTMODIFIER); + int nCostMod = GetPRCSwitch(PRC_X2_CRAFTWAND_COSTMODIFIER); if(nCostMod == 0) nCostMod = 750; int nCost = CIGetCraftGPCost(nLevel, nCostMod, PRC_CRAFT_WAND_CASTER_LEVEL); @@ -1027,7 +1193,7 @@ int CICraftCheckCraftStaff(object oSpellTarget, object oCaster, int nSpellID = 0 These dont work as IPs since they are hardcoded */ } } - int nCostMod = GetPRCSwitch(X2_CI_CRAFTSTAFF_COSTMODIFIER); + int nCostMod = GetPRCSwitch(PRC_X2_CRAFTSTAFF_COSTMODIFIER); if(!nCostMod) nCostMod = 750; int nLvlRow = IPGetIPConstCastSpellFromSpellID(nSpellID); int nCLevel = StringToInt(Get2DACache("iprp_spells","CasterLvl",nLvlRow)); @@ -1175,7 +1341,7 @@ int CICraftCheckCraftRod(object oSpellTarget, object oCaster, int nSpellID = 0) These dont work as IPs since they are hardcoded */ } } - int nCostMod = GetPRCSwitch(X2_CI_CRAFTROD_COSTMODIFIER); + int nCostMod = GetPRCSwitch(PRC_X2_CRAFTROD_COSTMODIFIER); if(!nCostMod) nCostMod = 750; int nLvlRow = IPGetIPConstCastSpellFromSpellID(nSpellID); int nCLevel = StringToInt(Get2DACache("iprp_spells","CasterLvl",nLvlRow)); @@ -1544,7 +1710,7 @@ int AttuneGem(object oTarget = OBJECT_INVALID, object oCaster = OBJECT_INVALID, // No point scribing Gems from items, and its not allowed. if (oItem != OBJECT_INVALID) { - FloatingTextStringOnCreature("You cannot scribe a Gem from an item.", oCaster, FALSE); + FloatingTextStringOnCreature("You cannot attune a Gem from an item.", oCaster, FALSE); return TRUE; } // oTarget here should be the gem. If it's not, fail. @@ -1951,7 +2117,13 @@ int CIGetSpellWasUsedForItemCreation(object oSpellTarget) // ------------------------------------------------- nRet = CICraftCheckCraftStaff(oSpellTarget,oCaster); break; - + + case BASE_ITEM_MUNDANE_HERB : + // ------------------------------------------------- + // Create Infusion + // ------------------------------------------------- + nRet = CICraftCheckCreateInfusion(oSpellTarget,oCaster); + break; // you could add more crafting basetypes here.... } @@ -2740,6 +2912,11 @@ int GetMagicalArtisanFeat(int nCraftingFeat) nReturn = FEAT_MAGICAL_ARTISAN_CRAFT_SKULL_TALISMAN; break; } + case FEAT_CREATE_INFUSION: + { + nReturn = FEAT_MAGICAL_ARTISAN_CREATE_INFUSION; + break; + } default: { if(DEBUG) DoDebug("GetMagicalArtisanFeat: invalid crafting feat"); @@ -2941,6 +3118,306 @@ int GetAlternativeCasterLevel(object oPC, int nLevel) return nLevel; } +// ----------------------------------------------------------------------------- +// Returns TRUE if the player successfully performed Create Infusion +// ----------------------------------------------------------------------------- +int CICraftCheckCreateInfusion(object oSpellTarget, object oCaster, int nID = 0) +{ + if (nID == 0) nID = PRCGetSpellId(); + + int bIsSubradial = GetIsSubradialSpell(nID); + + if(bIsSubradial) + { + nID = GetMasterSpellFromSubradial(nID); + } + + // ------------------------------------------------------------------------- + // Check if the caster has the Create Infusion feat + // ------------------------------------------------------------------------- + if (!GetHasFeat(FEAT_CREATE_INFUSION, oCaster)) + { + FloatingTextStrRefOnCreature(40487, oCaster); // Missing feat + return TRUE; + } + + // ------------------------------------------------------------------------- + // Divine spellcasters only + // ------------------------------------------------------------------------- + int nClass = PRCGetLastSpellCastClass(); + if (!GetIsDivineClass(nClass)) + { + FloatingTextStringOnCreature("Only divine casters can create infusions.", oCaster, FALSE); + return TRUE; + } + + // ------------------------------------------------------------------------- + // Check if spell is restricted for Create Infusion + // ------------------------------------------------------------------------- + if (CIGetIsSpellRestrictedFromCraftFeat(nID, X2_CI_CREATEINFUSION_FEAT_ID)) + { + FloatingTextStrRefOnCreature(83451, oCaster); // Spell not allowed + return TRUE; + } + + // ------------------------------------------------------------------------- + // Optional PnP Herb check + // ------------------------------------------------------------------------- + int bPnPHerbs = GetPRCSwitch(PRC_CREATE_INFUSION_OPTIONAL_HERBS); + if(bPnPHerbs) + { + int nSpellschool = GetSpellSchool(nID); + int nHerbSchool = GetHerbsSpellSchool(oSpellTarget); + + int nSpellLevel = PRCGetSpellLevelForClass(nID, nClass); + int nHerbLevel = GetHerbsInfusionSpellLevel(oSpellTarget); + + if(nSpellschool != nHerbSchool) + { + // Herb is for wrong spellschool + FloatingTextStringOnCreature("This herb isn't appropriate for this spell school", oCaster); + return TRUE; + } + + if(nSpellLevel > nHerbLevel) + { + // Herb spell circle level too low + FloatingTextStringOnCreature("This herb isn't appropriate for this spell level", oCaster); + return TRUE; + } + } + + // ------------------------------------------------------------------------- + // XP/GP Cost Calculation + // ------------------------------------------------------------------------- + int nLevel = CIGetSpellInnateLevel(nID, TRUE); + int nCostModifier = GetPRCSwitch(PRC_X2_CREATEINFUSION_COSTMODIFIER); + if (nCostModifier == 0) + nCostModifier = 25; + + int nCost = CIGetCraftGPCost(nLevel, nCostModifier, PRC_CREATE_INFUSION_CASTER_LEVEL); + struct craft_cost_struct costs = GetModifiedCostsFromBase(nCost, oCaster, FEAT_CREATE_INFUSION, FALSE); + + // Adjust level for metamagic + if (GetPRCSwitch(PRC_CREATE_INFUSION_CASTER_LEVEL)) + { + int nMetaMagic = PRCGetMetaMagicFeat(); + switch(nMetaMagic) + { + case METAMAGIC_EMPOWER: nLevel += 2; break; + case METAMAGIC_EXTEND: nLevel += 1; break; + case METAMAGIC_MAXIMIZE: nLevel += 3; break; + // Unsupported metamagic IPs not added + } + } + + // ------------------------------------------------------------------------- + // Check Gold + // ------------------------------------------------------------------------- + if (!GetHasGPToSpend(oCaster, costs.nGoldCost)) + { + FloatingTextStrRefOnCreature(3786, oCaster); // Not enough gold + return TRUE; + } + + // ------------------------------------------------------------------------- + // Check XP + // ------------------------------------------------------------------------- + if (!GetHasXPToSpend(oCaster, costs.nXPCost)) + { + FloatingTextStrRefOnCreature(3785, oCaster); // Not enough XP + return TRUE; + } + + // ------------------------------------------------------------------------- + // Check alternative spell emulation requirements + // ------------------------------------------------------------------------- + if (!CheckAlternativeCrafting(oCaster, nID, costs)) + { + FloatingTextStringOnCreature("*Crafting failed!*", oCaster, FALSE); + return TRUE; + } + + // ------------------------------------------------------------------------- + // Create the infused herb item + // ------------------------------------------------------------------------- + object oInfusion = CICreateInfusion(oCaster, nID); + + if (GetIsObjectValid(oInfusion)) + { + // Get the spell's display name from spells.2da via TLK + int nNameStrRef = StringToInt(Get2DAString("spells", "Name", nID)); + string sSpellName = GetStringByStrRef(nNameStrRef); + + // Rename the item + string sNewName = "Infusion of " + sSpellName; + SetName(oInfusion, sNewName); + + // Post-creation actions + SetIdentified(oInfusion, TRUE); + ActionPlayAnimation(ANIMATION_FIREFORGET_READ, 1.0); + SpendXP(oCaster, costs.nXPCost); + SpendGP(oCaster, costs.nGoldCost); + DestroyObject(oSpellTarget); + FloatingTextStrRefOnCreature(8502, oCaster); // Item creation successful + + if (!costs.nTimeCost) costs.nTimeCost = 1; + AdvanceTimeForPlayer(oCaster, RoundsToSeconds(costs.nTimeCost)); + return TRUE; + } + else + { + FloatingTextStringOnCreature("Infusion creation failed", oCaster); // Item creation failed + FloatingTextStrRefOnCreature(76417, oCaster); // Item creation failed + return TRUE; + } + +/* // ------------------------------------------------------------------------- + // Create the infused herb item + // ------------------------------------------------------------------------- + object oInfusion = CICreateInfusion(oCaster, nID); + + if (GetIsObjectValid(oInfusion)) + { + SetIdentified(oInfusion, TRUE); + ActionPlayAnimation(ANIMATION_FIREFORGET_READ, 1.0); + SpendXP(oCaster, costs.nXPCost); + SpendGP(oCaster, costs.nGoldCost); + DestroyObject(oSpellTarget); + FloatingTextStrRefOnCreature(8502, oCaster); // Item creation successful + + if (!costs.nTimeCost) costs.nTimeCost = 1; + AdvanceTimeForPlayer(oCaster, RoundsToSeconds(costs.nTimeCost)); + return TRUE; + } + else + { + FloatingTextStringOnCreature("Infusion creation failed", oCaster); // Item creation failed + FloatingTextStrRefOnCreature(76417, oCaster); // Item creation failed + return TRUE; + } */ + + return FALSE; +} + +// ----------------------------------------------------------------------------- +// Create and return an herbal infusion with an item property matching nSpellID +// ----------------------------------------------------------------------------- +object CICreateInfusion(object oCreator, int nSpellID) +{ + if (DEBUG) DoDebug("prc_x2_craft >> CICreateInfusion: Entering function"); + + // Keep the original spell id the engine gave us (may be a subradial) + int nSpellOriginal = nSpellID; + if (DEBUG) DoDebug("prc_x2_craft >> CICreateInfusion: nSpellOriginal is "+IntToString(nSpellOriginal)+"."); + + // Compute the master if this is a subradial. Keep original intact. + int nSpellMaster = nSpellOriginal; + if (GetIsSubradialSpell(nSpellOriginal)) + { + nSpellMaster = GetMasterSpellFromSubradial(nSpellOriginal); + if (DEBUG) DoDebug("CICreateInfusion: detected subradial " + IntToString(nSpellOriginal) + " master -> " + IntToString(nSpellMaster)); + } + if (DEBUG) DoDebug("prc_x2_craft >> CICreateInfusion: nSpellMaster is "+IntToString(nSpellMaster)+"."); + + // Try to find an iprp_spells row for the original subradial first (preferred). + int nPropID = IPGetIPConstCastSpellFromSpellID(nSpellOriginal); + int nSpellUsedForIP = nSpellOriginal; + + // If not found for original, fall back to the master/base spell. + if (nPropID < 0) + { + if (DEBUG) DoDebug("CICreateInfusion: no iprp row for original " + IntToString(nSpellOriginal) + ", trying master " + IntToString(nSpellMaster)); + nPropID = IPGetIPConstCastSpellFromSpellID(nSpellMaster); + nSpellUsedForIP = nSpellMaster; + } + + // If still invalid, bail out with a helpful message + if (nPropID < 0) + { + if (DEBUG) DoDebug("CICreateInfusion: No iprp_spells entry for either original " + IntToString(nSpellOriginal) + " or master " + IntToString(nSpellMaster)); + FloatingTextStringOnCreature("This spell cannot be infused (no item property mapping).", oCreator, FALSE); + return OBJECT_INVALID; + } + + if (DEBUG) DoDebug("CICreateInfusion: using spell " + IntToString(nSpellUsedForIP) + " (iprp row " + IntToString(nPropID) + ") for item property"); + + // Optional: check for material component (use the resolved iprp row) + string sMat = GetMaterialComponentTag(nPropID); + if (sMat != "") + { + object oMat = GetItemPossessedBy(oCreator, sMat); + if (oMat == OBJECT_INVALID) + { + FloatingTextStrRefOnCreature(83374, oCreator); // Missing material component + return OBJECT_INVALID; + } + else + { + DestroyObject(oMat); + } + } + + // Only allow divine spellcasters + int nClass = PRCGetLastSpellCastClass(); + if (!GetIsDivineClass(nClass)) + { + FloatingTextStringOnCreature("Only divine casters can use Create Infusion.", oCreator, FALSE); + return OBJECT_INVALID; + } + + // Create base infusion item (herb) + string sResRef = "prc_infusion_000"; + object oTarget = CreateItemOnObject(sResRef, oCreator); + if (oTarget == OBJECT_INVALID) + { + WriteTimestampedLogEntry("Create Infusion failed: couldn't create item with resref " + sResRef); + return OBJECT_INVALID; + } + + // Confirm that the item is a herb + int nBaseItem = GetBaseItemType(oTarget); + if (nBaseItem != BASE_ITEM_INFUSED_HERB) + { + FloatingTextStringOnCreature("Only herbs may be infused.", oCreator, FALSE); + DestroyObject(oTarget); + return OBJECT_INVALID; + } + + // Remove all non-material item properties from the herb + itemproperty ipRemove = GetFirstItemProperty(oTarget); + while (GetIsItemPropertyValid(ipRemove)) + { + itemproperty ipNext = GetNextItemProperty(oTarget); + if (GetItemPropertyType(ipRemove) != ITEM_PROPERTY_MATERIAL) + RemoveItemProperty(oTarget, ipRemove); + ipRemove = ipNext; + } + + // Add the cast-spell itemproperty using the iprp row we resolved + itemproperty ipSpell = ItemPropertyCastSpell(nPropID, IP_CONST_CASTSPELL_NUMUSES_SINGLE_USE); + AddItemProperty(DURATION_TYPE_PERMANENT, ipSpell, oTarget); + + // Optional PRC casting metadata: use the SAME spell id that matched the iprp row + // so caster level/DC/meta line up with the actual cast property on the item. + if (GetPRCSwitch(PRC_CREATE_INFUSION_CASTER_LEVEL)) + { + int nCasterLevel = GetAlternativeCasterLevel(oCreator, PRCGetCasterLevel(oCreator)); + // nSpellUsedForIP is either original (if that had an iprp row) or the master (fallback) + itemproperty ipLevel = ItemPropertyCastSpellCasterLevel(nSpellUsedForIP, nCasterLevel); + AddItemProperty(DURATION_TYPE_PERMANENT, ipLevel, oTarget); + + itemproperty ipMeta = ItemPropertyCastSpellMetamagic(nSpellUsedForIP, PRCGetMetaMagicFeat()); + AddItemProperty(DURATION_TYPE_PERMANENT, ipMeta, oTarget); + + int nDC = PRCGetSpellSaveDC(nSpellUsedForIP, GetSpellSchool(nSpellUsedForIP), OBJECT_SELF); + itemproperty ipDC = ItemPropertyCastSpellDC(nSpellUsedForIP, nDC); + AddItemProperty(DURATION_TYPE_PERMANENT, ipDC, oTarget); + } + + return oTarget; +} + // Test main -//void main(){} +// void main(){} diff --git a/src/include/prc_x2_itemprop.nss b/src/include/prc_x2_itemprop.nss index e4a1be0..17885cd 100644 --- a/src/include/prc_x2_itemprop.nss +++ b/src/include/prc_x2_itemprop.nss @@ -768,7 +768,6 @@ int IPGetIsBludgeoningWeapon(object oItem) // ---------------------------------------------------------------------------- // Return the IP_CONST_CASTSPELL_* ID matching to the SPELL_* constant given // in nSPELL_ID. -// This uses Get2DAstring, so it is slow. Avoid using in loops! // returns -1 if there is no matching property for a spell // ---------------------------------------------------------------------------- int IPGetIPConstCastSpellFromSpellID(int nSpellID) @@ -1883,7 +1882,7 @@ int IPDamageConstant(int nDamBon) case 49: nIPBonus = IP_CONST_DAMAGEBONUS_49; break; case 50: nIPBonus = IP_CONST_DAMAGEBONUS_50; break; } - if (nDamBon > 20) nIPBonus = IP_CONST_DAMAGEBONUS_50; + if (nDamBon > 50) nIPBonus = IP_CONST_DAMAGEBONUS_50; return nIPBonus; } diff --git a/src/include/shd_inc_mystknwn.nss b/src/include/shd_inc_mystknwn.nss index bc6ecc5..b335485 100644 --- a/src/include/shd_inc_mystknwn.nss +++ b/src/include/shd_inc_mystknwn.nss @@ -41,6 +41,7 @@ const string _MYSTERY_LIST_MISC_ARRAY = "_MysteriesKnownMiscArray"; const string _MYSTERY_LIST_LEVEL_ARRAY = "_MysteriesKnownLevelArray_"; const string _MYSTERY_LIST_GENERAL_ARRAY = "_MysteriesKnownGeneralArray"; +#include "shd_inc_shdfunc" ////////////////////////////////////////////////// /* Function prototypes */ diff --git a/src/include/shd_inc_shdfunc.nss b/src/include/shd_inc_shdfunc.nss index 63eb943..6ae4f63 100644 --- a/src/include/shd_inc_shdfunc.nss +++ b/src/include/shd_inc_shdfunc.nss @@ -236,12 +236,12 @@ int GetShadowcasterLevel(object oShadow = OBJECT_SELF, int nSpecificClass = CLAS // For when you want to assign the caster level. if(nLevel) { - if(DEBUG) SendMessageToPC(oShadow, "GetShadowcasterLevel(): Forced-level shadowcasting at level " + IntToString(nLevel)); + if(DEBUG) DoDebug("GetShadowcasterLevel(): Forced-level shadowcasting at level " + IntToString(nLevel)); //DelayCommand(1.0, DeleteLocalInt(oShadow, PRC_CASTERLEVEL_OVERRIDE)); return nLevel + nAdjust; } - if (DEBUG) FloatingTextStringOnCreature("GetShadowcasterLevel: "+GetName(oShadow)+" is a "+IntToString(nSpecificClass), oShadow); + if (DEBUG) DoDebug("GetShadowcasterLevel: "+GetName(oShadow)+" is a "+IntToString(nSpecificClass), oShadow); // The function user needs to know the character's Shadowcaster level in a specific class // instead of whatever the character last shadowcast a mystery as if(nSpecificClass != CLASS_TYPE_INVALID) @@ -288,7 +288,7 @@ int GetShadowcasterLevel(object oShadow = OBJECT_SELF, int nSpecificClass = CLAS nLevel -= 4; } - if(DEBUG) FloatingTextStringOnCreature("Shadowcaster Level: " + IntToString(nLevel), oShadow, FALSE); + if(DEBUG) DoDebug("Shadowcaster Level: " + IntToString(nLevel)); return nLevel + nAdjust; } diff --git a/src/include/x2_inc_spellhook.nss b/src/include/x2_inc_spellhook.nss index c21e3f1..92668bf 100644 --- a/src/include/x2_inc_spellhook.nss +++ b/src/include/x2_inc_spellhook.nss @@ -144,8 +144,103 @@ int PRCGetUserSpecificSpellScriptFinished(); #include "pnp_shft_main" #include "inc_dynconv" #include "inc_npc" +#include "inc_infusion" +#include "prc_add_spell_dc" + + +int Spontaneity(object oCaster, int nCastingClass, int nSpellID, int nSpellLevel) +{ + if(GetLocalInt(oCaster, "PRC_SpontRegen")) + { + DeleteLocalInt(oCaster, "PRC_SpontRegen"); + + int nMetamagic = GetMetaMagicFeat();//we need bioware metamagic here + nSpellLevel = PRCGetSpellLevelForClass(nSpellID, nCastingClass); + nSpellLevel += GetMetaMagicSpellLevelAdjustment(nMetamagic); + + int nRegenSpell; + + if(nCastingClass == CLASS_TYPE_DRUID) + { + switch(nSpellLevel) + { + case 0: return TRUE; + case 1: nRegenSpell = SPELL_REGEN_LIGHT_WOUNDS; break; + case 2: nRegenSpell = SPELL_REGEN_MODERATE_WOUNDS; break; + case 3: nRegenSpell = SPELL_REGEN_RING; break; + case 4: nRegenSpell = SPELL_REGEN_SERIOUS_WOUNDS; break; + case 5: nRegenSpell = SPELL_REGEN_CRITICAL_WOUNDS; break; + case 6: nRegenSpell = SPELL_REGEN_CIRCLE; break; + case 7: nRegenSpell = SPELL_REGEN_CIRCLE; break; + case 8: nRegenSpell = SPELL_REGEN_CIRCLE; break; + case 9: nRegenSpell = SPELL_REGENERATE; break; + } + ActionCastSpell(nRegenSpell, 0, 0, 0, METAMAGIC_NONE, CLASS_TYPE_DRUID); + } + else + { + switch(nSpellLevel) + { + case 0: return TRUE; + case 1: nRegenSpell = SPELL_REGEN_LIGHT_WOUNDS; break; + case 2: nRegenSpell = SPELL_REGEN_LIGHT_WOUNDS; break; + case 3: nRegenSpell = SPELL_REGEN_MODERATE_WOUNDS; break; + case 4: nRegenSpell = SPELL_REGEN_MODERATE_WOUNDS; break; + case 5: nRegenSpell = SPELL_REGEN_SERIOUS_WOUNDS; break; + case 6: nRegenSpell = SPELL_REGEN_CRITICAL_WOUNDS; break; + case 7: nRegenSpell = SPELL_REGENERATE; break; + case 8: nRegenSpell = SPELL_REGENERATE; break; + case 9: nRegenSpell = SPELL_REGENERATE; break; + } + + ActionCastSpell(nRegenSpell, 0, 0, 0, METAMAGIC_NONE, nCastingClass); + } + //Don't cast original spell + return FALSE; + } + return TRUE; +} int DruidSpontSummon(object oCaster, int nCastingClass, int nSpellID, int nSpellLevel) +{ + if(nCastingClass != CLASS_TYPE_DRUID) + return TRUE; + + if(GetLocalInt(oCaster, "PRC_SpontSummon")) + { + DeleteLocalInt(oCaster, "PRC_SpontSummon"); + int nMetamagic = GetMetaMagicFeat();//we need bioware metamagic here + int nSpellLevel = PRCGetSpellLevelForClass(nSpellID, CLASS_TYPE_DRUID); + nSpellLevel += GetMetaMagicSpellLevelAdjustment(nMetamagic); + int nSummonSpell; + switch(nSpellLevel) + { + case 0: return TRUE; + case 1: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_1; break; + case 2: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_2; break; + case 3: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_3; break; + case 4: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_4; break; + case 5: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_5; break; + case 6: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_6; break; + case 7: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_7; break; + case 8: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_8; break; + case 9: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_9; break; + } + + //:: All SNA spells are subradial spells + SetLocalInt(oCaster, "DomainOrigSpell", nSummonSpell); + SetLocalInt(oCaster, "DomainCastLevel", nSpellLevel); + SetLocalInt(oCaster, "DomainCastClass", CLASS_TYPE_DRUID); + StartDynamicConversation("prc_domain_conv", oCaster, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oCaster); + + //Don't cast original spell + return FALSE; + } + + return TRUE; +} + +/* int DruidSpontSummon(object oCaster, int nCastingClass, int nSpellID, int nSpellLevel) { if(nCastingClass != CLASS_TYPE_DRUID) return TRUE; @@ -191,6 +286,8 @@ int DruidSpontSummon(object oCaster, int nCastingClass, int nSpellID, int nSpell return TRUE; } + */ + int ArcaneSpellFailure(object oCaster, int nCastingClass, int nSpellLevel, int nMetamagic, string sComponents) { if(!GetIsArcaneClass(nCastingClass)) @@ -904,7 +1001,8 @@ int ShifterCasting(object oCaster, object oSpellCastItem, int nSpellLevel, int n { // Potion drinking is not restricted if(GetBaseItemType(oSpellCastItem) == BASE_ITEM_ENCHANTED_POTION - || GetBaseItemType(oSpellCastItem) == BASE_ITEM_POTIONS) + || GetBaseItemType(oSpellCastItem) == BASE_ITEM_POTIONS + || GetBaseItemType(oSpellCastItem) == BASE_ITEM_INFUSED_HERB) return TRUE; //OnHit properties on equipped items not restricted @@ -1441,8 +1539,9 @@ int CheckSecondaryPrC(object oPC = OBJECT_SELF) if (GetHasFeat(FEAT_WILDMAGE_SPELLCASTING_BARD)) return TRUE; if (GetHasFeat(FEAT_WWOC_SPELLCASTING_BARD)) return TRUE; } - else if (bBeguiler) + if (bBeguiler) { + if(DEBUG) DoDebug("x2_inc_spellhook: CheckSecondaryPrC >>> Entering Beguiler", oPC); if (GetHasFeat(FEAT_ABCHAMP_SPELLCASTING_BEGUILER)) return TRUE; if (GetHasFeat(FEAT_AOTS_SPELLCASTING_BEGUILER)) return TRUE; if (GetHasFeat(FEAT_ALCHEM_SPELLCASTING_BEGUILER)) return TRUE; @@ -1492,8 +1591,9 @@ int CheckSecondaryPrC(object oPC = OBJECT_SELF) } - else if (bDuskblade) + if (bDuskblade) { + if(DEBUG) DoDebug("x2_inc_spellhook: CheckSecondaryPrC >>> Entering Dusblade", oPC); if (GetHasFeat(FEAT_ABCHAMP_SPELLCASTING_DUSKBLADE)) return TRUE; if (GetHasFeat(FEAT_AOTS_SPELLCASTING_DUSKBLADE)) return TRUE; if (GetHasFeat(FEAT_ALCHEM_SPELLCASTING_DUSKBLADE)) return TRUE; @@ -1540,7 +1640,7 @@ int CheckSecondaryPrC(object oPC = OBJECT_SELF) } - else if (bSorcerer) + if (bSorcerer) { if(DEBUG) DoDebug("x2_inc_spellhook: CheckSecondaryPrC >>> Entering Sorcerer", oPC); if (GetHasFeat(FEAT_ABERRATION_SPELLCASTING_DRIDER)) return TRUE; @@ -1600,8 +1700,9 @@ int CheckSecondaryPrC(object oPC = OBJECT_SELF) if (GetHasFeat(FEAT_WILDMAGE_SPELLCASTING_SORCERER)) return TRUE; if (GetHasFeat(FEAT_WWOC_SPELLCASTING_SORCERER)) return TRUE; } - else if (bWarmage) + if (bWarmage) { + if(DEBUG) DoDebug("x2_inc_spellhook: CheckSecondaryPrC >>> Entering Warmage", oPC); if (GetHasFeat(FEAT_AOTS_SPELLCASTING_WARMAGE)) return TRUE; if (GetHasFeat(FEAT_ALCHEM_SPELLCASTING_WARMAGE)) return TRUE; if (GetHasFeat(FEAT_ANIMA_SPELLCASTING_WARMAGE)) return TRUE; @@ -1663,14 +1764,71 @@ int BardSorcPrCCheck(object oCaster, int nCastingClass, object oSpellCastItem) return TRUE; } - //check its a sorc spell + //check its a sorcerer spell if(nCastingClass == CLASS_TYPE_SORCERER) { - if (CheckSecondaryPrC(oCaster) == TRUE) + if(DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> nCastingClass is Sorcerer.", oCaster); + //no need to check further if new spellbooks are disabled + if(GetPRCSwitch(PRC_SORC_DISALLOW_NEWSPELLBOOK)) { - if (DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> Sorcerer w/RHD found.", oCaster); + if (DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> PRC_SORC_DISALLOW_NEWSPELLBOOK.", oCaster); return TRUE; } + //check they have sorcerer levels + if(!GetLevelByClass(CLASS_TYPE_SORCERER, oCaster)) + { + if(DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> Not a sorcerer.", oCaster); + return TRUE; + } + //check if they are casting via new spellbook + if(GetLocalInt(oCaster, "NSB_Class") != CLASS_TYPE_SORCERER && GetLevelByClass(CLASS_TYPE_ULTIMATE_MAGUS, oCaster)) + { + if(DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> UltMagus using new spellbook.", oCaster); + return FALSE; + } + //check if they are casting via new spellbook + if(GetLocalInt(oCaster, "NSB_Class") == CLASS_TYPE_SORCERER) + { + if(DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> Using new spellbook.", oCaster); + return TRUE; + } + if(GetLevelByClass(CLASS_TYPE_SUBLIME_CHORD, oCaster) > 0 && CheckSecondaryPrC(oCaster) == TRUE) + { + if (DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> Sublime Chord w/RHD found.", oCaster); + FloatingTextStringOnCreature("You must use the new spellbook on the class radial.", oCaster, FALSE); + return FALSE; + } + if (CheckSecondaryPrC(oCaster) == TRUE) + { + if (DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> Sorcerer w/RHD found.", oCaster); + FloatingTextStringOnCreature("You must use the new spellbook on the class radial.", oCaster, FALSE); + return FALSE; + } + //check they have arcane PrC or Draconic Arcane Grace/Breath + if(!(GetArcanePRCLevels(oCaster, nCastingClass) - GetLevelByClass(CLASS_TYPE_SUBLIME_CHORD, oCaster)) + && !(GetHasFeat(FEAT_DRACONIC_GRACE, oCaster) || GetHasFeat(FEAT_DRACONIC_BREATH, oCaster))) + { + if(DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> First Sublime Chord check.", oCaster); + return TRUE; + } + + //check they have sorcerer in first arcane slot + //if(GetPrimaryArcaneClass() != CLASS_TYPE_SORCERER) + if(GetPrCAdjustedCasterLevelByType(TYPE_ARCANE, oCaster, TRUE) != GetPrCAdjustedCasterLevelByType(CLASS_TYPE_SORCERER, oCaster, TRUE)) + { + if(DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> GetPrCAdjustedCasterLevelByType.", oCaster); + return TRUE; + } + //at this point, they must be using the bioware spellbook + //from a class that adds to bard + FloatingTextStringOnCreature("You must use the new spellbook on the class radial.", oCaster, FALSE); + return FALSE; + } + + +/* //check its a sorc spell + if(nCastingClass == CLASS_TYPE_SORCERER) + { //no need to check further if new spellbooks are disabled if(GetPRCSwitch(PRC_SORC_DISALLOW_NEWSPELLBOOK)) return TRUE; @@ -1709,7 +1867,7 @@ int BardSorcPrCCheck(object oCaster, int nCastingClass, object oSpellCastItem) //from a class that adds to sorc FloatingTextStringOnCreature("You must use the new spellbook on the class radial.", oCaster, FALSE); return FALSE; - } + } */ //check its a bard spell if(nCastingClass == CLASS_TYPE_BARD) @@ -3189,6 +3347,28 @@ int X2PreSpellCastCode2() X2BreakConcentrationSpells(); //--------------------------------------------------------------------------- + // Herbal Infusion Use check + //--------------------------------------------------------------------------- + if(nContinue && (GetBaseItemType(oSpellCastItem) == BASE_ITEM_INFUSED_HERB)) + { + int bIsSubradial = GetIsSubradialSpell(nSpellID); + + if(bIsSubradial) + { + nSpellID = GetMasterSpellFromSubradial(nSpellID); + } + int nItemCL = GetCastSpellCasterLevelFromItem(oSpellCastItem, nSpellID); + if(DEBUG) DoDebug("x2_inc_spellhook >> X2PreSpellCastCode2: Item Spellcaster Level: "+IntToString(nItemCL)+"."); + + if(DEBUG) DoDebug("x2_inc_spellhook >> X2PreSpellCastCode2: Herbal Infusion Found"); + if(!DoInfusionUseChecks(oCaster, oSpellCastItem, nSpellID)) + { + ApplyInfusionPoison(oCaster, nItemCL); + nContinue = FALSE; + } + } + + //--------------------------------------------------------------------------- // No casting while using expertise //--------------------------------------------------------------------------- if(nContinue) @@ -3339,6 +3519,12 @@ int X2PreSpellCastCode2() if (nContinue) nContinue = SpellAlignmentRestrictions(oCaster, nSpellID, nCastingClass); + //--------------------------------------------------------------------------- + // Verdant Lord Spontaneous Regernate + //--------------------------------------------------------------------------- + if(nContinue) + Spontaneity(oCaster, nCastingClass, nSpellID, nSpellLevel); + //--------------------------------------------------------------------------- // Druid spontaneous summoning //--------------------------------------------------------------------------- diff --git a/src/module/itp/creaturepalcus.itp.json b/src/module/itp/creaturepalcus.itp.json index b02f742..1d8b859 100644 --- a/src/module/itp/creaturepalcus.itp.json +++ b/src/module/itp/creaturepalcus.itp.json @@ -53074,7 +53074,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 0.5 + "value": 0.3333 }, "FACTION": { "type": "cexostring", diff --git a/src/module/itp/placeablepalcus.itp.json b/src/module/itp/placeablepalcus.itp.json index a70b4be..511c657 100644 --- a/src/module/itp/placeablepalcus.itp.json +++ b/src/module/itp/placeablepalcus.itp.json @@ -25165,22 +25165,22 @@ "__struct_id": 0, "RESREF": { "type": "resref", - "value": "zep_tree034" + "value": "zep_tree028" }, "STRREF": { "type": "dword", - "value": 16813282 + "value": 16813284 } }, { "__struct_id": 0, "RESREF": { "type": "resref", - "value": "zep_tree028" + "value": "zep_tree034" }, "STRREF": { "type": "dword", - "value": 16813284 + "value": 16813282 } }, { @@ -25227,17 +25227,6 @@ "value": 16813296 } }, - { - "__struct_id": 0, - "RESREF": { - "type": "resref", - "value": "zep_tree035" - }, - "STRREF": { - "type": "dword", - "value": 16813298 - } - }, { "__struct_id": 0, "RESREF": { @@ -25253,11 +25242,11 @@ "__struct_id": 0, "RESREF": { "type": "resref", - "value": "zep_tree038" + "value": "zep_tree035" }, "STRREF": { "type": "dword", - "value": 16813306 + "value": 16813298 } }, { @@ -25271,6 +25260,17 @@ "value": 16813308 } }, + { + "__struct_id": 0, + "RESREF": { + "type": "resref", + "value": "zep_tree038" + }, + "STRREF": { + "type": "dword", + "value": 16813306 + } + }, { "__struct_id": 0, "RESREF": { @@ -25644,17 +25644,6 @@ "value": 16813264 } }, - { - "__struct_id": 0, - "RESREF": { - "type": "resref", - "value": "zep_tree036" - }, - "STRREF": { - "type": "dword", - "value": 16813286 - } - }, { "__struct_id": 0, "RESREF": { @@ -25670,11 +25659,11 @@ "__struct_id": 0, "RESREF": { "type": "resref", - "value": "zep_tree093" + "value": "zep_tree036" }, "STRREF": { "type": "dword", - "value": 16813302 + "value": 16813286 } }, { @@ -25688,6 +25677,17 @@ "value": 16813304 } }, + { + "__struct_id": 0, + "RESREF": { + "type": "resref", + "value": "zep_tree093" + }, + "STRREF": { + "type": "dword", + "value": 16813302 + } + }, { "__struct_id": 0, "RESREF": { diff --git a/src/module/nss/nw_o2_coninclude.nss b/src/module/nss/nw_o2_coninclude.nss deleted file mode 100644 index 685ab84..0000000 --- a/src/module/nss/nw_o2_coninclude.nss +++ /dev/null @@ -1,1719 +0,0 @@ -//:://///////////////////////////////////////////// -//:: NW_O2_CONINCLUDE.nss -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - This include file handles the random treasure - distribution for treasure from creatures and containers - - [ ] Documented -*/ -//::////////////////////////////////////////////// -//:: Created By: Brent, Andrew -//:: Created On: November - May -//::////////////////////////////////////////////// -// :: MODS -// April 23 2002: Removed animal parts. They were silly. -// May 6 2002: Added Undead to the EXCLUSION treasure list (they drop nothing now) -// - redistributed treasure (to lessen amoun t of armor and increase 'class specific treasure' -// - Rangers with heavy armor prof. will be treated as Fighters else as Barbarians -// - Gave wizards, druids and monk their own function -// MAY 29 2002: Removed the heal potion from treasure -// Moved nymph cloak +4 to treasure bracket 6 -// Added Monk Enhancement items to random treasure -//::////////////////////////////////////////////// -//:: Modified by CRP. -//:: Modified for WoG (tweaks, plus removed the CRP parts that wasted resources). -// * Added: GetRangeCat -// * Fixed: CreateArcaneScroll (Replace TrimLevel with ArcaneScrollsByLevel) -// * Split some functions so a creature is not needed to give the level. -// * Moved treasure tables to wog_o2_treasure. -//::////////////////////////////////////////////// - -#include "wog_O2_treasure" -#include "prc_class_const" - -// * --------- -// * CONSTANTS -// * --------- - - -// * tweaking constants - - // * NUMBER OF ITEMS APPEARING - const int NUMBER_LOW_ONE = 100; const int NUMBER_MED_ONE = 60; const int NUMBER_HIGH_ONE = 40; const int NUMBER_BOSS_ONE = 100; - const int NUMBER_LOW_TWO = 0; const int NUMBER_MED_TWO = 30; const int NUMBER_HIGH_TWO = 40; const int NUMBER_BOSS_TWO = 0; - const int NUMBER_LOW_THREE = 0; const int NUMBER_MED_THREE = 10; const int NUMBER_HIGH_THREE = 20; const int NUMBER_BOSS_THREE = 0; - - const int NUMBER_BOOK_ONE = 75; - const int NUMBER_BOOK_TWO = 20; - const int NUMBER_BOOK_THREE = 5; - - // * AMOUNT OF GOLD BY VALUE - const float LOW_MOD_GOLD = 0.5; const float MEDIUM_MOD_GOLD = 1.0; const float HIGH_MOD_GOLD = 3.0; - // * FREQUENCY OF ITEM TYPE APPEARING BY TREASURE TYPE - const int LOW_PROB_BOOK = 1; const int MEDIUM_PROB_BOOK = 1; const int HIGH_PROB_BOOK =1; - const int LOW_PROB_ANIMAL = 0; const int MEDIUM_PROB_ANIMAL = 0; const int HIGH_PROB_ANIMAL = 0; - const int LOW_PROB_JUNK = 2; const int MEDIUM_PROB_JUNK = 1; const int HIGH_PROB_JUNK = 1; - const int LOW_PROB_GOLD = 43; const int MEDIUM_PROB_GOLD = 38; const int HIGH_PROB_GOLD = 15; - const int LOW_PROB_GEM = 9; const int MEDIUM_PROB_GEM = 15; const int HIGH_PROB_GEM = 15; - const int LOW_PROB_JEWEL = 4; const int MEDIUM_PROB_JEWEL = 6; const int HIGH_PROB_JEWEL = 15; - const int LOW_PROB_ARCANE = 3; const int MEDIUM_PROB_ARCANE = 3; const int HIGH_PROB_ARCANE = 3; - const int LOW_PROB_DIVINE = 3; const int MEDIUM_PROB_DIVINE = 3; const int HIGH_PROB_DIVINE = 3; - const int LOW_PROB_AMMO = 10; const int MEDIUM_PROB_AMMO = 5; const int HIGH_PROB_AMMO = 3; - const int LOW_PROB_KIT = 5; const int MEDIUM_PROB_KIT = 5; const int HIGH_PROB_KIT = 5; - const int LOW_PROB_POTION =17; const int MEDIUM_PROB_POTION = 20; const int HIGH_PROB_POTION= 9; - const int LOW_PROB_TABLE2 = 3; const int MEDIUM_PROB_TABLE2 = 3; const int HIGH_PROB_TABLE2= 30; - - -// * readability constants - -const int TREASURE_LOW = 1; -const int TREASURE_MEDIUM = 2; -const int TREASURE_HIGH = 3; -const int TREASURE_BOSS = 4; -const int TREASURE_BOOK = 5; - - -//* Declarations -int nDetermineClassToUse(object oCharacter); - - -// * -// * IMPLEMENTATION -// * - -// * -// * GET FUNCTIONS -// * - -// * Returns the object that either last opened the caller or destroyed it. -// * Modified for WoG to better handle chests that reset after a while. -- TK -object GetLastOpener() -{ - // In a death script, we want the one who destroyed us. - object oOpener = GetLastKiller(); - - // If not a death script, we want the one who opened us. - if ( oOpener == OBJECT_INVALID ) - oOpener = GetLastOpenedBy(); - - return oOpener; -} - -//:://///////////////////////////////////////////// -//:: GetNumberOfItems -//:: Copyright (c) 2002 Bioware Corp. -//::////////////////////////////////////////////// -/* - Returns the number of items to create. -*/ -//::////////////////////////////////////////////// -//:: Created By: Brent -//:: Created On: -//::////////////////////////////////////////////// -int GetNumberOfItems(int nTreasureType) -{ - int nItems = 0; - int nRandom = 0; - - int nProbThreeItems = 0; - int nProbTwoItems = 0; - int nProbOneItems = 0; - - if (nTreasureType == TREASURE_LOW) - { - nProbThreeItems = NUMBER_LOW_THREE; - nProbTwoItems = NUMBER_LOW_TWO; - nProbOneItems = NUMBER_LOW_ONE; - } - else - if (nTreasureType == TREASURE_MEDIUM) - { - nProbThreeItems = NUMBER_MED_THREE; - nProbTwoItems = NUMBER_MED_TWO; - nProbOneItems = NUMBER_MED_ONE; - } - else - if (nTreasureType == TREASURE_HIGH) - { - nProbThreeItems = NUMBER_HIGH_THREE; - nProbTwoItems = NUMBER_HIGH_TWO; - nProbOneItems = NUMBER_HIGH_ONE; - } - else - if (nTreasureType == TREASURE_BOSS) - { - nProbThreeItems = NUMBER_BOSS_THREE; - nProbTwoItems = NUMBER_BOSS_TWO; - nProbOneItems = NUMBER_BOSS_ONE; - } - else - if (nTreasureType == TREASURE_BOOK) - { - nProbThreeItems = NUMBER_BOOK_THREE; - nProbTwoItems = NUMBER_BOOK_TWO; - nProbOneItems = NUMBER_BOOK_ONE; - } - - - nRandom = d100(); - if (nRandom <= nProbThreeItems) - { - nItems = 3; - } - else - if (nRandom <= nProbTwoItems + nProbThreeItems) - { - nItems = 2; - } - else - { - nItems = 1; - } - - // * May 13 2002: Cap number of items, in case of logic error - if (nItems > 3) - { - nItems = 3; - } - - return nItems; -} - - -// * -// * TREASURE GENERATION FUNCTIONS -// * - void CreateGold(object oTarget, object oAdventurer, int nTreasureType, int nModifier = 0) - { - float nMod = 0.0; - if (nTreasureType == TREASURE_LOW) nMod = LOW_MOD_GOLD; - else if (nTreasureType == TREASURE_MEDIUM) nMod = MEDIUM_MOD_GOLD; - else if (nTreasureType == TREASURE_HIGH) nMod = HIGH_MOD_GOLD; - - CreateGoldByHD(oTarget, GetHitDice(oAdventurer) + nModifier, nMod); - } - void CreateKit(object oTarget, object oAdventurer, int nModifier = 0) - { - // * April 23 2002: Major restructuring of this function - // * to allow me to - - switch (Random(8) + 1) - { - case 1: CreateTrapKit(oTarget, oAdventurer, nModifier); break; - case 2: case 3: case 4: case 5: CreateHealingKit(oTarget, oAdventurer, nModifier); break; - case 6: case 7: case 8: CreateLockPick(oTarget, oAdventurer, nModifier); break; - } - } - - //:://///////////////////////////////////////////// - //:: CreateTable2GenericItem - //:: Copyright (c) 2002 Bioware Corp. - //::////////////////////////////////////////////// - /* - Creates an item based upon the class of - oAdventurer - */ - //::////////////////////////////////////////////// - //:: Created By: Brent - //:: Created On: - //::////////////////////////////////////////////// - - // * this function just returns an item that is more appropriate - // * for this class. Only wizards, sorcerers, clerics, monks, rogues and bards get this - void CreateGenericClassItem(object oTarget, object oAdventurer, int nSpecific =0) - { - - - if (GetLevelByClass(CLASS_TYPE_DRUID, oAdventurer)>= 1) - { - if (nSpecific == 0) - { - CreateGenericDruidWeapon(oTarget, oAdventurer); - } - else - { - CreateSpecificDruidWeapon(oTarget, oAdventurer); - } - } - else - if (GetLevelByClass(CLASS_TYPE_WIZARD, oAdventurer)>= 1 || GetLevelByClass(CLASS_TYPE_SORCERER, oAdventurer) >= 1) - { - // * 30% chance of getting a magic scroll else get a weapon suited for a wizard - if (Random(100) + 1 > 70) - { - // * grab an arcane scroll as if the wizard had +4 levels - CreateArcaneScroll(oTarget, oAdventurer, 4); - } - else - if (nSpecific == 0) - { - CreateGenericWizardWeapon(oTarget, oAdventurer); - } - else - { - CreateSpecificWizardWeapon(oTarget, oAdventurer); - } - - - } - else - if (GetLevelByClass(CLASS_TYPE_CLERIC, oAdventurer)>= 1) - { - // TK: The BioCode listed medkit ResRefs here. I replaced that - // with this call to get better scaling and better - // separation of treasure tables from decision logic. - CreateHealingKit(oTarget, oAdventurer); - } - else - if (GetLevelByClass(CLASS_TYPE_MONK, oAdventurer)>= 1) - { - //dbSpeak("in monk function"); - if (nSpecific == 0) - { - CreateGenericMonkWeapon(oTarget, oAdventurer); - } - else - { - CreateSpecificMonkWeapon(oTarget, oAdventurer); - } - } - else - if (GetLevelByClass(CLASS_TYPE_ROGUE, oAdventurer)>= 1) - { - // * give a misc item as if a couple levels higher - CreateGenericMiscItem(oTarget, oAdventurer, 2); - } - else - if (GetLevelByClass(CLASS_TYPE_BARD, oAdventurer)>= 1) - { - // * give a misc item as if a couple levels higher - CreateGenericMiscItem(oTarget, oAdventurer, 2); - } - - } - // * - // * SPECIC TREASURE ITEMS (re: Named Items) - // * - // * if nSpecific is = 1 then spawn in 'named' items at the higher levels - void CreateTable2Item(object oTarget, object oAdventurer, int nSpecific=0) - { - //dbSpeak("In CreateTable2Item"); - string sItem = ""; - int nProbMisc = 0; - int nProbClass = 0; - int nProbRodStaffWand = 0; - int nProbSimple = 0; - int nProbMartial = 0; - int nProbExotic = 0; - int nProbLight = 0; - int nProbMedium = 0; - int nProbHeavy = 0; - - int nSpecialRanger = 0; // 2 Means to treat the ranger as a barbarian. A 1 is to treat it as a fighter - - - // * May 2002: Changed using Preston's multiclass function - // * it randomly chooses one of your classes - int nClass = nDetermineClassToUse(oAdventurer); - - - // * SPECIAL RANGER BEHAVIOR - // * If the ranger has the Heavy Armor proficiency, will treat the ranger - if ( nClass == CLASS_TYPE_RANGER && GetHasFeat(FEAT_ARMOR_PROFICIENCY_HEAVY)) - { - nSpecialRanger = 1; - } - else - if (nClass == CLASS_TYPE_RANGER) - { - nSpecialRanger = 2; - } - - - - //* SETUP probabilities based on Class - if ( nClass == CLASS_TYPE_FIGHTER || nClass == CLASS_TYPE_PALADIN || nSpecialRanger == 1 - || nClass == CLASS_TYPE_ANTI_PALADIN || nClass == CLASS_TYPE_BRAWLER || nClass == CLASS_TYPE_CRUSADER - || nClass == CLASS_TYPE_DUSKBLADE || nClass == CLASS_TYPE_KNIGHT || nClass == CLASS_TYPE_MARSHAL - || nClass == CLASS_TYPE_PSYWAR || nClass == CLASS_TYPE_SOHEI) - { - //dbSpeak("I am fighter or paladin or heavy ranger"); - nProbMisc = 20; - nProbClass = 0; - nProbRodStaffWand = 5; - nProbSimple = 5; - nProbMartial = 20; - nProbExotic = 10; - nProbLight = 5; - nProbMedium = 15; - nProbHeavy = 20; - } - else - if (nClass == CLASS_TYPE_WIZARD || nClass == CLASS_TYPE_SORCERER) - { - //dbSpeak("I am wizard or sorcerer"); - nProbMisc = 40; - nProbClass = 30; - nProbRodStaffWand = 15; - nProbSimple = 3; - nProbMartial = 3; - nProbExotic = 3; - nProbLight = 2; - nProbMedium = 2; - nProbHeavy = 2; - } - else - if (nClass == CLASS_TYPE_BARBARIAN || nSpecialRanger == 2 || nClass == CLASS_TYPE_BOWMAN - || nClass == CLASS_TYPE_HEXBLADE || nClass == CLASS_TYPE_WARBLADE) - { - //dbSpeak("I am barbarian or light ranger"); - - nProbMisc = 20; - nProbClass = 0; - nProbRodStaffWand = 5; - nProbSimple = 17; - nProbMartial = 27; - nProbExotic = 15; - nProbLight = 8; - nProbMedium = 5; - nProbHeavy = 3; - } - else - if (nClass == CLASS_TYPE_ARCHIVIST || nClass == CLASS_TYPE_DRAGON_SHAMAN || nClass == CLASS_TYPE_FAVOURED_SOUL - || nClass == CLASS_TYPE_MYSTIC || nClass == CLASS_TYPE_WARMAGE || nClass == CLASS_TYPE_TEMPLAR) - { - //type 1 - nProbMisc = 25; - nProbClass = 0; - nProbRodStaffWand = 15; - nProbSimple = 15; - nProbMartial = 8; - nProbExotic = 6; - nProbLight = 15; - nProbMedium = 10; - nProbHeavy = 6; - } - else - if (nClass == CLASS_TYPE_NOBLE || nClass == CLASS_TYPE_SWASHBUCKLER || nClass == CLASS_TYPE_SWORDSAGE - || nClass == CLASS_TYPE_ULTIMATE_RANGER) - { - //type 2 - nProbMisc = 27; - nProbClass = 0; - nProbRodStaffWand = 5; - nProbSimple = 15; - nProbMartial = 20; - nProbExotic = 10; - nProbLight = 10; - nProbMedium = 8; - nProbHeavy = 5; - } - else - if (nClass == CLASS_TYPE_BEGUILER || nClass == CLASS_TYPE_DREAD_NECROMANCER || nClass == CLASS_TYPE_HEALER - || nClass == CLASS_TYPE_SCOUT || nClass == CLASS_TYPE_SHAMAN || nClass == CLASS_TYPE_SOULKNIFE - || nClass == CLASS_TYPE_TRUENAMER || nClass == CLASS_TYPE_WARLOCK || nClass == CLASS_TYPE_WILDER) - { - //type 3 - nProbMisc = 45; - nProbClass = 0; - nProbRodStaffWand = 7; - nProbSimple = 15; - nProbMartial = 5; - nProbExotic = 5; - nProbLight = 15; - nProbMedium = 4; - nProbHeavy = 4; - } - else - if (nClass == CLASS_TYPE_DRAGONFIRE_ADEPT || nClass == CLASS_TYPE_PSION || nClass == CLASS_TYPE_WITCH) - { - //type 4 - nProbMisc = 50; - nProbClass = 0; - nProbRodStaffWand = 10; - nProbSimple = 20; - nProbMartial = 5; - nProbExotic = 5; - nProbLight = 4; - nProbMedium = 3; - nProbHeavy = 3; - } - else - if (nClass == CLASS_TYPE_NINJA) - { - //type 5 - nProbMisc = 45; - nProbClass = 0; - nProbRodStaffWand = 2; - nProbSimple = 12; - nProbMartial = 6; - nProbExotic = 26; - nProbLight = 3; - nProbMedium = 3; - nProbHeavy = 3; - } - else - if (nClass == CLASS_TYPE_CW_SAMURAI || nClass == CLASS_TYPE_SAMURAI) - { - //type 6 - nProbMisc = 25; - nProbClass = 0; - nProbRodStaffWand = 5; - nProbSimple = 5; - nProbMartial = 10; - nProbExotic = 20; - nProbLight = 10; - nProbMedium = 20; - nProbHeavy = 5; - } - else - if (nClass == CLASS_TYPE_CLERIC) - { - //dbSpeak("I am cleric"); - - nProbMisc = 20; - nProbClass = 10; - nProbRodStaffWand = 10; - nProbSimple = 25; - nProbMartial = 7; - nProbExotic = 5; - nProbLight = 5; - nProbMedium = 8; - nProbHeavy = 10; - } - else - if (nClass == CLASS_TYPE_DRUID) - { - //dbSpeak("I am druid"); - - nProbMisc = 20; - nProbClass = 25; - nProbRodStaffWand = 15; - nProbSimple = 10; - nProbMartial = 5; - nProbExotic = 5; - nProbLight = 10; - nProbMedium = 5; - nProbHeavy = 5; - } - else - if (nClass == CLASS_TYPE_MONK) - { - //dbSpeak("I am monk"); - nProbMisc = 20; - nProbClass = 50; - nProbRodStaffWand = 2; - nProbSimple = 7; - nProbMartial = 2; - nProbExotic = 7; - nProbLight = 4; - nProbMedium = 4; - nProbHeavy = 4; - } - else - if (nClass == CLASS_TYPE_ROGUE || nClass == CLASS_TYPE_PSYCHIC_ROGUE) - { - //dbSpeak("I am rogue"); - - nProbMisc = 25; - nProbClass = 10; - nProbRodStaffWand = 10; - nProbSimple = 25; - nProbMartial = 5; - nProbExotic = 5; - nProbLight = 10; - nProbMedium = 5; - nProbHeavy = 5; - } - else - if (nClass == CLASS_TYPE_BARD) - { - //dbSpeak("I am bard"); - - nProbMisc = 25; - nProbClass = 5; - nProbRodStaffWand = 5; - nProbSimple = 25; - nProbMartial = 10; - nProbExotic = 10; - nProbLight = 10; - nProbMedium = 5; - nProbHeavy = 5; - } - //else - //{ - // dbSpeak("No Valid Class"); - //} - //dbSpeak("Table2Item: After Class Distribution"); - //* Create Items based on Probabilities - int nRandom = d100(); - if (nRandom <= nProbMisc) - { - if (nSpecific == 0) CreateGenericMiscItem(oTarget, oAdventurer); - else CreateSpecificMiscItem(oTarget, oAdventurer); - - } - else - if (nRandom <= nProbMisc + nProbClass) - { // * no need for a seperate specific function here - CreateGenericClassItem(oTarget, oAdventurer, nSpecific); - } - else - if (nRandom <= nProbMisc + nProbClass + nProbRodStaffWand) - { - if (nSpecific == 0) CreateGenericRodStaffWand(oTarget, oAdventurer); - else CreateSpecificRodStaffWand(oTarget, oAdventurer); - } - else - if (nRandom <= nProbMisc + nProbClass + nProbRodStaffWand + nProbSimple) - { - if (nSpecific == 0) CreateGenericSimple(oTarget, oAdventurer); - else CreateSpecificSimple(oTarget, oAdventurer); - } - else - if (nRandom <= nProbMisc + nProbClass + nProbRodStaffWand + nProbSimple + nProbMartial) - { - - if (nSpecific == 0) CreateGenericMartial(oTarget, oAdventurer); - else CreateSpecificMartial(oTarget, oAdventurer); - } - else - if (nRandom <= nProbMisc + nProbClass + nProbRodStaffWand + nProbSimple + nProbMartial + nProbExotic) - { - if (nSpecific == 0) CreateGenericExotic(oTarget, oAdventurer); - else CreateSpecificExotic(oTarget, oAdventurer); - } - else - if (nRandom <= nProbMisc + nProbClass + nProbRodStaffWand + nProbSimple + nProbMartial + nProbExotic + nProbLight) - { - if (nSpecific == 0) CreateGenericLightArmor(oTarget, oAdventurer); - else CreateSpecificLightArmor(oTarget, oAdventurer); - } - else - if (nRandom <= nProbMisc + nProbClass + nProbRodStaffWand + nProbSimple + nProbMartial + nProbExotic + nProbLight + nProbMedium) - { - if (nSpecific == 0) CreateGenericMediumArmor(oTarget, oAdventurer); - else CreateSpecificMediumArmor(oTarget, oAdventurer); - } - else - if (nRandom <= nProbMisc + nProbClass + nProbRodStaffWand + nProbSimple + nProbMartial + nProbExotic + nProbLight + nProbMedium + nProbHeavy) - { - if (nSpecific == 0) CreateGenericHeavyArmor(oTarget, oAdventurer); - else CreateSpecificHeavyArmor(oTarget, oAdventurer); - } - //else - //{ - // dbSpeak("Generic Generic or Specific; error: 3524"); - //} - } - -//:://///////////////////////////////////////////// -//:: GenerateTreasure -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Generate Treasure - NOTE: When used by NPCs, the treasure is scaled - to how powerful the NPC is. - - If used by containers, it is scaled by how - powerful the PC is. - - PARAMETERS - oLastOpener = The creature that opened the container - oCreateOn = The place to put the treasure. If this is - invalid then the treasure is placed on oLastOpener - - -*/ -//::////////////////////////////////////////////// -//:: Created By: Andrew -//:: Created On: -//::////////////////////////////////////////////// -void GenerateTreasure(int nTreasureType, object oLastOpener, object oCreateOn) -{ - - //dbSpeak("*********************NEW TREASURE*************************"); - - // * abort treasure if no one opened the container - if (GetIsObjectValid(oLastOpener) == FALSE) - { - //dbSpeak("Aborted. No valid Last Opener"); - return; - } - - // * if no valid create on object, then create on oLastOpener - if (oCreateOn == OBJECT_INVALID) - { - oCreateOn = oLastOpener; - } - - // * if an Animal then generate 100% animal treasure - - // not done yet - // * VARIABLES - int nProbBook = 0; - int nProbAnimal = 0; - int nProbJunk = 0; - int nProbGold = 0; - int nProbGem = 0; - int nProbJewel = 0; - int nProbArcane = 0; - int nProbDivine = 0; - int nProbAmmo = 0; - int nProbKit = 0; - int nProbPotion = 0; - int nProbTable2 = 0; - - int nSpecific = 0; - int i = 0; - int nNumberItems = GetNumberOfItems(nTreasureType); - - // * Set Treasure Type Values - if (nTreasureType == TREASURE_LOW) - { - nProbBook = LOW_PROB_BOOK; - nProbAnimal = LOW_PROB_ANIMAL; - nProbJunk = LOW_PROB_JUNK; - nProbGold = LOW_PROB_GOLD; - nProbGem = LOW_PROB_GEM; - nProbJewel = LOW_PROB_JEWEL; - nProbArcane = LOW_PROB_ARCANE; - nProbDivine = LOW_PROB_DIVINE; - nProbAmmo = LOW_PROB_AMMO ; - nProbKit = LOW_PROB_KIT; - nProbPotion = LOW_PROB_POTION; - nProbTable2 = LOW_PROB_TABLE2; - } - else if (nTreasureType == TREASURE_MEDIUM) - { - nProbBook = MEDIUM_PROB_BOOK; - nProbAnimal = MEDIUM_PROB_ANIMAL; - nProbJunk = MEDIUM_PROB_JUNK; - nProbGold = MEDIUM_PROB_GOLD; - nProbGem = MEDIUM_PROB_GEM; - nProbJewel = MEDIUM_PROB_JEWEL; - nProbArcane = MEDIUM_PROB_ARCANE; - nProbDivine = MEDIUM_PROB_DIVINE; - nProbAmmo = MEDIUM_PROB_AMMO ; - nProbKit = MEDIUM_PROB_KIT; - nProbPotion = MEDIUM_PROB_POTION; - nProbTable2 = MEDIUM_PROB_TABLE2; - } - else if (nTreasureType == TREASURE_HIGH) - { - nProbBook = HIGH_PROB_BOOK; - nProbAnimal = HIGH_PROB_ANIMAL; - nProbJunk = HIGH_PROB_JUNK; - nProbGold = HIGH_PROB_GOLD; - nProbGem = HIGH_PROB_GEM; - nProbJewel = HIGH_PROB_JEWEL; - nProbArcane = HIGH_PROB_ARCANE; - nProbDivine = HIGH_PROB_DIVINE; - nProbAmmo = HIGH_PROB_AMMO ; - nProbKit = HIGH_PROB_KIT; - nProbPotion = HIGH_PROB_POTION; - nProbTable2 = HIGH_PROB_TABLE2; - } - else if (nTreasureType == TREASURE_BOSS) - { //dbSpeak("boss"); - nProbTable2 = 100; - nSpecific = 1; - } - else if (nTreasureType == TREASURE_BOOK) - { - nProbBook = 90; - nProbArcane = 6; - nProbDivine = 4; - } - - //dbSpeak("Generate Treasure nSpecific = " + IntToString(nSpecific)); - - for (i = 1; i <= nNumberItems; i++) - { - int nRandom = d100(); - if (nRandom <= nProbBook) - CreateBook(oCreateOn); // * Book - else if (nRandom <= nProbBook + nProbAnimal) - CreateAnimalPart(oCreateOn); // * Animal - else if (nRandom <= nProbBook + nProbAnimal + nProbJunk) - CreateJunk(oCreateOn); // * Junk - else if (nRandom <= nProbBook + nProbAnimal + nProbJunk + nProbGold) - CreateGold(oCreateOn, oLastOpener, nTreasureType); // * Gold - else if (nRandom <= nProbBook + nProbAnimal + nProbJunk + nProbGold + nProbGem) - CreateGem(oCreateOn, oLastOpener, nTreasureType); // * Gem - else if (nRandom <= nProbBook + nProbAnimal + nProbJunk + nProbGold + nProbGem + nProbJewel) - CreateJewel(oCreateOn, oLastOpener, nTreasureType); // * Jewel - else if (nRandom <= nProbBook + nProbAnimal + nProbJunk + nProbGold + nProbGem + nProbJewel + nProbArcane) - CreateArcaneScroll(oCreateOn, oLastOpener); // * Arcane Scroll - else if (nRandom <= nProbBook + nProbAnimal + nProbJunk + nProbGold + nProbGem + nProbJewel + nProbArcane + nProbDivine) - CreateDivineScroll(oCreateOn, oLastOpener); // * Divine Scroll - else if (nRandom <= nProbBook + nProbAnimal + nProbJunk + nProbGold + nProbGem + nProbJewel + nProbArcane + nProbDivine + nProbAmmo) - CreateAmmo(oCreateOn, oLastOpener); // * Ammo - else if (nRandom <= nProbBook + nProbAnimal + nProbJunk + nProbGold + nProbGem + nProbJewel + nProbArcane + nProbDivine + nProbAmmo + nProbKit) - CreateKit(oCreateOn, oLastOpener); // * Healing, Trap, or Thief kit - else if (nRandom <= nProbBook + nProbAnimal + nProbJunk + nProbGold + nProbGem + nProbJewel + nProbArcane + nProbDivine + nProbAmmo + nProbKit + nProbPotion) - CreatePotion(oCreateOn, oLastOpener); // * Potion - else if (nRandom <= nProbBook + nProbAnimal + nProbJunk + nProbGold + nProbGem + nProbJewel + nProbArcane + nProbDivine + nProbAmmo + nProbKit + nProbPotion + nProbTable2) - { - CreateTable2Item(oCreateOn, oLastOpener, nSpecific); // * Weapons, Armor, Misc - Class based - } - //else - // dbSpeak("other stuff"); - - - - } -} -void GenerateLowTreasure(object oLastOpener, object oCreateOn=OBJECT_INVALID) -{ - GenerateTreasure(TREASURE_LOW, oLastOpener, oCreateOn); -} -void GenerateMediumTreasure(object oLastOpener, object oCreateOn=OBJECT_INVALID) -{ - GenerateTreasure(TREASURE_MEDIUM, oLastOpener, oCreateOn); -} -void GenerateHighTreasure(object oLastOpener, object oCreateOn=OBJECT_INVALID) -{ - GenerateTreasure(TREASURE_HIGH, oLastOpener, oCreateOn); -} -void GenerateBossTreasure(object oLastOpener, object oCreateOn=OBJECT_INVALID) -{ - GenerateTreasure(TREASURE_BOSS, oLastOpener, oCreateOn); -} -void GenerateBookTreasure(object oLastOpener, object oCreateOn=OBJECT_INVALID) -{ - GenerateTreasure(TREASURE_BOOK, oLastOpener, oCreateOn); -} -//:://///////////////////////////////////////////// -//:: GenerateNPCTreasure -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Preferrably called from OnSpawn scripts. - Use the random treasure functions to generate - appropriate treasure for the creature to drop. -*/ -//::////////////////////////////////////////////// -//:: Created By: Brent -//:: Created On: January 2002 -//::////////////////////////////////////////////// - -void GenerateNPCTreasure(int nTreasureValue=1, object oTreasureGetter=OBJECT_SELF, object oKiller=OBJECT_SELF) -{ - //DestroyObject(OBJECT_SELF); - // * if I am an animal ,then give me animal stuff instead - if (GetObjectType(oTreasureGetter) == OBJECT_TYPE_CREATURE) - { - if ( - (GetRacialType(oTreasureGetter) == RACIAL_TYPE_UNDEAD) || - (GetRacialType(oTreasureGetter) == RACIAL_TYPE_ANIMAL) || - (GetRacialType(oTreasureGetter) == RACIAL_TYPE_BEAST) || - (GetRacialType(oTreasureGetter) == RACIAL_TYPE_MAGICAL_BEAST) || - (GetRacialType(oTreasureGetter) == RACIAL_TYPE_VERMIN) - ) - { - //CreateAnimalPart(oTreasureGetter); - // April 23 2002: Removed animal parts. They are silly. - return; - } - } - - if (nTreasureValue == 1) - { - // April 2002: 30% chance of not getting any treasure now - // if a creature - if (Random(100)+1 >= 75) - GenerateTreasure(TREASURE_LOW, oTreasureGetter, oKiller); - } - else - if (nTreasureValue == 2) - { - GenerateTreasure(TREASURE_MEDIUM, oTreasureGetter, oKiller); - } - else - if (nTreasureValue == 3) - { - GenerateTreasure(TREASURE_HIGH, oTreasureGetter, oKiller); - } - else - if (nTreasureValue == 4) - { - GenerateBossTreasure(oKiller, oTreasureGetter); - } - -} - -// * -// * Theft Prevention -// * - -//:://///////////////////////////////////////////// -//:: ShoutDisturbed -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - -*/ -//::////////////////////////////////////////////// -//:: Created By: -//:: Created On: -//::////////////////////////////////////////////// - -// * Container shouts if disturbed -void ShoutDisturbed() -{ - if (GetIsDead(OBJECT_SELF) == TRUE) - { - object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(OBJECT_SELF), TRUE, OBJECT_TYPE_CREATURE); - //Cycle through the targets within the spell shape until an invalid object is captured. - while (GetIsObjectValid(oTarget)) - { - if (GetFactionEqual(oTarget, OBJECT_SELF) == TRUE) - { - // * Make anyone who is a member of my faction hostile if I am violated - object oAttacker = GetLastAttacker(); - SetIsTemporaryEnemy(oAttacker,oTarget); - AssignCommand(oTarget, ActionAttack(oAttacker)); - } - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(OBJECT_SELF), TRUE, OBJECT_TYPE_CREATURE); - } - } - else if (GetIsOpen(OBJECT_SELF) == TRUE) - { - object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(OBJECT_SELF), TRUE, OBJECT_TYPE_CREATURE); - //Cycle through the targets within the spell shape until an invalid object is captured. - while (GetIsObjectValid(oTarget)) - { - if (GetFactionEqual(oTarget, OBJECT_SELF) == TRUE) - { - // * Make anyone who is a member of my faction hostile if I am violated - object oAttacker = GetLastOpener(); - SetIsTemporaryEnemy(oAttacker,oTarget); - AssignCommand(oTarget, ActionAttack(oAttacker)); - - } - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(OBJECT_SELF), TRUE, OBJECT_TYPE_CREATURE); - } - } -} - - -//:://///////////////////////////////////////////// -//:: Determine Class to Use -//:: Copyright (c) 2002 Bioware Corp. -//::////////////////////////////////////////////// -/* - Determines which of a NPC's three classes to - use in the random treasure system -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: April 4, 2002 -//::////////////////////////////////////////////// -//:: Simplifications: The Krit (for WoG) -// (I also changed the probability skewing that occurs when oCharacter has -// a non-base class.) -//::////////////////////////////////////////////// - -int nDetermineClassToUse(object oCharacter) -{ - int nClass1 = GetClassByPosition(1, oCharacter); - int nClass2 = GetClassByPosition(2, oCharacter); - int nClass3 = GetClassByPosition(3, oCharacter); - - // correct for unrecognized classes - assumes the first class will be a non-prestige player class - if ( nClass2 > CLASS_TYPE_WIZARD ) nClass2 = CLASS_TYPE_INVALID; - if ( nClass3 > CLASS_TYPE_WIZARD ) nClass3 = CLASS_TYPE_INVALID; - - // Get levels - int nLevel1 = GetLevelByPosition(1, oCharacter); - int nLevel2 = (CLASS_TYPE_INVALID == nClass2) ? 0 : GetLevelByPosition(2, oCharacter); - int nLevel3 = (CLASS_TYPE_INVALID == nClass3) ? 0 : GetLevelByPosition(3, oCharacter); - - // Safety check. - if ( nLevel1 < 1 ) - nLevel1 = 1; - - // Choose one of the three classes. - int nUseClass = Random(nLevel1 + nLevel2 + nLevel3); // Note: 0-based - if ( nUseClass < nLevel1 ) // Note: strict inequality - return nClass1; - if ( nUseClass < nLevel1 + nLevel2 ) - return nClass2; - return nClass3; -} - - -//::////////////////////////////////////////////// -//:: Treasure logic that used to be in nw_o2_classweap -//::////////////////////////////////////////////// - - -// Given a number, converts to a string padded to the specified length. -// If the number is too big for the length, it will be truncated, so be careful! -// Currently, we support at most two spaces being added. (It's trivial to up -// this limit, should the need arise.) -string PaddedInt(int iNumber, int iLength); -string PaddedInt(int iNumber, int iLength) -{ - return GetStringRight(" " + IntToString(iNumber), iLength); -} - -// Returns a string indicating a single character's weapon-focus-based feats. -// The string consists of 5-character pieces. The first 3 characters are a -// BASE_ITEM_* constant converted to a string, and the last 2 characters are -// a level converted to a string. -string GetCharFocusPref(object oAdventurer) -{ - int nHD = GetHitDice(oAdventurer); - int nWM = GetLevelByClass(CLASS_TYPE_WEAPON_MASTER, oAdventurer); - string sFocus = ""; - string sChoice = ""; - string sArchery = ""; // Arcane archer focus - - // Pretty dreary here. Just check each weapon focus feat to see it the - // character has it. If so, also check for specialization and choice. - if ( GetHasFeat(FEAT_WEAPON_FOCUS_BASTARD_SWORD, oAdventurer) ) { - string sPiece = PaddedInt(BASE_ITEM_BASTARDSWORD, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_BASTARD_SWORD, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_BASTARDSWORD, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_BATTLE_AXE, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_BATTLEAXE, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_BATTLE_AXE, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_BATTLEAXE, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_CLUB, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_CLUB, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_CLUB, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_CLUB, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_DAGGER, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_DAGGER, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_DAGGER, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_DAGGER, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_DART, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_DART, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_DART, oAdventurer) ) - sFocus += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_DIRE_MACE, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_DIREMACE, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_DIRE_MACE, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_DIREMACE, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_DOUBLE_AXE, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_DOUBLEAXE, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_DOUBLE_AXE, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_DOUBLEAXE, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_DWAXE, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_DWARVENWARAXE, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_DWAXE, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_DWAXE, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_GREAT_AXE, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_GREATAXE, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_GREAT_AXE, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_GREATAXE, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_GREAT_SWORD, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_GREATSWORD, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_GREAT_SWORD, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_GREATSWORD, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_HALBERD, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_HALBERD, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_HALBERD, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_HALBERD, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_HAND_AXE, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_HANDAXE, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_HAND_AXE, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_HANDAXE, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_HEAVY_CROSSBOW, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_HEAVYCROSSBOW, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_HEAVY_CROSSBOW, oAdventurer) ) - sFocus += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_HEAVY_FLAIL, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_HEAVYFLAIL, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_HEAVY_FLAIL, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_HEAVYFLAIL, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_KAMA, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_KAMA, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_KAMA, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_KAMA, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_KATANA, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_KATANA, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_KATANA, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_KATANA, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_KUKRI, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_KUKRI, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_KUKRI, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_KUKRI, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_CROSSBOW, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_LIGHTCROSSBOW, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_LIGHT_CROSSBOW, oAdventurer) ) - sFocus += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_FLAIL, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_LIGHTFLAIL, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_LIGHT_FLAIL, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_LIGHTFLAIL, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_HAMMER, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_LIGHTHAMMER, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_LIGHT_HAMMER, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_LIGHTHAMMER, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_LONGBOW, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_LONGBOW, 3) + PaddedInt(nHD, 2); - sArchery += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_LONGBOW, oAdventurer) ) - sArchery += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_LONG_SWORD, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_LONGSWORD, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_LONG_SWORD, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_LONGSWORD, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_MACE, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_LIGHTMACE, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_LIGHT_MACE, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_LIGHTMACE, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_MORNING_STAR, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_MORNINGSTAR, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_MORNING_STAR, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_MORNINGSTAR, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_STAFF, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_QUARTERSTAFF, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_STAFF, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_QUARTERSTAFF, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_RAPIER, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_RAPIER, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_RAPIER, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_RAPIER, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_SCIMITAR, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_SCIMITAR, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_SCIMITAR, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_SCIMITAR, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_SCYTHE, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_SCYTHE, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_SCYTHE, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_SCYTHE, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_SHORTBOW, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_SHORTBOW, 3) + PaddedInt(nHD, 2); - sArchery += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_SHORTBOW, oAdventurer) ) - sArchery += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_SHORT_SWORD, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_SHORTSWORD, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_SHORT_SWORD, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_SHORTSWORD, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_SHURIKEN, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_SHURIKEN, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_SHURIKEN, oAdventurer) ) - sFocus += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_SICKLE, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_SICKLE, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_SICKLE, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_SICKLE, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_SLING, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_SLING, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_SLING, oAdventurer) ) - sFocus += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_SPEAR, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_SHORTSPEAR, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_SPEAR, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_SHORTSPEAR, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_THROWING_AXE, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_THROWINGAXE, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_THROWING_AXE, oAdventurer) ) - sFocus += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_TRIDENT, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_TRIDENT, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_TRIDENT, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_TRIDENT, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_TWO_BLADED_SWORD, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_TWOBLADEDSWORD, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_TWO_BLADED_SWORD, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_TWOBLADEDSWORD, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_WAR_HAMMER, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_WARHAMMER, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_WAR_HAMMER, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_WARHAMMER, oAdventurer) ) - sChoice += sPiece; - } - - if (GetHasFeat(FEAT_WEAPON_FOCUS_WHIP, oAdventurer)) { - string sPiece = PaddedInt(BASE_ITEM_WHIP, 3) + PaddedInt(nHD, 2); - sFocus += sPiece; - - if ( GetHasFeat(FEAT_WEAPON_SPECIALIZATION_WHIP, oAdventurer) ) - sFocus += sPiece; - - if ( nWM > 0 ) - if ( GetHasFeat(FEAT_WEAPON_OF_CHOICE_WHIP, oAdventurer) ) - sChoice += sPiece; - } - - // Archery counts for focus (AA levels will be factored in later). - sFocus += sArchery; - // Checking for the epic feats is tedious with little payoff. Instead, - // just assume the character will take the epic versions by, say, level 24. - if ( nHD > 23 ) - sFocus += sFocus; - // Weapon masters can get repeat-counted at levels 5 (superior focus) and - // 13 (epic superior focus). - if ( nWM > 12 ) - sChoice += sChoice + sChoice; - else if ( nWM > 4 ) - sChoice += sChoice; - // Arcane archers should get some parity with weapon masters. - // Slightly different cut-offs because AAs get feats at those levels). - if ( "" != sArchery ) { - int nAA = GetLevelByClass(CLASS_TYPE_ARCANE_ARCHER, oAdventurer); - if ( nAA > 13 ) - sChoice += sArchery + sArchery; - else if ( nAA > 5 ) - sChoice += sArchery; - } - - return sFocus + sChoice; -} - -// Returns a string indicating a single character's weapon-critical-based feats. -// The string consists of 5-character pieces. The first 3 characters are a -// BASE_ITEM_* constant converted to a string, and the last 2 characters are -// a level converted to a string. -string GetCharCriticalPref(object oAdventurer) -{ - int nHD = GetHitDice(oAdventurer); - string sCrits = ""; - - // Pretty dreary here. Just check each improved critical feat to see it the - // character has it. - if ( GetHasFeat(FEAT_IMPROVED_CRITICAL_BASTARD_SWORD, oAdventurer) ) { - sCrits += PaddedInt(BASE_ITEM_BASTARDSWORD, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_BATTLE_AXE, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_BATTLEAXE, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_CLUB, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_CLUB, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_DAGGER, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_DAGGER, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_DART, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_DART, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_DIRE_MACE, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_DIREMACE, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_DOUBLE_AXE, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_DOUBLEAXE, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_DWAXE, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_DWARVENWARAXE, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_GREAT_AXE, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_GREATAXE, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_GREAT_SWORD, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_GREATSWORD, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_HALBERD, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_HALBERD, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_HAND_AXE, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_HANDAXE, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_HEAVY_CROSSBOW, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_HEAVYCROSSBOW, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_HEAVY_FLAIL, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_HEAVYFLAIL, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_KAMA, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_KAMA, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_KATANA, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_KATANA, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_KUKRI, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_KUKRI, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_LIGHT_CROSSBOW, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_LIGHTCROSSBOW, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_LIGHT_FLAIL, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_LIGHTFLAIL, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_LIGHT_HAMMER, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_LIGHTHAMMER, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_LONGBOW, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_LONGBOW, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_LONG_SWORD, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_LONGSWORD, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_LIGHT_MACE, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_LIGHTMACE, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_MORNING_STAR, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_MORNINGSTAR, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_STAFF, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_QUARTERSTAFF, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_RAPIER, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_RAPIER, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_SCIMITAR, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_SCIMITAR, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_SCYTHE, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_SCYTHE, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_SHORTBOW, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_SHORTBOW, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_SHORT_SWORD, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_SHORTSWORD, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_SHURIKEN, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_SHURIKEN, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_SICKLE, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_SICKLE, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_SLING, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_SLING, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_SPEAR, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_SHORTSPEAR, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_THROWING_AXE, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_THROWINGAXE, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_TRIDENT, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_TRIDENT, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_TWO_BLADED_SWORD, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_TWOBLADEDSWORD, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_WAR_HAMMER, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_WARHAMMER, 3) + PaddedInt(nHD, 2); - } - - if (GetHasFeat(FEAT_IMPROVED_CRITICAL_WHIP, oAdventurer)) { - sCrits += PaddedInt(BASE_ITEM_WHIP, 3) + PaddedInt(nHD, 2); - } - - // Checking for the epic feats is tedious with little payoff. Instead, - // just assume the character will take the epic versions by a reasonable - // level if they meet the strength requirement. - int iBaseStrength = GetAbilityScore(oAdventurer, ABILITY_STRENGTH, TRUE); - if ( iBaseStrength > 24 && nHD > 29 ) // Devastating crit (and overwhelming) - sCrits += sCrits + sCrits; - else if ( iBaseStrength > 22 && nHD > 26 ) // Overwhelming crit - sCrits += sCrits; - - return sCrits; -} - -// Returns the weapon that we should assume a character wants based upon class. -// This is a three-character string. Aside from the special return values "DRU", -// "MNK", and "WIZ", this string will contain a BASE_ITEM_* constant. -string GetCharClassWeapon(object oAdventurer) -{ - switch ( nDetermineClassToUse(oAdventurer) ) - { - case CLASS_TYPE_BARBARIAN: return PaddedInt(BASE_ITEM_GREATAXE, 3); - case CLASS_TYPE_BARD: return PaddedInt(BASE_ITEM_SHORTSWORD, 3); - case CLASS_TYPE_CLERIC: return PaddedInt(BASE_ITEM_LIGHTMACE, 3); - case CLASS_TYPE_DRUID: return "DRU"; - case CLASS_TYPE_FIGHTER: return PaddedInt(BASE_ITEM_LONGSWORD, 3); - case CLASS_TYPE_MONK: return "MNK"; - case CLASS_TYPE_PALADIN: return PaddedInt(BASE_ITEM_LONGSWORD, 3); - case CLASS_TYPE_RANGER: return PaddedInt(BASE_ITEM_LONGSWORD, 3); - case CLASS_TYPE_ROGUE: return PaddedInt(BASE_ITEM_SHORTSWORD, 3); - case CLASS_TYPE_SORCERER: return PaddedInt(BASE_ITEM_DAGGER, 3); - case CLASS_TYPE_WIZARD: return "WIZ"; - } - - // Should not get here, but everyone can use a dagger. - return PaddedInt(BASE_ITEM_DAGGER, 3); -} - -// Returns a string indicating a single character's class-based weapon preference. -// The string consists of 5-characters. The first 3 characters are either a -// special code (DRU, MNK, WIZ, or EXT) or a BASE_ITEM_* constant converted to -// a string, and the last 2 characters are a level converted to a string. -string GetCharClassWeaponPref(object oAdventurer) -{ - // Let exotic proficiency override class considerations. - if ( GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oAdventurer) ) - return "EXT" + PaddedInt(GetHitDice(oAdventurer), 2); - - return GetCharClassWeapon(oAdventurer) + PaddedInt(GetHitDice(oAdventurer), 2); -} - -// Returns a string indicating a single character's preferred weapons. -// The string consists of 5-character pieces. The first 3 characters either -// a special code (DRU, MNK, WIZ, or EXT) or a BASE_ITEM_* constant converted -// to a string, and the last 2 characters are a level converted to a string. -string GetCharPreference(object oAdventurer) -{ - string sRetVal = GetCharFocusPref(oAdventurer) + - GetCharCriticalPref(oAdventurer); - - if ( "" == sRetVal ) { - // No feats, so choose a weapon based on class. - sRetVal = GetCharClassWeaponPref(oAdventurer); - } - else if ( GetStringLength(sRetVal) == 5 ) { - // Give people with a single weapon feat an edge over those getting - // a weapon via class. - sRetVal += sRetVal; - } - - return sRetVal; -} - - -// Returns a string indicating the party's preferred weapons. -// The string consists of 5-character pieces. The first 3 characters are either -// a special code (DRU, MNK, WIZ, or EXT) or a BASE_ITEM_* constant converted -// to a string, and the last 2 characters are a level converted to a string. -string GetPartyPreference(object oAdventurer) -{ - string sRetVal = ""; - object oArea = GetArea(oAdventurer); - - // Loop through the PCs in the party. - object oParty = GetFirstFactionMember(oAdventurer); - while ( OBJECT_INVALID != oParty ) { - // Only PCs' in the same area count. - if ( GetArea(oParty) == oArea ) - sRetVal += GetCharPreference(oParty); - - // Update the loop. - oParty = GetNextFactionMember(oAdventurer); - } - - return sRetVal; -} - -// Returns a string containig a particular preferred weapon for one party member. -// The string consists of 5 characters. The first 3 characters are either a -// special code (DRU, MNK, WIZ, or EXT) or a BASE_ITEM_* constant converted to -// a string, and the last 2 characters are a level converted to a string. -string ChoosePreferenceForParty(object oAdventurer) -{ - // Collect the party preferences, then choose one of them. - string sPrefs = GetPartyPreference(oAdventurer); - int iNumChoices = GetStringLength(sPrefs) / 5; - int iSelect = Random(iNumChoices); - - return GetSubString(sPrefs, 5 * iSelect, 5); -} - - -//::////////////////////////////////////////////// - -//void main () {} \ No newline at end of file diff --git a/src/module/nss/x2_inc_craft.nss b/src/module/nss/x2_inc_craft.nss index 8b524a4..3260293 100644 --- a/src/module/nss/x2_inc_craft.nss +++ b/src/module/nss/x2_inc_craft.nss @@ -14,7 +14,17 @@ #include "prc_x2_craft" #include "prc_inc_spells" -//:: void main (){} + +const int X2_CI_BREWPOTION_MAXLEVEL = 3; // Max Level for potions +const int X2_CI_BREWPOTION_COSTMODIFIER = 50; // gp Brew Potion XPCost Modifier + +// Scribe Scroll related constants +const int X2_CI_SCRIBESCROLL_COSTMODIFIER = 25; // Scribescroll Cost Modifier + +// Craft Wand related constants +const int X2_CI_CRAFTWAND_MAXLEVEL = 4; +const int X2_CI_CRAFTWAND_COSTMODIFIER = 750; + // New constants for my Craft Magic revisions. -- Krit const string TK_CRAFTMAGIC_2DA = "tk_craft_magic"; // The Krit's craft magic .2da file. @@ -282,14 +292,14 @@ int TK_CICraftCheckCraftMagic(object oSpellTarget) nFeat = X2_CI_BREWPOTION_FEAT_ID; nCantUseStrRef = 83450; // "This spell can not be used with the Brew Potion feat" - int nPotionMaxLevel = GetPRCSwitch(X2_CI_BREWPOTION_MAXLEVEL); + int nPotionMaxLevel = GetPRCSwitch(IntToString(X2_CI_BREWPOTION_MAXLEVEL)); if(nPotionMaxLevel == 0) nPotionMaxLevel = 3; nMaxLevel = nPotionMaxLevel; nMaxLevelStrRef = 76416;// "* Failure - potions can not hold spells higher than level 3 *" - int nCostModifier = GetPRCSwitch(X2_CI_BREWPOTION_COSTMODIFIER); + int nCostModifier = GetPRCSwitch(IntToString(X2_CI_BREWPOTION_COSTMODIFIER)); if(nCostModifier == 0) nCostModifier = 50; @@ -309,7 +319,7 @@ int TK_CICraftCheckCraftMagic(object oSpellTarget) nMaxLevelStrRef = 0; int nLevel = CIGetSpellInnateLevel(nID,TRUE); - int nCostModifier = GetPRCSwitch(X2_CI_SCRIBESCROLL_COSTMODIFIER); + int nCostModifier = GetPRCSwitch(IntToString(X2_CI_SCRIBESCROLL_COSTMODIFIER)); if(nCostModifier == 0) nCostModifier = 25; @@ -326,7 +336,7 @@ int TK_CICraftCheckCraftMagic(object oSpellTarget) nFeat = X2_CI_CRAFTWAND_FEAT_ID; nCantUseStrRef = 83452; // "This spell can not be used with the Craft Wand feat" - int nMaxLevel = GetPRCSwitch(X2_CI_CRAFTWAND_MAXLEVEL); + int nMaxLevel = GetPRCSwitch(IntToString((X2_CI_CRAFTWAND_MAXLEVEL))); if(nMaxLevel == 0) nMaxLevel = 4; if (nLevel > nMaxLevel) @@ -337,7 +347,7 @@ int TK_CICraftCheckCraftMagic(object oSpellTarget) //nMaxLevel = X2_CI_CRAFTWAND_MAXLEVEL; nMaxLevelStrRef = 83623;// "* Failure! - wands can not hold spells higher than level 4 *" - int nCostMod = GetPRCSwitch(X2_CI_CRAFTWAND_COSTMODIFIER); + int nCostMod = GetPRCSwitch(IntToString(X2_CI_CRAFTWAND_COSTMODIFIER)); if(nCostMod == 0) nCostMod = 750; nCostModifier = CIGetCraftGPCost(nLevel, nCostMod, PRC_CRAFT_WAND_CASTER_LEVEL); @@ -456,4 +466,7 @@ int TK_CICraftCheckCraftMagic(object oSpellTarget) DestroyObject (oSpellTarget); FloatingTextStrRefOnCreature(8502, OBJECT_SELF); // "* Success - Item created! *" return TRUE; -} \ No newline at end of file +} + + +//:: void main(){} \ No newline at end of file