Initial commit

Initial commit
This commit is contained in:
Jaysyn904
2025-06-23 16:40:21 -04:00
parent 343c093e94
commit 0bb3bbb7cd
2222 changed files with 2169962 additions and 238 deletions

View File

@@ -1,19 +1,19 @@
# Default Module Template
# D1-2 Descent Into the Depths of the Earth [PRC8-CEP3]
Repository for the development of the PRC8 version of .....
Repository for the development of the PRC8 version of D1-2 Descent Into the Depths of the Earth.
[Discussion Thread on Discord](https://discord.gg/ca2ru3KxYd)
## Requirements
1.) [Nasher](https://github.com/squattingmonk/nasher), installed in your system path.
2.) [Original module resources]()
2.) [Original module resources](https://neverwintervault.org/project/nwn1/module/descent-depths-earth-shrine-kuo-toa-d1d2)
3.) [PRC8](https://gitea.raptio.us/Jaysyn/PRC8/releases)
3.) [CEP3](https://neverwintervault.org/project/nwnee/hakpak/combined/cep-3-community-expansion-pack)
4.) [CEP2](https://neverwintervault.org/cep)
4.) [CEP1](https://neverwintervault.org/cep)
## Instructions

View File

@@ -1,9 +1,9 @@
[package]
name = "Default Module"
description = "PRC8 version of ..."
version = "1.01prc8"
name = "D1-2 Descent Into the Depths of the Earth [PRC8-CEP3]"
description = "PRC8 version of D1-2 Descent Into the Depths of the Earth."
version = "3.2.3prc8"
url = "https://discord.gg/ca2ru3KxYd"
author = "Original Author"
author = "Trev"
author = "Jaysyn904 <68194417+Jaysyn904@users.noreply.github.com>"
[package.sources]
@@ -15,8 +15,8 @@ author = "Jaysyn904 <68194417+Jaysyn904@users.noreply.github.com>"
[target]
name = "default"
file = "Default Module.mod"
description = "PRC8 version of ..."
file = "D1-2 Descent Into the Depths of the Earth [PRC8-CEP3].mod"
description = "PRC8 version of D1-2 Descent Into the Depths of the Earth."
[target.sources]
include = "src/module/**/*"
include = "src/include/**/*"
@@ -235,228 +235,4 @@ description = "PRC8 version of ..."
filter = "xchst_inc.nss"
[target.rules]
"*" = "src/module/$ext"
[target]
name = "tophak"
file = "HAKNAME.hak"
description = "PRC8 merge hakpak for PRC8 version of ..."
[target.sources]
include = "src/hakpak/HAKNAME/**/*"
include = "src/include/**/*"
filter = "bnd_inc_bndfunc.nss"
filter = "bnd_vestig_const.nss"
filter = "inc_2dacache.nss"
filter = "inc_abil_damage.nss"
filter = "inc_acp.nss"
filter = "inc_addragebonus.nss"
filter = "inc_area.nss"
filter = "inc_array_sort.nss"
filter = "inc_cache_setup.nss"
filter = "inc_debug.nss"
filter = "inc_dispel.nss"
filter = "inc_draw.nss"
filter = "inc_draw_prc.nss"
filter = "inc_draw_text.nss"
filter = "inc_draw_tools.nss"
filter = "inc_dynconv.nss"
filter = "inc_ecl.nss"
filter = "inc_epicspellai.nss"
filter = "inc_epicspelldef.nss"
filter = "inc_epicspellfnc.nss"
filter = "inc_epicspells.nss"
filter = "inc_eventhook.nss"
filter = "inc_heap.nss"
filter = "inc_item_props.nss"
filter = "inc_logmessage.nss"
filter = "inc_lookups.nss"
filter = "inc_metalocation.nss"
filter = "inc_newspellbook.nss"
filter = "inc_npc.nss"
filter = "inc_nwnx_funcs.nss"
filter = "inc_persistsql.nss"
filter = "inc_persist_loca.nss"
filter = "inc_pers_array.nss"
filter = "inc_poison.nss"
filter = "inc_prc_npc.nss"
filter = "inc_prc_poly.nss"
filter = "inc_rand_equip.nss"
filter = "inc_ravage.nss"
filter = "inc_rend.nss"
filter = "inc_sbr_readme.nss"
filter = "inc_set.nss"
filter = "inc_spirit_weapn.nss"
filter = "inc_sp_gain_mem.nss"
filter = "inc_sql.nss"
filter = "inc_switch_setup.nss"
filter = "inc_target_list.nss"
filter = "inc_threads.nss"
filter = "inc_time.nss"
filter = "inc_timestop.nss"
filter = "inc_uniqueid.nss"
filter = "inc_utility.nss"
filter = "inc_vfx_const.nss"
filter = "inv_inc_blast.nss"
filter = "inv_inc_invfunc.nss"
filter = "inv_inc_invknown.nss"
filter = "inv_inc_invoke.nss"
filter = "inv_invoc_const.nss"
filter = "inv_invokehook.nss"
filter = "lookup_2da_spell.nss"
filter = "moi_inc_moifunc.nss"
filter = "moi_meld_const.nss"
filter = "nw_o2_coninclude.nss"
filter = "pnp_lich_inc.nss"
filter = "pnp_shft_main.nss"
filter = "pnp_shft_poly.nss"
filter = "prcsp_archmaginc.nss"
filter = "prcsp_engine.nss"
filter = "prcsp_reputation.nss"
filter = "prc_add_spell_dc.nss"
filter = "prc_add_spl_pen.nss"
filter = "prc_allow_const.nss"
filter = "prc_alterations.nss"
filter = "prc_ccc_const.nss"
filter = "prc_ccc_readme.nss"
filter = "prc_class_const.nss"
filter = "prc_compan_inc.nss"
filter = "prc_craft_inc.nss"
filter = "prc_effect_inc.nss"
filter = "prc_feat_const.nss"
filter = "prc_getbest_inc.nss"
filter = "prc_inc_actions.nss"
filter = "prc_inc_array.nss"
filter = "prc_inc_assoc.nss"
filter = "prc_inc_breath.nss"
filter = "prc_inc_burn.nss"
filter = "prc_inc_castlvl.nss"
filter = "prc_inc_chat.nss"
filter = "prc_inc_chat_dm.nss"
filter = "prc_inc_chat_pow.nss"
filter = "prc_inc_chat_shf.nss"
filter = "prc_inc_clsfunc.nss"
filter = "prc_inc_combat.nss"
filter = "prc_inc_combmove.nss"
filter = "prc_inc_core.nss"
filter = "prc_inc_damage.nss"
filter = "prc_inc_descrptr.nss"
filter = "prc_inc_domain.nss"
filter = "prc_inc_dragsham.nss"
filter = "prc_inc_drugfunc.nss"
filter = "prc_inc_effect.nss"
filter = "prc_inc_factotum.nss"
filter = "prc_inc_fork.nss"
filter = "prc_inc_function.nss"
filter = "prc_inc_hextor.nss"
filter = "prc_inc_itmrstr.nss"
filter = "prc_inc_leadersh.nss"
filter = "prc_inc_listener.nss"
filter = "prc_inc_material.nss"
filter = "prc_inc_natweap.nss"
filter = "prc_inc_nat_hb.nss"
filter = "prc_inc_newip.nss"
filter = "prc_inc_nwscript.nss"
filter = "prc_inc_onhit.nss"
filter = "prc_inc_racial.nss"
filter = "prc_inc_sbheir.nss"
filter = "prc_inc_sb_const.nss"
filter = "prc_inc_scry.nss"
filter = "prc_inc_shifting.nss"
filter = "prc_inc_skills.nss"
filter = "prc_inc_skin.nss"
filter = "prc_inc_smite.nss"
filter = "prc_inc_sneak.nss"
filter = "prc_inc_spells.nss"
filter = "prc_inc_sp_tch.nss"
filter = "prc_inc_stunfist.nss"
filter = "prc_inc_switch.nss"
filter = "prc_inc_s_det.nss"
filter = "prc_inc_teleport.nss"
filter = "prc_inc_template.nss"
filter = "prc_inc_turning.nss"
filter = "prc_inc_unarmed.nss"
filter = "prc_inc_util.nss"
filter = "prc_inc_wpnrest.nss"
filter = "prc_ipfeat_const.nss"
filter = "prc_ip_srcost.nss"
filter = "prc_misc_const.nss"
filter = "prc_racial_const.nss"
filter = "prc_shifter_info.nss"
filter = "prc_spellf_inc.nss"
filter = "prc_spellhook.nss"
filter = "prc_spell_const.nss"
filter = "prc_sp_func.nss"
filter = "prc_template_con.nss"
filter = "prc_weap_apt.nss"
filter = "prc_x2_craft.nss"
filter = "prc_x2_itemprop.nss"
filter = "prgt_inc.nss"
filter = "prgt_inc_trap.nss"
filter = "psi_inc_ac_const.nss"
filter = "psi_inc_ac_convo.nss"
filter = "psi_inc_ac_manif.nss"
filter = "psi_inc_ac_spawn.nss"
filter = "psi_inc_augment.nss"
filter = "psi_inc_const.nss"
filter = "psi_inc_core.nss"
filter = "psi_inc_enrgypow.nss"
filter = "psi_inc_metapsi.nss"
filter = "psi_inc_onhit.nss"
filter = "psi_inc_powknown.nss"
filter = "psi_inc_ppoints.nss"
filter = "psi_inc_psicraft.nss"
filter = "psi_inc_psifunc.nss"
filter = "psi_inc_pwresist.nss"
filter = "psi_inc_soulkn.nss"
filter = "psi_power_const.nss"
filter = "psi_spellhook.nss"
filter = "sbr_include.nss"
filter = "shd_inc_metashd.nss"
filter = "shd_inc_myst.nss"
filter = "shd_inc_mystknwn.nss"
filter = "shd_inc_shdfunc.nss"
filter = "shd_mysthook.nss"
filter = "shd_myst_const.nss"
filter = "spinc_bolt.nss"
filter = "spinc_burst.nss"
filter = "spinc_cone.nss"
filter = "spinc_dimdoor.nss"
filter = "spinc_engimm.nss"
filter = "spinc_fdisk.nss"
filter = "spinc_greenfire.nss"
filter = "spinc_lessorb.nss"
filter = "spinc_maze.nss"
filter = "spinc_necro_cyst.nss"
filter = "spinc_orb.nss"
filter = "spinc_remeffct.nss"
filter = "spinc_telecircle.nss"
filter = "spinc_teleport.nss"
filter = "spinc_trans.nss"
filter = "tob_inc_martlore.nss"
filter = "tob_inc_move.nss"
filter = "tob_inc_moveknwn.nss"
filter = "tob_inc_recovery.nss"
filter = "tob_inc_tobfunc.nss"
filter = "tob_movehook.nss"
filter = "tob_move_const.nss"
filter = "true_inc_metautr.nss"
filter = "true_inc_truespk.nss"
filter = "true_inc_trufunc.nss"
filter = "true_inc_truknwn.nss"
filter = "true_inc_utter.nss"
filter = "true_utterhook.nss"
filter = "true_utter_const.nss"
filter = "utl_i_sqluuid.nss"
filter = "x0_i0_transport.nss"
filter = "x2_inc_cutscenep.nss"
filter = "x2_inc_spellhook.nss"
filter = "x3_inc_horse.nss"
filter = "prc_inc_string.nss"
filter = "prc_nui_sc_inc.nss"
filter = "prc_nui_scd_inc.nss"
filter = "prc_nui_consts.nss"
filter = "nw_inc_nui"
filter = "xchst_inc.nss"
[target.rules]
"*" = "src/hakpak/HAKNAME/$ext"
"*" = "src/module/$ext"

View File

@@ -1 +0,0 @@
nasher pack tophak --verbose

View File

@@ -0,0 +1,968 @@
//::///////////////////////////////////////////////
//:: Binding/Vestiges main include: Miscellaneous
//:: bnd_inc_bndfunc
//::///////////////////////////////////////////////
/** @file
Defines various functions and other stuff that
do something related to Binding.
@author Stratovarius
@date Created - 2021.02.02
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Determines the given creature's Binder level.
* The vestige is used for Favored Vestige
*
* @param oBinder The creature whose Binder level to determine
* @param nVestige The rowid of the vestige in spells.2da
*
* @return The Binder level
*/
int GetBinderLevel(object oBinder, int nVestige = -1);
/**
* Determines whether a given class is a Binding-related class or not.
*
* @param nClass CLASS_TYPE_* of the class to test
* @return TRUE if the class is a Binding-related class, FALSE otherwise
*/
int GetIsBindingClass(int nClass);
/**
* Calculates how many Binder levels are gained by a given creature from
* it's levels in prestige classes.
*
* @param oBinder Creature to calculate added Binder levels for
* @return The number of Binder levels gained
*/
int GetBindingPRCLevels(object oBinder);
/**
* Returns the master 2da of all vestiges - "vestiges"
*/
string GetVestigeFile();
/**
* Returns the master 2da of binds and bind levels - "cls_bind_binder"
*/
string GetBindingClassFile(int nClass);
/**
* Casts a particular vestige on the binder
* Should only ever be called via Contact Vestige
*
* @param oBinder The binder
* @param nVestige The vestige to attempt binding
*/
void ApplyVestige(object oBinder, int nVestige);
/**
* Removes a particular vestige from the binder
* Should only ever be called via Contact Vestige
*
* @param oBinder The binder
* @param nVestige The vestige to expel
*/
void ExpelVestige(object oBinder, int nVestige);
/**
* Rolls the check to see whether it is a good or bad pact
* Sets a local int to mark pact quality
*
* @param oBinder The binder attempting the check
* @param nVestige The rowid of the vestige in vestiges.2da
*
* @return The rowid of the vestige in spells.2da
*/
int DoBindingCheck(object oBinder, int nVestige);
/**
* Does the animations and count down to bind a particular vestige
*
* @param oBinder The binder
* @param nTime Should always be 66 seconds
* @param nVestige The vestige to attempt binding
* @param nExpel Whether this is a usage of expel vestige or not
*/
void ContactVestige(object oBinder, int nTime, int nVestige, int nExpel = FALSE);
/**
* Does the animations and count down to bind a particular vestige
* Should only ever be called via Contact Vestige
*
* @param oBinder The binder
* @param nTime Should always be 60 seconds
* @param nVestige The vestige to attempt binding
* @param nExpel Whether this is a usage of expel vestige or not
*/
void BindVestige(object oBinder, int nTime, int nVestige, int nExpel = FALSE);
/**
* Checks to see whether an ability is off cooldown or not
* Sets the cooldown if the ability is usable
* Informs the player via floating text
*
* @param oBinder The binder
* @param nAbil The vestige ability (such as Amon's Fire Breath SpellId)
* @param nVestige The vestige the ability comes from (such as VESTIGE_AMON)
*
* @return TRUE/FALSE for off cooldown or not
*/
int BindAbilCooldown(object oBinder, int nAbil, int nVestige);
/**
* How many vestiges can the binder have bound
*
* @param oBinder The binder
*
* @return A number between 1 and 4
*/
int GetMaxVestigeCount(object oBinder);
/**
* What is the highest level vestige the binder can bind?
*
* @param oBinder The binder
*
* @return A number between 1 and 8
*/
int GetMaxVestigeLevel(object oBinder);
/**
* What is the vestige's level?
*
* @param nVestige The vestige rowid in vestiges.2da
*
* @return A number between 1 and 8
*/
int GetVestigeLevel(int nVestige);
/**
* How many total binds are active on the binder?
* Checks via the spellid of the vestiges
*
* @param oBinder The binder
*
* @return 0 or higher
*/
int GetBindCount(object oBinder);
/**
* How many uses of pact augmentation does the
* binder get when he binds a vestige?
*
* @param oBinder The binder
*
* @return 0 to 5
*/
int GetPactAugmentCount(object oBinder);
/**
* Returns the penalty to be applied if the
* binder made a bad pact with the vestige
* Should never be called directly
*
* @param oBinder The binder
*
* @return Linked effect
*/
effect EffectPact(object oBinder);
/**
* Checks whether the binder has the rapid recovery
* feat for the named vestige
*
* @param oBinder The binder
* @param nVestige The vestige rowid in spells.2da
*
* @return TRUE/FALSE
*/
int RapidRecovery(object oBinder, int nVestige);
/**
* Checks whether the binder has the favored vestige
* feat for the named vestige
*
* @param oBinder The binder
* @param nVestige The vestige rowid in spells.2da
*
* @return TRUE/FALSE
*/
int FavoredVestige(object oBinder, int nVestige);
/**
* Checks whether the binder has the favored vestige
* focus feat for the named vestige
*
* @param oBinder The binder
* @param nVestige The vestige rowid in spells.2da
*
* @return TRUE/FALSE
*/
int FavoredVestigeFocus(object oBinder, int nVestige);
/**
* Returns the DC for saving against a vestige's abilities
* 10 + 1/2 Binding level + Charisma Modifier + bonuses
*
* @param oBinder The binder
* @param nVestige The vestige rowid in spells.2da
*
* @return A number
*/
int GetBinderDC(object oBinder, int nVestige);
/**
* Checks for the special requirements of each vestige
* or for the presence of the Ignore Special Requirements
* feat. True means passing requirements, False is a fail
*
* @param oBinder The binder
* @param nVestige The vestige rowid in spells.2da
*
* @return TRUE/FALSE
*/
int DoSpecialRequirements(object oBinder, int nVestige);
/**
* Checks for the special requirements of each vestige
* or for the presence of the Ignore Special Requirements
* feat. True means passing requirements, False is a fail
*
* This is for requirements that apply during the summoning process
* due to having a cost that applies only after the user has selected
* which vestige they wish to bind
*
* @param oBinder The binder
* @param nVestige The vestige rowid in spells.2da
*
* @return TRUE/FALSE
*/
int DoSummonRequirements(object oBinder, int nVestige);
/**
* Checks for whether the vestige ability was exploited (meaning not
* granted) by the Anima Mage class feature.
*
* @param oBinder The binder
* @param nVestige The vestige ability rowid in vestigeabil.2da
*
* @return TRUE if exploited/FALSE otherwise
*/
int GetIsVestigeExploited(object oBinder, int nVestigeAbil);
/**
* Marks a vestige ability as exploited (meaning it will not be
* granted) by the Anima Mage class feature.
*
* @param oBinder The binder
* @param nVestige The vestige ability rowid in vestigeabil.2da
*/
void SetIsVestigeExploited(object oBinder, int nVestigeAbil);
/**
* Checks whether the patron vestige is bound to a Knight of the Sacred Seal
* If not, the class loses all class features
*
* @param oBinder The binder
*
* @return TRUE if bound, FALSE otherwise
*/
int GetIsPatronVestigeBound(object oBinder);
/**
* Checks who the patron vestige is for a Knight of the Sacred Seal
* Used to ensure they always have a good pact with their patron
*
* @param oBinder The binder
*
* @return The VESTIGE_* const if one exists, -1 otherwise
*/
int GetPatronVestige(object oBinder);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
#include "prc_inc_spells"
#include "inc_dynconv"
//////////////////////////////////////////////////
/* Constants */
//////////////////////////////////////////////////
const int VESTIGE_CONTACT_TIME = 66;
const int VESTIGE_BINDING_TIME = 60;
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
int GetBinderLevel(object oBinder, int nVestige = -1)
{
int nLevel;
if(GetLevelByClass(CLASS_TYPE_BINDER, oBinder))
{
// Binder level is class level + prestige
nLevel = GetLevelByClass(CLASS_TYPE_BINDER, oBinder);
nLevel += GetBindingPRCLevels(oBinder);
}
// If you have no levels in binder, but you have Bind Vestige feat
else if (GetHasFeat(FEAT_BIND_VESTIGE, oBinder))
{
nLevel = 1;
if (GetHasFeat(FEAT_BIND_VESTIGE_IMPROVED, oBinder)) nLevel += 4;
}
if (FavoredVestige(oBinder, nVestige)) nLevel += 1;
if (GetHasSpellEffect(VESTIGE_IPOS, oBinder) && !GetIsVestigeExploited(oBinder, VESTIGE_IPOS_INFLUENCE) && nVestige >= VESTIGE_AMON) nLevel += 1;
if(DEBUG) DoDebug("Binder Level: " + IntToString(nLevel));
return nLevel;
}
int GetIsBindingClass(int nClass)
{
return nClass == CLASS_TYPE_BINDER;
}
int GetBindingPRCLevels(object oBinder)
{
int nLevel = GetLevelByClass(CLASS_TYPE_ANIMA_MAGE, oBinder);
nLevel += GetLevelByClass(CLASS_TYPE_KNIGHT_SACRED_SEAL, oBinder);
nLevel += GetLevelByClass(CLASS_TYPE_SCION_DANTALION, oBinder);
// These don't add at 1st level
if (GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oBinder))
nLevel += GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oBinder) - 1;
return nLevel;
}
string GetVestigeFile()
{
return "vestiges";
}
string GetBindingClassFile(int nClass)
{
string sFile;
if (nClass == CLASS_TYPE_BINDER) sFile = "cls_bind_binder";
return sFile;
}
void ApplyVestige(object oBinder, int nVestige)
{
PRCRemoveSpellEffects(nVestige, oBinder, oBinder);
GZPRCRemoveSpellEffects(nVestige, oBinder, FALSE);
ActionCastSpellOnSelf(nVestige, METAMAGIC_NONE, oBinder);
if (GetLevelByClass(CLASS_TYPE_BINDER, oBinder) >= 2)
{
PRCRemoveSpellEffects(VESTIGE_PACT_AUGMENTATION, oBinder, oBinder);
GZPRCRemoveSpellEffects(VESTIGE_PACT_AUGMENTATION, oBinder, FALSE);
ActionCastSpellOnSelf(VESTIGE_PACT_AUGMENTATION, METAMAGIC_NONE, oBinder);
}
if (DEBUG) DoDebug("Applying Vestige "+IntToString(nVestige)+" on "+GetName(oBinder));
// If you have hosted one of these spirits within the last 24 hours, Amon refuses to answer your call.
if (nVestige == VESTIGE_LERAJE ||
nVestige == VESTIGE_CHUPOCLOPS ||
nVestige == VESTIGE_KARSUS ||
nVestige == VESTIGE_EURYNOME)
{
SetLocalInt(oBinder, "AmonHater", TRUE);
DelayCommand(HoursToSeconds(48), DeleteLocalInt(oBinder, "AmonHater"));
}
// Only good quality pacts get the bonus spell
if (GetLocalInt(oBinder, "PactQuality"+IntToString(nVestige)) && GetLocalInt(oBinder, "ExploitVestigeConv"))
{
DelayCommand(0.5, StartDynamicConversation("bnd_exploitcnv", oBinder, DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, FALSE, TRUE, oBinder));
DeleteLocalInt(oBinder, "ExploitVestigeConv");
}
}
void ExpelVestige(object oBinder, int nVestige)
{
SetPersistantLocalInt(oBinder, "ExpelledVestige", TRUE);
SetPersistantLocalInt(oBinder, "ExpelledVestige"+IntToString(nVestige), TRUE);
// Here, making a good pack means we can unbind it
if (GetLocalInt(oBinder, "PactQuality"+IntToString(nVestige)))
{
PRCRemoveSpellEffects(nVestige, oBinder, oBinder);
GZPRCRemoveSpellEffects(nVestige, oBinder, FALSE);
FloatingTextStringOnCreature("Expelled "+GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nVestige)))+" successfully!", oBinder, FALSE);
}
else
FloatingTextStringOnCreature("Failed to expel "+GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nVestige))), oBinder, FALSE);
}
int DoBindingCheck(object oBinder, int nVestige)
{
int nApply = StringToInt(Get2DACache("vestiges", "SpellID", nVestige));
// Knights of the Sacred Seal always have a good pact with their Patron
if (GetPatronVestige(oBinder) == nApply)
{
SetLocalInt(oBinder, "PactQuality"+IntToString(nApply), TRUE);
return nApply; //We don't need the rest of the function here.
}
// Scions of Dantalion always have a good pact with Dantalion
if (GetLevelByClass(CLASS_TYPE_SCION_DANTALION, oBinder) && VESTIGE_DANTALION == nApply)
{
SetLocalInt(oBinder, "PactQuality"+IntToString(nApply), TRUE);
return nApply; //We don't need the rest of the function here.
}
int nRoll = d20()+ GetBinderLevel(oBinder) + GetAbilityModifier(ABILITY_CHARISMA, oBinder);
if (GetHasFeat(FEAT_SKILLED_PACT_MAKING, oBinder)) nRoll += 4;
// -10 penalty on the check
if (GetLocalInt(oBinder, "RushedBinding"))
{
DeleteLocalInt(oBinder, "RushedBinding");
nRoll -= 10;
}
// After expelling a vestige, take a -10 penalty on the check
if (GetPersistantLocalInt(oBinder, "ExpelledVestige"))
{
DeletePersistantLocalInt(oBinder, "ExpelledVestige");
nRoll -= 10;
}
// Next time you rebind an expelled vestige, take a penalty on the check
if (GetPersistantLocalInt(oBinder, "ExpelledVestige"+IntToString(nApply)))
{
DeletePersistantLocalInt(oBinder, "ExpelledVestige"+IntToString(nApply));
nRoll -= 10;
}
// Exploiting a vestige grants a -5 on the check
if (GetLocalInt(oBinder, "ExploitVestigeTemp"))
{
nRoll -= 5;
FloatingTextStringOnCreature("Exploiting vestige", oBinder);
// This int is only for this Binding check
DeleteLocalInt(oBinder, "ExploitVestigeTemp");
}
int nDC = StringToInt(Get2DACache("vestiges", "BindDC", nVestige));
SendMessageToPC(oBinder, "Binding Check: "+IntToString(nRoll)+" vs a DC of "+IntToString(nDC));
DeleteLocalInt(oBinder, "PactQuality"+IntToString(nApply));
// Mark a good pact
if (nRoll >= nDC) SetLocalInt(oBinder, "PactQuality"+IntToString(nApply), TRUE);
return nApply;
}
void BindVestige(object oBinder, int nTime, int nVestige, int nExpel = FALSE)
{
if (0 >= nTime)
{
SetCutsceneMode(oBinder, FALSE);
// We're expelling a vestige, not binding one
if (nExpel)
ExpelVestige(oBinder, DoBindingCheck(oBinder, nVestige));
// Make a check and apply the vestige
else
ApplyVestige(oBinder, DoBindingCheck(oBinder, nVestige));
}
else if (!GetIsInCombat(oBinder)) // Being in combat causes this to fail
{
FloatingTextStringOnCreature("You must spend " + IntToString(nTime) +" more seconds to complete the binding", oBinder, FALSE);
DelayCommand(6.0, BindVestige(oBinder, nTime - 6, nVestige, nExpel));
SetCutsceneMode(oBinder, TRUE);
AssignCommand(oBinder, ActionPlayAnimation(ANIMATION_LOOPING_TALK_PLEADING, 1.0, 6.0));
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_MAZE), GetLocation(oBinder), 6.0);
}
else
SetCutsceneMode(oBinder, FALSE);
}
void ContactVestige(object oBinder, int nTime, int nVestige, int nExpel = FALSE)
{
if (0 >= nTime)
{
SetCutsceneMode(oBinder, FALSE);
if (!DoSummonRequirements(oBinder, nVestige)) return;
int nBindTime = VESTIGE_BINDING_TIME;
if(GetPRCSwitch(PRC_BIND_VESTIGE_TIMER) >= 12) nBindTime = GetPRCSwitch(PRC_BIND_VESTIGE_TIMER);
if (GetLocalInt(oBinder, "RushedBinding") || GetLocalInt(oBinder, "RapidPactMaking")) nBindTime = 6;
BindVestige(oBinder, nBindTime, nVestige, nExpel);
}
else if (!GetIsInCombat(oBinder)) // Being in combat causes this to fail
{
FloatingTextStringOnCreature("You must draw the symbol for another " + IntToString(nTime) +" seconds", oBinder, FALSE);
DelayCommand(6.0, ContactVestige(oBinder, nTime - 6, nVestige, nExpel));
SetCutsceneMode(oBinder, TRUE);
AssignCommand(oBinder, ActionPlayAnimation(ANIMATION_LOOPING_MEDITATE, 1.0, 6.0));
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_SYMB_INSAN), GetLocation(oBinder), 6.0);
}
else
SetCutsceneMode(oBinder, FALSE);
}
int BindAbilCooldown(object oBinder, int nAbil, int nVestige)
{
int nCheck = GetLocalInt(oBinder, "Bind"+IntToString(nAbil));
// On Cooldown
if (nCheck)
{
// Free use
if (GetLocalInt(oBinder, "KotSSSurge"))
{
DeleteLocalInt(oBinder, "KotSSSurge");
FloatingTextStringOnCreature("Using Vestige's Surge on "+GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nAbil))), oBinder, FALSE);
return TRUE;
}
FloatingTextStringOnCreature(GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nAbil)))+" is still on cooldown!", oBinder, FALSE);
return FALSE;
}
else
{
SetLocalInt(oBinder, "Bind"+IntToString(nAbil), TRUE);
// Default number of rounds
int nDelay = 5;
// Makes it one round faster
if (RapidRecovery(oBinder, nVestige)) nDelay -= 1;
DelayCommand(RoundsToSeconds(nDelay), DeleteLocalInt(oBinder, "Bind"+IntToString(nAbil)));
DelayCommand(RoundsToSeconds(nDelay), FloatingTextStringOnCreature(GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nAbil)))+" is off cooldown", oBinder, FALSE));
FloatingTextStringOnCreature("You must wait " + IntToString(nDelay) +" rounds before using "+GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nAbil)))+" again", oBinder, FALSE);
}
return TRUE;
}
int GetMaxVestigeCount(object oBinder)
{
int nMax = StringToInt(Get2DACache(GetBindingClassFile(CLASS_TYPE_BINDER), "Vestiges", GetBinderLevel(oBinder)));
if (DEBUG) DoDebug("GetMaxVestigeCount is "+IntToString(nMax));
return nMax;
}
int GetMaxVestigeLevel(object oBinder)
{
int nLevel = GetBinderLevel(oBinder);
if (GetHasFeat(FEAT_IMPROVED_BINDING, oBinder)) nLevel += 2;
// Due to the 2da starting at row 0
int nMax = StringToInt(Get2DACache(GetBindingClassFile(CLASS_TYPE_BINDER), "VestigeLvl", nLevel - 1));
if (DEBUG) DoDebug("GetMaxVestigeLevel is "+IntToString(nMax));
return nMax;
}
int GetVestigeLevel(int nVestige)
{
int nMax = StringToInt(Get2DACache("Vestiges", "Level", nVestige));
if (DEBUG) DoDebug("GetVestigeLevel is "+IntToString(nMax));
return nMax;
}
int GetBindCount(object oBinder)
{
int i, nCount;
for(i = VESTIGE_AMON; i <= VESTIGE_ABYSM; i++)
if(GetHasSpellEffect(i, oBinder)) nCount++;
if (DEBUG) DoDebug("GetBindCount is "+IntToString(nCount));
return nCount;
}
int GetPactAugmentCount(object oBinder)
{
int nClass = GetLevelByClass(CLASS_TYPE_BINDER, oBinder);
int nCount = 0;
if (nClass >= 20) nCount = 5;
else if (nClass >= 16) nCount = 4;
else if (nClass >= 10) nCount = 3;
else if (nClass >= 5) nCount = 2;
else if (nClass >= 2) nCount = 1;
if (DEBUG) DoDebug("GetPactAugmentCount is "+IntToString(nCount));
return nCount;
}
effect EffectPact(object oBinder)
{
effect eEffect;
if (!GetLocalInt(oBinder, "PactQuality"+IntToString(GetSpellId())))
{
// <20>1 penalty on attack rolls, saving throws, and skill checks
eEffect = EffectLinkEffects(EffectSkillDecrease(SKILL_ALL_SKILLS, 1), EffectSavingThrowDecrease(SAVING_THROW_ALL, 1));
eEffect = EffectLinkEffects(eEffect, EffectAttackDecrease(1));
}
else // NWN hates having a blank effect
eEffect = EffectLinkEffects(EffectSkillDecrease(SKILL_DISCIPLINE, 1), EffectSkillIncrease(SKILL_DISCIPLINE, 1));
return eEffect;
}
int RapidRecovery(object oBinder, int nVestige)
{
int nFavored;
if (GetHasFeat(FEAT_RAPID_RECOVERY_AMON, oBinder) && nVestige == VESTIGE_AMON) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_AYM , oBinder) && nVestige == VESTIGE_AYM ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_LERAJE , oBinder) && nVestige == VESTIGE_LERAJE ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_NABERIUS , oBinder) && nVestige == VESTIGE_NABERIUS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_RONOVE , oBinder) && nVestige == VESTIGE_RONOVE ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_DAHLVERNAR , oBinder) && nVestige == VESTIGE_DAHLVERNAR ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_HAAGENTI , oBinder) && nVestige == VESTIGE_HAAGENTI ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_MALPHAS , oBinder) && nVestige == VESTIGE_MALPHAS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_SAVNOK , oBinder) && nVestige == VESTIGE_SAVNOK ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_ANDROMALIUS, oBinder) && nVestige == VESTIGE_ANDROMALIUS) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_FOCALOR , oBinder) && nVestige == VESTIGE_FOCALOR ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_KARSUS , oBinder) && nVestige == VESTIGE_KARSUS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_PAIMON , oBinder) && nVestige == VESTIGE_PAIMON ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_AGARES , oBinder) && nVestige == VESTIGE_AGARES ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_ANDRAS , oBinder) && nVestige == VESTIGE_ANDRAS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_BUER , oBinder) && nVestige == VESTIGE_BUER ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_EURYNOME , oBinder) && nVestige == VESTIGE_EURYNOME ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_TENEBROUS , oBinder) && nVestige == VESTIGE_TENEBROUS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_ARETE , oBinder) && nVestige == VESTIGE_ARETE ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_ASTAROTH , oBinder) && nVestige == VESTIGE_ASTAROTH ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_ACERERAK , oBinder) && nVestige == VESTIGE_ACERERAK ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_BALAM , oBinder) && nVestige == VESTIGE_BALAM ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_DANTALION , oBinder) && nVestige == VESTIGE_DANTALION ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_GERYON , oBinder) && nVestige == VESTIGE_GERYON ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_OTIAX , oBinder) && nVestige == VESTIGE_OTIAX ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_CHUPOCLOPS , oBinder) && nVestige == VESTIGE_CHUPOCLOPS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_HAURES , oBinder) && nVestige == VESTIGE_HAURES ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_IPOS , oBinder) && nVestige == VESTIGE_IPOS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_SHAX , oBinder) && nVestige == VESTIGE_SHAX ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_ZAGAN , oBinder) && nVestige == VESTIGE_ZAGAN ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_VANUS , oBinder) && nVestige == VESTIGE_VANUS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_THETRIAD , oBinder) && nVestige == VESTIGE_THETRIAD ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_DESHARIS , oBinder) && nVestige == VESTIGE_DESHARIS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_ZCERYLL , oBinder) && nVestige == VESTIGE_ZCERYLL ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_ELIGOR , oBinder) && nVestige == VESTIGE_ELIGOR ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_MARCHOSIAS , oBinder) && nVestige == VESTIGE_MARCHOSIAS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_ASHARDALON , oBinder) && nVestige == VESTIGE_ASHARDALON ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_HALPHAX , oBinder) && nVestige == VESTIGE_HALPHAX ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_ORTHOS , oBinder) && nVestige == VESTIGE_ORTHOS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_RAPID_RECOVERY_ABYSM , oBinder) && nVestige == VESTIGE_ABYSM ) nFavored = TRUE;
if (DEBUG) DoDebug("RapidRecovery return value "+IntToString(nFavored));
return nFavored;
}
int FavoredVestige(object oBinder, int nVestige)
{
int nFavored;
if (GetHasFeat(FEAT_FAVORED_VESTIGE_AMON, oBinder) && nVestige == VESTIGE_AMON) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_AYM , oBinder) && nVestige == VESTIGE_AYM ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_LERAJE , oBinder) && nVestige == VESTIGE_LERAJE ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_NABERIUS , oBinder) && nVestige == VESTIGE_NABERIUS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_RONOVE , oBinder) && nVestige == VESTIGE_RONOVE ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_DAHLVERNAR , oBinder) && nVestige == VESTIGE_DAHLVERNAR ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_HAAGENTI , oBinder) && nVestige == VESTIGE_HAAGENTI ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_MALPHAS , oBinder) && nVestige == VESTIGE_MALPHAS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_SAVNOK , oBinder) && nVestige == VESTIGE_SAVNOK ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_ANDROMALIUS, oBinder) && nVestige == VESTIGE_ANDROMALIUS) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCALOR , oBinder) && nVestige == VESTIGE_FOCALOR ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_KARSUS , oBinder) && nVestige == VESTIGE_KARSUS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_PAIMON , oBinder) && nVestige == VESTIGE_PAIMON ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_AGARES , oBinder) && nVestige == VESTIGE_AGARES ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_ANDRAS , oBinder) && nVestige == VESTIGE_ANDRAS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_BUER , oBinder) && nVestige == VESTIGE_BUER ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_EURYNOME , oBinder) && nVestige == VESTIGE_EURYNOME ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_TENEBROUS , oBinder) && nVestige == VESTIGE_TENEBROUS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_ARETE , oBinder) && nVestige == VESTIGE_ARETE ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_ASTAROTH , oBinder) && nVestige == VESTIGE_ASTAROTH ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_ACERERAK , oBinder) && nVestige == VESTIGE_ACERERAK ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_BALAM , oBinder) && nVestige == VESTIGE_BALAM ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_DANTALION , oBinder) && nVestige == VESTIGE_DANTALION ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_GERYON , oBinder) && nVestige == VESTIGE_GERYON ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_OTIAX , oBinder) && nVestige == VESTIGE_OTIAX ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_CHUPOCLOPS , oBinder) && nVestige == VESTIGE_CHUPOCLOPS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_HAURES , oBinder) && nVestige == VESTIGE_HAURES ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_IPOS , oBinder) && nVestige == VESTIGE_IPOS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_SHAX , oBinder) && nVestige == VESTIGE_SHAX ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_ZAGAN , oBinder) && nVestige == VESTIGE_ZAGAN ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_VANUS , oBinder) && nVestige == VESTIGE_VANUS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_THETRIAD , oBinder) && nVestige == VESTIGE_THETRIAD ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_DESHARIS , oBinder) && nVestige == VESTIGE_DESHARIS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_ZCERYLL , oBinder) && nVestige == VESTIGE_ZCERYLL ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_ELIGOR , oBinder) && nVestige == VESTIGE_ELIGOR ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_MARCHOSIAS , oBinder) && nVestige == VESTIGE_MARCHOSIAS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_ASHARDALON , oBinder) && nVestige == VESTIGE_ASHARDALON ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_HALPHAX , oBinder) && nVestige == VESTIGE_HALPHAX ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_ORTHOS , oBinder) && nVestige == VESTIGE_ORTHOS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_ABYSM , oBinder) && nVestige == VESTIGE_ABYSM ) nFavored = TRUE;
if (DEBUG) DoDebug("FavoredVestige return value "+IntToString(nFavored));
return nFavored;
}
int FavoredVestigeFocus(object oBinder, int nVestige)
{
int nFavored;
if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_AMON, oBinder) && nVestige == VESTIGE_AMON) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_AYM , oBinder) && nVestige == VESTIGE_AYM ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_LERAJE , oBinder) && nVestige == VESTIGE_LERAJE ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_NABERIUS , oBinder) && nVestige == VESTIGE_NABERIUS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_RONOVE , oBinder) && nVestige == VESTIGE_RONOVE ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_DAHLVERNAR , oBinder) && nVestige == VESTIGE_DAHLVERNAR ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_HAAGENTI , oBinder) && nVestige == VESTIGE_HAAGENTI ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_MALPHAS , oBinder) && nVestige == VESTIGE_MALPHAS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_SAVNOK , oBinder) && nVestige == VESTIGE_SAVNOK ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_ANDROMALIUS, oBinder) && nVestige == VESTIGE_ANDROMALIUS) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_FOCALOR , oBinder) && nVestige == VESTIGE_FOCALOR ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_KARSUS , oBinder) && nVestige == VESTIGE_KARSUS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_PAIMON , oBinder) && nVestige == VESTIGE_PAIMON ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_AGARES , oBinder) && nVestige == VESTIGE_AGARES ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_ANDRAS , oBinder) && nVestige == VESTIGE_ANDRAS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_BUER , oBinder) && nVestige == VESTIGE_BUER ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_EURYNOME , oBinder) && nVestige == VESTIGE_EURYNOME ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_TENEBROUS , oBinder) && nVestige == VESTIGE_TENEBROUS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_ARETE , oBinder) && nVestige == VESTIGE_ARETE ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_ASTAROTH , oBinder) && nVestige == VESTIGE_ASTAROTH ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_ACERERAK , oBinder) && nVestige == VESTIGE_ACERERAK ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_BALAM , oBinder) && nVestige == VESTIGE_BALAM ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_DANTALION , oBinder) && nVestige == VESTIGE_DANTALION ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_GERYON , oBinder) && nVestige == VESTIGE_GERYON ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_OTIAX , oBinder) && nVestige == VESTIGE_OTIAX ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_CHUPOCLOPS , oBinder) && nVestige == VESTIGE_CHUPOCLOPS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_HAURES , oBinder) && nVestige == VESTIGE_HAURES ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_IPOS , oBinder) && nVestige == VESTIGE_IPOS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_SHAX , oBinder) && nVestige == VESTIGE_SHAX ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_ZAGAN , oBinder) && nVestige == VESTIGE_ZAGAN ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_VANUS , oBinder) && nVestige == VESTIGE_VANUS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_THETRIAD , oBinder) && nVestige == VESTIGE_THETRIAD ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_DESHARIS , oBinder) && nVestige == VESTIGE_DESHARIS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_ZCERYLL , oBinder) && nVestige == VESTIGE_ZCERYLL ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_ELIGOR , oBinder) && nVestige == VESTIGE_ELIGOR ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_MARCHOSIAS , oBinder) && nVestige == VESTIGE_MARCHOSIAS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_ASHARDALON , oBinder) && nVestige == VESTIGE_ASHARDALON ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_HALPHAX , oBinder) && nVestige == VESTIGE_HALPHAX ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_ORTHOS , oBinder) && nVestige == VESTIGE_ORTHOS ) nFavored = TRUE;
else if (GetHasFeat(FEAT_FAVORED_VESTIGE_FOCUS_ABYSM , oBinder) && nVestige == VESTIGE_ABYSM ) nFavored = TRUE;
if (DEBUG) DoDebug("FavoredVestigeFocus return value "+IntToString(nFavored));
return nFavored;
}
int GetBinderDC(object oBinder, int nVestige)
{
int nDC = 10 + GetBinderLevel(oBinder, nVestige)/2 + GetAbilityModifier(ABILITY_CHARISMA, oBinder);
if (FavoredVestigeFocus(oBinder, nVestige)) nDC += 1;
if (GetHasSpellEffect(VESTIGE_IPOS, oBinder) && !GetIsVestigeExploited(oBinder, VESTIGE_IPOS_INFLUENCE)) nDC += 1;
return nDC;
}
int DoSpecialRequirements(object oBinder, int nVestige)
{
if (GetHasFeat(FEAT_IGNORE_SPECIAL_REQUIREMENTS, oBinder)) return TRUE;
if (nVestige == VESTIGE_AMON && (GetLocalInt(oBinder, "AmonHater") ||
GetHasSpellEffect(VESTIGE_LERAJE, oBinder) ||
GetHasSpellEffect(VESTIGE_EURYNOME, oBinder) ||
GetHasSpellEffect(VESTIGE_KARSUS, oBinder) ||
GetHasSpellEffect(VESTIGE_CHUPOCLOPS, oBinder)))
return FALSE;
if (nVestige == VESTIGE_LERAJE && GetHasSpellEffect(VESTIGE_AMON, oBinder))
return FALSE;
if (nVestige == VESTIGE_NABERIUS && 4 > GetSkillRank(SKILL_LORE, oBinder, TRUE) && 4 > GetSkillRank(SKILL_BLUFF, oBinder, TRUE))
return FALSE;
// Ronove<76>s seal must be drawn in the soil under the sky.
if (nVestige == VESTIGE_RONOVE && (GetIsAreaNatural(GetArea(oBinder)) != AREA_NATURAL || GetIsAreaAboveGround(GetArea(oBinder)) != AREA_ABOVEGROUND))
return FALSE;
if (nVestige == VESTIGE_HAAGENTI && (CREATURE_SIZE_LARGE > PRCGetCreatureSize(oBinder) || (GetHasFeat(FEAT_RACE_POWERFUL_BUILD, oBinder) && CREATURE_SIZE_MEDIUM > PRCGetCreatureSize(oBinder))))
return FALSE;
if (nVestige == VESTIGE_KARSUS && GetHasSpellEffect(VESTIGE_AMON, oBinder))
return FALSE;
if (nVestige == VESTIGE_KARSUS && 5 > GetSkillRank(SKILL_LORE, oBinder, TRUE) && 5 > GetSkillRank(SKILL_SPELLCRAFT, oBinder, TRUE))
return FALSE;
if (nVestige == VESTIGE_KARSUS)
{
effect eTest = GetFirstEffect(oBinder);
while(GetIsEffectValid(eTest))
{
if(GetEffectType(eTest) == EFFECT_TYPE_AREA_OF_EFFECT)
return FALSE;
eTest = GetNextEffect(oBinder);
}
}
// Agagres<65>s seal must be drawn in the soil
if (nVestige == VESTIGE_AGARES && GetIsAreaNatural(GetArea(oBinder)) != AREA_NATURAL)
return FALSE;
if (nVestige == VESTIGE_BUER && GetIsAreaInterior(GetArea(oBinder)))
return FALSE;
if (nVestige == VESTIGE_EURYNOME && GetHasSpellEffect(VESTIGE_AMON, oBinder))
return FALSE;
if (nVestige == VESTIGE_TENEBROUS && !GetIsNight())
return FALSE;
if (nVestige == VESTIGE_BALAM)
{
int nCur = GetCurrentHitPoints(oBinder);
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(1, DAMAGE_TYPE_SLASHING), oBinder);
if (nCur > GetCurrentHitPoints(oBinder))
return FALSE;
}
if (nVestige == VESTIGE_GERYON && 5 > GetSkillRank(SKILL_LORE, oBinder, TRUE))
return FALSE;
if (nVestige == VESTIGE_ARETE && (GetHasSpellEffect(VESTIGE_EURYNOME, oBinder) || GetHasSpellEffect(VESTIGE_CHUPOCLOPS, oBinder)))
return FALSE;
if (nVestige == VESTIGE_CHUPOCLOPS && GetHasSpellEffect(VESTIGE_AMON, oBinder))
return FALSE;
if (nVestige == VESTIGE_IPOS && 5 > GetSkillRank(SKILL_LORE, oBinder, TRUE) && 5 > GetSkillRank(SKILL_SPELLCRAFT, oBinder, TRUE))
return FALSE;
if (nVestige == VESTIGE_VANUS && GetIsAreaNatural(GetArea(oBinder)) != AREA_NATURAL)
return FALSE;
if (nVestige == VESTIGE_DESHARIS && GetIsAreaNatural(GetArea(oBinder)) == AREA_NATURAL)
return FALSE;
if (nVestige == VESTIGE_HALPHAX && !GetIsAreaInterior(GetArea(oBinder)))
return FALSE;
if (nVestige == VESTIGE_HALPHAX && GetIsAreaInterior(GetArea(oBinder)) && GetIsAreaAboveGround(GetArea(oBinder)) == AREA_UNDERGROUND)
return FALSE;
if (nVestige == VESTIGE_ORTHOS && GetTileMainLight1Color(GetLocation(oBinder)) != TILE_MAIN_LIGHT_COLOR_WHITE && GetTileMainLight1Color(GetLocation(oBinder)) != TILE_MAIN_LIGHT_COLOR_YELLOW)
return FALSE;
return TRUE;
}
int DoSummonRequirements(object oBinder, int nVestige)
{
if (GetHasFeat(FEAT_IGNORE_SPECIAL_REQUIREMENTS, oBinder)) return TRUE;
int nSpellId = StringToInt(Get2DACache(GetVestigeFile(), "SpellID", nVestige));
if (nSpellId == VESTIGE_LERAJE)
{
object oArrow = GetItemInSlot(INVENTORY_SLOT_ARROWS, oBinder);
int nStack = GetItemStackSize(oArrow);
if (nStack)
SetItemStackSize(oArrow, nStack-1);
else
{
FloatingTextStringOnCreature("You have failed to break an arrow for Leraje, and she refuses your call!", oBinder, FALSE);
return FALSE;
}
}
return TRUE;
}
int GetIsVestigeExploited(object oBinder, int nVestigeAbil)
{
if (GetLocalInt(oBinder, "ExploitVestige") == nVestigeAbil) return TRUE;
return FALSE;
}
void SetIsVestigeExploited(object oBinder, int nVestigeAbil)
{
SetLocalInt(oBinder, "ExploitVestige", nVestigeAbil);
SetLocalInt(oBinder, "ExploitVestigeTemp", TRUE);
SetLocalInt(oBinder, "ExploitVestigeConv", TRUE);
}
int GetIsPatronVestigeBound(object oBinder)
{
int nPatron;
if (GetHasFeat(FEAT_PATRON_VESTIGE_AMON , oBinder)) nPatron = VESTIGE_AMON;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_AYM , oBinder)) nPatron = VESTIGE_AYM;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_LERAJE , oBinder)) nPatron = VESTIGE_LERAJE;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_NABERIUS , oBinder)) nPatron = VESTIGE_NABERIUS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_RONOVE , oBinder)) nPatron = VESTIGE_RONOVE;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_DAHLVERNAR , oBinder)) nPatron = VESTIGE_DAHLVERNAR;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_HAAGENTI , oBinder)) nPatron = VESTIGE_HAAGENTI;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_MALPHAS , oBinder)) nPatron = VESTIGE_MALPHAS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_SAVNOK , oBinder)) nPatron = VESTIGE_SAVNOK;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_ANDROMALIUS, oBinder)) nPatron = VESTIGE_ANDROMALIUS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_FOCALOR , oBinder)) nPatron = VESTIGE_FOCALOR;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_KARSUS , oBinder)) nPatron = VESTIGE_KARSUS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_PAIMON , oBinder)) nPatron = VESTIGE_PAIMON;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_AGARES , oBinder)) nPatron = VESTIGE_AGARES;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_ANDRAS , oBinder)) nPatron = VESTIGE_ANDRAS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_BUER , oBinder)) nPatron = VESTIGE_BUER;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_EURYNOME , oBinder)) nPatron = VESTIGE_EURYNOME;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_TENEBROUS , oBinder)) nPatron = VESTIGE_TENEBROUS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_ARETE , oBinder)) nPatron = VESTIGE_ARETE;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_ASTAROTH , oBinder)) nPatron = VESTIGE_ASTAROTH;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_ACERERAK , oBinder)) nPatron = VESTIGE_ACERERAK;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_BALAM , oBinder)) nPatron = VESTIGE_BALAM;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_DANTALION , oBinder)) nPatron = VESTIGE_DANTALION;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_GERYON , oBinder)) nPatron = VESTIGE_GERYON;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_OTIAX , oBinder)) nPatron = VESTIGE_OTIAX;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_CHUPOCLOPS , oBinder)) nPatron = VESTIGE_CHUPOCLOPS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_HAURES , oBinder)) nPatron = VESTIGE_HAURES;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_IPOS , oBinder)) nPatron = VESTIGE_IPOS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_SHAX , oBinder)) nPatron = VESTIGE_SHAX;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_ZAGAN , oBinder)) nPatron = VESTIGE_ZAGAN;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_VANUS , oBinder)) nPatron = VESTIGE_VANUS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_THETRIAD , oBinder)) nPatron = VESTIGE_THETRIAD;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_DESHARIS , oBinder)) nPatron = VESTIGE_DESHARIS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_ZCERYLL , oBinder)) nPatron = VESTIGE_ZCERYLL;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_ELIGOR , oBinder)) nPatron = VESTIGE_ELIGOR;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_MARCHOSIAS , oBinder)) nPatron = VESTIGE_MARCHOSIAS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_ASHARDALON , oBinder)) nPatron = VESTIGE_ASHARDALON;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_HALPHAX , oBinder)) nPatron = VESTIGE_HALPHAX;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_ORTHOS , oBinder)) nPatron = VESTIGE_ORTHOS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_ABYSM , oBinder)) nPatron = VESTIGE_ABYSM;
if(GetHasSpellEffect(nPatron, oBinder)) return TRUE;
return FALSE;
}
int GetPatronVestige(object oBinder)
{
int nPatron = -1;
if (GetHasFeat(FEAT_PATRON_VESTIGE_AMON , oBinder)) nPatron = VESTIGE_AMON;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_AYM , oBinder)) nPatron = VESTIGE_AYM;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_LERAJE , oBinder)) nPatron = VESTIGE_LERAJE;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_NABERIUS , oBinder)) nPatron = VESTIGE_NABERIUS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_RONOVE , oBinder)) nPatron = VESTIGE_RONOVE;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_DAHLVERNAR , oBinder)) nPatron = VESTIGE_DAHLVERNAR;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_HAAGENTI , oBinder)) nPatron = VESTIGE_HAAGENTI;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_MALPHAS , oBinder)) nPatron = VESTIGE_MALPHAS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_SAVNOK , oBinder)) nPatron = VESTIGE_SAVNOK;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_ANDROMALIUS, oBinder)) nPatron = VESTIGE_ANDROMALIUS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_FOCALOR , oBinder)) nPatron = VESTIGE_FOCALOR;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_KARSUS , oBinder)) nPatron = VESTIGE_KARSUS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_PAIMON , oBinder)) nPatron = VESTIGE_PAIMON;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_AGARES , oBinder)) nPatron = VESTIGE_AGARES;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_ANDRAS , oBinder)) nPatron = VESTIGE_ANDRAS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_BUER , oBinder)) nPatron = VESTIGE_BUER;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_EURYNOME , oBinder)) nPatron = VESTIGE_EURYNOME;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_TENEBROUS , oBinder)) nPatron = VESTIGE_TENEBROUS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_ARETE , oBinder)) nPatron = VESTIGE_ARETE;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_ASTAROTH , oBinder)) nPatron = VESTIGE_ASTAROTH;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_ACERERAK , oBinder)) nPatron = VESTIGE_ACERERAK;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_BALAM , oBinder)) nPatron = VESTIGE_BALAM;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_DANTALION , oBinder)) nPatron = VESTIGE_DANTALION;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_GERYON , oBinder)) nPatron = VESTIGE_GERYON;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_OTIAX , oBinder)) nPatron = VESTIGE_OTIAX;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_CHUPOCLOPS , oBinder)) nPatron = VESTIGE_CHUPOCLOPS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_HAURES , oBinder)) nPatron = VESTIGE_HAURES;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_IPOS , oBinder)) nPatron = VESTIGE_IPOS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_SHAX , oBinder)) nPatron = VESTIGE_SHAX;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_ZAGAN , oBinder)) nPatron = VESTIGE_ZAGAN;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_VANUS , oBinder)) nPatron = VESTIGE_VANUS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_THETRIAD , oBinder)) nPatron = VESTIGE_THETRIAD;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_DESHARIS , oBinder)) nPatron = VESTIGE_DESHARIS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_ZCERYLL , oBinder)) nPatron = VESTIGE_ZCERYLL;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_ELIGOR , oBinder)) nPatron = VESTIGE_ELIGOR;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_MARCHOSIAS , oBinder)) nPatron = VESTIGE_MARCHOSIAS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_ASHARDALON , oBinder)) nPatron = VESTIGE_ASHARDALON;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_HALPHAX , oBinder)) nPatron = VESTIGE_HALPHAX;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_ORTHOS , oBinder)) nPatron = VESTIGE_ORTHOS;
else if (GetHasFeat(FEAT_PATRON_VESTIGE_ABYSM , oBinder)) nPatron = VESTIGE_ABYSM;
return nPatron;
}

View File

@@ -0,0 +1,321 @@
// Vestige SpellId Constants
const int VESTIGE_AMON = 19020;
const int VESTIGE_AYM = 19021;
const int VESTIGE_LERAJE = 19022;
const int VESTIGE_NABERIUS = 19023;
const int VESTIGE_RONOVE = 19024;
const int VESTIGE_DAHLVERNAR = 19025;
const int VESTIGE_HAAGENTI = 19026;
const int VESTIGE_MALPHAS = 19027;
const int VESTIGE_SAVNOK = 19028;
const int VESTIGE_ANDROMALIUS = 19029;
const int VESTIGE_FOCALOR = 19030;
const int VESTIGE_KARSUS = 19031;
const int VESTIGE_PAIMON = 19032;
const int VESTIGE_AGARES = 19033;
const int VESTIGE_ANDRAS = 19034;
const int VESTIGE_BUER = 19035;
const int VESTIGE_EURYNOME = 19036;
const int VESTIGE_TENEBROUS = 19037;
const int VESTIGE_ARETE = 19038;
const int VESTIGE_ASTAROTH = 19039;
const int VESTIGE_ACERERAK = 19040;
const int VESTIGE_BALAM = 19041;
const int VESTIGE_DANTALION = 19042;
const int VESTIGE_GERYON = 19043;
const int VESTIGE_OTIAX = 19044;
const int VESTIGE_CHUPOCLOPS = 19045;
const int VESTIGE_HAURES = 19046;
const int VESTIGE_IPOS = 19047;
const int VESTIGE_SHAX = 19048;
const int VESTIGE_ZAGAN = 19049;
const int VESTIGE_VANUS = 19050;
const int VESTIGE_THETRIAD = 19051;
const int VESTIGE_DESHARIS = 19052;
const int VESTIGE_ZCERYLL = 19053;
const int VESTIGE_ELIGOR = 19054;
const int VESTIGE_MARCHOSIAS = 19055;
const int VESTIGE_ASHARDALON = 19056;
const int VESTIGE_HALPHAX = 19057;
const int VESTIGE_ORTHOS = 19058;
const int VESTIGE_ABYSM = 19059;
// Vestige IPFeat Constants
const int IP_CONST_VESTIGE_AMON_BREATH = 13730;
const int IP_CONST_VESTIGE_AYM_HALO = 13731;
const int IP_CONST_VESTIGE_LERAJE_RICOCHET = 13732;
const int IP_CONST_VESTIGE_NABERIUS_DISGUISE = 13733;
const int IP_CONST_VESTIGE_NABERIUS_COMMAND = 13734;
const int IP_CONST_VESTIGE_RONOVE_FARHAND = 13735;
const int IP_CONST_VESTIGE_RONOVE_BULLRUSH = 13736;
const int IP_CONST_VESTIGE_DAHLVER_MOAN = 13737;
const int IP_CONST_VESTIGE_DAHLVER_SHARE = 13738;
const int IP_CONST_VESTIGE_HAAGENTI_TOUCH = 13739;
const int IP_CONST_VESTIGE_MALPHAS_EYE = 13740;
const int IP_CONST_VESTIGE_MALPHAS_INVIS_ST = 13741;
const int IP_CONST_VESTIGE_MALPHAS_INVIS_SW = 13742;
const int IP_CONST_VESTIGE_SAVNOK_CALL = 13743;
const int IP_CONST_VESTIGE_SAVNOK_MOVE_ST = 13744;
const int IP_CONST_VESTIGE_SAVNOK_MOVE_SW = 13745;
const int IP_CONST_VESTIGE_ANDRO_MIRTH = 13746;
const int IP_CONST_VESTIGE_ANDRO_LOCATE = 13747;
const int IP_CONST_VESTIGE_ANDRO_SEE = 13748;
const int IP_CONST_VESTIGE_FOCALOR_AURA = 13749;
const int IP_CONST_VESTIGE_FOCALOR_BOLT = 13750;
const int IP_CONST_VESTIGE_FOCALOR_BREATH = 13751;
const int IP_CONST_VESTIGE_KARSUS_SENSES = 13752;
const int IP_CONST_VESTIGE_KARSUS_TOUCH = 13753;
const int IP_CONST_VESTIGE_PAIMON_DANCE = 13754;
const int IP_CONST_VESTIGE_AGARES_STEP = 13755;
const int IP_CONST_VESTIGE_AGARES_ELEMENTAL = 13756;
const int IP_CONST_VESTIGE_ANDRAS_SMITE = 13757;
const int IP_CONST_VESTIGE_ANDRAS_DISCORD = 13758;
const int IP_CONST_VESTIGE_ANDRAS_MOUNT = 13759;
const int IP_CONST_VESTIGE_BUER_HEAL = 13760;
const int IP_CONST_VESTIGE_TENEBROUS_DARKNESS = 13761;
const int IP_CONST_VESTIGE_TENEBROUS_TOUCH_VOID = 13762;
const int IP_CONST_VESTIGE_TENEBROUS_TURN = 13763;
const int IP_CONST_VESTIGE_TENEBROUS_VESSEL = 13764;
const int IP_CONST_VESTIGE_ACERERAK_DETECT = 13765;
const int IP_CONST_VESTIGE_ACERERAK_HIDE = 13766;
const int IP_CONST_VESTIGE_ACERERAK_TOUCH = 13767;
const int IP_CONST_VESTIGE_BALAM_CUNNING = 13768;
const int IP_CONST_VESTIGE_BALAM_GLARE = 13769;
const int IP_CONST_VESTIGE_DANTALION_AWE = 13770;
const int IP_CONST_VESTIGE_DANTALION_READ = 13771;
const int IP_CONST_VESTIGE_DANTALION_TRAVEL = 13772;
const int IP_CONST_VESTIGE_GERYON_GAZE = 13773;
const int IP_CONST_VESTIGE_GERYON_FLIGHT = 13774;
const int IP_CONST_VESTIGE_OTIAX_AIR_BLAST = 13775;
const int IP_CONST_VESTIGE_OTIAX_OPEN = 13776;
const int IP_CONST_VESTIGE_OTIAX_UNLOCK = 13777;
const int IP_CONST_VESTIGE_ARETE_RESISTANCE = 13778;
const int IP_CONST_VESTIGE_ASTAROTH_BREATH = 13779;
const int IP_CONST_VESTIGE_ASTAROTH_WORD = 13780;
const int IP_CONST_VESTIGE_CHUPOCLOPS_DESPAIR = 13781;
const int IP_CONST_VESTIGE_CHUPOCLOPS_ETHEREAL = 13782;
const int IP_CONST_VESTIGE_HAURES_IMAGE = 13783;
const int IP_CONST_VESTIGE_HAURES_KILLER = 13784;
const int IP_CONST_VESTIGE_IPOS_INSIGHT = 13785;
const int IP_CONST_VESTIGE_SHAX_FREEDOM = 13786;
const int IP_CONST_VESTIGE_SHAX_STRIKE = 13787;
const int IP_CONST_VESTIGE_ZAGAN_AVERSION = 13788;
const int IP_CONST_VESTIGE_VANUS_FREE_ALLY = 13789;
const int IP_CONST_VESTIGE_THE_TRIAD_SMITE = 13790;
const int IP_CONST_VESTIGE_DESHARIS_TELEPORT = 13791;
const int IP_CONST_VESTIGE_DESHARIS_SMITE = 13792;
const int IP_CONST_VESTIGE_DESHARIS_ANIMATE = 13793;
const int IP_CONST_VESTIGE_ZCERYLL_BOLTS = 13794;
const int IP_CONST_VESTIGE_ZCERYLL_SUMMON = 13795;
const int IP_CONST_VESTIGE_ZCERYLL_TRUE_STRIKE = 13796;
const int IP_CONST_VESTIGE_ELIGOR_STRIKE = 13797;
const int IP_CONST_VESTIGE_MARCHOSIAS_SMOKE = 13798;
const int IP_CONST_VESTIGE_ASHARDALON_PRESENCE = 13799;
const int IP_CONST_VESTIGE_ASHARDALON_LOCATE = 13800;
const int IP_CONST_VESTIGE_HALPHAX_IMPRISON = 13801;
const int IP_CONST_VESTIGE_HALPHAX_BARRIER = 13802;
const int IP_CONST_VESTIGE_HALPHAX_SHELTER = 13803;
const int IP_CONST_VESTIGE_ORTHOS_BREATH = 13804;
// Vestige Ability SpellId Constants
const int VESTIGE_NABERIUS_DISGUISE_SELF_LEARN = 19074;
const int VESTIGE_NABERIUS_DISGUISE_SELF_OPTIONS = 19075;
const int VESTIGE_NABERIUS_DISGUISE_SELF_QS1 = 19076;
const int VESTIGE_NABERIUS_DISGUISE_SELF_QS2 = 19077;
const int VESTIGE_NABERIUS_DISGUISE_SELF_QS3 = 19078;
const int VESTIGE_NABERIUS_COMMAND_APPROACH = 19080;
const int VESTIGE_NABERIUS_COMMAND_DROP = 19081;
const int VESTIGE_NABERIUS_COMMAND_FALL = 19082;
const int VESTIGE_NABERIUS_COMMAND_FLEE = 19083;
const int VESTIGE_NABERIUS_COMMAND_HALT = 19084;
const int VESTIGE_RONOVE_FARHAND = 19085;
const int VESTIGE_RONOVE_BULLRUSH = 19086;
const int VESTIGE_FOCALOR_AURA_SADNESS = 19097;
const int VESTIGE_KARSUS_SENSES = 19100;
const int VESTIGE_KARSUS_DISPEL = 19101;
const int VESTIGE_TENEBROUS_TURN = 19111;
const int VESTIGE_TENEBROUS_FLICKER = 19112;
const int VESTIGE_DANTALION_READ_THOUGHTS = 19119;
const int VESTIGE_DANTALION_TRAVEL_SPELL = 19120;
const int VESTIGE_ARETE_RESIST = 19126;
const int VESTIGE_CHUPOCLOPS_AURA_DESPAIR = 19129;
const int VESTIGE_CHUPOCLOPS_ETHEREAL_WATCHER = 19130;
const int VESTIGE_THE_TRIAD_SMITE = 19138;
// General Binding SpellId Constants
const int VESTIGE_PACT_AUGMENTATION = 19171;
// Vestige Ability Constants, matches line # in vestigeabil.2da
const int VESTIGE_AMON_DARKVISION = 1 ;
const int VESTIGE_AMON_FIREBREATH = 2 ;
const int VESTIGE_AMON_RAMATTACK = 3 ;
const int VESTIGE_AYM_DWARVEN_STEP = 4 ;
const int VESTIGE_AYM_HALO_FIRE = 5 ;
const int VESTIGE_AYM_IMP_DISARM = 6 ;
const int VESTIGE_AYM_MEDIUM_ARMOR = 7 ;
const int VESTIGE_AYM_RESIST_FIRE = 8 ;
const int VESTIGE_AYM_RUINOUS_ATTACK = 9 ;
const int VESTIGE_LERAJE_HIDE_BONUS = 10;
const int VESTIGE_LERAJE_LOW_LIGHT_VISION = 11;
const int VESTIGE_LERAJE_PBSHOT = 12;
const int VESTIGE_LERAJE_RICOCHET = 13;
const int VESTIGE_LERAJE_WEAPON_PROF = 14;
const int VESTIGE_NABERIUS_DISGUISE_SELF = 15;
const int VESTIGE_NABERIUS_ABILITY_HEALING = 16;
const int VESTIGE_NABERIUS_SKILLS = 17;
const int VESTIGE_NABERIUS_PERSUASIVE = 18;
const int VESTIGE_NABERIUS_SILVER_TONGUE = 19;
const int VESTIGE_RONOVE_COLD_IRON = 20;
const int VESTIGE_RONOVE_FAR_HAND = 21;
const int VESTIGE_RONOVE_FISTS = 22;
const int VESTIGE_RONOVE_SPRINT = 23;
const int VESTIGE_DAHLVERNAR_MAD_SOUL = 24;
const int VESTIGE_DAHLVERNAR_MADDENING_MOAN = 25;
const int VESTIGE_DAHLVERNAR_NATURAL_ARMOR = 26;
const int VESTIGE_DAHLVERNAR_SHIELD_SELF = 27;
const int VESTIGE_HAAGENTI_CONFUSE = 28;
const int VESTIGE_HAAGENTI_IMMUNE_TRANS = 29;
const int VESTIGE_HAAGENTI_SHIELD_PROF = 30;
const int VESTIGE_HAAGENTI_WEAPON_PROF = 31;
const int VESTIGE_MALPHAS_ARCANE_EYE = 32;
const int VESTIGE_MALPHAS_INVIS = 33;
const int VESTIGE_MALPHAS_POISON_USE = 34;
const int VESTIGE_MALPHAS_SNEAK_ATTACK = 35;
const int VESTIGE_SAVNOK_CALL_ARMOR = 36;
const int VESTIGE_SAVNOK_HEAVY_ARMOR_PROF = 37;
const int VESTIGE_SAVNOK_MOVE_ALLY = 38;
const int VESTIGE_SAVNOK_SAVNOKS_ARMOR = 39;
const int VESTIGE_ANDROMALIUS_JESTER = 40;
const int VESTIGE_ANDROMALIUS_LOCATE = 41;
const int VESTIGE_ANDROMALIUS_SEE = 42;
const int VESTIGE_ANDROMALIUS_SENSE = 43;
const int VESTIGE_ANDROMALIUS_SNEAK = 44;
const int VESTIGE_FOCALOR_AURA = 45;
const int VESTIGE_FOCALOR_BREATH = 46;
const int VESTIGE_FOCALOR_LIGHTNING = 47;
const int VESTIGE_FOCALOR_BREATHING = 48;
const int VESTIGE_KARSUS_HEAVY_MAGIC = 49;
const int VESTIGE_KARSUS_SENSES_ABIL = 50;
const int VESTIGE_KARSUS_TOUCH = 51;
const int VESTIGE_KARSUS_WILL = 52;
const int VESTIGE_PAIMON_BLADES = 53;
const int VESTIGE_PAIMON_DEX = 54;
const int VESTIGE_PAIMON_SKILLS = 55;
const int VESTIGE_PAIMON_DODGE = 56;
const int VESTIGE_PAIMON_WHIRLWIND = 57;
const int VESTIGE_PAIMON_DANCE = 58;
const int VESTIGE_AGARES_EARTH_MASTERY = 59;
const int VESTIGE_AGARES_EARTHSHAKING = 60;
const int VESTIGE_AGARES_COMPANION = 61;
const int VESTIGE_AGARES_FEAR = 62;
const int VESTIGE_ANDRAS_WEAPON_PROF = 63;
const int VESTIGE_ANDRAS_MOUNT = 64;
const int VESTIGE_ANDRAS_SADDLE_SURE = 65;
const int VESTIGE_ANDRAS_SMITE = 66;
const int VESTIGE_ANDRAS_DISCORD = 67;
const int VESTIGE_ANDRAS_SURE_BLOWS = 68;
const int VESTIGE_BUER_KNOWLEDGE = 69;
const int VESTIGE_BUER_PURITY = 70;
const int VESTIGE_BUER_DELAY_DISEASE = 71;
const int VESTIGE_BUER_FAST_HEALING = 72;
const int VESTIGE_BUER_HEALING_GIFT = 73;
const int VESTIGE_BUER_TRACK = 74;
const int VESTIGE_EURYNOME_ANIMAL_FRIEND = 75;
const int VESTIGE_EURYNOME_DR = 76;
const int VESTIGE_EURYNOME_MAUL = 77;
const int VESTIGE_EURYNOME_POISON = 78;
const int VESTIGE_TENEBROUS_DARKNESS = 79;
const int VESTIGE_TENEBROUS_SEE_DARKNESS = 80;
const int VESTIGE_TENEBROUS_TOUCH_VOID = 81;
const int VESTIGE_TENEBROUS_TURN_UNDEAD = 82;
const int VESTIGE_TENEBROUS_EMPTY_VESSEL = 83;
const int VESTIGE_ARETE_PSIONIC_BOON = 84;
const int VESTIGE_ARETE_RESISTANCE = 85;
const int VESTIGE_ARETE_DR = 86;
const int VESTIGE_ARETE_REPLETION = 87;
const int VESTIGE_ASTAROTH_LORE = 88;
const int VESTIGE_ASTAROTH_BREATH = 89;
const int VESTIGE_ASTAROTH_TONGUE = 90;
const int VESTIGE_ASTAROTH_CRAFT = 91;
const int VESTIGE_ASTAROTH_WORD = 92;
const int VESTIGE_ACERERAK_DETECT = 93;
const int VESTIGE_ACERERAK_HIDE = 94;
const int VESTIGE_ACERERAK_LICH = 95;
const int VESTIGE_ACERERAK_TOUCH = 96;
const int VESTIGE_ACERERAK_HEALING = 97;
const int VESTIGE_BALAM_CUNNING = 98;
const int VESTIGE_BALAM_GLARE = 99;
const int VESTIGE_BALAM_PRESCIENCE = 100;
const int VESTIGE_BALAM_FINESSE = 101;
const int VESTIGE_DANTALION_AWE = 102;
const int VESTIGE_DANTALION_KNOWS = 103;
const int VESTIGE_DANTALION_READ = 104;
const int VESTIGE_DANTALION_TRAVEL = 105;
const int VESTIGE_GERYON_GAZE = 106;
const int VESTIGE_GERYON_VISION = 107;
const int VESTIGE_GERYON_DARKNESS = 108;
const int VESTIGE_GERYON_FLIGHT = 109;
const int VESTIGE_OTIAX_AIR_BLAST = 110;
const int VESTIGE_OTIAX_MIST = 111;
const int VESTIGE_OTIAX_OPEN = 112;
const int VESTIGE_OTIAX_UNLOCK = 113;
const int VESTIGE_CHUPOCLOPS_DESPAIR = 114;
const int VESTIGE_CHUPOCLOPS_ETHEREAL = 115;
const int VESTIGE_CHUPOCLOPS_BITE = 116;
const int VESTIGE_CHUPOCLOPS_POUNCE = 117;
const int VESTIGE_CHUPOCLOPS_SOULSENSE = 118;
const int VESTIGE_HAURES_MIND = 119;
const int VESTIGE_HAURES_MOVE = 120;
const int VESTIGE_HAURES_IMAGE = 121;
const int VESTIGE_HAURES_KILLER = 122;
const int VESTIGE_IPOS_CLAWS = 123;
const int VESTIGE_IPOS_INSIGHT = 124;
const int VESTIGE_IPOS_INFLUENCE = 125;
const int VESTIGE_IPOS_REND = 126;
const int VESTIGE_SHAX_FREEDOM = 127;
const int VESTIGE_SHAX_IMMUNITY = 128;
const int VESTIGE_SHAX_STORM_STRIKE = 129;
const int VESTIGE_ZAGAN_AVERSION = 130;
const int VESTIGE_ZAGAN_GRAPPLE = 131;
const int VESTIGE_ZAGAN_SCENT = 132;
const int VESTIGE_ZAGAN_CONSTRICT = 133;
const int VESTIGE_ZAGAN_LIZARD_BANE = 134;
const int VESTIGE_VANUS_FEAR_AURA = 135;
const int VESTIGE_VANUS_FREE_ALLY = 136;
const int VESTIGE_VANUS_DISDAIN = 137;
const int VESTIGE_VANUS_EARS = 138;
const int VESTIGE_THE_TRIAD_PSIONIC_BOON = 139;
const int VESTIGE_THE_TRIAD_GORN = 140;
const int VESTIGE_THE_TRIAD_RUJSHA = 141;
const int VESTIGE_THE_TRIAD_MINTAR = 142;
const int VESTIGE_DESHARIS_CITY_DWELLER = 143;
const int VESTIGE_DESHARIS_TELEPORT = 144;
const int VESTIGE_DESHARIS_SMITE = 145;
const int VESTIGE_DESHARIS_ANIMATE = 146;
const int VESTIGE_ZCERYLL_ALIEN_FORM = 147;
const int VESTIGE_ZCERYLL_ALIEN_MIND = 148;
const int VESTIGE_ZCERYLL_BOLTS = 149;
const int VESTIGE_ZCERYLL_SUMMON = 150;
const int VESTIGE_ELIGOR_STRIKE = 151;
const int VESTIGE_ELIGOR_SADDLE = 152;
const int VESTIGE_ELIGOR_STRENGTH = 153;
const int VESTIGE_ELIGOR_RESILIENCE = 154;
const int VESTIGE_ELIGOR_ARMOR = 155;
const int VESTIGE_MARCHOSIAS_DEATH_ATTACK = 156;
const int VESTIGE_MARCHOSIAS_RETRIBUTION = 157;
const int VESTIGE_MARCHOSIAS_SMOKE = 158;
const int VESTIGE_MARCHOSIAS_SILENT = 159;
const int VESTIGE_ASHARDALON_CREED = 160;
const int VESTIGE_ASHARDALON_PRESENCE = 161;
const int VESTIGE_ASHARDALON_VIGOR = 162;
const int VESTIGE_ASHARDALON_HEART = 163;
const int VESTIGE_HALPHAX_DR = 164;
const int VESTIGE_HALPHAX_KNOWLEDGE = 165;
const int VESTIGE_HALPHAX_IMPRISON = 166;
const int VESTIGE_HALPHAX_BARRIER = 167;
const int VESTIGE_HALPHAX_SHELTER = 168;
const int VESTIGE_ORTHOS_SIGHT = 169;
const int VESTIGE_ORTHOS_DISPLACEMENT = 170;
const int VESTIGE_ORTHOS_BREATH = 171;
const int VESTIGE_ABYSM_PSIONIC_BOON = 172;
const int VESTIGE_ABYSM_OVERPOWER = 173;

View File

@@ -0,0 +1,190 @@
/** @file
* Caching 2da read function and related.
*
* SQL/NWNx functions now in inc_sql
* @author Primogenitor
*
* @todo Document the constants and functions
*/
const int DEBUG_GET2DACACHE = FALSE;
string Get2DACache(string s2DA, string sColumn, int nRow);
string GetBiowareDBName();
//////////////////////////////////////////////////
/* Include section */
//////////////////////////////////////////////////
#include "inc_debug"
//#include "prc_inc_switch"
//////////////////////////////////////////////////
/* Function defintions */
//////////////////////////////////////////////////
/*
This is fugly and long. Should maybe be refactored to multiple functions. But everything inline does give
a few less instructions used.
Caching behaviour: Tokens in creature inventory
*/
string Get2DACache(string s2DA, string sColumn, int nRow)
{
//lower case the 2da and column
s2DA = GetStringLowerCase(s2DA);
sColumn = GetStringLowerCase(sColumn);
/*//get the chest that contains the cache
object oCacheWP = GetObjectByTag("Bioware2DACache");
//if no chest, use HEARTOFCHAOS in limbo as a location to make a new one
if (!GetIsObjectValid(oCacheWP))
{
if(DEBUG_GET2DACACHE) DoDebug("Get2DACache: Cache container creature does not exist, creating new one");
//oCacheWP = CreateObject(OBJECT_TYPE_PLACEABLE, "plc_chest2",
// GetLocation(GetObjectByTag("HEARTOFCHAOS")), FALSE, "Bioware2DACache");
//has to be a creature, placeables cant go through the DB
oCacheWP = CreateObject(OBJECT_TYPE_CREATURE, "prc_2da_cache",
GetLocation(GetObjectByTag("HEARTOFCHAOS")), FALSE, "Bioware2DACache");
}
//get the token for this file
string sFileWPName = s2DA + "_" + sColumn + "_" + IntToString(nRow / 1000);
//if(DEBUG_GET2DACACHE) DoDebug("Get2DACache: Token tag is " + sFileWPName);
object oFileWP = GetObjectByTag(sFileWPName);
//token doesnt exist make it
if(!GetIsObjectValid(oFileWP))
{
if(DEBUG_GET2DACACHE) DoDebug("Get2DACache: Token does not exist, creating new one");
// Use containers to avoid running out of inventory space
int nContainer = 0;
string sContainerName = "Bio2DACacheTokenContainer_" + GetSubString(s2DA, 0, 1) + "_";
object oContainer = GetObjectByTag(sContainerName + IntToString(nContainer));
// Find last existing container
if(GetIsObjectValid(oContainer))
{
if(DEBUG_GET2DACACHE) DoDebug("Get2DACache: Seeking last container in series: " + sContainerName);
// find the last container
nContainer = GetLocalInt(oContainer, "ContainerCount");
oContainer = GetObjectByTag(sContainerName + IntToString(nContainer));
if(DEBUG_GET2DACACHE) DoDebug("Get2DACache: Found: " + DebugObject2Str(oContainer));
// Make sure it's not full
if(GetLocalInt(oContainer, "NumTokensInside") >= 34) // Container has 35 slots. Attempt to not use them all, just in case
{
if(DEBUG_GET2DACACHE) DoDebug("Get2DACache: Container full: " + DebugObject2Str(oContainer));
oContainer = OBJECT_INVALID;
++nContainer; // new container is 1 higher than last one
}
}
// We need to create a container
if(!GetIsObjectValid(oContainer))
{
if(DEBUG_GET2DACACHE) DoDebug("Get2DACache: Creating new container");
oContainer = CreateObject(OBJECT_TYPE_ITEM, "nw_it_contain001", GetLocation(oCacheWP), FALSE, sContainerName + IntToString(nContainer));
DestroyObject(oContainer);
oContainer = CopyObject(oContainer, GetLocation(oCacheWP), oCacheWP, sContainerName + IntToString(nContainer));
// store the new number of containers in this series
if (nContainer)
SetLocalInt( GetObjectByTag(sContainerName + "0"), "ContainerCount", nContainer);
// else this is the first container - do nothing as this is the same as storing 0 on it.
// Also here we still have 2 objects with the same tag so above code may get
// the object destroyed at the end of the function if this is the first container.
}
if(DEBUG_GET2DACACHE) DoDebug("Get2DACache: Using container: " + DebugObject2Str(oContainer));
// Create the new token
//oFileWP = CreateObject(OBJECT_TYPE_ITEM, "hidetoken", GetLocation(oCacheWP), FALSE, sFileWPName);
//DestroyObject(oFileWP);
//oFileWP = CopyObject(oFileWP, GetLocation(oCacheWP), oCacheWP, sFileWPName);
oFileWP = CreateItemOnObject("hidetoken", oContainer, 1, sFileWPName);
//SetName(oFileWP, "2da Cache - " + sFileWPName);
// Increment token count tracking variable
SetLocalInt(oContainer, "NumTokensInside", GetLocalInt(oContainer, "NumTokensInside") + 1);
}
// get the value from the cache
string s = GetLocalString(oFileWP, s2DA+"|"+sColumn+"|"+IntToString(nRow));
//entry didnt exist in the cache
if(s == "")
{
//fetch from the 2da file
s = Get2DAString(s2DA, sColumn, nRow);
// store it on the waypoint
SetLocalString(oFileWP, s2DA+"|"+sColumn+"|"+IntToString(nRow),
(s == "" ? "****" : s) ); // this sets the stored string to "****" if s is an empty string (else stores s)
if(DEBUG_GET2DACACHE) DoDebug("Get2DACache: Missing from cache: " + s2DA + "|" + sColumn + "|" + IntToString(nRow));
}
//if(DEBUG_GET2DACACHE) PrintString("Get2DACache: Returned value is '" + s + "'");*/
string s = Get2DAString(s2DA, sColumn, nRow);
return s == "****" ? "" : s;
}
string GetBiowareDBName()
{
string sReturn;
sReturn = "prc_data";
//if(GetPRCSwitch(MARKER_PRC_COMPANION))
// sReturn += "cp";
if(GetPRCSwitch(MARKER_CEP1))
sReturn += "c1";
if(GetPRCSwitch(MARKER_CEP2))
sReturn += "c2";
if(GetPRCSwitch(MARKER_Q))
sReturn += "q";
return sReturn;
}
/**
* Gets the file end for the given 2da.
*
* @param sTable The 2da to get the file end for
* @return The file end value of the 2da.
*/
int PRCGetFileEnd(string sTable)
{
sTable = GetStringLowerCase(sTable);
return GetPRCSwitch("PRC_FILE_END_" + sTable);
/* //check fileends.2da first
int nEnd = StringToInt(Get2DACache("fileends", sTable, 0));
//still nothing - check
if(!nEnd) nEnd = StringToInt(Get2DACache("fileends", GetStringLeft(sTable, 8)+"*", 0));
return nEnd;*/
}
/**
* Gets the file end for special PRC files - used in new spellbook system.
*
* cls_psipw_*
* cls_move_*
* cls_true_*
* cls_inv_*
* cls_spell_*
*
* @param sTable The 2da to get the file end for
* @return The file end value of the 2da.
*/
int PRCGetDynamicFileEnd(string sTable)
{
int nRet = StringToInt(Get2DACache(sTable, "label", 0));
if(!nRet)
{
if (DEBUG) DoDebug("FileEnd for "+sTable+" not found! Using default value.");
nRet = 2720;
}
return nRet;
}
//Cache setup functions moved to inc_cache_setup

View File

@@ -0,0 +1,215 @@
//::///////////////////////////////////////////////
//:: Ability Damage special effects include
//:: inc_abil_damage
//:://////////////////////////////////////////////
/** @file
Implements the special effects of an ability
score falling down to 0 as according to PnP.
Strength: Lies helpless on ground (knockdown)
Dexterity: Paralyzed
Constitution: Death
Intelligence: Coma (knockdown)
Wisdom: Coma (knockdown)
Charisma: Coma (knockdown)
This can be turned off with a switch in
prc_inc_switches : PRC_NO_PNP_ABILITY_DAMAGE
NOTE: Due to BioOptimization (tm), Dex reaching
0 from above 3 when any other stat is already
at 0 will result in Dex being considered
restored at the same time the other stat is.
This might be workable around, but not
efficiently.
*/
//:://////////////////////////////////////////////
//:: Created By: Ornedan
//:: Created On: 09.04.2005
//:: Modified On: 25.06.2005
//:://////////////////////////////////////////////
/*
[00:55] <Stratovarius> yup
[00:56] <Stratovarius> well, something to add
[00:56] <Stratovarius> if KTTS reduces target to 0 (or would, i know NWN goes to 3)
[00:56] <Stratovarius> drop a cutscene paralyze on em
[00:56] <Stratovarius> and a long duration knockdown
[01:00] <Ornedan> 'k. And spawn a pseudo-hb on them to do recovery if they ever regain the mental stat
[01:01] <Ornedan> Also, test result: You lose spellcasting if your casting stat drops below the required, even if the reduction is a magical penalty
[01:03] <Stratovarius> you do? cool
*/
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
// Internal function. Called by a threadscript. Handles checking if any ability that has reached 0 has been restored
void AbilityDamageMonitor();
// Dex needs special handling due to the way CutsceneParalyze works (sets Dex to 3)
void DoDexCheck(object oCreature, int bFirstPart = TRUE);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
//#include "prc_inc_spells"
#include "prc_inc_damage" //functions to apply damage
//////////////////////////////////////////////////
/* Function defintions */
//////////////////////////////////////////////////
void AbilityDamageMonitor()
{
object oCreature = OBJECT_SELF;
int nMonitoredAbilities = GetLocalInt(oCreature, ABILITY_DAMAGE_MONITOR);
int nEffects = GetLocalInt(oCreature, ABILITY_DAMAGE_SPECIALS);
if (DEBUG) DoDebug("AbilityDamageMonitor running");
// Check each of the monitored abilities
if(nMonitoredAbilities & (1 << ABILITY_STRENGTH))
{
if(GetAbilityScore(oCreature, ABILITY_STRENGTH) > 3)
{
DeleteLocalInt(oCreature, VIRTUAL_ABILITY_SCORE + IntToString(ABILITY_STRENGTH));
SetLocalInt(oCreature, ABILITY_DAMAGE_MONITOR, GetLocalInt(oCreature, ABILITY_DAMAGE_MONITOR) ^ (1 << ABILITY_STRENGTH));
if (DEBUG) DoDebug("AbilityDamageMonitor Strength healed");
}
}
/*if(nMonitoredAbilities & (1 << ABILITY_DEXTERITY))
{
if(GetAbilityScore(oCreature, ABILITY_DEXTERITY) > 3)
{
DeleteLocalInt(oCreature, VIRTUAL_ABILITY_SCORE + IntToString(ABILITY_DEXTERITY));
SetLocalInt(oCreature, ABILITY_DAMAGE_MONITOR, GetLocalInt(oCreature, ABILITY_DAMAGE_MONITOR) ^ (1 << ABILITY_DEXTERITY));
}
}*/
if(nMonitoredAbilities & (1 << ABILITY_INTELLIGENCE))
{
if(GetAbilityScore(oCreature, ABILITY_INTELLIGENCE) > 3)
{
DeleteLocalInt(oCreature, VIRTUAL_ABILITY_SCORE + IntToString(ABILITY_INTELLIGENCE));
SetLocalInt(oCreature, ABILITY_DAMAGE_MONITOR, GetLocalInt(oCreature, ABILITY_DAMAGE_MONITOR) ^ (1 << ABILITY_INTELLIGENCE));
if (DEBUG) DoDebug("AbilityDamageMonitor Int healed");
}
}
if(nMonitoredAbilities & (1 << ABILITY_WISDOM))
{
if(GetAbilityScore(oCreature, ABILITY_WISDOM) > 3)
{
DeleteLocalInt(oCreature, VIRTUAL_ABILITY_SCORE + IntToString(ABILITY_WISDOM));
SetLocalInt(oCreature, ABILITY_DAMAGE_MONITOR, GetLocalInt(oCreature, ABILITY_DAMAGE_MONITOR) ^ (1 << ABILITY_WISDOM));
if (DEBUG) DoDebug("AbilityDamageMonitor Wis healed");
}
}
if(nMonitoredAbilities & (1 << ABILITY_CHARISMA))
{
if(GetAbilityScore(oCreature, ABILITY_CHARISMA) > 3)
{
DeleteLocalInt(oCreature, VIRTUAL_ABILITY_SCORE + IntToString(ABILITY_CHARISMA));
SetLocalInt(oCreature, ABILITY_DAMAGE_MONITOR, GetLocalInt(oCreature, ABILITY_DAMAGE_MONITOR) ^ (1 << ABILITY_CHARISMA));
if (DEBUG) DoDebug("AbilityDamageMonitor Cha healed");
}
}
// Check which effects, if any, need to be removed
int bRemovePara, bRemoveKnock;
nMonitoredAbilities = GetLocalInt(oCreature, ABILITY_DAMAGE_MONITOR);
if(!(nMonitoredAbilities & (1 << ABILITY_STRENGTH) ||
nMonitoredAbilities & (1 << ABILITY_INTELLIGENCE) ||
nMonitoredAbilities & (1 << ABILITY_WISDOM) ||
nMonitoredAbilities & (1 << ABILITY_CHARISMA)
) )
{
// Only remove effects if they are present
if(nEffects & ABILITY_DAMAGE_EFFECT_KNOCKDOWN)
{
bRemoveKnock = TRUE;
nEffects ^= ABILITY_DAMAGE_EFFECT_KNOCKDOWN;
}
if(!(nMonitoredAbilities & (1 << ABILITY_DEXTERITY)))
{
if(nEffects & ABILITY_DAMAGE_EFFECT_PARALYZE)
{
bRemovePara = TRUE;
nEffects ^= ABILITY_DAMAGE_EFFECT_KNOCKDOWN;
}
}
// Dex is the only remaining stat keeping CutscenePara on, so run the dexcheck
else
DelayCommand(0.1f, DoDexCheck(oCreature, TRUE));
SetLocalInt(oCreature, ABILITY_DAMAGE_SPECIALS, nEffects);
}
if (DEBUG) DoDebug("AbilityDamageMonitor bRemovePara:" + IntToString(bRemovePara));
if (DEBUG) DoDebug("AbilityDamageMonitor bRemoveKnock:" + IntToString(bRemoveKnock));
// Do effect removal
if(bRemovePara || bRemoveKnock)
{
effect eCheck = GetFirstEffect(oCreature);
while(GetIsEffectValid(eCheck))
{
if(bRemovePara && GetEffectType(eCheck) == EFFECT_TYPE_CUTSCENE_PARALYZE){
if (DEBUG) DoDebug("AbilityDamageMonitor Removed para");
RemoveEffect(oCreature, eCheck);
}
else if(bRemoveKnock && GetEffectType(eCheck) == 0){
RemoveEffect(oCreature, eCheck);
if (DEBUG) DoDebug("AbilityDamageMonitor Removed knock");
}
eCheck = GetNextEffect(oCreature);
}
}
if (DEBUG) DoDebug("AbilityDamageMonitor Monitored abilities:" + IntToString(nMonitoredAbilities));
// Stop the thread if there is nothing to monitor anymore
if(!nMonitoredAbilities)
TerminateCurrentThread();
}
void DoDexCheck(object oCreature, int bFirstPart = TRUE)
{
// Remove CutscenePara
if(bFirstPart)
{
effect eCheck = GetFirstEffect(oCreature);
while(GetIsEffectValid(eCheck))
{
if(GetEffectType(eCheck) == EFFECT_TYPE_CUTSCENE_PARALYZE)
RemoveEffect(oCreature, eCheck);
eCheck = GetNextEffect(oCreature);
}
DelayCommand(0.1f, DoDexCheck(oCreature, FALSE));
if (DEBUG) DoDebug("First part ran");
}
// Check if Dex is over 3 when it's gone
else
{
// It is, so remove Dex from the monitored list
if(GetAbilityScore(oCreature, ABILITY_DEXTERITY) > 3)
{
DeleteLocalInt(oCreature, VIRTUAL_ABILITY_SCORE + IntToString(ABILITY_DEXTERITY));
SetLocalInt(oCreature, ABILITY_DAMAGE_MONITOR, GetLocalInt(oCreature, ABILITY_DAMAGE_MONITOR) ^ (1 << ABILITY_DEXTERITY));
if (DEBUG) DoDebug("Dex check +");
}
/*else
SendMessageToPC(GetFirstPC(), "Dex check -");*/
// Apply CutscenePara back in either case. Next monitor call will remove it if it's supposed to be gone
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectCutsceneParalyze(), oCreature);
}
}
// Test main
//void main(){}

98
src/include/inc_acp.nss Normal file
View File

@@ -0,0 +1,98 @@
#include "prc_inc_switch"
const int PHENOTYPE_KENSAI = 49;
const int PHENOTYPE_ASSASSIN = 50;
const int PHENOTYPE_BARBARIAN = 51;
const int PHENOTYPE_FENCING = 52;
const int PHENOTYPE_ARCANE = 53;
const int PHENOTYPE_DEMONBLADE = 54;
const int PHENOTYPE_WARRIOR = 55;
const int PHENOTYPE_TIGERFANG = 56;
const int PHENOTYPE_SUNFIST = 57;
const int PHENOTYPE_DRAGONPALM = 58;
const int PHENOTYPE_BEARSCLAW = 59;
string sLock = "acp_fightingstyle_lock";
/* This creates a LocalInt - a "lock" - ..we check further down if it exists...
* if it does, we don't allow phenotype changing. To prevent lag spam. */
void LockThisFeat()
{
SetLocalInt(OBJECT_SELF, sLock, TRUE);
float fDelay = IntToFloat(GetPRCSwitch(PRC_ACP_DELAY))*60.0;
if(fDelay == 0.0)
fDelay = 90.0;
if(fDelay == -60.0)
fDelay = 0.0;
DelayCommand(fDelay, DeleteLocalInt(OBJECT_SELF, sLock)); //Lock persists 1 min times switchval
}
void ResetFightingStyle() //Resets the character phenotype to 0
{
int nCurrentPheno = GetPhenoType(OBJECT_SELF);
//If we are at phenotype 0 or 2, we do nothing. Tell the player that.
if(nCurrentPheno == PHENOTYPE_NORMAL
|| nCurrentPheno == PHENOTYPE_BIG)
SendMessageToPC(OBJECT_SELF, "You are already using the default combat style.");
//else if we are at an ACP phenotype we want to reset it to neutral.
else if(nCurrentPheno == PHENOTYPE_KENSAI
|| nCurrentPheno == PHENOTYPE_ASSASSIN
|| nCurrentPheno == PHENOTYPE_BARBARIAN
|| nCurrentPheno == PHENOTYPE_FENCING
|| nCurrentPheno == PHENOTYPE_ARCANE
|| nCurrentPheno == PHENOTYPE_DEMONBLADE
|| nCurrentPheno == PHENOTYPE_WARRIOR
|| nCurrentPheno == PHENOTYPE_TIGERFANG
|| nCurrentPheno == PHENOTYPE_SUNFIST
|| nCurrentPheno == PHENOTYPE_DRAGONPALM
|| nCurrentPheno == PHENOTYPE_BEARSCLAW)
{
SetPhenoType(PHENOTYPE_NORMAL);
LockThisFeat(); // Lock use!
}
//else, warn that the player doesn't have a phenotype which can be reset right now
else
SendMessageToPC(OBJECT_SELF, "Your phenotype is non-standard and cannot be reset this way.");
}
void SetCustomFightingStyle(int iStyle) //Sets character phenotype to 5,6,7 or 8
{
int nCurrentPheno = GetPhenoType(OBJECT_SELF);
//Maybe we're already using this fighting style? Just warn the player.
if(nCurrentPheno == iStyle)
SendMessageToPC(OBJECT_SELF, "You're already using this fighting style!");
//If we are at phenotype 0 or one of the styles themselves, we go ahead
//and set the creature's phenotype accordingly! (safe thanks to previous 'if')
else if(nCurrentPheno == PHENOTYPE_NORMAL
|| nCurrentPheno == PHENOTYPE_KENSAI
|| nCurrentPheno == PHENOTYPE_ASSASSIN
|| nCurrentPheno == PHENOTYPE_FENCING
|| nCurrentPheno == PHENOTYPE_ARCANE
|| nCurrentPheno == PHENOTYPE_BARBARIAN
|| nCurrentPheno == PHENOTYPE_DEMONBLADE
|| nCurrentPheno == PHENOTYPE_WARRIOR
|| nCurrentPheno == PHENOTYPE_TIGERFANG
|| nCurrentPheno == PHENOTYPE_SUNFIST
|| nCurrentPheno == PHENOTYPE_DRAGONPALM
|| nCurrentPheno == PHENOTYPE_BEARSCLAW)
{
SetPhenoType(iStyle);
LockThisFeat(); // Lock use!
}
//At phenotype 2? Tell the player they're too fat!
else if (nCurrentPheno == PHENOTYPE_BIG)
SendMessageToPC(OBJECT_SELF, "You're too fat to use a different fighting style!");
//...we didn't fulfil the above conditions? Warn the player.
else
SendMessageToPC(OBJECT_SELF, "Your phenotype is non-standard / Unable to change style");
}
// Test main
//void main(){}

View File

@@ -0,0 +1,202 @@
#include "inc_utility"
//:: Created by Mr. Bumpkin
//:: Include for all rages
//:: This function gets called right after the attribute bonuses are
//:: Applied.
// Applies all the bonus damage, to hit, and temporary hp to barbarians who would go over their
// +12 attribute caps by raging.
void GiveExtraRageBonuses(int nDuration, int nStrBeforeRaging, int nConBeforeRaging, int strBonus, int conBonus, int nSave, int nDamageBonusType, object oRager = OBJECT_SELF);
// Returns the damage type of the weapon held in nInventorySlot by oCreature. If they aren't
// holding a weapon, or the weapon they're holding is a x-bow, sling, shuriken, or dart, it returns
// either the damage type of slashing or bludgeoning, depending on whether they have a prc creature
// slashing weapon or not. It's bludgeoning if they don't have a prc creature slashing weapon.
int GetDamageTypeOfWeapon(int nInventorySlot, object oCreature = OBJECT_SELF);
// Applies all the bonus damage, to hit, and temporary hp to barbarians who would go over their
// +12 attribute caps by raging.
void GiveExtraRageBonuses(int nDuration, int nStrBeforeRaging, int nConBeforeRaging, int strBonus, int conBonus, int nSave, int nDamageBonusType, object oRager = OBJECT_SELF)
{
float nDelayed = 0.1;
int nStrSinceRaging = GetAbilityScore(oRager, ABILITY_STRENGTH);
int nConSinceRaging = GetAbilityScore(oRager, ABILITY_CONSTITUTION);
int nStrAdded = nStrSinceRaging - nStrBeforeRaging;
// The amount that was added to the str
int nStrWeWouldAdd = strBonus - nStrAdded;
// The amount we would have to theorhetically add if we wanted to give them the full bonus.
effect eDamage;
effect eToHit;
if(nStrAdded < strBonus)
{
//int nDamageBonusType = GetDamageTypeOfWeapon(INVENTORY_SLOT_RIGHTHAND, oRager);
if((nStrSinceRaging/2) * 2 != nStrSinceRaging)
// determine if their current Str right now is odd
{
if((nStrWeWouldAdd/2) * 2 != nStrWeWouldAdd)
// determine if the amount we would theorhetically have to add is odd.
// If so, then we're adding 2 odd numbers together to get an even. Add one to the bonuses
{
//::::: in this event we add nStrWeWouldAdd/2 + 1
//int nAmountToAdd = nStrWeWouldAdd/2 + 1;
eDamage = EffectDamageIncrease(nStrWeWouldAdd/2 + 1, nDamageBonusType);
eToHit = EffectAttackIncrease(nStrWeWouldAdd/2 +1);
}
else
{
//::::: in this event we add nStrWeWouldAdd/2
eDamage = EffectDamageIncrease(nStrWeWouldAdd/2, nDamageBonusType);
eToHit = EffectAttackIncrease(nStrWeWouldAdd/2);
}
}
else
{
//::::: in this event we add nStrWeWouldAdd/2
eDamage = EffectDamageIncrease(nStrWeWouldAdd/2, nDamageBonusType);
eToHit = EffectAttackIncrease(nStrWeWouldAdd/2);
}
effect eLink2 = ExtraordinaryEffect(EffectLinkEffects(eDamage, eToHit));
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink2, oRager, RoundsToSeconds(nDuration) - nDelayed);
// Applies the damage and toHit effects. I couldn't help myself, so I made the damage type be fire.
}
// If nStrAdded >= nStrBonus, then no need to add any special bonuses. :)
int nConAdded = nConSinceRaging - nConBeforeRaging;
// The amount that was added to the Con
int nConWeWouldAdd = conBonus - nConAdded;
// The amount we would have to theorhetically add if we wanted to give them the full bonus.
if(nConAdded < conBonus)
{
effect eHitPoints;
effect eHPRemoved;
int nCharacterLevel = GetHitDice(oRager);
if((nConSinceRaging/2) * 2 != nConSinceRaging)
// determine if their current Con right now is odd
{
if((nConWeWouldAdd/2) * 2 != nConWeWouldAdd)
// determine if the amount we would theorhetically have to add is odd.
// If so, then we're adding 2 odd numbers together to get an even. Add one to the bonuses
{
//::::: in this event we add nConWeWouldAdd/2 + 1
eHitPoints = EffectTemporaryHitpoints((nConWeWouldAdd/2 +1) * nCharacterLevel);
eHPRemoved = EffectDamage(((nConWeWouldAdd/2 +1) * nCharacterLevel), DAMAGE_TYPE_MAGICAL);
// We have to remove the temporary HP at the end of the rage via a damage effect, hehe.
// The damage type will be magical, something to keep in mind of magical resistances exist
// on your module. :) If that's a problem, change the damage type.
}
else
{
//::::: in this event we add nConWeWouldAdd/2
eHitPoints = EffectTemporaryHitpoints((nConWeWouldAdd/2) * nCharacterLevel);
eHPRemoved = EffectDamage(((nConWeWouldAdd/2) * nCharacterLevel), DAMAGE_TYPE_MAGICAL);
// We have to remove the temporary HP at the end of the rage via a damage effect, hehe.
// The damage type will be magical, something to keep in mind of magical resistances exist
// on your module. :) If that's a problem, change the damage type.
}
}
else
{
//::::: in this event we add nConWeWouldAdd/2
eHitPoints = EffectTemporaryHitpoints((nConWeWouldAdd/2) * nCharacterLevel);
eHPRemoved = EffectDamage(((nConWeWouldAdd/2) * nCharacterLevel), DAMAGE_TYPE_MAGICAL);
// We have to remove the temporary HP at the end of the rage via a damage effect, hehe.
// The damage type will be magical, something to keep in mind of magical resistances exist
// on your module. :) If that's a problem, change the damage type.
}
eHitPoints = ExtraordinaryEffect(eHitPoints);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eHitPoints, oRager, RoundsToSeconds(nDuration)- nDelayed);
//::: Had to ditch applying the damage effect, cause it would apply it even if they rested during their
//::: rage, and the resting was what ended it. Pretty Ironic.
//::: If you reactivate it, make sure to have the temporary HP effect last longer than the delay on the damage effect. 8j
//DelayCommand(RoundsToSeconds(nDuration) - nDelayed, ApplyEffectToObject(DURATION_TYPE_INSTANT, eHPRemoved, oRager));
// This is really how the temporary hp are going to get removed. I just didn't want to take any chances,
// so I gave the temporary hp a temporary duration.
}
// If nConAdded >= nConBonus, then no need to add any special bonuses. :)
}// End of the whole function.
// Returns the damage type of the weapon held in nInventorySlot by oCreature. If they aren't
// holding a weapon, or the weapon they're holding is a x-bow, sling, shuriken, or dart, it returns
// either the damage type of slashing or bludgeoning, depending on whether they have a prc creature
// slashing weapon or not. It's bludgeoning if they don't have a prc creature slashing weapon.
int GetDamageTypeOfWeapon(int nInventorySlot, object oCreature = OBJECT_SELF)
{
// 2da lookup to see what kind of damage it deals, then find the equivalent constant
int iDamageType = StringToInt(Get2DACache("baseitems","WeaponType",GetBaseItemType(GetItemInSlot(nInventorySlot, oCreature))));
switch(iDamageType)
{
case 1: return DAMAGE_TYPE_PIERCING;
case 2: return DAMAGE_TYPE_BLUDGEONING;
case 3: return DAMAGE_TYPE_SLASHING;
case 4: return DAMAGE_TYPE_SLASHING; // slashing & piercing... slashing bonus.
case 5: return DAMAGE_TYPE_BLUDGEONING; // bludeoning & piercing... bludeoning bonus.
}
// If none of the above types got a hit, we must assume the character is unarmed.
if(GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oCreature)) == BASE_ITEM_CSLSHPRCWEAP
|| GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oCreature)) == BASE_ITEM_CSLSHPRCWEAP
|| GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oCreature)) == BASE_ITEM_CSLSHPRCWEAP)
{
return DAMAGE_TYPE_SLASHING;
}
// If they're unarmed and have no creature weapons from a prc, we must assume they are just using their fists.
return DAMAGE_TYPE_BLUDGEONING;
}
// function I typed out to add duration to the rage, only to realize happily that there is no need.
// the normal rage function calculates duration as being what it naturally should be, even if there
// were no +12 bonus cap. :)
/*
if(nBonusDuration)
{
effect eStr = EffectAbilityIncrease(ABILITY_CONSTITUTION, nBonus);
effect eCon = EffectAbilityIncrease(ABILITY_STRENGTH, nBonus);
effect eSave = EffectSavingThrowIncrease(SAVING_THROW_WILL, nSave);
effect eAC = EffectACDecrease(2, AC_DODGE_BONUS);
effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE);
effect eLink = EffectLinkEffects(eCon, eStr);
eLink = EffectLinkEffects(eLink, eSave);
eLink = EffectLinkEffects(eLink, eAC);
eLink = EffectLinkEffects(eLink, eDur);
SignalEvent(OBJECT_SELF, EventSpellCastAt(OBJECT_SELF, SPELLABILITY_BARBARIAN_RAGE, FALSE));
//Make effect extraordinary
eLink = ExtraordinaryEffect(eLink);
DelayCommand(RoundsToSeconds(nDuration, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oRager, RoundsToSeconds(nBonusDuration)));
}
*/

83
src/include/inc_area.nss Normal file
View File

@@ -0,0 +1,83 @@
// Moved to a seperate inc to prevent a circular dependency error
/*********************\
* Function Prototypes *
\*********************/
/**
* This function will get the width of the area passed in.
*
* Created By: Zaddix
* Created On: July 17, 2002
* Optimized: March , 2003 by Knat
*
* @param oArea The area to get the width of.
* @return The width of oArea, as number of tiles. One tile = 10 meters.
*/
int GetAreaWidth(object oArea);
/**
* This function will get the height of the area passed in.
*
* Created By: Zaddix
* Created On: July 17, 2002
* Optimized: March , 2003 by Knat
*
* @param oArea The area to get the height of.
* @return The height of oArea, as number of tiles. One tile = 10 meters.
*/
int GetAreaHeight(object oArea);
//////////////////////////////////////////////////
/* Include section */
//////////////////////////////////////////////////
/**********************\
* Function Definitions *
\**********************/
int GetAreaWidth(object oArea)
{
int nX = GetLocalInt(oArea,"#WIDTH");
if( nX == 0)
{
int nY = 0; int nColor;
for (nX = 0; nX < 32; ++nX)
{
nColor = GetTileMainLight1Color(Location(oArea, Vector(IntToFloat(nX), 0.0, 0.0), 0.0));
if (nColor < 0 || nColor > 255)
{
SetLocalInt(oArea,"#WIDTH", nX);
return(nX);
}
}
SetLocalInt(oArea,"#WIDTH", 32);
return 32;
}
else
return nX;
}
int GetAreaHeight(object oArea)
{
int nY = GetLocalInt(oArea,"#HEIGHT");
if( nY == 0)
{
int nX = 0; int nColor;
for (nY=0; nY<32; ++nY)
{
nColor = GetTileMainLight1Color(Location(oArea, Vector(0.0, IntToFloat(nY), 0.0),0.0));
if (nColor < 0 || nColor > 255)
{
SetLocalInt(oArea,"#HEIGHT",nY);
return(nY);
}
}
SetLocalInt(oArea,"#HEIGHT",32);
return 32;
}
else
return nY;
}

View File

@@ -0,0 +1,380 @@
//:://////////////////////////////////////////////
//:: Array sorting functions
//:: inc_array_sort
//:://////////////////////////////////////////////
/** @file
A bunch of sorting functions for different
data types.
TMI may occur if attempting to sort too
large arrays.
For the quicksorts, 100 elements should always
be safe. TMI becomes almost certain past 150 elements.
The counting sort can handle 200 elements, with
250 being near upper limit.
It is not recommended that one directly use the
insertion sort, but 50 elements are probably safe.
Array implementation is assumed to follow
certain constraints:
- Array elements begin at index 0
- The value returned by the function to get
array size returns the number of elements
in the array.
- The index of the last element in the array
is the number of elements - 1.
- Array reads change no stored data
- Array writes are allowed to write over
existing entries.
@author Ornedan
@data Created 2006.05.27
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Constants */
//////////////////////////////////////////////////
/// At a certain point when the sort range is small enough, the overhead of quicksort exceeds
/// the higher order of efficiency in comparison to insertion sort, which has minimal overhead,
/// but still decent performance. At that point, switch to insertion sort.
const int QUICKSORT_TO_INSERTIONSORT_TRESHOLD = 6; // Anything betweem 4 - 10 seems to work. 6 was best in testing with randomly created arrays
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Implements a quicksort for integers. The array given for sorting should only contain
* integer elements. Sane results not guaranteed otherwise.
*
* @param oStore The object the array to sort is stored on
* @param sArrayName The name of the array to sort
*
* @param nLower The lower sort bound. Set by the function itself to 0 for recursive calls if
* left to default value (-1).
* @param nUpper The upper sort bound. Set by the function itself to array size - 1 for recursive
* calls if left to default value (-1).
*/
void QuickSortInt(object oStore, string sArrayName, int nLower = -1, int nUpper = -1);
/**
* Implements a quicksort for floating point numbers. The array given for sorting should only contain
* float elements. Sane results not guaranteed otherwise.
*
* @param oStore The object the array to sort is stored on
* @param sArrayName The name of the array to sort
*
* @param nLower The lower sort bound. Set by the function itself to 0 for recursive calls if
* left to default value (-1).
* @param nUpper The upper sort bound. Set by the function itself to array size - 1 for recursive
* calls if left to default value (-1).
*/
void QuickSortFloat(object oStore, string sArrayName, int nLower = -1, int nUpper = -1);
/**
* Implements an insertion sort for integers. The array given for sorting should only contain
* integer elements. Sane results not guaranteed otherwise.
*
* @param oStore The object the array to sort is stored on
* @param sArrayName The name of the array to sort
*
* @param nLower The lower sort bound. Set by the function itself to 0 for recursive calls if
* left to default value (-1).
* @param nUpper The upper sort bound. Set by the function itself to array size - 1 for recursive
* calls if left to default value (-1).
*/
void InsertionSortInt(object oStore, string sArrayName, int nLower = -1, int nUpper = -1);
/**
* Implements an insertion sort for floating point numbers. The array given for sorting should only contain
* float elements. Sane results not guaranteed otherwise.
*
* @param oStore The object the array to sort is stored on
* @param sArrayName The name of the array to sort
*
* @param nLower The lower sort bound. Set by the function itself to 0 for recursive calls if
* left to default value (-1).
* @param nUpper The upper sort bound. Set by the function itself to array size - 1 for recursive
* calls if left to default value (-1).
*/
void InsertionSortFloat(object oStore, string sArrayName, int nLower = -1, int nUpper = -1);
/**
* Implements counting sort for integers. The array given for sorting should only contain
* integer elements. Sane results not guaranteed otherwise.
*
* @param oStore The object the array to sort is stored on
* @param sArrayName The name of the array to sort
*/
void CountingSortInt(object oStore, string sArrayName);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
#include "prc_inc_array"
#include "inc_debug"
//////////////////////////////////////////////////
/* Internal functions */
//////////////////////////////////////////////////
/** Internal function.
* Shuffles elements around until they are a bit more in order.
*
* @param oStore The object the array to sort is stored on
* @param sArrayName The name of the array to sort
* @param nLower The lower sort bound of the range to sort.
* @param nUpper The upper sort bound of the range to sort.
* @return The array index around which the array has been "sorted".
*/
int _inc_array_sort_PartitionInt(object oStore, string sArrayName, int nLower, int nUpper)
{
int nDivider, nSwap;
// Attempt to determine the median of the values in the array positions nLower, nMid and nUpper
int nLowerVal = array_get_int(oStore, sArrayName, nLower),
nMidVal = array_get_int(oStore, sArrayName, (nLower + nUpper) / 2),
nUpperVal = array_get_int(oStore, sArrayName, nUpper);
if(nLowerVal < nMidVal)
{
if(nLowerVal < nUpperVal) nDivider = (nMidVal < nUpperVal) ? nMidVal : nUpperVal;
else nDivider = nLowerVal;
}
else if(nLowerVal < nUpperVal) nDivider = nLowerVal;
else nDivider = (nMidVal > nUpperVal) ? nMidVal : nUpperVal;
// Loop to sort the array around the median value
nLower -= 1; nUpper += 1; // Hack - The loops below need to be pre-increment, so we need to move the index variables to make the first elements examined be the ones at the original values
while(TRUE)
{
while(array_get_int(oStore, sArrayName, ++nLower) < nDivider) {} // Seek an element in the lower range of the array that is lesser than the divider
while(array_get_int(oStore, sArrayName, --nUpper) > nDivider) {} // Seek an element in the upper range of the array that is greater than the divider
// If the indexes haven't passed each other yet, swap the elements
if(nLower < nUpper)
{
nSwap = array_get_int(oStore, sArrayName, nLower);
array_set_int(oStore, sArrayName, nLower, array_get_int(oStore, sArrayName, nUpper));
array_set_int(oStore, sArrayName, nUpper, nSwap);
}
// Otherwise, the array is now arranged so that all elements at positions nUpper and higher are greater than or equal to the
// elements lower in the array
else
return nUpper;
}
// Never going to reach here, but compiler can't figure that out :P
Assert(FALSE, "FALSE", "Execution reached code that shouldn't be reachable", "inc_array_sort", "_inc_arrays_sort_PartitionInt");
return -1;
}
/** Internal function.
* Shuffles elements around until they are a bit more in order.
*
* @param oStore The object the array to sort is stored on
* @param sArrayName The name of the array to sort
* @param nLower The lower sort bound of the range to sort.
* @param nUpper The upper sort bound of the range to sort.
* @return The array index around which the array has been "sorted".
*/
int _inc_array_sort_PartitionFloat(object oStore, string sArrayName, int nLower, int nUpper)
{
float fDivider, fSwap;
// Attempt to determine the median of the values in the array positions nLower, nMid and nUpper
float fLowerVal = array_get_float(oStore, sArrayName, nLower),
fMidVal = array_get_float(oStore, sArrayName, (nLower + nUpper) / 2),
fUpperVal = array_get_float(oStore, sArrayName, nUpper);
if(fLowerVal < fMidVal)
{
if(fLowerVal < fUpperVal) fDivider = (fMidVal < fUpperVal) ? fMidVal : fUpperVal;
else fDivider = fLowerVal;
}
else if(fLowerVal < fUpperVal) fDivider = fLowerVal;
else fDivider = (fMidVal > fUpperVal) ? fMidVal : fUpperVal;
// Loop to sort the array around the median value
nLower -= 1; nUpper += 1; // Hack - The loops below need to be pre-increment, so we need to move the index variables to make the first elements examined be the ones at the original values
while(TRUE)
{
while(array_get_float(oStore, sArrayName, ++nLower) < fDivider) {} // Seek an element in the lower range of the array that is lesser than the divider
while(array_get_float(oStore, sArrayName, --nUpper) > fDivider) {} // Seek an element in the upper range of the array that is greater than the divider
// If the indexes haven't passed each other yet, swap the elements
if(nLower < nUpper)
{
fSwap = array_get_float(oStore, sArrayName, nLower);
array_set_float(oStore, sArrayName, nLower, array_get_float(oStore, sArrayName, nUpper));
array_set_float(oStore, sArrayName, nUpper, fSwap);
}
// Otherwise, the array is now arranged so that all elements at positions nUpper and higher are greater than or equal to the
// elements lower in the array
else
return nUpper;
}
// Never going to reach here, but compiler can't figure that out :P
Assert(FALSE, "FALSE", "Execution reached code that shouldn't be reachable", "inc_array_sort", "_inc_array_sort_PartitionFloat");
return -1;
}
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
void QuickSortInt(object oStore, string sArrayName, int nLower = -1, int nUpper = -1)
{
// If range limits are not given, initialise them to defaults
if(nLower == -1) nLower = 0;
if(nUpper == -1) nUpper = array_get_size(oStore, sArrayName) - 1;
// See if we have reached the point when quicksort becomes less efficient than insertion sort.
if((nUpper - nLower) <= QUICKSORT_TO_INSERTIONSORT_TRESHOLD)
InsertionSortInt(oStore, sArrayName, nLower, nUpper);
else
{
// Move entries into a slightly more sorted order by arranging them around a median value
// nDivider is the position of the beginning of the range where all the elements are
// greater or equal to the median used
int nDivider = _inc_array_sort_PartitionInt(oStore, sArrayName, nLower, nUpper);
// Recurse into the halves of the array generated by the above sorting
QuickSortInt(oStore, sArrayName, nLower, nDivider);
QuickSortInt(oStore, sArrayName, nDivider + 1, nUpper);
}
}
void QuickSortFloat(object oStore, string sArrayName, int nLower = -1, int nUpper = -1)
{
// If range limits are not given, initialise them to defaults
if(nLower == -1) nLower = 0;
if(nUpper == -1) nUpper = array_get_size(oStore, sArrayName) - 1;
// See if we have reached the point when quicksort becomes less efficient than insertion sort.
if((nUpper - nLower) <= QUICKSORT_TO_INSERTIONSORT_TRESHOLD)
InsertionSortFloat(oStore, sArrayName, nLower, nUpper);
else
{
// Move entries into a slightly more sorted order by arranging them around a median value
// nDivider is the position of the beginning of the range where all the elements are
// greater or equal to the median used
int nDivider = _inc_array_sort_PartitionFloat(oStore, sArrayName, nLower, nUpper);
// Recurse into the halves of the array generated by the above sorting
QuickSortFloat(oStore, sArrayName, nLower, nDivider);
QuickSortFloat(oStore, sArrayName, nDivider + 1, nUpper);
}
}
void InsertionSortInt(object oStore, string sArrayName, int nLower = -1, int nUpper = -1)
{
// If range limits are not given, initialise them to defaults
if(nLower == -1) nLower = 0;
if(nUpper == -1) nUpper = array_get_size(oStore, sArrayName) - 1;
// Some variables
int i, nSwap;
// Run the insertion sort loop
for(nLower += 1; nLower <= nUpper; nLower++)
{
// Store current entry in temporary variable
nSwap = array_get_int(oStore, sArrayName, nLower);
// Move preceding elements forward by one until we encounter index 0 or an element <= nSwap,
// whereupon we insert the swapped out element
i = nLower;
while(i > 0 && array_get_int(oStore, sArrayName, i - 1) > nSwap)
{
array_set_int(oStore, sArrayName, i,
array_get_int(oStore, sArrayName, i - 1)
);
i--;
}
// Insert the swapped out element at the position where all elements with index less than it's are lesser than or equal to it
array_set_int(oStore, sArrayName, i, nSwap);
}
}
void InsertionSortFloat(object oStore, string sArrayName, int nLower = -1, int nUpper = -1)
{
// If range limits are not given, initialise them to defaults
if(nLower == -1) nLower = 0;
if(nUpper == -1) nUpper = array_get_size(oStore, sArrayName) - 1;
// Some variables
int i;
float fSwap;
// Run the insertion sort loop
for(nLower += 1; nLower <= nUpper; nLower++)
{
// Store current entry in temporary variable
fSwap = array_get_float(oStore, sArrayName, nLower);
// Move preceding elements forward by one until we encounter index 0 or an element <= nSwap,
// whereupon we insert the swapped out element
i = nLower;
while(i > 0 && array_get_float(oStore, sArrayName, i - 1) > fSwap)
{
array_set_float(oStore, sArrayName, i,
array_get_float(oStore, sArrayName, i - 1)
);
i--;
}
// Insert the swapped out element at the position where all elements with index less than it's are lesser than or equal to it
array_set_float(oStore, sArrayName, i, fSwap);
}
}
void CountingSortInt(object oStore, string sArrayName)
{
int nMin = 0, nMax = 0,
nCount = 0,
i, size = array_get_size(oStore, sArrayName),
nTemp;
/* Find the least and greatest elements of the array */
for(i = 0; i < size; i++)
{
nTemp = array_get_int(oStore, sArrayName, i);
if(nTemp < nMin) nMin = nTemp;
if(nTemp > nMax) nMax = nTemp;
}
// Create temporary array
string sTempArray = "_CSort";
while(array_exists(oStore, sTempArray)) sTempArray += "_";
array_create(oStore, sTempArray);
// Get the amount of each number in the array
for(i = 0; i < size; i++)
{
nTemp = array_get_int(oStore, sArrayName, i) - nMin;
array_set_int(oStore, sTempArray, nTemp, array_get_int(oStore, sTempArray, nTemp) + 1);
}
// Set the values in the sortable array
size = array_get_size(oStore, sTempArray);
for(i = 0; i < size; i++)
{
while(array_get_int(oStore, sTempArray, i) > 0)
{
array_set_int(oStore, sArrayName, nCount++, i + nMin);
array_set_int(oStore, sTempArray, i, array_get_int(oStore, sTempArray, i) - 1);
}
}
// Delete the temporary array
array_delete(oStore, sTempArray);
}
// Test main
//void main(){}

View File

@@ -0,0 +1,362 @@
//::///////////////////////////////////////////////
//:: 2da cache creation include
//:: inc_cache_setup
//::///////////////////////////////////////////////
/** @file
* Creation and setting up of 2da caching databases
* Functions moved from inc_2dacache
* Removed SQL caching using the module, removed
* ability to use bioDB or nwnDB as cache (this is
* slow for single gets).
*
* @author Primogenitor
* moved by fluffyamoeba 2008-4-23
* @todo Document the constants and functions
*/
//////////////////////////////////////////////////
/* Include section */
//////////////////////////////////////////////////
#include "inc_2dacache"
//////////////////////////////////////////////////
/* Function defintions */
//////////////////////////////////////////////////
void Cache_Done()
{
WriteTimestampedLogEntry("2da caching complete");
}
void Cache_Class_Feat(int nClass, int nRow = 0)
{
string sFile = Get2DACache("classes", "FeatsTable", nClass);
if(sFile != ""
&& sFile != "****"
&& nRow < GetPRCSwitch(FILE_END_CLASS_FEAT))
{
Get2DACache(sFile, "FeatLabel", nRow);
Get2DACache(sFile, "FeatIndex", nRow);
Get2DACache(sFile, "List", nRow);
Get2DACache(sFile, "GrantedOnLevel", nRow);
Get2DACache(sFile, "OnMenu", nRow);
nRow++;
DelayCommand(0.1, Cache_Class_Feat(nClass, nRow));
}
else
{
if(nClass == 254)
Cache_Done();
else
{
DelayCommand(0.1, Cache_Class_Feat(nClass+1)); //need to delay to prevent TMI
}
}
}
void Cache_Classes(int nRow = 0)
{
if(nRow < GetPRCSwitch(FILE_END_CLASSES))
{
Get2DACache("classes", "Label", nRow);
Get2DACache("classes", "Name", nRow);
Get2DACache("classes", "Plural", nRow);
Get2DACache("classes", "Lower", nRow);
Get2DACache("classes", "Description", nRow);
Get2DACache("classes", "Icon", nRow);
Get2DACache("classes", "HitDie", nRow);
Get2DACache("classes", "AttackBonusTable", nRow);
Get2DACache("classes", "FeatsTable", nRow);
Get2DACache("classes", "SavingThrowTable", nRow);
Get2DACache("classes", "SkillsTable", nRow);
Get2DACache("classes", "BonusFeatsTable", nRow);
Get2DACache("classes", "SkillPointBase", nRow);
Get2DACache("classes", "SpellGainTable", nRow);
Get2DACache("classes", "SpellKnownTable", nRow);
Get2DACache("classes", "PlayerClass", nRow);
Get2DACache("classes", "SpellCaster", nRow);
Get2DACache("classes", "Str", nRow);
Get2DACache("classes", "Dex", nRow);
Get2DACache("classes", "Con", nRow);
Get2DACache("classes", "Wis", nRow);
Get2DACache("classes", "Int", nRow);
Get2DACache("classes", "Cha", nRow);
Get2DACache("classes", "PrimaryAbil", nRow);
Get2DACache("classes", "AlignRestrict", nRow);
Get2DACache("classes", "AlignRstrctType", nRow);
Get2DACache("classes", "InvertRestrict", nRow);
Get2DACache("classes", "Constant", nRow);
Get2DACache("classes", "EffCRLvl01", nRow);
Get2DACache("classes", "EffCRLvl02", nRow);
Get2DACache("classes", "EffCRLvl03", nRow);
Get2DACache("classes", "EffCRLvl04", nRow);
Get2DACache("classes", "EffCRLvl05", nRow);
Get2DACache("classes", "EffCRLvl06", nRow);
Get2DACache("classes", "EffCRLvl07", nRow);
Get2DACache("classes", "EffCRLvl08", nRow);
Get2DACache("classes", "EffCRLvl09", nRow);
Get2DACache("classes", "EffCRLvl10", nRow);
Get2DACache("classes", "EffCRLvl12", nRow);
Get2DACache("classes", "EffCRLvl13", nRow);
Get2DACache("classes", "EffCRLvl14", nRow);
Get2DACache("classes", "EffCRLvl15", nRow);
Get2DACache("classes", "EffCRLvl16", nRow);
Get2DACache("classes", "EffCRLvl17", nRow);
Get2DACache("classes", "EffCRLvl18", nRow);
Get2DACache("classes", "EffCRLvl19", nRow);
Get2DACache("classes", "EffCRLvl20", nRow);
Get2DACache("classes", "PreReqTable", nRow);
Get2DACache("classes", "MaxLevel", nRow);
Get2DACache("classes", "XPPenalty", nRow);
Get2DACache("classes", "ArcSpellLvlMod", nRow);
Get2DACache("classes", "DivSpellLvlMod", nRow);
Get2DACache("classes", "EpicLevel", nRow);
Get2DACache("classes", "Package", nRow);
nRow++;
DelayCommand(0.1, Cache_Classes(nRow));
}
else
DelayCommand(1.0, Cache_Class_Feat(0));
}
void Cache_RacialTypes(int nRow = 0)
{
if(nRow < GetPRCSwitch(FILE_END_RACIALTYPES))
{
Get2DACache("racialtypes", "Label", nRow);
Get2DACache("racialtypes", "Abrev", nRow);
Get2DACache("racialtypes", "Name", nRow);
Get2DACache("racialtypes", "ConverName", nRow);
Get2DACache("racialtypes", "ConverNameLower", nRow);
Get2DACache("racialtypes", "NamePlural", nRow);
Get2DACache("racialtypes", "Description", nRow);
Get2DACache("racialtypes", "Appearance", nRow);
Get2DACache("racialtypes", "StrAdjust", nRow);
Get2DACache("racialtypes", "DexAdjust", nRow);
Get2DACache("racialtypes", "IntAdjust", nRow);
Get2DACache("racialtypes", "ChaAdjust", nRow);
Get2DACache("racialtypes", "WisAdjust", nRow);
Get2DACache("racialtypes", "ConAdjust", nRow);
Get2DACache("racialtypes", "Endurance", nRow);
Get2DACache("racialtypes", "Favored", nRow);
Get2DACache("racialtypes", "FeatsTable", nRow);
Get2DACache("racialtypes", "Biography", nRow);
Get2DACache("racialtypes", "PlayerRace", nRow);
Get2DACache("racialtypes", "Constant", nRow);
Get2DACache("racialtypes", "AGE", nRow);
Get2DACache("racialtypes", "ToolsetDefaultClass", nRow);
Get2DACache("racialtypes", "CRModifier", nRow);
nRow++;
DelayCommand(0.1, Cache_RacialTypes(nRow));
}
else
DelayCommand(1.0, Cache_Classes(0));
}
void Cache_Feat(int nRow = 0)
{
if(nRow < GetPRCSwitch(FILE_END_FEAT))
{
Get2DACache("feat", "LABEL", nRow);
Get2DACache("feat", "FEAT", nRow);
Get2DACache("feat", "DESCRIPTION", nRow);
Get2DACache("feat", "MINATTACKBONUS", nRow);
Get2DACache("feat", "MINSTR", nRow);
Get2DACache("feat", "MINDEX", nRow);
Get2DACache("feat", "MININT", nRow);
Get2DACache("feat", "MINWIS", nRow);
Get2DACache("feat", "MINCON", nRow);
Get2DACache("feat", "MINCHA", nRow);
Get2DACache("feat", "MINSPELLLVL", nRow);
Get2DACache("feat", "PREREQFEAT1", nRow);
Get2DACache("feat", "PREREQFEAT2", nRow);
Get2DACache("feat", "GAINMULTIPLE", nRow);
Get2DACache("feat", "EFFECTSSTACK", nRow);
Get2DACache("feat", "ALLCLASSESCANUSE", nRow);
Get2DACache("feat", "CATEGORY", nRow);
Get2DACache("feat", "MAXCR", nRow);
Get2DACache("feat", "SPELLID", nRow);
Get2DACache("feat", "SUCCESSOR", nRow);
Get2DACache("feat", "CRValue", nRow);
Get2DACache("feat", "USESPERDAY", nRow);
Get2DACache("feat", "MASTERFEAT", nRow);
Get2DACache("feat", "TARGETSELF", nRow);
Get2DACache("feat", "OrReqFeat0", nRow);
Get2DACache("feat", "OrReqFeat1", nRow);
Get2DACache("feat", "OrReqFeat2", nRow);
Get2DACache("feat", "OrReqFeat3", nRow);
Get2DACache("feat", "OrReqFeat4", nRow);
Get2DACache("feat", "REQSKILL", nRow);
Get2DACache("feat", "ReqSkillMinRanks", nRow);
Get2DACache("feat", "REQSKILL2", nRow);
Get2DACache("feat", "ReqSkillMinRanks2", nRow);
Get2DACache("feat", "Constant", nRow);
Get2DACache("feat", "TOOLSCATEGORIES", nRow);
Get2DACache("feat", "HostileFeat", nRow);
Get2DACache("feat", "MinLevel", nRow);
Get2DACache("feat", "MinLevelClass", nRow);
Get2DACache("feat", "MaxLevel", nRow);
Get2DACache("feat", "MinFortSave", nRow);
Get2DACache("feat", "PreReqEpic", nRow);
Get2DACache("feat", "ReqAction", nRow);
nRow++;
DelayCommand(0.01, Cache_Feat(nRow));
}
else
DelayCommand(1.0, Cache_RacialTypes());
}
void Cache_Spells(int nRow = 0)
{
if(nRow < GetPRCSwitch(FILE_END_SPELLS))
{
Get2DACache("spells", "Label", nRow);
Get2DACache("spells", "Name", nRow);
Get2DACache("spells", "IconResRef", nRow);
Get2DACache("spells", "School", nRow);
Get2DACache("spells", "Range", nRow);
Get2DACache("spells", "VS", nRow);
Get2DACache("spells", "MetaMagic", nRow);
Get2DACache("spells", "TargetType", nRow);
Get2DACache("spells", "ImpactScript", nRow);
Get2DACache("spells", "Bard", nRow);
Get2DACache("spells", "Cleric", nRow);
Get2DACache("spells", "Druid", nRow);
Get2DACache("spells", "Paladin", nRow);
Get2DACache("spells", "Ranger", nRow);
Get2DACache("spells", "Wiz_Sorc", nRow);
Get2DACache("spells", "Innate", nRow);
Get2DACache("spells", "ConjTime", nRow);
Get2DACache("spells", "ConjAnim", nRow);
Get2DACache("spells", "ConjHeadVisual", nRow);
Get2DACache("spells", "ConjHandVisual", nRow);
Get2DACache("spells", "ConjGrndVisual", nRow);
Get2DACache("spells", "ConjSoundVFX", nRow);
Get2DACache("spells", "ConjSoundMale", nRow);
Get2DACache("spells", "ConjSoundFemale", nRow);
Get2DACache("spells", "CastAnim", nRow);
Get2DACache("spells", "CastTime", nRow);
Get2DACache("spells", "CastHeadVisual", nRow);
Get2DACache("spells", "CastHandVisual", nRow);
Get2DACache("spells", "CastGrndVisual", nRow);
Get2DACache("spells", "CastSound", nRow);
Get2DACache("spells", "Proj", nRow);
Get2DACache("spells", "ProjModel", nRow);
Get2DACache("spells", "ProjType", nRow);
Get2DACache("spells", "ProjSpwnPoint", nRow);
Get2DACache("spells", "ProjSound", nRow);
Get2DACache("spells", "ProjOrientation", nRow);
Get2DACache("spells", "ImmunityType", nRow);
Get2DACache("spells", "ItemImmunity", nRow);
Get2DACache("spells", "SubRadSpell1", nRow);
Get2DACache("spells", "SubRadSpell2", nRow);
Get2DACache("spells", "SubRadSpell3", nRow);
Get2DACache("spells", "SubRadSpell4", nRow);
Get2DACache("spells", "SubRadSpell5", nRow);
Get2DACache("spells", "Category", nRow);
Get2DACache("spells", "Master", nRow);
Get2DACache("spells", "UserType", nRow);
Get2DACache("spells", "SpellDesc", nRow);
Get2DACache("spells", "UseConcentration", nRow);
Get2DACache("spells", "SpontaneouslyCast", nRow);
Get2DACache("spells", "AltMessage", nRow);
Get2DACache("spells", "HostileSetting", nRow);
Get2DACache("spells", "FeatID", nRow);
Get2DACache("spells", "Counter1", nRow);
Get2DACache("spells", "Counter2", nRow);
Get2DACache("spells", "HasProjectile", nRow);
nRow++;
DelayCommand(0.01, Cache_Spells(nRow));
}
else
DelayCommand(0.1, Cache_Feat());
}
void Cache_Portraits(int nRow = 0)
{
if(nRow < GetPRCSwitch(FILE_END_PORTRAITS))
{
Get2DACache("portraits", "BaseResRef", nRow);
Get2DACache("portraits", "Sex", nRow);
Get2DACache("portraits", "Race", nRow);
Get2DACache("portraits", "InanimateType", nRow);
Get2DACache("portraits", "Plot", nRow);
Get2DACache("portraits", "LowGore", nRow);
nRow++;
DelayCommand(0.1, Cache_Portraits(nRow));
}
else
DelayCommand(1.0, Cache_Spells());
}
void Cache_Soundset(int nRow = 0)
{
if(nRow < GetPRCSwitch(FILE_END_SOUNDSET))
{
Get2DACache("soundset", "LABEL", nRow);
Get2DACache("soundset", "RESREF", nRow);
Get2DACache("soundset", "STRREF", nRow);
Get2DACache("soundset", "GENDER", nRow);
Get2DACache("soundset", "TYPE", nRow);
nRow++;
DelayCommand(0.1, Cache_Soundset(nRow));
}
else
DelayCommand(1.0, Cache_Portraits());
}
void Cache_Appearance(int nRow = 0)
{
if(nRow < GetPRCSwitch(FILE_END_APPEARANCE))
{
Get2DACache("appearance", "LABEL", nRow);
Get2DACache("appearance", "STRING_REF", nRow);
Get2DACache("appearance", "NAME", nRow);
Get2DACache("appearance", "RACE", nRow);
Get2DACache("appearance", "ENVMAP", nRow);
Get2DACache("appearance", "BLOODCOLR", nRow);
Get2DACache("appearance", "MODELTYPE", nRow);
Get2DACache("appearance", "WEAPONSCALE", nRow);
Get2DACache("appearance", "WING_TAIL_SCALE", nRow);
Get2DACache("appearance", "HELMET_SCALE_M", nRow);
Get2DACache("appearance", "HELMET_SCALE_F", nRow);
Get2DACache("appearance", "MOVERATE", nRow);
Get2DACache("appearance", "WALKDIST", nRow);
Get2DACache("appearance", "RUNDIST", nRow);
Get2DACache("appearance", "PERSPACE", nRow);
Get2DACache("appearance", "CREPERSPACE", nRow);
Get2DACache("appearance", "HEIGHT", nRow);
Get2DACache("appearance", "HITDIST", nRow);
Get2DACache("appearance", "PREFATCKDIST", nRow);
Get2DACache("appearance", "TARGETHEIGHT", nRow);
Get2DACache("appearance", "ABORTONPARRY", nRow);
Get2DACache("appearance", "RACIALTYPE", nRow);
Get2DACache("appearance", "HASLEGS", nRow);
Get2DACache("appearance", "HASARMS", nRow);
Get2DACache("appearance", "PORTRAIT", nRow);
Get2DACache("appearance", "SIZECATEGORY", nRow);
Get2DACache("appearance", "PERCEPTIONDIST", nRow);
Get2DACache("appearance", "FOOTSTEPTYPE", nRow);
Get2DACache("appearance", "SOUNDAPPTYPE", nRow);
Get2DACache("appearance", "HEADTRACK", nRow);
Get2DACache("appearance", "HEAD_ARC_H", nRow);
Get2DACache("appearance", "HEAD_ARC_V", nRow);
Get2DACache("appearance", "HEAD_NAME", nRow);
Get2DACache("appearance", "BODY_BAG", nRow);
Get2DACache("appearance", "TARGETABLE", nRow);
nRow++;
DelayCommand(0.1, Cache_Appearance(nRow));
}
else
DelayCommand(1.0, Cache_Soundset());
}
void Cache_2da_data()
{
Cache_Appearance();
}

218
src/include/inc_debug.nss Normal file
View File

@@ -0,0 +1,218 @@
//:://////////////////////////////////////////////
//:: Debug include
//:: inc_debug
//:://////////////////////////////////////////////
/** @file
This file contains a debug printing function, the
purpose of which is to be leavable in place in code,
so that debug printing can be centrally turned off
by commenting out the contents of the function.
Also, an assertion function and related function for
killing script execution.
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Globals */
//////////////////////////////////////////////////
/**
* Prefix all your debug calls with an if(DEBUG) so that they get stripped away
* during compilation as dead code when this is turned off.
*/
//const int DEBUG = FALSE;
#include "prc_inc_switch"
int DEBUG = GetPRCSwitch(PRC_DEBUG);
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* May print the given string, depending on whether debug printing is needed.
*
* Calls to this function should be guarded by an "if(DEBUG)" clause in order
* to be disableable.
*
* @param sString The string to print
*/
void DoDebug(string sString, object oAdditionalRecipient = OBJECT_INVALID);
/**
* Kills script execution using the Die() function if the given assertion
* is false. If a message has been given, also prints it using DoDebug().
* An assertion is something that should always be true if the program
* is functioning correctly. An assertion being false indicates a fatal error.
*
* The format of the string printed when an assertion fails is:
* "Assertion failed: sAssertion\nsMessage; At sScriptName: sFunction"
*
* Calls to this function should be guarded by an "if(DEBUG)" clause in order
* to be disableable.
*
* Example use:
*
* if(DEBUG) Assert(1 == 1, "1 == 1", "Oh noes! Arithmetic processing is b0rked.", "fooscript", "Baz()");
*
* @param bAssertion The result of some evaluation that should always be true.
* @param sAssertion A string containing the statement evalueated for bAssertion.
* @param sMessage The message to print if bAssertion is FALSE. Will be
* prefixed with "Assertion failed: " when printed.
* If left to default (empty), the message printed will simply
* be "Assertion failed!".
* @param sFileName Name of the script file where the call to this function occurs.
* @param sFunction Name of the function where the call to this function occurs.
*/
void Assert(int bAssertion, string sAssertion, string sMessage = "", string sFileName = "", string sFunction = "");
/**
* Kills the execution of the current script by forcing a Too Many Instructions
* error.
* Not recommended for use outside of debugging purposes. Scripts should be able
* to handle expectable error conditions gracefully.
*/
void Die();
/**
* Converts data about a given object into a string of the following format:
* "'GetName' - 'GetTag' - 'GetResRef' - ObjectToString"
*
* @param o Object to convert into a string
* @return A string containing identifying data about o
*/
string DebugObject2Str(object o);
/**
* Converts the given location into a string representation.
*
* @param loc Location to convert into a string
* @return A string representation of loc
*/
string DebugLocation2Str(location loc);
/**
* Converts the given itemproperty into a string representation.
*
* @param iprop Itemproperty to convert into a string
* @return A string representation of iprop
*/
string DebugIProp2Str(itemproperty iprop);
/**
* Converts a boolean to a string. Quick debug version.
* @see BooleanToString to use the tlkified one
*
* @param bool The boolean value to convert. 0 is considered false
* and everything else is true.
*/
string DebugBool2String(int bool);
/**
* Converts the given effect into a string representation.
*
* @param eEffect effect to convert into a string
* @return A string representation of effect
*/
string DebugEffect2String(effect eEffect);
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
void DoDebug(string sString, object oAdditionalRecipient = OBJECT_INVALID)
{
SendMessageToPC(GetFirstPC(), "<c<>j<EFBFBD>>" + sString + "</c>");
if(oAdditionalRecipient != OBJECT_INVALID)
SendMessageToPC(oAdditionalRecipient, "<c<>j<EFBFBD>>" + sString + "</c>");
WriteTimestampedLogEntry(sString);
}
void Assert(int bAssertion, string sAssertion, string sMessage = "", string sFileName = "", string sFunction = "")
{
if(bAssertion == FALSE)
{
//SpawnScriptDebugger();
string sErr = "Assertion failed: " + sAssertion;
if(sMessage != "" || sFileName != "" || sFunction != "")
{
sErr += "\n";
if(sMessage != "")
sErr += sMessage;
if(sFileName != "" || sFunction != "")
{
if(sMessage != "")
sErr += "\n";
sErr += "At " + sFileName;
if(sFileName != "" && sFunction != "")
sErr += ": ";
sErr += sFunction;
}
}
DoDebug(sErr);
Die();
}
}
void Die()
{
while(TRUE) {;}
}
string DebugObject2Str(object o)
{
return o == OBJECT_INVALID ?
"OBJECT_INVALID" : // Special case
"'" + GetName(o) + "' - '" + GetTag(o) + "' - '" + GetResRef(o) + "' - " + ObjectToString(o);
}
string DebugLocation2Str(location loc)
{
object oArea = GetAreaFromLocation(loc);
vector vPos = GetPositionFromLocation(loc);
string sX, sY, sZ, sF;
// 3 decimal places and no leading whitespace
sX = FloatToString(vPos.x,0,3);
sY = FloatToString(vPos.y,0,3);
sZ = FloatToString(vPos.z,0,3);
sF = FloatToString(GetFacingFromLocation(loc),0,3);
return "Area: Name = '" + GetName(oArea) + "', Tag = '" + GetTag(oArea) + "'; Position: (" + sX + ", " + sY + ", " + sZ + ",); Facing: " + sF;
}
string DebugIProp2Str(itemproperty iprop)
{
return "Type: " + IntToString(GetItemPropertyType(iprop)) + "; "
+ "Subtype: " + IntToString(GetItemPropertySubType(iprop)) + "; "
+ "Duration type: " + (GetItemPropertyDurationType(iprop) == DURATION_TYPE_INSTANT ? "DURATION_TYPE_INSTANT" :
GetItemPropertyDurationType(iprop) == DURATION_TYPE_TEMPORARY ? "DURATION_TYPE_TEMPORARY" :
GetItemPropertyDurationType(iprop) == DURATION_TYPE_PERMANENT ? "DURATION_TYPE_PERMANENT" :
IntToString(GetItemPropertyDurationType(iprop))) + "; "
+ "Param1: " + IntToString(GetItemPropertyParam1(iprop)) + "; "
+ "Param1 value: " + IntToString(GetItemPropertyParam1Value(iprop)) + "; "
+ "Cost table: " + IntToString(GetItemPropertyCostTable(iprop)) + "; "
+ "Cost table value: " + IntToString(GetItemPropertyCostTableValue(iprop));
}
string DebugBool2String(int bool)
{
return bool ? "True" : "False";
}
string DebugEffect2String(effect eEffect)
{
return "Effect; Type = " + IntToString(GetEffectType(eEffect))
+ ", SpellID: " + IntToString(GetEffectSpellId(eEffect))
+ ", Subtype: " + IntToString(GetEffectSubType(eEffect))
+ ", Duration: " + IntToString(GetEffectDurationType(eEffect))
+ ", Creator: " + GetName(GetEffectCreator(eEffect));
}

1108
src/include/inc_dispel.nss Normal file

File diff suppressed because it is too large Load Diff

4241
src/include/inc_draw.nss Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,65 @@
//::///////////////////////////////////////////////
//:: Drawing include - PRC-created functions
//:: inc_draw_prc
//::///////////////////////////////////////////////
/** @file
PRC extensions and additions to gaoneng's
Pentagrams & Summoning Circles system.
@author Ornedan
@date Created - 2005.12.05
*/
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* An attempt at conical VFX. Draws a bunch from the center towards the edge
* of a quarter-circle.
*
* @param nLines Number of lines to draw
* @param fLength Length of the cone
* @param lOrigin The origin of the cone
* @param fDirection The direction of the cone
*
* @param nDurationType The duration type of the applied VFX
* @param nVFX Visual effect to use
* @param fDuration Duration of the visualeffects, if temporary
* @param nFrequency How many VFX per line
* @param fTime How long it takes to draw the whole thing
*/
void DrawLinesInACone(int nLines, float fLength, location lOrigin, float fDirection,
int nDurationType, int nVFX, float fDuration, int nFrequency, float fTime);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
#include "inc_draw"
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
void DrawLinesInACone(int nLines, float fLength, location lOrigin, float fDirection,
int nDurationType, int nVFX, float fDuration, int nFrequency, float fTime)
{
float fTheta = 90.0f / nLines;
vector vCenter = GetPositionFromLocation(lOrigin);
object oArea = GetAreaFromLocation(lOrigin);
int i;
float f, fAngle;
vector vTarget;
for(i = 0; i < nLines; i++)
{
f = IntToFloat(i);
fAngle = fTheta * f + (fDirection - 45.0);
vTarget = vCenter + Vector(cos(fAngle), sin(fAngle), 0.0f);
DrawLineFromVectorToVector(nDurationType, nVFX, oArea, vCenter, vTarget, fDuration, nFrequency, fTime);
}
}

View File

@@ -0,0 +1,366 @@
/*
=============================================
PENTAGRAMS & SUMMONING CIRCLES -
BEAM-STYLE TEXT
=============================================
gaoneng January 17, 2005
#include "inc_draw_text"
last updated on April 25, 2005
Extension library for PENTAGRAMS & SUMMONING
CIRCLES. Used for creating text display.
=============================================
*/
/*
==================================
FUNCTIONS DECLARATIONS
==================================
*/
// Assigns oData to display sMessage
// =================================
// sMessage = message to display
// oData = target group
// fSpeed = second per letter
// fLifetime = seconds text lasts
// fFontHeight = height of font in meters
// fFontWidth = width of font in meters
// nVFX = VFX_BEAM_* constant
void TextMessage(string sMessage, object oData, float fSpeed=2.0f, float fLifetime=0.0f, float fFontHeight=0.5f, float fFontWidth=0.25f, int nVFX=VFX_BEAM_FIRE_W_SILENT);
/*
==================================
PRIVATE FUNCTIONS
==================================
*/
// void gao_BeamLetter(object oNode, string sAlphabet, int nVFX, int nDurationType=2, float fFlashRate=0.0f);
// void gao_CreateTextGrid(object oNode, float fFontHeight, float fFontWidth);
// void gao_AlphabetBlink(object oNode, string sAlphabet, int nVFX, float fFlashRate, float fLifetime);
// void gao_AlphabetPermanent(object oNode, string sAlphabet, int nVFX, float fLifetime);
// void gao_AlphabetScroll(object oNode, string sMessage, int nVFX, float fFlashRate, float fLifetime=0.0f);
// string gao_ReverseMessage(string sMessage);
/*
==================================
FUNCTIONS IMPLEMENTATIONS
==================================
*/
void gao_CreateTextGrid(object oNode, float fFontHeight, float fFontWidth, object oData, float fLifetime)
{
object oArea = GetArea(oNode);
vector vPos = GetPosition(oNode);
float fFacing = GetFacing(oNode);
vector vFacing = AngleToVector(fFacing + 90.0);
vector vLedNode;
object oLedNode;
fFontWidth /= 2.0;
fFontHeight /= 2.0;
int i, j, nTotal;
float f, g;
for (i=0; i<3; i++)
{
f = IntToFloat(i);
for (j=0; j<3; j++)
{
g = IntToFloat(j-1);
vLedNode = vPos - fFontWidth*g*vFacing + f*Vector(0.0, 0.0, fFontHeight);
oLedNode = CreateObject(OBJECT_TYPE_PLACEABLE, "prc_invisobj", Location(oArea, vLedNode, fFacing), FALSE, "PSC_X_TEXTMESSAGE");
AssignCommand(oLedNode, ActionDoCommand(SetLocalObject(oNode, "led" + IntToString(j) + IntToString(i), oLedNode)));
if (fLifetime == 0.0)
{
nTotal = GetLocalInt(oData, "storetotal");
AssignCommand(oLedNode, ActionDoCommand(SetLocalObject(oData, "store" + IntToString(nTotal), oLedNode)));
SetLocalInt(oData, "storetotal", nTotal + 1);
}
}
}
}
void gao_DestroyTextGrid(object oNode)
{
DestroyObject(GetLocalObject(oNode, "led00"));
DestroyObject(GetLocalObject(oNode, "led10"));
DestroyObject(GetLocalObject(oNode, "led20"));
DestroyObject(GetLocalObject(oNode, "led01"));
DestroyObject(GetLocalObject(oNode, "led11"));
DestroyObject(GetLocalObject(oNode, "led21"));
DestroyObject(GetLocalObject(oNode, "led02"));
DestroyObject(GetLocalObject(oNode, "led12"));
DestroyObject(GetLocalObject(oNode, "led22"));
}
void gao_BeamLetter(object oNode, string sAlphabet, int nVFX)
{
object oNode1 = GetLocalObject(oNode, "led00");
object oNode2 = GetLocalObject(oNode, "led10");
object oNode3 = GetLocalObject(oNode, "led20");
object oNode4 = GetLocalObject(oNode, "led01");
object oNode5 = GetLocalObject(oNode, "led11");
object oNode6 = GetLocalObject(oNode, "led21");
object oNode7 = GetLocalObject(oNode, "led02");
object oNode8 = GetLocalObject(oNode, "led12");
object oNode9 = GetLocalObject(oNode, "led22");
if (sAlphabet == "a")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode7, BODY_NODE_CHEST), oNode9);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode4, BODY_NODE_CHEST), oNode6);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode3, BODY_NODE_CHEST), oNode9);
}
else if (sAlphabet == "b")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode3);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode4, BODY_NODE_CHEST), oNode6);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode7, BODY_NODE_CHEST), oNode8);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode5, BODY_NODE_CHEST), oNode8);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode3, BODY_NODE_CHEST), oNode6);
}
else if (sAlphabet == "c")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode3);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode7, BODY_NODE_CHEST), oNode9);
}
else if (sAlphabet == "d")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode2);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode2, BODY_NODE_CHEST), oNode6);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode8, BODY_NODE_CHEST), oNode6);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode7, BODY_NODE_CHEST), oNode8);
}
else if (sAlphabet == "e")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode3);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode4, BODY_NODE_CHEST), oNode5);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode7, BODY_NODE_CHEST), oNode9);
}
else if (sAlphabet == "f")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode4, BODY_NODE_CHEST), oNode5);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode7, BODY_NODE_CHEST), oNode9);
}
else if (sAlphabet == "g")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode3);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode3, BODY_NODE_CHEST), oNode6);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode5, BODY_NODE_CHEST), oNode6);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode7, BODY_NODE_CHEST), oNode9);
}
else if (sAlphabet == "h")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode3, BODY_NODE_CHEST), oNode9);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode4, BODY_NODE_CHEST), oNode6);
}
else if (sAlphabet == "i")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode3);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode2, BODY_NODE_CHEST), oNode8);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode7, BODY_NODE_CHEST), oNode9);
}
else if (sAlphabet == "j")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode4);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode3);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode3, BODY_NODE_CHEST), oNode9);
}
else if (sAlphabet == "k")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode3, BODY_NODE_CHEST), oNode5);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode4, BODY_NODE_CHEST), oNode5);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode5, BODY_NODE_CHEST), oNode9);
}
else if (sAlphabet == "l")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode3);
}
else if (sAlphabet == "m")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode3, BODY_NODE_CHEST), oNode9);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode7, BODY_NODE_CHEST), oNode9);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode5, BODY_NODE_CHEST), oNode8);
}
else if (sAlphabet == "n")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode7, BODY_NODE_CHEST), oNode3);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode3, BODY_NODE_CHEST), oNode9);
}
else if (sAlphabet == "o" || sAlphabet == "0")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode3, BODY_NODE_CHEST), oNode9);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode3);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode7, BODY_NODE_CHEST), oNode9);
}
else if (sAlphabet == "p")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode7, BODY_NODE_CHEST), oNode9);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode4, BODY_NODE_CHEST), oNode6);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode6, BODY_NODE_CHEST), oNode9);
}
else if (sAlphabet == "q")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode3, BODY_NODE_CHEST), oNode9);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode7, BODY_NODE_CHEST), oNode9);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode3);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode5, BODY_NODE_CHEST), oNode3);
}
else if (sAlphabet == "r")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode4, BODY_NODE_CHEST), oNode6);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode7, BODY_NODE_CHEST), oNode9);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode6, BODY_NODE_CHEST), oNode9);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode3, BODY_NODE_CHEST), oNode5);
}
else if (sAlphabet == "s" || sAlphabet == "5")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode3);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode4, BODY_NODE_CHEST), oNode6);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode7, BODY_NODE_CHEST), oNode9);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode4, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode3, BODY_NODE_CHEST), oNode6);
}
else if (sAlphabet == "t")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode2, BODY_NODE_CHEST), oNode8);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode7, BODY_NODE_CHEST), oNode9);
}
else if (sAlphabet == "u")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode3);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode3, BODY_NODE_CHEST), oNode9);
}
else if (sAlphabet == "v")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode2, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode2, BODY_NODE_CHEST), oNode9);
}
else if (sAlphabet == "w")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode3);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode3, BODY_NODE_CHEST), oNode9);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode2, BODY_NODE_CHEST), oNode5);
}
else if (sAlphabet == "x")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode9);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode3, BODY_NODE_CHEST), oNode7);
}
else if (sAlphabet == "y")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode5, BODY_NODE_CHEST), oNode9);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode5, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode2, BODY_NODE_CHEST), oNode5);
}
else if (sAlphabet == "z")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode3);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode9);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode7, BODY_NODE_CHEST), oNode9);
}
else if (sAlphabet == "1")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode3, BODY_NODE_CHEST), oNode9);
}
else if (sAlphabet == "2")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode3);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode4, BODY_NODE_CHEST), oNode6);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode7, BODY_NODE_CHEST), oNode9);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode4);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode6, BODY_NODE_CHEST), oNode9);
}
else if (sAlphabet == "3")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode3);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode4, BODY_NODE_CHEST), oNode6);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode7, BODY_NODE_CHEST), oNode9);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode3, BODY_NODE_CHEST), oNode9);
}
else if (sAlphabet == "4")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode4, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode4, BODY_NODE_CHEST), oNode6);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode3, BODY_NODE_CHEST), oNode9);
}
else if (sAlphabet == "6")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode3);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode4, BODY_NODE_CHEST), oNode6);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode7, BODY_NODE_CHEST), oNode9);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode3, BODY_NODE_CHEST), oNode6);
}
else if (sAlphabet == "7")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode9);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode7, BODY_NODE_CHEST), oNode9);
}
else if (sAlphabet == "8")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode3, BODY_NODE_CHEST), oNode9);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode3);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode4, BODY_NODE_CHEST), oNode6);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode7, BODY_NODE_CHEST), oNode9);
}
else if (sAlphabet == "9")
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode1, BODY_NODE_CHEST), oNode3);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode4, BODY_NODE_CHEST), oNode6);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode7, BODY_NODE_CHEST), oNode9);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode4, BODY_NODE_CHEST), oNode7);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectBeam(nVFX, oNode3, BODY_NODE_CHEST), oNode9);
}
else gao_DestroyTextGrid(oNode);
}
void gao_AlphabetPermanent(object oNode, string sAlphabet, int nVFX, float fLifetime)
{
gao_BeamLetter(oNode, sAlphabet, nVFX);
if (fLifetime > 0.0) DelayCommand(fLifetime, gao_DestroyTextGrid(oNode));
}
void TextMessage(string sMessage, object oData=OBJECT_SELF, float fSpeed=2.0f, float fLifetime=0.0f, float fFontHeight=0.5f, float fFontWidth=0.25f, int nVFX=VFX_BEAM_FIRE_W_SILENT)
{
int i;
object oNode;
sMessage = GetStringLowerCase(sMessage);
int nLength = GetStringLength(sMessage);
int nData = GetLocalInt(oData, "storetotal");
if (nLength > nData) nLength = nData;
for (i=0; i<nLength; i++)
{
oNode = GetLocalObject(oData, "store" + IntToString(i));
if (oNode != OBJECT_INVALID)
{
gao_CreateTextGrid(oNode, fFontHeight, fFontWidth, oData, fLifetime);
DelayCommand(fSpeed*IntToFloat(i) + 1.0, gao_AlphabetPermanent(oNode, GetSubString(sMessage, i, 1), nVFX, fLifetime));
}
else break;
}
}

View File

@@ -0,0 +1,231 @@
/*
=============================================
PENTAGRAMS & SUMMONING CIRCLES -
UTILITY FUNCTIONS
=============================================
gaoneng January 17, 2005
#include "inc_draw_tools"
last updated on August 8, 2005
Library of utility tools for PENTAGRAMS &
SUMMONING CIRCLES. Already coincluded in
"inc_draw", so do not include if already
including "inc_draw".
=============================================
*/
/*
=============================================
GROUP* FUNCTIONS DECLARATIONS
=============================================
*/
// Set oData's group of objects plot status
void GroupSetPlotFlag(object oData, int bPlotFlag);
// Destroy oData and oData's group of objects (irrevocably) over fOvertime seconds
void GroupDestroyObject(object oData, float fDelay=0.0f, float fOvertime=3.0f, int bReverseOrder=FALSE);
// Apply eEffect to oData's group of objects over fOvertime seconds
void GroupApplyEffectToObject(int nDurationType, effect eEffect, object oData, float fDuration=0.0f, float fOvertime=3.0f, int bReverseOrder=FALSE);
// Make oData's group of objects run sScript over fOvertime seconds and then return execution to the calling script
void GroupExecuteScript(string sScript, object oData, float fOvertime=3.0f, int bReverseOrder=FALSE);
// Cause oData's group of objects to face fDirection / rotate fDirection
// bRelative - FALSE for absolute face fDirection
// - TRUE for rotate fDirection degrees (DEFAULT : TRUE)
void GroupSetFacing(float fDirection, object oData, int bRelative=TRUE, float fOvertime=3.0f, int bReverseOrder=FALSE);
// Cause oData's group of objects to face vTarget
void GroupSetFacingPoint(vector vTarget, object oData, float fOvertime=3.0f, int bReverseOrder=FALSE);
// Make oData's group of objects play nAnimation over fOvertime seconds
// nAnimation: ANIMATION_PLACEABLE_* only
void GroupPlayAnimation(int nAnimation, object oData, float fSpeed=1.0f, float fOvertime=3.0f, int bReverseOrder=FALSE);
/*
=============================================
GROUP* FUNCTIONS IMPLEMENTATIONS
=============================================
*/
void GroupExecuteScript(string sScript, object oData, float fOvertime=3.0f, int bReverseOrder=FALSE)
{
int i;
int nTotal = GetLocalInt(oData, "storetotal");
if (nTotal < 1) return;
float fBreak = fOvertime/IntToFloat(nTotal);
if (bReverseOrder)
{
int j = 0;
for (i=nTotal-1; i>-1; i--)
{
DelayCommand(fBreak*IntToFloat(j), ExecuteScript(sScript, GetLocalObject(oData, "store" + IntToString(i))));
j++;
}
}
else
{
for (i=0; i<nTotal; i++)
{
DelayCommand(fBreak*IntToFloat(i), ExecuteScript(sScript, GetLocalObject(oData, "store" + IntToString(i))));
}
}
}
void GroupSetPlotFlag(object oData, int bPlotFlag)
{
int i;
int nTotal = GetLocalInt(oData, "storetotal");
for (i=0; i<nTotal; i++)
{
SetPlotFlag(GetLocalObject(oData, "store" + IntToString(i)), bPlotFlag);
}
}
void GroupDestroyObject(object oData, float fDelay=0.0f, float fOvertime=3.0f, int bReverseOrder=FALSE)
{
int i;
int nTotal = GetLocalInt(oData, "storetotal");
if (nTotal < 1) return;
float fBreak = fOvertime/IntToFloat(nTotal);
if (bReverseOrder)
{
int j = 0;
for (i=nTotal-1; i>-1; i--)
{
DelayCommand(fDelay + fBreak*IntToFloat(j), DestroyObject(GetLocalObject(oData, "store" + IntToString(i))));
j++;
}
}
else
{
for (i=0; i<nTotal; i++)
{
DelayCommand(fDelay + fBreak*IntToFloat(i), DestroyObject(GetLocalObject(oData, "store" + IntToString(i))));
}
}
DestroyObject(oData, fDelay + fOvertime + 0.5);
}
void GroupApplyEffectToObject(int nDurationType, effect eEffect, object oData, float fDuration=0.0f, float fOvertime=3.0f, int bReverseOrder=FALSE)
{
int i;
int nTotal = GetLocalInt(oData, "storetotal");
if (nTotal < 1) return;
float fBreak = fOvertime/IntToFloat(nTotal);
if (bReverseOrder)
{
int j = 0;
for (i=nTotal-1; i>-1; i--)
{
DelayCommand(fBreak*IntToFloat(j), ApplyEffectToObject(nDurationType, eEffect, GetLocalObject(oData, "store" + IntToString(i)), fDuration));
j++;
}
}
else
{
for (i=0; i<nTotal; i++)
{
DelayCommand(fBreak*IntToFloat(i), ApplyEffectToObject(nDurationType, eEffect, GetLocalObject(oData, "store" + IntToString(i)), fDuration));
}
}
}
void GroupSetFacing(float fDirection, object oData, int bRelative=TRUE, float fOvertime=3.0f, int bReverseOrder=FALSE)
{
int i;
int nTotal = GetLocalInt(oData, "storetotal");
if (nTotal < 1) return;
float fBreak = fOvertime/IntToFloat(nTotal);
if (bReverseOrder)
{
int j = 0;
if (bRelative)
{
object oNode;
for (i=nTotal-1; i>-1; i--)
{
oNode = GetLocalObject(oData, "store" + IntToString(i));
DelayCommand(fBreak*IntToFloat(j), AssignCommand(oNode, SetFacing(GetFacing(oNode) + fDirection)));
j++;
}
}
else
{
for (i=nTotal-1; i>-1; i--)
{
DelayCommand(fBreak*IntToFloat(j), AssignCommand(GetLocalObject(oData, "store" + IntToString(i)), SetFacing(fDirection)));
j++;
}
}
}
else
{
if (bRelative)
{
object oNode;
for (i=0; i<nTotal; i++)
{
oNode = GetLocalObject(oData, "store" + IntToString(i));
DelayCommand(fBreak*IntToFloat(i), AssignCommand(oNode, SetFacing(GetFacing(oNode) + fDirection)));
}
}
else
{
for (i=0; i<nTotal; i++)
{
DelayCommand(fBreak*IntToFloat(i), AssignCommand(GetLocalObject(oData, "store" + IntToString(i)), SetFacing(fDirection)));
}
}
}
}
void GroupSetFacingPoint(vector vTarget, object oData, float fOvertime=3.0f, int bReverseOrder=FALSE)
{
int i;
int nTotal = GetLocalInt(oData, "storetotal");
if (nTotal < 1) return;
float fBreak = fOvertime/IntToFloat(nTotal);
if (bReverseOrder)
{
int j = 0;
for (i=nTotal-1; i>-1; i--)
{
DelayCommand(fBreak*IntToFloat(j), AssignCommand(GetLocalObject(oData, "store" + IntToString(i)), SetFacingPoint(vTarget)));
j++;
}
}
else
{
for (i=0; i<nTotal; i++)
{
DelayCommand(fBreak*IntToFloat(i), AssignCommand(GetLocalObject(oData, "store" + IntToString(i)), SetFacingPoint(vTarget)));
}
}
}
void GroupPlayAnimation(int nAnimation, object oData, float fSpeed=1.0f, float fOvertime=3.0f, int bReverseOrder=FALSE)
{
int i;
int nTotal = GetLocalInt(oData, "storetotal");
if (nTotal < 1) return;
float fBreak = fOvertime/IntToFloat(nTotal);
if (bReverseOrder)
{
int j = 0;
for (i=nTotal-1; i>-1; i--)
{
DelayCommand(fBreak*IntToFloat(j), AssignCommand(GetLocalObject(oData, "store" + IntToString(i)), PlayAnimation(nAnimation, fSpeed)));
j++;
}
}
else
{
for (i=0; i<nTotal; i++)
{
DelayCommand(fBreak*IntToFloat(i), AssignCommand(GetLocalObject(oData, "store" + IntToString(i)), PlayAnimation(nAnimation, fSpeed)));
}
}
}

709
src/include/inc_dynconv.nss Normal file
View File

@@ -0,0 +1,709 @@
//:://////////////////////////////////////////////
//:: Dynamic Conversation System include
//:: inc_dynconv
//:://////////////////////////////////////////////
/** @file
@author Primogenitor
@date 2005.09.23 - Rebuilt the system - Ornedan
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Constant definitions */
//////////////////////////////////////////////////
const int DYNCONV_EXITED = -2;
const int DYNCONV_ABORTED = -3;
const int DYNCONV_SETUP_STAGE = -1;
const int DYNCONV_TOKEN_HEADER = 99;
const int DYNCONV_TOKEN_REPLY_0 = 100;
const int DYNCONV_TOKEN_REPLY_1 = 101;
const int DYNCONV_TOKEN_REPLY_2 = 102;
const int DYNCONV_TOKEN_REPLY_3 = 103;
const int DYNCONV_TOKEN_REPLY_4 = 104;
const int DYNCONV_TOKEN_REPLY_5 = 105;
const int DYNCONV_TOKEN_REPLY_6 = 106;
const int DYNCONV_TOKEN_REPLY_7 = 107;
const int DYNCONV_TOKEN_REPLY_8 = 108;
const int DYNCONV_TOKEN_REPLY_9 = 109;
const int DYNCONV_TOKEN_EXIT = 110;
const int DYNCONV_TOKEN_WAIT = 111;
const int DYNCONV_TOKEN_NEXT = 112;
const int DYNCONV_TOKEN_PREV = 113;
const int DYNCONV_MIN_TOKEN = 99;
const int DYNCONV_MAX_TOKEN = 113;
const int DYNCONV_STRREF_PLEASE_WAIT = 16824202; // "Please wait"
const int DYNCONV_STRREF_PREVIOUS = 16824203; // "Previous"
const int DYNCONV_STRREF_NEXT = 16824204; // "Next"
const int DYNCONV_STRREF_ABORT_CONVO = 16824212; // "Abort"
const int DYNCONV_STRREF_EXIT_CONVO = 78; // "Exit"
const string DYNCONV_SCRIPT = "DynConv_Script";
const string DYNCONV_VARIABLE = "DynConv_Var";
const string DYNCONV_STAGE = "DynConv_Stage";
const string DYNCONV_TOKEN_BASE = "DynConv_TOKEN";
const string DYNCONV_CHOICEOFFSET = "ChoiceOffset";
/**
* Exiting the conversation is not allowed. The exit
* choice is not shown
*/
const int DYNCONV_EXIT_NOT_ALLOWED = 0;
/**
* Exiting the conversation is allowed and it is
* forced to exit due to no nodes being shown.
*/
const int DYNCONV_EXIT_FORCE_EXIT = -1;
/**
* Exiting the conversation is allowed and the exit
* choice is shown.
*/
const int DYNCONV_EXIT_ALLOWED_SHOW_CHOICE = 1;
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Sets the header token and reply tokens for the PC to values stored
* via SetHeader and AddChoice, respectively.
*
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
*/
void SetupTokens(object oPC = OBJECT_INVALID);
/**
* Builds the local variable name for a token.
*
* @param nTokenID One of the DYNCONV_TOKEN_* constants
*/
string GetTokenIDString(int nTokenID);
/**
* Sets the dynamic conversation header. ie, the "NPC"'s reply.
*
* @param sText The text to set the header to
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
*/
void SetHeader(string sText, object oPC = OBJECT_INVALID);
/**
* A wrapper for SetHeader() that uses TLK references.
*
* @param nStrRef The TLK entry to use
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
*/
void SetHeaderStrRef(int nStrRef, object oPC = OBJECT_INVALID);
/**
* Add a reply choice to be displayed. The replies are displayed in
* the same order as they are added.
*
* @param sText The text of the choice
* @param nValue The numeric value of the choice. This is what will be
* returned by GetChoice()
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
*/
void AddChoice(string sText, int nValue, object oPC = OBJECT_INVALID);
/**
* A wrapper for AddChoice() that uses TLK references.
*
* @param nStrRef The TLK entry to use
* @param nValue The numeric value of the choice. This is what will be
* returned by GetChoice()
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
*/
void AddChoiceStrRef(int nStrRef, int nValue, object oPC = OBJECT_INVALID);
/**
* Sets the custom token at nTokenID to be the given string and stores
* the value in a local variable on OBJECT_SELF.
* Used by the dyynamic onversation system to track token assignment.
*
* @param nTokenID The custom token number to store the string in
* @param sString The string to store
* @param oPC The PC whose conversation this token belongs to
*/
void SetToken(int nTokenID, string sString, object oPC = OBJECT_SELF);
/**
* Sets the default values for the Exit, Wait, Next and Previous
* tokens. The values will be as follows, or their translated
* equivalents should a non-english TLK be used.
*
* Exit = "Exit"
* Wait = "Please wait"
* Next = "Next"
* Previous = "Previous"
*/
void SetDefaultTokens();
/**
* Changes the conversation stage. If the new stage given is
* the same as the current, nothing happens. Otherwise
* the stage is changed and the choices stored for the old
* stage are deleted.
*
* @param nNewStage The stage to enter
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
*/
void SetStage(int nNewStage, object oPC = OBJECT_INVALID);
/**
* Gets the current stage of the conversation.
*
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
* @return The current stage of the conversation, as previously
* set via SetStage() or 0 if no calls to SetStage()
* have been done yet.
*/
int GetStage(object oPC = OBJECT_INVALID);
/**
* Gets the value of the choice selected by the PC.
*
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
* @return The value of the choice the PC made, as set
* by a call to AddChoice().
*/
int GetChoice(object oPC = OBJECT_INVALID);
/**
* Gets the text of the choice selected by the PC.
*
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
* @return The text of the choice the PC made, as set
* by a call to AddChoice().
*/
string GetChoiceText(object oPC = OBJECT_INVALID);
/**
* Starts a dynamic conversation. Results are unspecified if called while
* already inside a dynamic conversation.
*
* @param sConversationScript The script to use for controlling the conversation.
* @param oPC The PC that is to be doing the responding in the conversation.
* @param bAllowExit One of the DYNCONV_EXIT_* constants.
* @param bAllowAbort If TRUE, the PC is allowed to aborts the conversation by moving / doing
* some other action or being involved in combat. This can be changed later
* on using AllowAbort()
* @param bForceStart If TRUE, the PC's actions are cleared, so the conversation starts immediately
* and cannot be avoided by the PC cancelling the action while it is in the queue.
* @param oConverseWith The object to speak the "NPC" side of the conversation. Usually, this is also
* the PC, which will be used when this parameter is left to it's default value.
* NOTE: If this parameter is given a value other than OBJECT_INVALID, no validity
* testing is performed upon that object. The function caller needs to make sure
* the object exists.
*/
void StartDynamicConversation(string sConversationScript, object oPC,
int nAllowExit = DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, int bAllowAbort = FALSE,
int bForceStart = FALSE, object oConverseWith = OBJECT_INVALID);
/**
* Starts using another dynamic conversation script while inside a
* dynamic conversation. Should only be called from a dynamic conversation
* script.
* The current conversation's script and allow exit/abort variables are
* saved. When the conversation entered via this call exits, the system
* returns to the current conversation, with stage being the one specified
* in the call to this function.
* NOTE: Any stage setup markers are not stored for the return.
*
* @param sConversationToEnter The conversation script to use in the branch
* @param nStageToReturnTo The value of stage variable upong return
* from the branch.
* @param bAllowExit The branch's initial exit allowance state. See
* StartDynamicConversation() for more details.
* @param bAllowAbort The branch's initial abort allowance state. See
* StartDynamicConversation() for more details.
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used.
*/
void BranchDynamicConversation(string sConversationToEnter, int nStageToReturnTo,
int bAllowExit = TRUE, int bAllowAbort = FALSE,
object oPC = OBJECT_INVALID);
/**
* Marks the current dynconvo as exitable via the exit conversation
* choice.
*
* @param nNewValue One of the DYNCONV_EXIT_* constants
* @param bChangeExitTokenText If this is TRUE, then changes the text on
* DYNCONV_TOKEN_EXIT to "Exit"
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used.
*/
void AllowExit(int nNewValue = DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, int bChangeExitTokenText = TRUE, object oPC = OBJECT_INVALID);
/**
* Marks the conversation as abortable, meaning that the player is
* allowed to leave the conversation via means other than the
* exit conversation choice.
*
* @param oPC The PC involved in the conversation. If left to
* default, GetPCSpeaker is used.
*/
void AllowAbort(object oPC = OBJECT_INVALID);
/**
* Checks whether the given stage is marked as already set up.
*
* @param nStage The stage to check
* @param oPC The PC involved in the conversation. If left to
* default, GetPCSpeaker is used.
*/
int GetIsStageSetUp(int nStage, object oPC = OBJECT_INVALID);
/**
* Marks a stage as being set up. This means that when
* the conversation script is called to set up the
* stage, nothing is done and old values are used instead.
* This is useful for scrolling lists, as CPU is not
* wasted on rebuilding the exact same list.
*
* @param nStage The stage to set marker for
* @param oPC The PC involved in the conversation. If left to
* default, GetPCSpeaker is used.
*/
void MarkStageSetUp(int nStage, object oPC = OBJECT_INVALID);
/**
* Marks the stage as not set up. This is used to undo
* the effects of MarkStageSetUp() when there is
* need to rerun the stage's builder.
* An example of such situation would be returning to
* a stage from another.
*
* @param nStage The stage to unset marker for
* @param oPC The PC involved in the conversation. If left to
* default, GetPCSpeaker is used.
*/
void MarkStageNotSetUp(int nStage, object oPC = OBJECT_INVALID);
/**
* Clears the current stage's choices and marks it not set up.
*
* @param oPC The PC involved in the conversation. If left to
* default, GetPCSpeaker is used.
*/
void ClearCurrentStage(object oPC = OBJECT_INVALID);
//////////////////////////////////////////////////
/* Include section */
//////////////////////////////////////////////////
#include "prc_inc_array"
#include "inc_debug"
//////////////////////////////////////////////////
/* Internal function prototypes */
//////////////////////////////////////////////////
void _DynConvInternal_ExitedConvo(object oPC, int bAbort);
void _DynConvInternal_RunScript(object oPC, int nDynConvVar);
void _DynConvInternal_PreScript(object oPC);
void _DynConvInternal_PostScript(object oPC);
object _DynConvInternal_ResolvePC(object oPC);
//////////////////////////////////////////////////
/* Function Definitions */
//////////////////////////////////////////////////
void SetupTokens(object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
// Set header
SetCustomToken(DYNCONV_TOKEN_HEADER, GetLocalString(oPC, "DynConv_HeaderText"));
// Set reply tokens. Assumes that the tokens used are a continuous block.
int nOffset = GetLocalInt(oPC, DYNCONV_CHOICEOFFSET);
int i;
for (i = 0; i < 10; i++)
{
SetToken(DYNCONV_TOKEN_REPLY_0 + i, array_get_string(oPC, "ChoiceTokens", nOffset + i), oPC);
}
}
void SetHeader(string sText, object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
SetLocalString(oPC, "DynConv_HeaderText", sText);
}
void SetHeaderStrRef(int nStrRef, object oPC = OBJECT_INVALID)
{
SetHeader(GetStringByStrRef(nStrRef), oPC);
}
string GetTokenIDString(int nTokenID)
{
return DYNCONV_TOKEN_BASE + IntToString(nTokenID);
}
void AddChoice(string sText, int nValue, object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
if(!array_exists(oPC, "ChoiceTokens"))
array_create(oPC, "ChoiceTokens");
if(!array_exists(oPC, "ChoiceValues"))
array_create(oPC, "ChoiceValues");
array_set_string(oPC, "ChoiceTokens", array_get_size(oPC, "ChoiceTokens"), sText);
array_set_int (oPC, "ChoiceValues", array_get_size(oPC, "ChoiceValues"), nValue);
}
void AddChoiceStrRef(int nStrRef, int nValue, object oPC = OBJECT_INVALID)
{
AddChoice(GetStringByStrRef(nStrRef), nValue, oPC);
}
void SetToken(int nTokenID, string sString, object oPC = OBJECT_SELF)
{
// Set the token
SetCustomToken(nTokenID, sString);
// Set a marker on the PC for the reply conditional scripts to check
SetLocalString(oPC, GetTokenIDString(nTokenID), sString);
}
string GetToken(int nTokenID, object oPC = OBJECT_SELF)
{
// Set a marker on the PC for the reply conditional scripts to check
return GetLocalString(oPC, GetTokenIDString(nTokenID));
}
void SetDefaultTokens()
{
SetCustomToken(DYNCONV_TOKEN_EXIT, GetStringByStrRef(DYNCONV_STRREF_EXIT_CONVO));
SetCustomToken(DYNCONV_TOKEN_WAIT, GetStringByStrRef(DYNCONV_STRREF_PLEASE_WAIT));
SetCustomToken(DYNCONV_TOKEN_NEXT, GetStringByStrRef(DYNCONV_STRREF_NEXT));
SetCustomToken(DYNCONV_TOKEN_PREV, GetStringByStrRef(DYNCONV_STRREF_PREVIOUS));
}
void _DynConvInternal_ExitedConvo(object oPC, int bAbort)
{
// Restart convo if not allowed to leave yet
if(bAbort && !GetLocalInt(oPC, "DynConv_AllowAbort")) // Allowed to abort?
{
if(DEBUG) DoDebug("_DynConvInternal_ExitedConvo(): Conversation aborted, restarting.");
AssignCommand(oPC, ClearAllActions(TRUE));
AssignCommand(oPC, ActionStartConversation(oPC, "dyncov_base", TRUE, FALSE));
SetLocalInt(oPC, "DynConv_RestartMarker", TRUE);
}
// Allowed to exit? Technically, the only way this branch should ever be run is by there not being any response choices available
else if(!bAbort &&
(GetLocalInt(oPC, "DynConv_AllowExit") == DYNCONV_EXIT_NOT_ALLOWED))
{
if(DEBUG) DoDebug("_DynConvInternal_ExitedConvo(): ERROR: Conversation exited via exit node while exiting not allowed!\n"
+ "DYNCONV_SCRIPT = '" + GetLocalString(oPC, DYNCONV_SCRIPT) + "'\n"
);
AssignCommand(oPC, ClearAllActions(TRUE));
AssignCommand(oPC, ActionStartConversation(oPC, "dyncov_base", TRUE, FALSE));
SetLocalInt(oPC, "DynConv_RestartMarker", TRUE);
}
else{
// Run the conversation script's exit handler
SetLocalInt(oPC, DYNCONV_VARIABLE, bAbort ? DYNCONV_ABORTED : DYNCONV_EXITED);
ExecuteScript(GetLocalString(oPC, DYNCONV_SCRIPT), OBJECT_SELF);
// If there are entries remaining in the stack, pop the previous conversation
if(GetLocalInt(oPC, "DynConv_Stack"))
{
if(DEBUG) DoDebug("_DynConvInternal_ExitedConvo(): Exited a branch");
// Clean up after the previous conversation
array_delete(oPC, "ChoiceTokens");
array_delete(oPC, "ChoiceValues");
array_delete(oPC, "StagesSetup");
DeleteLocalInt(oPC, "ChoiceOffset");
// Pop the data from the stack
int nStack = GetLocalInt(oPC, "DynConv_Stack");
int nStage = GetLocalInt(oPC, "DynConv_Stack_ReturnToStage_" + IntToString(nStack));
int nAllowExit = GetLocalInt(oPC, "DynConv_Stack_AllowExit_" + IntToString(nStack));
int nAllowAbort = GetLocalInt(oPC, "DynConv_Stack_AllowAbort_" + IntToString(nStack));
string sScript = GetLocalString(oPC, "DynConv_Stack_Script_" + IntToString(nStack));
// Delete the stack level
DeleteLocalInt(oPC, "DynConv_Stack_ReturnToStage_" + IntToString(nStack));
DeleteLocalInt(oPC, "DynConv_Stack_AllowExit_" + IntToString(nStack));
DeleteLocalInt(oPC, "DynConv_Stack_AllowAbort_" + IntToString(nStack));
DeleteLocalString(oPC, "DynConv_Stack_Script_" + IntToString(nStack));
if(nStack - 1 > 0) SetLocalInt(oPC, "DynConv_Stack", nStack - 1);
else DeleteLocalInt(oPC, "DynConv_Stack");
// Store the date in the conversation variables
SetLocalInt(oPC, DYNCONV_STAGE, nStage);
SetLocalInt(oPC, "DynConv_AllowExit", nAllowExit);
SetLocalInt(oPC, "DynConv_AllowAbort", nAllowAbort);
SetLocalString(oPC, DYNCONV_SCRIPT, sScript);
// Restart the conversation
AssignCommand(oPC, ClearAllActions(TRUE));
AssignCommand(oPC, ActionStartConversation(oPC, "dyncov_base", TRUE, FALSE));
}
// Fully exited the conversation. Clean up
else
{
if(DEBUG) DoDebug("_DynConvInternal_ExitedConvo(): Fully exited conversation");
array_delete(oPC, "ChoiceTokens");
array_delete(oPC, "ChoiceValues");
array_delete(oPC, "StagesSetup");
DeleteLocalInt(oPC, "ChoiceOffset");
DeleteLocalInt(oPC, "DynConv_AllowExit");
DeleteLocalInt(oPC, "DynConv_AllowAbort");
DeleteLocalInt(oPC, DYNCONV_VARIABLE);
DeleteLocalInt(oPC, DYNCONV_STAGE);
DeleteLocalString(oPC, DYNCONV_SCRIPT);
DeleteLocalString(oPC, "DynConv_HeaderText");
int i;
for(i = DYNCONV_MIN_TOKEN; i <= DYNCONV_MAX_TOKEN; i++)
DeleteLocalString(oPC, GetTokenIDString(i));
}
}
}
void _DynConvInternal_RunScript(object oPC, int nDynConvVar)
{
if(!GetLocalInt(oPC, "DynConv_RestartMarker"))
{
_DynConvInternal_PreScript(oPC);
string sScript = GetLocalString(oPC, DYNCONV_SCRIPT);
SetLocalInt(oPC, DYNCONV_VARIABLE, nDynConvVar);
ExecuteScript(sScript, OBJECT_SELF);
_DynConvInternal_PostScript(oPC);
}
else
{
SetupTokens(oPC);
DeleteLocalInt(oPC, "DynConv_RestartMarker");
}
}
void _DynConvInternal_PreScript(object oPC)
{
// Create the choice arrays
array_create(oPC, "ChoiceTokens");
array_create(oPC, "ChoiceValues");
}
void _DynConvInternal_PostScript(object oPC)
{
// If debugging is active, check that the conversations have at least one response node
// when exiting is off
if(DEBUG)
{
if(GetLocalInt(oPC, DYNCONV_VARIABLE) == DYNCONV_SETUP_STAGE &&
GetLocalInt(oPC, "DynConv_AllowExit") == DYNCONV_EXIT_NOT_ALLOWED &&
array_get_size(oPC, "ChoiceTokens") == 0
)
{
DoDebug("Dynconvo ERROR: No response tokens set up and exiting not allowed!");
}
}
}
object _DynConvInternal_ResolvePC(object oPC)
{
return oPC == OBJECT_INVALID ? GetPCSpeaker() : oPC; // If no valid PC reference was passed, get it via GetPCSpeaker
}
void SetStage(int nNewStage, object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
// No need to act if the stage wasn't changed
if(nNewStage != GetStage(oPC))
{
SetLocalInt(oPC, DYNCONV_STAGE, nNewStage);
// Clear the choice data
array_delete(oPC, "ChoiceTokens");
array_delete(oPC, "ChoiceValues");
DeleteLocalInt(oPC, "ChoiceOffset");
}
}
int GetStage(object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
return GetLocalInt(oPC, DYNCONV_STAGE);
}
int GetChoice(object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
return array_get_int(oPC, "ChoiceValues", GetLocalInt(oPC, DYNCONV_VARIABLE) // Number of choice
- 1 // Which begins at index 1 instead of the index 0 we need here
+ GetLocalInt(oPC, "ChoiceOffset"));
}
string GetChoiceText(object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
return array_get_string(oPC, "ChoiceTokens", GetLocalInt(oPC, DYNCONV_VARIABLE) // Number of choice
- 1 // Which begins at index 1 instead of the index 0 we need here
+ GetLocalInt(oPC, "ChoiceOffset"));
}
void StartDynamicConversation(string sConversationScript, object oPC,
int nAllowExit = DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, int bAllowAbort = FALSE,
int bForceStart = FALSE, object oConverseWith = OBJECT_INVALID)
{
if(IsInConversation(oPC))
{
if(DEBUG) DoDebug("StartDynamicConversation(): Aborting--already in conversation");
return;
}
if(DEBUG) DoDebug("StartDynamicConversation(): Starting new dynamic conversation, parameters:\n"
+ "sConversationScript = '" + sConversationScript + "'\n"
+ "oPC = " + DebugObject2Str(oPC) + "\n"
+ "nAllowExit = " + (nAllowExit == DYNCONV_EXIT_NOT_ALLOWED ? "DYNCONV_EXIT_NOT_ALLOWED" :
nAllowExit == DYNCONV_EXIT_FORCE_EXIT ? "DYNCONV_EXIT_FORCE_EXIT" :
nAllowExit == DYNCONV_EXIT_ALLOWED_SHOW_CHOICE ? "DYNCONV_EXIT_ALLOWED_SHOW_CHOICE" :
"ERROR: Unsupported value: " + IntToString(nAllowExit)
) + "\n"
+ "bAllowAbort = " + DebugBool2String(bAllowAbort) + "\n"
+ "bForceStart = " + DebugBool2String(bForceStart) + "\n"
+ "oConverseWith = " + DebugObject2Str(oConverseWith) + "\n"
);
// By default, the PC converses with itself
oConverseWith = oConverseWith == OBJECT_INVALID ? oPC : oConverseWith;
if(DEBUG) if(!GetIsObjectValid(oConverseWith)) DoDebug("StartDynamicConversation(): ERROR: oConverseWith is not valid!");
// Store the exit control variables
SetLocalInt(oPC, "DynConv_AllowExit", nAllowExit);
SetLocalInt(oPC, "DynConv_AllowAbort", bAllowAbort);
// Initiate conversation
if(bForceStart) AssignCommand(oPC, ClearAllActions(TRUE));
SetLocalString(oPC, DYNCONV_SCRIPT, sConversationScript);
AssignCommand(oPC, ActionStartConversation(oConverseWith, "dyncov_base", TRUE, FALSE));
}
void BranchDynamicConversation(string sConversationToEnter, int nStageToReturnTo,
int nAllowExit = DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, int bAllowAbort = FALSE,
object oPC = OBJECT_INVALID)
{
if(DEBUG) DoDebug("BranchDynamicConversation(): Entering another dynamic conversation, parameters:\n"
+ "sConversationToEnter = '" + sConversationToEnter + "'\n"
+ "nStageToReturnTo = " + IntToString(nStageToReturnTo) + "\n"
+ "nAllowExit = " + (nAllowExit == DYNCONV_EXIT_NOT_ALLOWED ? "DYNCONV_EXIT_NOT_ALLOWED" :
nAllowExit == DYNCONV_EXIT_FORCE_EXIT ? "DYNCONV_EXIT_FORCE_EXIT" :
nAllowExit == DYNCONV_EXIT_ALLOWED_SHOW_CHOICE ? "DYNCONV_EXIT_ALLOWED_SHOW_CHOICE" :
"ERROR: Unsupported value: " + IntToString(nAllowExit)
) + "\n"
+ "bAllowAbort = " + DebugBool2String(bAllowAbort) + "\n"
+ "oPC = " + DebugObject2Str(oPC) + "\n "
);
oPC = _DynConvInternal_ResolvePC(oPC);
// Get current stack level
int nStack = GetLocalInt(oPC, "DynConv_Stack") + 1;
// Push the return data onto the stack
SetLocalInt(oPC, "DynConv_Stack_ReturnToStage_" + IntToString(nStack), nStageToReturnTo);
SetLocalInt(oPC, "DynConv_Stack_AllowExit_" + IntToString(nStack),
GetLocalInt(oPC, "DynConv_AllowExit"));
SetLocalInt(oPC, "DynConv_Stack_AllowAbort_" + IntToString(nStack),
GetLocalInt(oPC, "DynConv_AllowAbort"));
SetLocalString(oPC, "DynConv_Stack_Script_" + IntToString(nStack),
GetLocalString(oPC, DYNCONV_SCRIPT));
SetLocalInt(oPC, "DynConv_Stack", nStack);
// Clean the current conversation data
array_delete(oPC, "ChoiceTokens");
array_delete(oPC, "ChoiceValues");
array_delete(oPC, "StagesSetup");
DeleteLocalInt(oPC, "ChoiceOffset");
DeleteLocalInt(oPC, DYNCONV_STAGE);
// Set the new conversation as active
SetLocalString(oPC, DYNCONV_SCRIPT, sConversationToEnter);
SetLocalInt(oPC, "DynConv_AllowExit", nAllowExit);
SetLocalInt(oPC, "DynConv_AllowAbort", bAllowAbort);
}
/// @todo Rename to SetExitable
void AllowExit(int nNewValue = DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, int bChangeExitTokenText = TRUE, object oPC = OBJECT_INVALID)
{
if(DEBUG) DoDebug("AllowExit():\n"
+ "nNewValue = " + (nNewValue == DYNCONV_EXIT_NOT_ALLOWED ? "DYNCONV_EXIT_NOT_ALLOWED" :
nNewValue == DYNCONV_EXIT_FORCE_EXIT ? "DYNCONV_EXIT_FORCE_EXIT" :
nNewValue == DYNCONV_EXIT_ALLOWED_SHOW_CHOICE ? "DYNCONV_EXIT_ALLOWED_SHOW_CHOICE" :
"ERROR: Unsupported value: " + IntToString(nNewValue)
) + "\n"
+ "bChangeExitTokenText = " + DebugBool2String(bChangeExitTokenText) + "\n"
+ "oPC = " + DebugObject2Str(_DynConvInternal_ResolvePC(oPC)) + "\n"
);
SetLocalInt(_DynConvInternal_ResolvePC(oPC), "DynConv_AllowExit", nNewValue);
if(bChangeExitTokenText)
SetCustomToken(DYNCONV_TOKEN_EXIT, GetStringByStrRef(DYNCONV_STRREF_EXIT_CONVO));
}
/// @todo Replace with SetAbortable(int bAllow, object oPC = OBJECT_INVALID)
void AllowAbort(object oPC = OBJECT_INVALID)
{
SetLocalInt(_DynConvInternal_ResolvePC(oPC), "DynConv_AllowAbort", TRUE);
}
int GetIsStageSetUp(int nStage, object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
if(!array_exists(oPC, "StagesSetup"))
return FALSE;
return array_get_int(oPC, "StagesSetup", nStage);
}
void MarkStageSetUp(int nStage, object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
if(!array_exists(oPC, "StagesSetup"))
array_create(oPC, "StagesSetup");
array_set_int(oPC, "StagesSetup", nStage, TRUE);
}
void MarkStageNotSetUp(int nStage, object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
if(!array_exists(oPC, "StagesSetup"))
return;
array_set_int(oPC, "StagesSetup", nStage, FALSE);
}
void ClearCurrentStage(object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
// Clear the choice data
array_delete(oPC, "ChoiceTokens");
array_delete(oPC, "ChoiceValues");
DeleteLocalInt(oPC, "ChoiceOffset");
MarkStageNotSetUp(GetStage(oPC), oPC);
}

371
src/include/inc_ecl.nss Normal file
View File

@@ -0,0 +1,371 @@
/** @file
* ECL handling.
*
* @author Primogenitor
*
* @todo Primo, could you document this one? More details to header and comment function prototypes
*/
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
// returns oTarget's LA value, including their race and template(s) LA
int GetTotalLA(object oTarget);
// returns oTarget's level adjusted by their LA
int GetECL(object oTarget);
void GiveXPReward(object oCreature, int nXP, int bIsPC = TRUE);
void GiveXPRewardToParty(object oKiller, object oDead, int nCR = 0);
//////////////////////////////////////////////////
/* Include section */
//////////////////////////////////////////////////
//#include "inc_utility"
//#include "prc_inc_template"
#include "inc_npc"
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
int GetTotalLA(object oTarget)
{
int nLA;
int nRace = GetRacialType(oTarget);
if(GetPRCSwitch(PRC_XP_USE_SIMPLE_LA))
nLA += StringToInt(Get2DACache("ECL", "LA", nRace));
if(GetPRCSwitch(PRC_XP_INCLUDE_RACIAL_HIT_DIE_IN_LA))
nLA += StringToInt(Get2DACache("ECL", "RaceHD", nRace));
nLA += GetPersistantLocalInt(oTarget, "template_LA");
nLA -= GetPersistantLocalInt(oTarget, "LA_Buyoff");
return nLA;
}
int GetECL(object oTarget)
{
int nLevel;
// we need to use a derivation of the base xp formular to compute the
// pc level based on total XP.
//
// base XP formula (x = pc level, t = total xp):
//
// t = x * (x-1) * 500
//
// need to use some base math..
// transform for pq formula use (remove brackets with x inside and zero right side)
//
// x^2 - x - (t / 500) = 0
//
// use pq formula to solve it [ x^2 + px + q = 0, p = -1, q = -(t/500) ]...
//
// that's our new formula to get the level based on total xp:
// level = 0.5 + sqrt(0.25 + (t/500))
//
if(GetPRCSwitch(PRC_ECL_USES_XP_NOT_HD) && GetIsPC(oTarget))
nLevel = FloatToInt(0.5 + sqrt(0.25 + ( IntToFloat(GetXP(oTarget)) / 500 )));
else
nLevel = GetHitDice(oTarget);
nLevel += GetTotalLA(oTarget);
return nLevel;
}
int CheckDistance(object oDead, object oTest)
{
if(GetPRCSwitch(PRC_XP_MUST_BE_IN_AREA))
{
if(GetArea(oDead) != GetArea(oTest))
return FALSE;
if(GetDistanceBetween(oDead, oTest) > IntToFloat(GetPRCSwitch(PRC_XP_MAX_PHYSICAL_DISTANCE)))
return FALSE;
}
return TRUE;
}
float GetGroupBonusModifier(int nPartySize)
{
return 1 + ((nPartySize-1) * IntToFloat(GetPRCSwitch(PRC_XP_GROUP_BONUS))/100.0);
}
void GiveXPRewardToParty(object oKiller, object oDead, int nCR = 0)
{
//get prc switches
int bSPAM = GetPRCSwitch(PRC_XP_DISABLE_SPAM);
float fPRC_XP_DIVISOR_PC = IntToFloat(GetPRCSwitch(PRC_XP_PC_PARTY_COUNT_x100))/100.0;
float fPRC_XP_DIVISOR_HENCHMAN = IntToFloat(GetPRCSwitch(PRC_XP_HENCHMAN_PARTY_COUNT_x100))/100.0;
float fPRC_XP_DIVISOR_ANIMALCOMPANION = IntToFloat(GetPRCSwitch(PRC_XP_ANIMALCOMPANION_PARTY_COUNT_x100))/100.0;
float fPRC_XP_DIVISOR_FAMILIAR = IntToFloat(GetPRCSwitch(PRC_XP_FAMILIAR_PARTY_COUNT_x100))/100.0;
float fPRC_XP_DIVISOR_DOMINATED = IntToFloat(GetPRCSwitch(PRC_XP_DOMINATED_PARTY_COUNT_x100))/100.0;
float fPRC_XP_DIVISOR_SUMMONED = IntToFloat(GetPRCSwitch(PRC_XP_SUMMONED_PARTY_COUNT_x100))/100.0;
float fPRC_XP_DIVISOR_UNKNOWN = IntToFloat(GetPRCSwitch(PRC_XP_UNKNOWN_PARTY_COUNT_x100))/100.0;
//number of PCs in the party, average party level
int nPartySize, nAvgLevel;
//xp divisor
float fDivisor;
//get some basic group data like average PC level , PC group size, and XP divisor
object oTest = GetFirstFactionMember(oKiller, FALSE);
while(GetIsObjectValid(oTest))
{
if(CheckDistance(oDead, oTest))
{
if(GetIsPC(oTest))
{
nPartySize++;
nAvgLevel += GetECL(oTest);
fDivisor += fPRC_XP_DIVISOR_PC;
}
else
{
switch(GetAssociateTypeNPC(oTest))
{
case ASSOCIATE_TYPE_HENCHMAN: fDivisor += fPRC_XP_DIVISOR_HENCHMAN; break;
case ASSOCIATE_TYPE_ANIMALCOMPANION: fDivisor += fPRC_XP_DIVISOR_ANIMALCOMPANION; break;
case ASSOCIATE_TYPE_FAMILIAR: fDivisor += fPRC_XP_DIVISOR_FAMILIAR; break;
case ASSOCIATE_TYPE_DOMINATED: fDivisor += fPRC_XP_DIVISOR_DOMINATED; break;
case ASSOCIATE_TYPE_SUMMONED: fDivisor += fPRC_XP_DIVISOR_SUMMONED; break;
default: fDivisor += fPRC_XP_DIVISOR_UNKNOWN; break;
}
}
}
else if(!bSPAM && GetIsPC(oTest))
SendMessageToPC(oTest, "You are too far away from the combat to gain any experience.");
oTest = GetNextFactionMember(oKiller, FALSE);
}
//in case something weird is happenening
if(fDivisor == 0.0f)
return;
//calculate average partylevel
nAvgLevel /= nPartySize;
int nBaseXP;
if(!nCR) nCR = GetPRCSwitch(PRC_XP_USE_ECL_NOT_CR) ? GetECL(oDead) : FloatToInt(GetChallengeRating(oDead));
if(nCR < 1) nCR = 1;
if(GetPRCSwitch(PRC_XP_USE_BIOWARE_XPTABLE))
{
if(nCR > 40) nCR = 40;
if(nAvgLevel > 40) nAvgLevel = 40;
nBaseXP = StringToInt(Get2DACache("xptable", "C"+IntToString(nCR), nAvgLevel-1));
}
else
{
if(nCR > 70) nCR = 70;
if(nAvgLevel > 60) nAvgLevel = 60;
nBaseXP = StringToInt(Get2DACache("dmgxp", IntToString(nCR), nAvgLevel-1));
}
//average xp per party member
int nXPAward = FloatToInt(IntToFloat(nBaseXP)/fDivisor);
//now the module slider
nXPAward = FloatToInt(IntToFloat(nXPAward) * IntToFloat(GetPRCSwitch(PRC_XP_SLIDER_x100))/100.0);
//xp = 0, quit
if(!nXPAward)
return;
//group bonus
nXPAward = FloatToInt(IntToFloat(nXPAward) * GetGroupBonusModifier(nPartySize));
int nKillerLevel = GetECL(oKiller);
//calculate xp for each party member individually
oTest = GetFirstFactionMember(oKiller, FALSE);
float fPCAdjust;
int nMbrLevel;
while(GetIsObjectValid(oTest))
{
if(CheckDistance(oDead, oTest))
{
if(GetIsPC(oTest))
{
nMbrLevel = GetECL(oTest);
if(abs(nMbrLevel - nKillerLevel) <= GetPRCSwitch(PRC_XP_MAX_LEVEL_DIFF))
{
//now the individual slider
fPCAdjust = IntToFloat(GetLocalInt(oTest, PRC_XP_SLIDER_x100))/100.0;
if(fPCAdjust == 0.0) fPCAdjust = 1.0;
nXPAward = FloatToInt(IntToFloat(nXPAward) * fPCAdjust);
GiveXPReward(oTest, nXPAward);
}
else if(!bSPAM)
SendMessageToPC(oTest, "You are too high level to gain any experience.");
}
else
GiveXPReward(oTest, nXPAward, FALSE);
}
oTest = GetNextFactionMember(oKiller, FALSE);
}
}
void GiveXPReward(object oCreature, int nXP, int bIsPC = TRUE)
{
//actually give the XP
if(bIsPC)
{
if(GetPRCSwitch(PRC_XP_USE_SETXP))
SetXP(oCreature, GetXP(oCreature)+nXP);
else
GiveXPToCreature(oCreature, nXP);
}
else if(GetPRCSwitch(PRC_XP_GIVE_XP_TO_NPCS))
SetLocalInt(oCreature, "NPC_XP", GetLocalInt(oCreature, "NPC_XP")+nXP);
}
//::///////////////////////////////////////////////
//:: Effective Character Level Experience Script
//:: ecl_exp
//:: Copyright (c) 2004 Theo Brinkman
//:://////////////////////////////////////////////
/*
Call ApplyECLToXP() from applicable heartbeat script(s)
to cause experience to be adjusted according to ECL.
*/
//:://////////////////////////////////////////////
//:: Created By: Theo Brinkman
//:: Last Updated On: 2004-07-28
//:://////////////////////////////////////////////
// CONSTANTS
const string sLEVEL_ADJUSTMENT = "ecl_LevelAdjustment";
const string sXP_AT_LAST_HEARTBEAT = "ecl_LastExperience";
int GetXPForLevel(int nLevel)
{
return nLevel*(nLevel-1)*500;
}
void ApplyECLToXP(object oPC)
{
//abort if simple LA is disabled
if(!GetPRCSwitch(PRC_XP_USE_SIMPLE_LA))
return;
//abort if it's not valid, still loading, or a PC
if(!GetIsObjectValid(oPC) || GetLocalInt(oPC, "PRC_ECL_Delay") || !GetIsPC(oPC))
return;
// Abort if they are registering as a cohort
if(GetLocalInt(oPC, "OriginalXP") || GetPersistantLocalInt(oPC, "RegisteringAsCohort"))
return;
// Let them make it to level 3 in peace
if(GetTag(GetModule()) == "Prelude")
return;
// And start HotU in peace
if(GetTag(GetArea(oPC)) == "q2a_yprooms")
return;
// Abort if they were just relevelled
if(GetLocalInt(oPC, "RelevelXP"))
{
DeleteLocalInt(oPC, "RelevelXP");
return;
}
//this is done first because leadership uses it too
int iCurXP = GetXP(oPC);
//if (DEBUG) DoDebug("ApplyECLToXP - iCurXP "+IntToString(iCurXP));
int iLastXP = GetPersistantLocalInt(oPC, sXP_AT_LAST_HEARTBEAT);
//if (DEBUG) DoDebug("ApplyECLToXP - iLastXP "+IntToString(iLastXP));
if(iCurXP > iLastXP)
{
//if (DEBUG) DoDebug("ApplyECLToXP - gained XP");
int iLvlAdj = GetTotalLA(oPC);
if(iLvlAdj)
{
//if (DEBUG) DoDebug("ApplyECLToXP - have LA");
int iPCLvl = GetHitDice(oPC);
// Get XP Ratio (multiply new XP by this to see what to subtract)
float fRealXPToLevel = IntToFloat(GetXPForLevel(iPCLvl+1));
float fECLXPToLevel = IntToFloat(GetXPForLevel(iPCLvl+1+iLvlAdj));
float fXPRatio = 1.0 - (fRealXPToLevel/fECLXPToLevel);
//At this point the ratio is based on total XP
//This is not correct, it should be based on the XP required to reach
//the next level.
//fRealXPToLevel = IntToFloat(iPCLvl*1000);
//fECLXPToLevel = IntToFloat((iPCLvl+iLvlAdj)*1000);
//fXPRatio = 1.0 - (fRealXPToLevel/fECLXPToLevel);
float fXPDif = IntToFloat(iCurXP - iLastXP);
int iXPDif = FloatToInt(fXPDif * fXPRatio);
int newXP = iCurXP - iXPDif;
SendMessageToPC(oPC, "XP gained since last heartbeat "+IntToString(FloatToInt(fXPDif)));
SendMessageToPC(oPC, "Real XP to level: "+IntToString(FloatToInt(fRealXPToLevel)));
SendMessageToPC(oPC, "ECL XP to level: "+IntToString(FloatToInt(fECLXPToLevel)));
SendMessageToPC(oPC, "Level Adjustment +"+IntToString(iLvlAdj)+". Reducing XP by " + IntToString(iXPDif));
SetXP(oPC, newXP);
}
}
iCurXP = GetXP(oPC);
SetPersistantLocalInt(oPC, sXP_AT_LAST_HEARTBEAT, iCurXP);
}
int GetBuyoffCost(object oPC)
{
int nECL = GetECL(oPC);
int nXP = (nECL-1) * 1000;
return nXP;
}
void BuyoffLevel(object oPC)
{
int nECL = GetECL(oPC);
int nXP = (nECL-1) * 1000;
SetXP(oPC, GetXP(oPC)-nXP);
int nBuyoff = GetPersistantLocalInt(oPC, "LA_Buyoff");
SetPersistantLocalInt(oPC, "LA_Buyoff", nBuyoff+1);
}
int GetCanBuyoffLA(object oPC)
{
int nReturn = FALSE;
int nBuyoff = GetPersistantLocalInt(oPC, "LA_Buyoff");
int nChar = GetHitDice(oPC);
int nLA = StringToInt(Get2DACache("ECL", "LA", GetRacialType(oPC))) + GetPersistantLocalInt(oPC, "template_LA");
int nCheck = nLA - nBuyoff;
if (DEBUG) DoDebug("PRE-LA nBuyoff "+IntToString(nBuyoff)+" nChar "+IntToString(nChar)+" nLA "+IntToString(nLA)+" nCheck "+IntToString(nCheck));
if (0 >= nCheck) // no LA
return FALSE;
if (!nBuyoff) // Not purchased anything yet
{
if (nChar >= StringToInt(Get2DACache("la_buyoff", "1st", nLA)))
nReturn = TRUE;
}
if (nBuyoff == 1) // Purchased first already
{
if (nChar >= StringToInt(Get2DACache("la_buyoff", "2nd", nLA)))
nReturn = TRUE;
}
if (nBuyoff == 2) // Purchased second already
{
if (nChar >= StringToInt(Get2DACache("la_buyoff", "3rd", nLA)))
nReturn = TRUE;
}
if (nBuyoff == 3) // Purchased third already
{
if (nChar >= StringToInt(Get2DACache("la_buyoff", "4th", nLA)))
nReturn = TRUE;
}
if (nBuyoff == 4) // Purchased fourth already
{
if (nChar >= StringToInt(Get2DACache("la_buyoff", "5th", nLA)))
nReturn = TRUE;
}
if (nBuyoff == 5) // Purchased fifth already
{
if (nChar >= StringToInt(Get2DACache("la_buyoff", "6th", nLA)))
nReturn = TRUE;
}
if (DEBUG) DoDebug("nReturn "+IntToString(nReturn)+" nBuyoff "+IntToString(nBuyoff)+" nChar "+IntToString(nChar)+" nLA "+IntToString(nLA));
return nReturn;
}

View File

@@ -0,0 +1,708 @@
/*
for reference
SpellRngPers 0
SpellRngTouch 2.25
SpellRngShrt 8
SpellRngMed 20
SpellRngLng 40
*/
void DoEpicSpellcasterSpawn();
int DoEpicSpells();
int TestConditions(int nSpellID);
object GetSuitableTaget(int nSpellID);
void MakeEpicSpellsKnownAIList();
#include "inc_epicspells"
//#include "inc_epicspelldef"
//#include "inc_epicspellfnc"
#include "inc_utility"
//returns True if it casts something
int DoEpicSpells()
{
//checks for able to cast anything epic
if(!GetIsEpicSpellcaster(OBJECT_SELF))
return FALSE;
if(GetSpellSlots(OBJECT_SELF) < 1)
return FALSE;
// DoDebug("Checking for EpicSpells");
int nSpellID;
int bTest;
int i;
object oTarget;
//sanity test
if(!array_exists(OBJECT_SELF,"AI_KnownEpicSpells"))
{
if(DEBUG) DoDebug("ERROR: DoEpicSpells: AI_KnownEpicSpells array does not exist, creating");
MakeEpicSpellsKnownAIList();
}
//do specific conditon tests first
//non implemented at moment
//test all spells in known spell array setup on spawn
for(i=0; i<array_get_size(OBJECT_SELF,"AI_KnownEpicSpells");i++)
{
nSpellID = array_get_int(OBJECT_SELF,"AI_KnownEpicSpells", i);
oTarget = GetSuitableTaget(nSpellID);
if(GetIsObjectValid(oTarget)
&& TestConditions(nSpellID)
&& GetCanCastSpell(OBJECT_SELF, nSpellID))
{
ClearAllActions();
int nRealSpellID = StringToInt(Get2DACache("feats", "SpellID",
StringToInt(Get2DACache("EpicSpells", "SpellFeatID", nSpellID))));
ActionCastSpellAtObject(nRealSpellID,oTarget, METAMAGIC_NONE, TRUE);
return TRUE;
}
}
//if no epic spell can be cast, go through normal tests
return FALSE;
}
int TestConditions(int nSpellID)
{
int i;
float fDist;
switch(nSpellID)
{
//personal buffs have no extra checks
//gethasspelleffect is automatically done
case SPELL_EPIC_ACHHEEL:
case SPELL_EPIC_EP_WARD:
case SPELL_EPIC_WHIP_SH:
case SPELL_EPIC_CON_RES:
return TRUE;
break;
//not sure what or how to test at the moment
case SPELL_EPIC_ARMY_UN:
case SPELL_EPIC_PATHS_B:
case SPELL_EPIC_GEMCAGE:
return FALSE;
break;
//timestop checks if already cast
case SPELL_EPIC_GR_TIME:
if(GetHasSpellEffect(
StringToInt(Get2DACache("feats", "SpellID",
StringToInt(Get2DACache("EpicSpells", "SpellFeatID", nSpellID)))
))
)
return FALSE;
else
return TRUE;
break;
//summons check if a summon already exists
case SPELL_EPIC_UNHOLYD:
case SPELL_EPIC_SUMABER:
case SPELL_EPIC_TWINF:
case SPELL_EPIC_MUMDUST:
case SPELL_EPIC_DRG_KNI:
if(GetIsObjectValid(GetAssociate(ASSOCIATE_TYPE_SUMMONED))
&& !GetPRCSwitch(PRC_MULTISUMMON))
return FALSE;
else
return TRUE;
break;
//leechfield checks if enemy undead nearby (25m)
case SPELL_EPIC_LEECH_F:
fDist = GetDistanceToObject(GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, 1, CREATURE_TYPE_RACIAL_TYPE,
RACIAL_TYPE_UNDEAD));
if(fDist == -1.0 || fDist > 25.0)
return TRUE;
else
return FALSE;
//Order Restored is alignment sensitive. Only castable by lawful
case SPELL_EPIC_ORDER_R:
if(GetAlignmentLawChaos(OBJECT_SELF) == ALIGNMENT_LAWFUL
&& GetAlignmentLawChaos(GetNearestCreature(
CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY)) == ALIGNMENT_CHAOTIC)
return TRUE;
else
return FALSE;
//Anarchy's Call is alignment sensitive. Only castable by Chaotic
case SPELL_EPIC_ANARCHY:
if(GetAlignmentLawChaos(OBJECT_SELF) == ALIGNMENT_CHAOTIC
&& GetAlignmentLawChaos(GetNearestCreature(
CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY)) == ALIGNMENT_LAWFUL)
return TRUE;
else
return FALSE;
//touchbuffs pass automatically because of target selection checks
case SPELL_EPIC_HERCALL:
case SPELL_EPIC_CHAMP_V:
case SPELL_EPIC_DEADEYE:
case SPELL_EPIC_DULBLAD:
case SPELL_EPIC_EP_M_AR:
case SPELL_EPIC_EP_SP_R:
case SPELL_EPIC_ET_FREE:
case SPELL_EPIC_FLEETNS:
case SPELL_EPIC_GR_SP_RE:
case SPELL_EPIC_HERCEMP:
case SPELL_EPIC_IMPENET:
case SPELL_EPIC_TRANVIT:
case SPELL_EPIC_UNIMPIN:
case SPELL_EPIC_AL_MART:
return TRUE;
break;
//single hostile spells
case SPELL_EPIC_GR_RUIN:
case SPELL_EPIC_RUINN:
case SPELL_EPIC_GODSMIT:
case SPELL_EPIC_NAILSKY:
case SPELL_EPIC_ENSLAVE:
case SPELL_EPIC_MORI:
case SPELL_EPIC_THEWITH:
case SPELL_EPIC_PSION_S:
case SPELL_EPIC_DWEO_TH:
case SPELL_EPIC_SP_WORM:
case SPELL_EPIC_SINGSUN:
return TRUE;
break;
//aoe hostile spells
case SPELL_EPIC_ANBLAST:
case SPELL_EPIC_ANBLIZZ:
case SPELL_EPIC_A_STONE:
case SPELL_EPIC_MASSPEN:
case SPELL_EPIC_HELBALL:
case SPELL_EPIC_MAGMA_B:
case SPELL_EPIC_TOLO_KW:
return TRUE;
break;
//fail spells that tha AI cant work with anyway
case SPELL_EPIC_CELCOUN:
case SPELL_EPIC_CON_REU:
case SPELL_EPIC_DREAMSC:
case SPELL_EPIC_EP_RPLS:
case SPELL_EPIC_FIEND_W:
case SPELL_EPIC_HELSEND:
case SPELL_EPIC_LEG_ART:
case SPELL_EPIC_PIOUS_P:
case SPELL_EPIC_PLANCEL:
case SPELL_EPIC_RISEN_R:
case SPELL_EPIC_UNSEENW:
return FALSE;
//fail spells that dont work at the moment
case SPELL_EPIC_BATTLEB:
case SPELL_EPIC_DTHMARK:
// case SPELL_EPIC_HELSEND:
// case SPELL_EPIC_EP_RPLS:
// case SPELL_EPIC_LEG_ART:
case SPELL_EPIC_LIFE_FT:
case SPELL_EPIC_NIGHTSU:
case SPELL_EPIC_PEERPEN:
// case SPELL_EPIC_RISEN_R:
case SPELL_EPIC_SYMRUST:
return FALSE;
}
return FALSE;
}
object GetSuitableTaget(int nSpellID)
{
object oTarget;
object oTest;
int i;
float fDist;
int nRealSpellID = StringToInt(Get2DACache("feats", "SpellID",
StringToInt(Get2DACache("EpicSpells", "SpellFeatID", nSpellID))));
switch(nSpellID)
{
//personal spells always target self
case SPELL_EPIC_ACHHEEL:
case SPELL_EPIC_ALLHOPE:
case SPELL_EPIC_ANARCHY:
case SPELL_EPIC_ARMY_UN:
case SPELL_EPIC_BATTLEB:
case SPELL_EPIC_CELCOUN:
case SPELL_EPIC_DIREWIN:
case SPELL_EPIC_DREAMSC:
case SPELL_EPIC_EP_WARD:
case SPELL_EPIC_FIEND_W:
case SPELL_EPIC_GR_TIME:
case SPELL_EPIC_HELSEND:
case SPELL_EPIC_LEG_ART:
case SPELL_EPIC_ORDER_R:
case SPELL_EPIC_PATHS_B:
case SPELL_EPIC_PEERPEN:
case SPELL_EPIC_PESTIL:
case SPELL_EPIC_PIOUS_P:
case SPELL_EPIC_RAINFIR:
case SPELL_EPIC_RISEN_R:
case SPELL_EPIC_WHIP_SH:
return OBJECT_SELF;
break;
//summons target nearest enemy, or self if enemies over short range
case SPELL_EPIC_UNHOLYD:
case SPELL_EPIC_SUMABER:
case SPELL_EPIC_TWINF:
case SPELL_EPIC_MUMDUST:
case SPELL_EPIC_DRG_KNI:
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
if(GetDistanceToObject(oTarget) > RADIUS_SIZE_SMALL)//assuming radius size is the same as range
return OBJECT_SELF;
else
return oTarget;
break;
//touchbuffs target self, or nearest ally without the effect
//maximum 5m distance, dont want to wander too far
//will separate those best cast on others laters
case SPELL_EPIC_HERCALL:
case SPELL_EPIC_CHAMP_V:
case SPELL_EPIC_DEADEYE:
case SPELL_EPIC_DULBLAD:
case SPELL_EPIC_EP_M_AR:
case SPELL_EPIC_EP_RPLS:
case SPELL_EPIC_EP_SP_R:
case SPELL_EPIC_ET_FREE:
case SPELL_EPIC_FLEETNS:
case SPELL_EPIC_GR_SP_RE:
case SPELL_EPIC_HERCEMP:
case SPELL_EPIC_IMPENET:
case SPELL_EPIC_TRANVIT:
case SPELL_EPIC_UNIMPIN:
case SPELL_EPIC_UNSEENW:
case SPELL_EPIC_CON_RES:
fDist = 5.0;
if(!GetHasSpellEffect(nRealSpellID))
return OBJECT_SELF;
else
{
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_FRIEND,OBJECT_SELF, i);
while(!GetHasSpellEffect(nRealSpellID, oTarget)
&& GetDistanceToObject(oTarget) < fDist
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_FRIEND,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) >= fDist
|| i >= 10)
return OBJECT_INVALID; //no suitable targets
else
return oTarget;
}
break;
case SPELL_EPIC_AL_MART:
fDist = 5.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_FRIEND,OBJECT_SELF, i);
while(!GetHasSpellEffect(nRealSpellID, oTarget)
&& GetCurrentHitPoints(oTarget) > GetCurrentHitPoints(OBJECT_SELF)
&& GetDistanceToObject(oTarget) < fDist
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_FRIEND,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) >= fDist
|| i >= 10)
return OBJECT_INVALID; //no suitable targets
else
{
oTest = GetLocalObject(OBJECT_SELF, "oAILastMart");
if(GetIsObjectValid(oTest)
&& !GetIsDead(oTest)
&& GetCurrentHitPoints(oTest) > GetMaxHitPoints(oTest)/10)
return OBJECT_INVALID;
return oTarget;
}
break;
//hostile spells
//area effect descriminants
case SPELL_EPIC_ANBLAST:
fDist = 40.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetCurrentHitPoints(oTarget) > 35
&& GetDistanceToObject(oTarget) < fDist
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) >= fDist
|| i >= 10)
return OBJECT_INVALID; //no suitable targets
else
return oTarget;
break;
case SPELL_EPIC_ANBLIZZ:
fDist = 40.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetCurrentHitPoints(oTarget) > 70
&& GetDistanceToObject(oTarget) < fDist
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) >= fDist
|| i >= 10)
return OBJECT_INVALID; //no suitable targets
else
return oTarget;
break;
case SPELL_EPIC_A_STONE:
fDist = 20.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetFortitudeSavingThrow(oTarget)+10 >
GetEpicSpellSaveDC(OBJECT_SELF, oTarget, nSpellID)
&& GetDistanceToObject(oTarget) < fDist
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) >= fDist
|| i >= 10)
return OBJECT_INVALID; //no suitable targets
else
return oTarget;
break;
case SPELL_EPIC_MASSPEN:
fDist = 40.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetFortitudeSavingThrow(oTarget)+10 >
GetEpicSpellSaveDC(OBJECT_SELF, oTarget, nSpellID)
&& GetDistanceToObject(oTarget) < fDist
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) > fDist
|| i >= 10)
return OBJECT_INVALID;
else
return oTarget; //no suitable targets
break;
//singe target
case SPELL_EPIC_ENSLAVE:
fDist = 80.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetWillSavingThrow(oTarget)+10 >
GetEpicSpellSaveDC(OBJECT_SELF, oTarget, nSpellID)
&& GetDistanceToObject(oTarget) < fDist
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) > fDist
|| i >= 10)
return OBJECT_INVALID;
else
return oTarget; //no suitable targets
break;
case SPELL_EPIC_NAILSKY:
fDist = 20.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetWillSavingThrow(oTarget)+10 >
GetEpicSpellSaveDC(OBJECT_SELF, oTarget, nSpellID)
&& GetDistanceToObject(oTarget) < fDist
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) > fDist
|| i >= 10)
return OBJECT_INVALID;
else
return oTarget; //no suitable targets
break;
case SPELL_EPIC_GR_RUIN:
case SPELL_EPIC_RUINN:
case SPELL_EPIC_DTHMARK:
case SPELL_EPIC_GODSMIT:
case SPELL_EPIC_SINGSUN:
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
return oTarget;
break;
//area effect indescriminants
case SPELL_EPIC_HELBALL:
case SPELL_EPIC_MAGMA_B:
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
return oTarget;
break;
case SPELL_EPIC_LEECH_F:
fDist = 40.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetWillSavingThrow(oTarget)+10 >
GetEpicSpellSaveDC(OBJECT_SELF, oTarget, nSpellID)
&& GetDistanceToObject(oTarget) < fDist
&& GetRacialType(oTarget) == RACIAL_TYPE_UNDEAD
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) > fDist
|| i >= 10)
return OBJECT_INVALID;
else
return oTarget; //no suitable targets
break;
//check to not target those immune to insta-death
case SPELL_EPIC_TOLO_KW:
fDist = 40.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetIsImmune(oTarget,IMMUNITY_TYPE_DEATH)
&& GetDistanceToObject(oTarget) < fDist
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) >= fDist
|| i >= 10)
return OBJECT_INVALID; //no suitable targets
else
return oTarget;
break;
case SPELL_EPIC_MORI:
fDist = 20.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetIsImmune(oTarget,IMMUNITY_TYPE_DEATH)
&& GetDistanceToObject(oTarget) < fDist
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) >= fDist
|| i >= 10)
return OBJECT_INVALID; //no suitable targets
else
return oTarget;
break;
//check to not target those immune to ability lowering
case SPELL_EPIC_THEWITH:
fDist = 20.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetIsImmune(oTarget,IMMUNITY_TYPE_ABILITY_DECREASE)
&& GetDistanceToObject(oTarget) < fDist
&& i < 10
&& GetFortitudeSavingThrow(oTarget)+10 >
GetEpicSpellSaveDC(OBJECT_SELF, oTarget, nSpellID))
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) > fDist
|| i >= 10)
return OBJECT_INVALID;
else
return oTarget; //no suitable targets
break;
//aslo willcheck
case SPELL_EPIC_PSION_S:
fDist = 20.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetIsImmune(oTarget,IMMUNITY_TYPE_ABILITY_DECREASE)
&& GetDistanceToObject(oTarget) < fDist
&& i < 10
&& GetWillSavingThrow(oTarget)+10 >
GetEpicSpellSaveDC(OBJECT_SELF, oTarget, nSpellID))
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) > fDist
|| i >= 10)
return OBJECT_INVALID;
else
return oTarget; //no suitable targets
break;
//target spellcasters
//just gets last spellcaster
//or those with classes in spellcasting
case SPELL_EPIC_DWEO_TH:
fDist = 20.0;
oTarget = GetLastSpellCaster();
if(GetDistanceToObject(oTarget) < fDist
&& i < 10
&& GetIsEnemy(oTarget))
return oTarget;
else
{
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetLevelByClass(CLASS_TYPE_CLERIC) ==0
&& GetLevelByClass(CLASS_TYPE_DRUID) ==0
&& GetLevelByClass(CLASS_TYPE_WIZARD) ==0
&& GetLevelByClass(CLASS_TYPE_SORCERER) ==0
&& GetDistanceToObject(oTarget) < fDist
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) > fDist
|| i >= 10)
return OBJECT_INVALID; //no suitable targets
else
return oTarget;
}
break;
//target spellcasters
//just gets last spellcaster
//or those with classes in spellcasting
//also checks will fail will test
case SPELL_EPIC_SP_WORM:
fDist = 8.0;
oTarget = GetLastSpellCaster();
if(GetDistanceToObject(oTarget) < fDist
&& i < 10
&& GetIsEnemy(oTarget)
&& GetWillSavingThrow(oTarget)+10 >
GetEpicSpellSaveDC(OBJECT_SELF) +
GetEpicSpellSaveDC(OBJECT_SELF, oTarget, nSpellID))
return oTarget;
else
{
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetLevelByClass(CLASS_TYPE_CLERIC) ==0
&& GetLevelByClass(CLASS_TYPE_DRUID) ==0
&& GetLevelByClass(CLASS_TYPE_WIZARD) ==0
&& GetLevelByClass(CLASS_TYPE_SORCERER) ==0
&& GetDistanceToObject(oTarget) < fDist
&& i < 10
&& GetWillSavingThrow(oTarget)+10 >
GetEpicSpellSaveDC(OBJECT_SELF, oTarget, nSpellID))
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) > fDist
|| i >= 10)
return OBJECT_INVALID;
else
return oTarget; //no suitable targets
}
break;
}
return OBJECT_INVALID;
}
void DoEpicSpellcasterSpawn()
{
//checks for able to cast anything epic
if(!GetIsEpicSpellcaster(OBJECT_SELF))
return;
int nLevel = GetHitDice(OBJECT_SELF);
//give pseudoXP if not already given
if(!GetXP(OBJECT_SELF))
{
int nXP =(nLevel*(nLevel-1))*500;
nXP = nXP + FloatToInt(IntToFloat(nLevel)*1000.0*((IntToFloat(Random(51))+25.0)/100.0));
SetXP(OBJECT_SELF, nXP);
}
//fill slots
ReplenishSlots(OBJECT_SELF);
//TEMP
//This stuff gives them some Epic Spells for free
if(!GetCastableFeatCount(OBJECT_SELF))
{
int nSlots = GetEpicSpellSlotLimit(OBJECT_SELF)+3;
int i;
for(i=0;i<nSlots;i++)
{
GiveFeat(OBJECT_SELF, Random(71)+429);
}
}
//setup AI list
DelayCommand(1.0, ActionDoCommand(MakeEpicSpellsKnownAIList()));
}
void MakeEpicSpellsKnownAIList()
{
// DoDebug("Building EpicSpells Known list");
int nTemp;
int nHighestDC;
int nHighestDCID;
int j;
int i;
array_create(OBJECT_SELF, "AI_KnownEpicSpells");
//record what spells in an array
// array_create(OBJECT_SELF, "AI_KnownEpicSpells");
string sLabel = Get2DACache("epicspellseeds", "LABEL", i);
while(sLabel != "")
{
if(GetHasFeat(GetFeatForSpell(i)))
{
array_set_int(OBJECT_SELF, "AI_KnownEpicSpells",array_get_size(OBJECT_SELF, "AI_KnownEpicSpells") ,i);
}
i++;
sLabel = Get2DACache("epicspellseeds", "LABEL", i);
}
// DoDebug("Finished recording known spells");
//sort spells into descending DC order
//move starting point down list
for (j=0;j<array_get_size(OBJECT_SELF, "AI_KnownEpicSpells");j++)
{
//for each start get the first spells DC + position
nHighestDC = GetDCForSpell(array_get_int(OBJECT_SELF, "AI_KnownEpicSpells",j));
nHighestDCID = j;
//check each spell lower on the list for higher DC
for (i=j;i<array_get_size(OBJECT_SELF, "AI_KnownEpicSpells");i++)
{
//if so, mark highest to that spell
if(GetDCForSpell(array_get_int(OBJECT_SELF, "AI_KnownEpicSpells",i)) > nHighestDC)
{
nHighestDC = GetDCForSpell(array_get_int(OBJECT_SELF, "AI_KnownEpicSpells",i));
nHighestDCID = i;
}
}
//once you have checked all spells lower, swap the top one with the highest DC
nTemp = array_get_int(OBJECT_SELF, "AI_KnownEpicSpells",j);
array_set_int(OBJECT_SELF, "AI_KnownEpicSpells",j,array_get_int(OBJECT_SELF, "AI_KnownEpicSpells",nHighestDCID));
array_set_int(OBJECT_SELF, "AI_KnownEpicSpells",nHighestDCID, nTemp);
}
// DoDebug("Finished sorting known spells");
}
// Test main
//void main(){}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,273 @@
int GetFeatForSeed(int nSeedID);
int GetIPForSeed(int nSeedID);
int GetDCForSeed(int nSeedID);
int GetClassForSeed(int nSeedID);
int GetCanLearnSeed(object oPC, int nSeedID);
int GetSeedFromAbrev(string sAbrev);
string GetNameForSeed(int nSeedID);
int GetDCForSpell(int nSpellID);
int GetFeatForSpell(int nSpellID);
int GetResearchFeatForSpell(int nSpellID);
int GetIPForSpell(int nSpellID);
int GetResearchIPForSpell(int nSpellID);
int GetCastXPForSpell(int nSpellID);
string GetSchoolForSpell(int nSpellID);
int GetR1ForSpell(int nSpellID);
int GetR2ForSpell(int nSpellID);
int GetR3ForSpell(int nSpellID);
int GetR4ForSpell(int nSpellID);
string GetNameForSpell(int nSpellID);
int GetSpellFromAbrev(string sAbrev);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
#include "inc_utility"
//#include "inc_epicspelldef"
// SEED FUNCTIONS
int GetFeatForSeed(int nSeedID)
{
return StringToInt(Get2DACache("epicspellseeds", "FeatID", nSeedID));
}
int GetIPForSeed(int nSeedID)
{
return StringToInt(Get2DACache("epicspellseeds", "FeatIPID", nSeedID));
}
int GetDCForSeed(int nSeedID)
{
return StringToInt(Get2DACache("epicspellseeds", "DC", nSeedID));
}
int GetClassForSeed(int nSeedID)
{
return StringToInt(Get2DACache("epicspellseeds", "Class", nSeedID));
}
int GetSeedFromAbrev(string sAbrev)
{
sAbrev = GetStringLowerCase(sAbrev);
if(GetStringLeft(sAbrev, 8) == "epic_sd_")
sAbrev = GetStringRight(sAbrev, GetStringLength(sAbrev)-8);
int i = 0;
string sLabel = GetStringLowerCase(Get2DACache("epicspellseeds", "LABEL", i));
while(sLabel != "")
{
if(sAbrev == sLabel)
return i;
i++;
sLabel = GetStringLowerCase(Get2DACache("epicspellseeds", "LABEL", i));
}
return -1;
}
string GetNameForSeed(int nSeedID)
{
int nFeat = GetFeatForSeed(nSeedID);
string sName = GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT", nFeat)));
return sName;
}
/*
Bit-flags set in epicspellseeds.2da in Class column
used to restrict access to epic spell seeds for some classes
ie: 13 means that only clerics, sorcerers and wizards can learn that seed (1 + 4 + 8),
all classes can use == 32767
*/
int _Class2BitFlag(int nClass)
{
switch(nClass)
{
case CLASS_TYPE_CLERIC: return 1;
case CLASS_TYPE_DRUID: return 2;
case CLASS_TYPE_SORCERER: return 4;
case CLASS_TYPE_WIZARD: return 8;
case CLASS_TYPE_HEALER: return 16;
case CLASS_TYPE_BEGUILER: return 32;
case CLASS_TYPE_SUBLIME_CHORD: return 64;
case CLASS_TYPE_DREAD_NECROMANCER: return 128;
case CLASS_TYPE_MYSTIC: return 256;
case CLASS_TYPE_ARCHIVIST: return 512;
case CLASS_TYPE_SHAMAN: return 4096;
case CLASS_TYPE_FAVOURED_SOUL: return 8192;
case CLASS_TYPE_WARMAGE: return 16384;
case CLASS_TYPE_UR_PRIEST: return 1;
case CLASS_TYPE_BLIGHTER: return 2;
}
return -1;
}
int _CheckEpicSpellcastingForClass(object oPC, int nClass)
{
if(GetHitDice(oPC) < 21)
return FALSE;
switch(nClass)
{
case CLASS_TYPE_CLERIC: return GetIsEpicCleric(oPC);
case CLASS_TYPE_DRUID: return GetIsEpicDruid(oPC);
case CLASS_TYPE_SORCERER: return GetIsEpicSorcerer(oPC);
case CLASS_TYPE_WIZARD: return GetIsEpicWizard(oPC);
case CLASS_TYPE_HEALER: return GetIsEpicHealer(oPC);
case CLASS_TYPE_BEGUILER: return GetIsEpicBeguiler(oPC);
case CLASS_TYPE_SUBLIME_CHORD: return GetIsEpicSublimeChord(oPC);
case CLASS_TYPE_DREAD_NECROMANCER: return GetIsEpicDreadNecromancer(oPC);
case CLASS_TYPE_ARCHIVIST: return GetIsEpicArchivist(oPC);
case CLASS_TYPE_SHAMAN: return GetIsEpicShaman(oPC);
case CLASS_TYPE_FAVOURED_SOUL: return GetIsEpicFavSoul(oPC);
case CLASS_TYPE_WARMAGE: return GetIsEpicWarmage(oPC);
case CLASS_TYPE_BLIGHTER: return GetIsEpicBlighter(oPC);
case CLASS_TYPE_UR_PRIEST: return GetIsEpicUrPriest(oPC);
}
return FALSE;
}
int GetCanLearnSeed(object oPC, int nSeedID)
{
int nRestr = GetClassForSeed(nSeedID);
int i, nClass;
for(i = 1; i <= 8; i++)
{
nClass = GetClassByPosition(i, oPC);
if(_CheckEpicSpellcastingForClass(oPC, nClass)//this class has epic spellcasting
&& (nRestr & _Class2BitFlag(nClass)))//and was added to class column in epicspellseeds.2da
{
return TRUE;
}
}
return FALSE;
}
// SPELL FUNCTIONS
int GetDCForSpell(int nSpellID)
{
return StringToInt(Get2DACache("epicspells", "DC", nSpellID));
}
int GetFeatForSpell(int nSpellID)
{
return StringToInt(Get2DACache("epicspells", "SpellFeatID", nSpellID));
}
int GetResearchFeatForSpell(int nSpellID)
{
return StringToInt(Get2DACache("epicspells", "ResFeatID", nSpellID));
}
int GetIPForSpell(int nSpellID)
{
return StringToInt(Get2DACache("epicspells", "SpellFeatIPID", nSpellID));
}
int GetResearchIPForSpell(int nSpellID)
{
return StringToInt(Get2DACache("epicspells", "ResFeatIPID", nSpellID));
}
int GetCastXPForSpell(int nSpellID)
{
return StringToInt(Get2DACache("epicspells", "CastingXP", nSpellID));
}
string GetSchoolForSpell(int nSpellID)
{
return Get2DACache("epicspells", "School", nSpellID);
}
int GetR1ForSpell(int nSpellID)
{
return StringToInt(Get2DACache("epicspells", "Prereq1", nSpellID));
}
int GetR2ForSpell(int nSpellID)
{
return StringToInt(Get2DACache("epicspells", "Prereq2", nSpellID));
}
int GetR3ForSpell(int nSpellID)
{
return StringToInt(Get2DACache("epicspells", "Prereq3", nSpellID));
}
int GetR4ForSpell(int nSpellID)
{
return StringToInt(Get2DACache("epicspells", "Prereq4", nSpellID));
}
int GetS1ForSpell(int nSpellID)
{
string sSeed = Get2DACache("epicspells", "PrereqSeed1", nSpellID);
if(sSeed == "")
return -1;
return StringToInt(sSeed);
}
int GetS2ForSpell(int nSpellID)
{
string sSeed = Get2DACache("epicspells", "PrereqSeed2", nSpellID);
if(sSeed == "")
return -1;
return StringToInt(sSeed);
}
int GetS3ForSpell(int nSpellID)
{
string sSeed = Get2DACache("epicspells", "PrereqSeed3", nSpellID);
if(sSeed == "")
return -1;
return StringToInt(sSeed);
}
int GetS4ForSpell(int nSpellID)
{
string sSeed = Get2DACache("epicspells", "PrereqSeed4", nSpellID);
if(sSeed == "")
return -1;
return StringToInt(sSeed);
}
int GetS5ForSpell(int nSpellID)
{
string sSeed = Get2DACache("epicspells", "PrereqSeed5", nSpellID);
if(sSeed == "")
return -1;
return StringToInt(sSeed);
}
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);
int i = 0;
string sLabel = GetStringLowerCase(Get2DACache("epicspells", "LABEL", i));
while(sLabel != "")
{
if(DEBUG) DoDebug("sLabel to check vs: " + sLabel);
if(sAbrev == sLabel)
{
if(DEBUG) DoDebug("SpellID: " + IntToString(i));
return i;
}
i++;
sLabel = GetStringLowerCase(Get2DACache("epicspells", "LABEL", i));
}
return -1;
}
string GetNameForSpell(int nSpellID)
{
int nFeat = GetFeatForSpell(nSpellID);
string sName = GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT", nFeat)));
return sName;
}
//:: void main (){}

View File

@@ -0,0 +1,857 @@
//:://////////////////////////////////////////////
//:: FileName: "inc_epicspells"
/* Purpose: This is the #include file that contains all constants and
functions needed for the Epic Spellcasting System.
*/
//:://////////////////////////////////////////////
//:: Created By: Boneshank (Don Armstrong)
//:: Last Updated On: March 18, 2004
//:://////////////////////////////////////////////
/*
CONSTANTS FOR OPTIONAL FEATURES
*/
/* moved to prc_inc_switch as runtime switches rather than compiletime
// Use the "XP Costs" option, making casters expend some experience when they
// cast certain spells?
const int XP_COSTS = TRUE;
// Use the "Take 10" variant rule?
// If TRUE, all Spellcraft checks will be automatically equal to the caster's
// Spellcraft skill level, plus 10. The outcome is never a surprise.
// If FALSE, every Spellcraft check is a roll of the dice, being equal to the
// caster's Spellcraft skill level, plus 1d20. Risky, but more fun!
const int TAKE_TEN_RULE = FALSE;
// Use the "Primary Ability Modifier Bonus to Skills" variant rule?
// If TRUE, caster's use their primary ability (WISDOM for clerics and druids,
// CHARISMA for sorcerers) instead of intelligence as a modifier on their
// Spellcraft checks for casting and researching epic spells, as well as
// their total Lore skill level for determining spell slots per day.
const int PRIMARY_ABILITY_MODIFIER_RULE = TRUE;
// Enable BACKLASH damage on spells? TRUE for yes, FALSE for no.
const int BACKLASH_DAMAGE = TRUE;
// Sets the DC adjustment active or inactive for researching spells.
// If TRUE, the player's spell foci feats are used to lower the spell's DC which
// lowers the overall costs of researching the spell. For example, if the
// spell is from the school of Necromancy, and the player has the feat Epic
// Spell Focus: Necromancy, then the DC for the rearch would be lowered by
// six. This would (under default ELHB settings) lower the gold cost by
// 54000 gold and 2160 exp. points, as well as makee the spell accessible
// to the player earlier and with a greater chance of success (due to the
// Spellcraft check).
// Setting this to FALSE will disable this feature.
const int FOCI_ADJUST_DC = TRUE;
// This sets the multiplier for the cost, in gold, to a player for the
// researching of an epic spell. The number is multiplied by the DC of
// the spell to be researched. ELHB default is 9000.
const int GOLD_MULTIPLIER = 9000;
// This sets the number to divide the gold cost by to determine the cost,
// in experience, to research an epic spell. The formula is as follows:
// XP Cost = Spell's DC x GOLD_MULTIPLIER / XP_FRACTION. The default from
// the ELHB is 25.
const int XP_FRACTION = 25;
// Set the number you want to divide the gold cost by for research failures.
// Examples: 2 would result in half the loss of the researcher's gold.
// 3 would result in a third of the gold lost.
// 4 would result in a quarter, etc.
const int FAILURE_FRACTION_GOLD = 2;
// Sets the percentage chance that a seed book is destroyed on a use of it.
// 0 = the book is never randomly destroyed from reading (using) it.
// 100 = the book is always destroyed from reading it.
// NOTE! This function is only ever called when the player actually acquires
// the seed feat. It is a way to control mass "gift-giving" amongst players
const int BOOK_DESTRUCTION = 50;
*/
// Play cutscenes for learning Epic Spell Seeds and researching Epic Spells?
const int PLAY_RESEARCH_CUTS = FALSE;
const int PLAY_SPELLSEED_CUT = FALSE;
// What school of magic does each spell belong to? (for research cutscenes)
// A = Abjuration
// C = Conjuration
// D = Divination
// E = Enchantment
// V = Evocation
// I = Illusion
// N = Necromancy
// T = Transmutation
// Between the quotation marks, enter the name of the cutscene script.
const string SCHOOL_A = "";
const string SCHOOL_C = "";
const string SCHOOL_D = "";
const string SCHOOL_E = "";
const string SCHOOL_V = "";
const string SCHOOL_I = "";
const string SCHOOL_N = "";
const string SCHOOL_T = "";
const string SPELLSEEDS_CUT = "";
/******************************************************************************
FUNCTION DECLARATIONS
******************************************************************************/
// Returns the combined caster level of oPC.
int GetTotalCastingLevel(object oPC);
// returns TRUE if oPC is an Epic level Dread Necromancer
int GetIsEpicDreadNecromancer(object oPC);
// returns TRUE if oPC is an Epic level warmage
int GetIsEpicWarmage(object oPC);
// returns TRUE if oPC is an Epic level healer.
int GetIsEpicHealer(object oPC);
// returns TRUE if oPC is an Epic level favored soul.
int GetIsEpicFavSoul(object oPC);
// Returns TRUE if oPC is an Epic level cleric.
int GetIsEpicCleric(object oPC);
// Returns TRUE if oPC is an Epic level druid.
int GetIsEpicDruid(object oPC);
// Returns TRUE if oPC is an Epic level sorcerer.
int GetIsEpicSorcerer(object oPC);
// Returns TRUE if oPC is an Epic level wizard.
int GetIsEpicWizard(object oPC);
// returns TRUE if oPC is an epic level shaman.
int GetIsEpicShaman(object oPC);
// returns TRUE if oPC is an epic level witch.
int GetIsEpicWitch(object oPC);
// returns TRUE if oPC is an epic level sublime chord.
int GetIsEpicSublimeChord(object oPC);
// returns TRUE if oPC is an epic level archivist.
int GetIsEpicArchivist(object oPC);
// returns TRUE if oPC is an epic level beguiler.
int GetIsEpicBeguiler(object oPC);
// returns TRUE if oPC is an epic level ur-priest.
int GetIsEpicUrPriest(object oPC);
// returns TRUE if oPC is an epic level blighter.
int GetIsEpicBlighter(object oPC);
// returns TRUE if oPC is an Epic spellcaster
int GetIsEpicSpellcaster(object oPC);
// Performs a check on the book to randomly destroy it or not when used.
void DoBookDecay(object oBook, object oPC);
// Returns oPC's spell slot limit, based on Lore and on optional rules.
int GetEpicSpellSlotLimit(object oPC);
// Returns the number of remaining unused spell slots for oPC.
int GetSpellSlots(object oPC);
// Replenishes oPC's Epic spell slots.
void ReplenishSlots(object oPC);
// Decrements oPC's Epic spell slots by one.
void DecrementSpellSlots(object oPC);
// Lets oPC know how many Epic spell slots remain for use.
void MessageSpellSlots(object oPC);
// Returns a Spellcraft check for oPC, based on optional rules.
int GetSpellcraftCheck(object oPC);
// Returns the Spellcraft skill level of oPC, based on optional rules.
int GetSpellcraftSkill(object oPC);
// Returns TRUE if oPC has enough gold to research the spell.
int GetHasEnoughGoldToResearch(object oPC, int nSpellDC);
// Returns TRUE if oPC has enough excess experience to research the spell.
int GetHasEnoughExperienceToResearch(object oPC, int nSpellDC);
// Returns TRUE if oPC has the passed in required feats (Seeds or other Epic spells)... needs BLAH_IP's
int GetHasRequiredFeatsForResearch(object oPC, int nReq1, int nReq2 = 0, int nReq3 = 0, int nReq4 = 0,
int nSeed1 = 0, int nSeed2 = 0, int nSeed3 = 0, int nSeed4 = 0, int nSeed5 = 0);
// Returns success (TRUE) or failure (FALSE) in oPC's researching of a spell.
int GetResearchResult(object oPC, int nSpellDC);
// Takes the gold & experience (depending on success) from oPC for researching.
void TakeResourcesFromPC(object oPC, int nSpellDC, int nSuccess);
// Returns TRUE if oPC can cast the spell.
int GetCanCastSpell(object oPC, int nEpicSpell);
// Returns the adjusted DC of a spell that takes into account oPC's Spell Foci.
int GetDCSchoolFocusAdjustment(object oPC, string sChool);
// Checks to see if oPC has a creature hide. If not, create and equip one.
void EnsurePCHasSkin(object oPC);
// Add nFeatIP to oPC's creature hide.
void GiveFeat(object oPC, int nFeatIP);
// Remove nFeatIP from oPC's creature hide.
void TakeFeat(object oPC, int nFeatIP);
// Checks to see how many castable epic spell feats oPC has ready to use.
// This is used for the control of the radial menu issue.
int GetCastableFeatCount(object oPC);
// When a contingency spell is active, oCaster loses the use of one slot per day
void PenalizeSpellSlotForCaster(object oCaster);
// When a contingecy expires, restore the spell slot for the caster.
void RestoreSpellSlotForCaster(object oCaster);
// Researches an Epic Spell for the caster.
void DoSpellResearch(object oCaster, int nSpellDC, int nSpellIP, string sSchool, object oBook);
// Cycles through equipped items on oTarget, and unequips any having nImmunityType
void UnequipAnyImmunityItems(object oTarget, int nImmType);
// Finds a given spell's DC
int GetEpicSpellSaveDC(object oCaster = OBJECT_SELF, object oTarget = OBJECT_INVALID, int nSpellID = -1);
int GetHasEpicSpellKnown(int nEpicSpell, object oPC);
void SetEpicSpellKnown(int nEpicSpell, object oPC, int nState = TRUE);
int GetHasEpicSeedKnown(int nEpicSeed, object oPC);
void SetEpicSeedKnown(int nEpicSeed, object oPC, int nState = TRUE);
#include "prc_inc_spells"
#include "prc_class_const"
#include "inc_epicspelldef"
#include "inc_epicspellfnc"
#include "inc_utility"
#include "prc_add_spell_dc"
//#include "x2_inc_spellhook"
/******************************************************************************
FUNCTION BODIES
******************************************************************************/
int GetIsEpicArchivist(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_ARCHIVIST, oPC, FALSE) > 16
&& GetAbilityScore(oPC, ABILITY_INTELLIGENCE) > 18;
}
int GetIsEpicBeguiler(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_BEGUILER, oPC, FALSE) > 17
&& GetAbilityScore(oPC, ABILITY_INTELLIGENCE) > 18;
}
int GetIsEpicCleric(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_CLERIC, oPC, FALSE) > 16
&& GetAbilityScore(oPC, ABILITY_WISDOM) > 18;
}
int GetIsEpicDreadNecromancer(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_DREAD_NECROMANCER, oPC, FALSE) > 17
&& GetAbilityScore(oPC, ABILITY_CHARISMA) > 18;
}
int GetIsEpicDruid(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_DRUID, oPC, FALSE) > 16
&& GetAbilityScore(oPC, ABILITY_WISDOM) > 18;
}
int GetIsEpicFavSoul(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_FAVOURED_SOUL, oPC, FALSE) > 17
&& GetAbilityScore(oPC, ABILITY_CHARISMA) > 18;
}
int GetIsEpicHealer(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_HEALER, oPC, FALSE) > 16
&& GetAbilityScore(oPC, ABILITY_WISDOM) > 18;
}
int GetIsEpicUrPriest(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_UR_PRIEST, oPC, FALSE) > 8
&& GetAbilityScore(oPC, ABILITY_WISDOM) > 18;
}
int GetIsEpicShaman(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_SHAMAN, oPC, FALSE) > 16
&& GetAbilityScore(oPC, ABILITY_WISDOM) > 18;
}
int GetIsEpicSorcerer(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_SORCERER, oPC, FALSE) > 17
&& GetAbilityScore(oPC, ABILITY_CHARISMA) > 18;
}
int GetIsEpicSublimeChord(object oPC)
{
return GetLevelByClass(CLASS_TYPE_SUBLIME_CHORD, oPC) > 8
&& GetAbilityScore(oPC, ABILITY_CHARISMA) > 18;
}
int GetIsEpicBlighter(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_BLIGHTER, oPC, FALSE) > 8
&& GetAbilityScore(oPC, ABILITY_WISDOM) > 18;
}
int GetIsEpicWarmage(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_WARMAGE, oPC, FALSE) > 17
&& GetAbilityScore(oPC, ABILITY_CHARISMA) > 18;
}
int GetIsEpicWitch(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_WITCH, oPC, FALSE) > 17
&& GetAbilityScore(oPC, ABILITY_WISDOM) > 18;
}
int GetIsEpicWizard(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_WIZARD, oPC, FALSE) >= 17
&& GetAbilityScore(oPC, ABILITY_INTELLIGENCE) > 18;
}
int GetIsEpicSpellcaster(object oPC)
{
if(GetHitDice(oPC) < 21)
return FALSE;
if(GetIsEpicArchivist(oPC)
|| GetIsEpicBeguiler(oPC)
|| GetIsEpicCleric(oPC)
|| GetIsEpicDreadNecromancer(oPC)
|| GetIsEpicDruid(oPC)
|| GetIsEpicFavSoul(oPC)
|| GetIsEpicHealer(oPC)
|| GetIsEpicUrPriest(oPC)
|| GetIsEpicShaman(oPC)
|| GetIsEpicSorcerer(oPC)
|| GetIsEpicSublimeChord(oPC)
|| GetIsEpicBlighter(oPC)
|| GetIsEpicWarmage(oPC)
|| GetIsEpicWitch(oPC)
|| GetIsEpicWizard(oPC))
return TRUE;
return FALSE;
}
void DoBookDecay(object oBook, object oPC)
{
if (d100() >= GetPRCSwitch(PRC_EPIC_BOOK_DESTRUCTION))
{
DestroyObject(oBook, 2.0);
SendMessageToPC(oPC, MES_BOOK_DESTROYED);
}
}
int GetEpicSpellSlotLimit(object oPC)
{
int nLimit;
int nPen = GetLocalInt(oPC, "nSpellSlotPenalty");
int nBon = GetLocalInt(oPC, "nSpellSlotBonus");
// What's oPC's Lore skill?.
nLimit = GetSkillRank(SKILL_LORE, oPC);
// Variant rule implementation.
if (GetPRCSwitch(PRC_EPIC_PRIMARY_ABILITY_MODIFIER_RULE) == TRUE)
{
if (GetIsEpicSorcerer(oPC) || GetIsEpicFavSoul(oPC) || GetIsEpicWarmage(oPC) || GetIsEpicDreadNecromancer(oPC))
{
nLimit -= GetAbilityModifier(ABILITY_INTELLIGENCE, oPC);
nLimit += GetAbilityModifier(ABILITY_CHARISMA, oPC);
}
else if (GetIsEpicCleric(oPC) || GetIsEpicDruid(oPC) || GetIsEpicHealer(oPC) || GetIsEpicBlighter(oPC) || GetIsEpicShaman(oPC) || GetIsEpicUrPriest(oPC))
{
nLimit -= GetAbilityModifier(ABILITY_INTELLIGENCE, oPC);
nLimit += GetAbilityModifier(ABILITY_WISDOM, oPC);
}
}
// Primary calculation of slots.
nLimit /= 10;
// Modified calculation (for contingencies, bonuses, etc)
nLimit = nLimit + nBon;
nLimit = nLimit - nPen;
return nLimit;
}
int GetSpellSlots(object oPC)
{
int nSlots = GetLocalInt(oPC, "nEpicSpellSlots");
if(!GetIsPC(oPC) && !GetLocalInt(oPC, "EpicSpellSlotsReplenished"))
{
nSlots = GetEpicSpellSlotLimit(oPC);
SetLocalInt(oPC, "EpicSpellSlotsReplenished", TRUE);
SetLocalInt(oPC, "nEpicSpellSlots", nSlots);
}
return nSlots;
}
void ReplenishSlots(object oPC)
{
SetLocalInt(oPC, "nEpicSpellSlots", GetEpicSpellSlotLimit(oPC));
MessageSpellSlots(oPC);
}
void DecrementSpellSlots(object oPC)
{
SetLocalInt(oPC, "nEpicSpellSlots", GetLocalInt(oPC, "nEpicSpellSlots")-1);
MessageSpellSlots(oPC);
}
void MessageSpellSlots(object oPC)
{
SendMessageToPC(oPC, "You now have " +
IntToString(GetSpellSlots(oPC)) +
" Epic spell slots available.");
}
int GetHasEpicSpellKnown(int nEpicSpell, object oPC)
{
int nReturn = GetPersistantLocalInt(oPC, "EpicSpellKnown_"+IntToString(nEpicSpell));
if(!nReturn)
nReturn = GetHasFeat(GetResearchFeatForSpell(nEpicSpell), oPC);
return nReturn;
}
void SetEpicSpellKnown(int nEpicSpell, object oPC, int nState = TRUE)
{
SetPersistantLocalInt(oPC, "EpicSpellKnown_"+IntToString(nEpicSpell), nState);
}
int GetHasEpicSeedKnown(int nEpicSeed, object oPC)
{
int nReturn = GetPersistantLocalInt(oPC, "EpicSeedKnown_"+IntToString(nEpicSeed));
if(!nReturn)
nReturn = GetHasFeat(GetFeatForSeed(nEpicSeed), oPC);
return nReturn;
}
void SetEpicSeedKnown(int nEpicSeed, object oPC, int nState = TRUE)
{
SetPersistantLocalInt(oPC, "EpicSeedKnown_"+IntToString(nEpicSeed), nState);
}
int GetSpellcraftCheck(object oPC)
{
// Get oPC's skill rank.
int nCheck = GetSpellcraftSkill(oPC);
// Do the check, dependant on "Take 10" variant rule.
if (GetPRCSwitch(PRC_EPIC_TAKE_TEN_RULE) == TRUE)
nCheck += 10;
else
nCheck += d20();
return nCheck;
}
int GetSpellcraftSkill(object oPC)
{
// Determine initial Spellcraft skill.
int nSkill = GetSkillRank(SKILL_SPELLCRAFT, oPC);
// Variant rule implementation.
if (GetPRCSwitch(PRC_EPIC_PRIMARY_ABILITY_MODIFIER_RULE) == TRUE)
{
if (GetIsEpicSorcerer(oPC) || GetIsEpicFavSoul(oPC) || GetIsEpicWarmage(oPC) || GetIsEpicDreadNecromancer(oPC))
{
nSkill -= GetAbilityModifier(ABILITY_INTELLIGENCE, oPC);
nSkill += GetAbilityModifier(ABILITY_CHARISMA, oPC);
}
else if (GetIsEpicCleric(oPC) || GetIsEpicDruid(oPC) || GetIsEpicHealer(oPC) || GetIsEpicBlighter(oPC) || GetIsEpicShaman(oPC) || GetIsEpicUrPriest(oPC))
{
nSkill -= GetAbilityModifier(ABILITY_INTELLIGENCE, oPC);
nSkill += GetAbilityModifier(ABILITY_WISDOM, oPC);
}
}
return nSkill;
}
int GetHasEnoughGoldToResearch(object oPC, int nSpellDC)
{
int nCost = nSpellDC * GetPRCSwitch(PRC_EPIC_GOLD_MULTIPLIER);
if (GetHasGPToSpend(oPC, nCost))
return TRUE;
return FALSE;
}
int GetHasEnoughExperienceToResearch(object oPC, int nSpellDC)
{
int nXPCost = nSpellDC * GetPRCSwitch(PRC_EPIC_GOLD_MULTIPLIER) / GetPRCSwitch(PRC_EPIC_XP_FRACTION);
if (GetHasXPToSpend(oPC, nXPCost))
return TRUE;
return FALSE;
}
int GetHasRequiredFeatsForResearch(object oPC, int nReq1, int nReq2 = 0, int nReq3 = 0, int nReq4 = 0,
int nSeed1 = 0, int nSeed2 = 0, int nSeed3 = 0, int nSeed4 = 0, int nSeed5 = 0)
{
if(DEBUG)
{
DoDebug("Requirement #1: " + IntToString(nReq1));
DoDebug("Requirement #2: " + IntToString(nReq2));
DoDebug("Requirement #3: " + IntToString(nReq3));
DoDebug("Requirement #4: " + IntToString(nReq4));
DoDebug("Seed #1: " + IntToString(nSeed1));
DoDebug("Seed #2: " + IntToString(nSeed2));
DoDebug("Seed #3: " + IntToString(nSeed3));
DoDebug("Seed #4: " + IntToString(nSeed4));
DoDebug("Seed #4: " + IntToString(nSeed5));
}
if ((GetHasFeat(nReq1, oPC) || nReq1 == 0)
&& (GetHasFeat(nReq2, oPC) || nReq2 == 0)
&& (GetHasFeat(nReq3, oPC) || nReq3 == 0)
&& (GetHasFeat(nReq4, oPC) || nReq4 == 0)
&& (GetHasEpicSeedKnown(nSeed1, oPC) || nSeed1 == -1)
&& (GetHasEpicSeedKnown(nSeed2, oPC) || nSeed2 == -1)
&& (GetHasEpicSeedKnown(nSeed3, oPC) || nSeed3 == -1)
&& (GetHasEpicSeedKnown(nSeed4, oPC) || nSeed4 == -1)
&& (GetHasEpicSeedKnown(nSeed5, oPC) || nSeed5 == -1))
{
return TRUE;
}
return FALSE;
}
int GetResearchResult(object oPC, int nSpellDC)
{
int nCheck = GetSpellcraftCheck(oPC);
SendMessageToPC(oPC, "Your spellcraft check was a " +
IntToString(nCheck) + ", against a researching DC of " +
IntToString(nSpellDC));
if (nCheck >= nSpellDC)
{
SendMessageToPC(oPC, MES_SPELLCRAFT_CHECK_PASS);
return TRUE;
}
else
{
SendMessageToPC(oPC, MES_SPELLCRAFT_CHECK_FAIL);
return FALSE;
}
}
void TakeResourcesFromPC(object oPC, int nSpellDC, int nSuccess)
{
if (nSuccess != TRUE)
{
int nGold = nSpellDC *
GetPRCSwitch(PRC_EPIC_GOLD_MULTIPLIER) / GetPRCSwitch(PRC_EPIC_FAILURE_FRACTION_GOLD);
SpendGP(oPC, nGold);
}
else
{
int nGold = nSpellDC * GetPRCSwitch(PRC_EPIC_GOLD_MULTIPLIER);
SpendGP(oPC, nGold);
int nXP = nSpellDC * GetPRCSwitch(PRC_EPIC_GOLD_MULTIPLIER) / GetPRCSwitch(PRC_EPIC_XP_FRACTION);
SpendXP(oPC, nXP);
}
}
int GetCanCastSpell(object oPC, int nEpicSpell)
{
int nSpellDC = GetDCForSpell(nEpicSpell);
string sChool = GetSchoolForSpell(nEpicSpell);
int nSpellXP =GetCastXPForSpell(nEpicSpell);
// Adjust the DC to account for Spell Foci feats.
nSpellDC -= GetDCSchoolFocusAdjustment(oPC, sChool);
int nCheck = GetSpellcraftCheck(oPC);
// Does oPC already know it
if (!GetHasEpicSpellKnown(nEpicSpell, oPC))
{
return FALSE;
}
if (!(GetSpellSlots(oPC) >= 1))
{ // No? Cancel spell, then.
SendMessageToPC(oPC, MES_CANNOT_CAST_SLOTS);
return FALSE;
}
if (GetPRCSwitch(PRC_EPIC_XP_COSTS) == TRUE)
{
// Does oPC have the needed XP available to cast the spell?
if (!GetHasXPToSpend(oPC, nSpellXP))
{ // No? Cancel spell, then.
SendMessageToPC(oPC, MES_CANNOT_CAST_XP);
return FALSE;
}
}
// Does oPC pass the Spellcraft check for the spell's casting?
if (!(nCheck >= nSpellDC))
{ // No?
SendMessageToPC(oPC, MES_SPELLCRAFT_CHECK_FAIL);
SendMessageToPC(oPC,
IntToString(nCheck) + " against a DC of " + IntToString(nSpellDC));
// Failing a Spellcraft check still costs a spell slot, so decrement...
DecrementSpellSlots(oPC);
return FALSE;
}
// If the answer is YES to all three, cast the spell!
SendMessageToPC(oPC, MES_SPELLCRAFT_CHECK_PASS);
SendMessageToPC(oPC,
IntToString(nCheck) + " against a DC of " + IntToString(nSpellDC));
SpendXP(oPC, nSpellXP); // Only spends the XP on a successful casting.
DecrementSpellSlots(oPC);
return TRUE;
}
void GiveFeat(object oPC, int nFeatIP)
{
object oSkin = GetPCSkin(oPC);
if (oSkin != OBJECT_INVALID)
IPSafeAddItemProperty(oSkin, PRCItemPropertyBonusFeat(nFeatIP), 0.0f, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
}
void TakeFeat(object oPC, int nFeatIP)
{
object oSkin = GetPCSkin(oPC);
itemproperty ipX = GetFirstItemProperty(oSkin);
while (GetIsItemPropertyValid(ipX))
{
if (GetItemPropertyType(ipX) == ITEM_PROPERTY_BONUS_FEAT)
{
if(GetItemPropertySubType(ipX) == nFeatIP)
{
RemoveItemProperty(oSkin, ipX);
break;
}
}
ipX = GetNextItemProperty(oSkin);
}
}
int GetCastableFeatCount(object oPC)
{
int nX = 0;
int i = 0;
int nFeat = GetFeatForSpell(i);
while(nFeat != 0)
{
//test for the castable feat
if(GetHasFeat(nFeat, oPC))
nX += 1;
i++;
nFeat = GetFeatForSpell(i);
}
return nX;
}
void PenalizeSpellSlotForCaster(object oCaster)
{
int nMod = GetLocalInt(oCaster, "nSpellSlotPenalty");
SetLocalInt(oCaster, "nSpellSlotPenalty", nMod + 1);
SendMessageToPC(oCaster, MES_CONTINGENCIES_YES1);
SendMessageToPC(oCaster, MES_CONTINGENCIES_YES2);
SendMessageToPC(oCaster, "Your epic spell slot limit is now " +
IntToString(GetEpicSpellSlotLimit(oCaster)) + ".");
}
void RestoreSpellSlotForCaster(object oCaster)
{
int nMod = GetLocalInt(oCaster, "nSpellSlotPenalty");
if (nMod > 0) SetLocalInt(oCaster, "nSpellSlotPenalty", nMod - 1);
SendMessageToPC(oCaster, "Your epic spell slot limit is now " +
IntToString(GetEpicSpellSlotLimit(oCaster)) + ".");
}
void DoSpellResearch(object oCaster, int nSpellDC, int nSpellIP, string sSchool, object oBook)
{
float fDelay = 2.0;
string sCutScript;
int nResult = GetResearchResult(oCaster, nSpellDC);
if (PLAY_RESEARCH_CUTS == TRUE)
{
if (sSchool == "A") sCutScript = SCHOOL_A;
if (sSchool == "C") sCutScript = SCHOOL_C;
if (sSchool == "D") sCutScript = SCHOOL_D;
if (sSchool == "E") sCutScript = SCHOOL_E;
if (sSchool == "I") sCutScript = SCHOOL_I;
if (sSchool == "N") sCutScript = SCHOOL_N;
if (sSchool == "T") sCutScript = SCHOOL_T;
if (sSchool == "V") sCutScript = SCHOOL_V;
ExecuteScript(sCutScript, oCaster);
fDelay = 10.0;
}
DelayCommand(fDelay, TakeResourcesFromPC(oCaster, nSpellDC, nResult));
if (nResult == TRUE)
{
DelayCommand(fDelay, SendMessageToPC(oCaster, GetName(oCaster) + " " + MES_RESEARCH_SUCCESS));
//DelayCommand(fDelay, GiveFeat(oCaster, nSpellIP));
DelayCommand(fDelay, SetEpicSpellKnown(nSpellIP, oCaster, TRUE));
DelayCommand(fDelay, DestroyObject(oBook));
//research time
//1 day per 50,000GP +1
int nDays = (nSpellDC * GetPRCSwitch(PRC_EPIC_GOLD_MULTIPLIER))/50000;
nDays++;
float fSeconds = HoursToSeconds(24*nDays);
AdvanceTimeForPlayer(oCaster, fSeconds);
}
else
{
DelayCommand(fDelay, SendMessageToPC(oCaster, GetName(oCaster) + " " + MES_RESEARCH_FAILURE));
}
}
void UnequipAnyImmunityItems(object oTarget, int nImmType)
{
object oItem;
int nX;
for (nX = 0; nX <= 13; nX++) // Does not include creature items in search.
{
oItem = GetItemInSlot(nX, oTarget);
// Debug.
//SendMessageToPC(oTarget, "Checking slot " + IntToString(nX));
if (oItem != OBJECT_INVALID)
{
// Debug.
//SendMessageToPC(oTarget, "Valid item.");
itemproperty ipX = GetFirstItemProperty(oItem);
while (GetIsItemPropertyValid(ipX))
{
// Debug.
//SendMessageToPC(oTarget, "Valid ip");
if (GetItemPropertySubType(ipX) == nImmType)
{
// Debug.
//SendMessageToPC(oTarget, "ip match!!");
SendMessageToPC(oTarget, GetName(oItem) +
" cannot be equipped at this time.");
AssignCommand(oTarget, ClearAllActions());
AssignCommand(oTarget, ActionUnequipItem(oItem));
break;
}
else
ipX = GetNextItemProperty(oItem);
}
}
}
}
int GetTotalCastingLevel(object oCaster)
{
int iBestArcane = GetLevelByTypeArcaneFeats();
int iBestDivine = GetLevelByTypeDivineFeats();
int iBest = (iBestDivine > iBestArcane) ? iBestDivine : iBestArcane;
//SendMessageToPC(oCaster, "Epic casting at level " + IntToString(iBest));
return iBest;
}
int GetDCSchoolFocusAdjustment(object oPC, string sChool)
{
int nNewDC = 0;
if (sChool == "A") // Abjuration spell?
{
if (GetHasFeat(FEAT_EPIC_SPELL_FOCUS_ABJURATION, oPC)) nNewDC = 6;
else if (GetHasFeat(FEAT_GREATER_SPELL_FOCUS_ABJURATION, oPC)) nNewDC = 4;
else if (GetHasFeat(FEAT_SPELL_FOCUS_ABJURATION, oPC)) nNewDC = 2;
}
if (sChool == "C") // Conjuration spell?
{
if (GetHasFeat(FEAT_EPIC_SPELL_FOCUS_CONJURATION, oPC)) nNewDC = 6;
else if (GetHasFeat(FEAT_GREATER_SPELL_FOCUS_CONJURATION, oPC)) nNewDC = 4;
else if (GetHasFeat(FEAT_SPELL_FOCUS_CONJURATION, oPC)) nNewDC = 2;
}
if (sChool == "D") // Divination spell?
{
if (GetHasFeat(FEAT_EPIC_SPELL_FOCUS_DIVINATION, oPC)) nNewDC = 6;
else if (GetHasFeat(FEAT_GREATER_SPELL_FOCUS_DIVINIATION, oPC)) nNewDC = 4;
else if (GetHasFeat(FEAT_SPELL_FOCUS_DIVINATION, oPC)) nNewDC = 2;
}
if (sChool == "E") // Enchantment spell?
{
if (GetHasFeat(FEAT_EPIC_SPELL_FOCUS_ENCHANTMENT, oPC)) nNewDC = 6;
else if (GetHasFeat(FEAT_GREATER_SPELL_FOCUS_ENCHANTMENT, oPC)) nNewDC = 4;
else if (GetHasFeat(FEAT_SPELL_FOCUS_ENCHANTMENT, oPC)) nNewDC = 2;
}
if (sChool == "V") // Evocation spell?
{
if (GetHasFeat(FEAT_EPIC_SPELL_FOCUS_EVOCATION, oPC)) nNewDC = 6;
else if (GetHasFeat(FEAT_GREATER_SPELL_FOCUS_EVOCATION, oPC)) nNewDC = 4;
else if (GetHasFeat(FEAT_SPELL_FOCUS_EVOCATION, oPC)) nNewDC = 2;
}
if (sChool == "I") // Illusion spell?
{
if (GetHasFeat(FEAT_EPIC_SPELL_FOCUS_ILLUSION, oPC)) nNewDC = 6;
else if (GetHasFeat(FEAT_GREATER_SPELL_FOCUS_ILLUSION, oPC)) nNewDC = 4;
else if (GetHasFeat(FEAT_SPELL_FOCUS_ILLUSION, oPC)) nNewDC = 2;
}
if (sChool == "N") // Necromancy spell?
{
if (GetHasFeat(FEAT_EPIC_SPELL_FOCUS_NECROMANCY, oPC)) nNewDC = 6;
else if (GetHasFeat(FEAT_GREATER_SPELL_FOCUS_NECROMANCY, oPC)) nNewDC = 4;
else if (GetHasFeat(FEAT_SPELL_FOCUS_NECROMANCY, oPC)) nNewDC = 2;
}
if (sChool == "T") // Transmutation spell?
{
if (GetHasFeat(FEAT_EPIC_SPELL_FOCUS_TRANSMUTATION, oPC)) nNewDC = 6;
else if (GetHasFeat(FEAT_GREATER_SPELL_FOCUS_TRANSMUTATION, oPC)) nNewDC = 4;
else if (GetHasFeat(FEAT_SPELL_FOCUS_TRANSMUTATION, oPC)) nNewDC = 2;
}
return nNewDC;
}
int GetEpicSpellSaveDC(object oCaster = OBJECT_SELF, object oTarget = OBJECT_INVALID, int nSpellID = -1)
{
int iDiv = GetPrCAdjustedCasterLevelByType(TYPE_DIVINE, oCaster); // ie. wisdom determines DC
int iWiz = GetPrCAdjustedCasterLevel(CLASS_TYPE_WIZARD, oCaster); // int determines DC
int iWMa = GetPrCAdjustedCasterLevel(CLASS_TYPE_WARMAGE, oCaster); // cha determines DC
int iDNc = GetPrCAdjustedCasterLevel(CLASS_TYPE_DREAD_NECROMANCER, oCaster); // cha determines DC
int iSor = GetPrCAdjustedCasterLevel(CLASS_TYPE_SORCERER, oCaster); // cha determines DC
int iWit = GetPrCAdjustedCasterLevel(CLASS_TYPE_WITCH, oCaster); // wis determines DC
int iArc = GetPrCAdjustedCasterLevel(CLASS_TYPE_ARCHIVIST, oCaster); // int determines DC
int iBeg = GetPrCAdjustedCasterLevel(CLASS_TYPE_BEGUILER, oCaster); // int determines DC
int iTpl = GetPrCAdjustedCasterLevel(CLASS_TYPE_TEMPLAR, oCaster); // cha determines DC
int iBest = 0;
int iAbility;
if(nSpellID == -1)
nSpellID = PRCGetSpellId();
if (iArc > iBest) { iAbility = ABILITY_INTELLIGENCE; iBest = iWit; }
if (iTpl > iBest) { iAbility = ABILITY_CHARISMA; iBest = iTpl; }
if (iWiz > iBest) { iAbility = ABILITY_INTELLIGENCE; iBest = iWiz; }
if (iWMa > iBest) { iAbility = ABILITY_CHARISMA; iBest = iWMa; }
if (iDNc > iBest) { iAbility = ABILITY_CHARISMA; iBest = iDNc; }
if (iSor > iBest) { iAbility = ABILITY_CHARISMA; iBest = iSor; }
if (iWit > iBest) { iAbility = ABILITY_WISDOM; iBest = iWit; }
if (iBeg > iBest) { iAbility = ABILITY_INTELLIGENCE; iBest = iBeg; }
if (iDiv > iBest) { iAbility = ABILITY_WISDOM; iBest = iDiv; }
int nDC;
if (iBest) nDC = 20 + GetAbilityModifier(iAbility, oCaster);
else nDC = 20; // DC = 20 if the epic spell is cast some other way.
nDC += GetDCSchoolFocusAdjustment(oCaster, Get2DACache("spells", "school", nSpellID));
nDC += GetChangesToSaveDC(oTarget, oCaster, nSpellID, GetSpellSchool(nSpellID));
return nDC;
}
// Test main
//void main(){}

View File

@@ -0,0 +1,883 @@
//::///////////////////////////////////////////////
//:: Generic eventhook include
//:: inc_eventhook
//:://////////////////////////////////////////////
/** @file
A system for scheduling scripts to be run on
an arbitrary event during runtime (instead of
being hardcoded in compilation).
Scheduling a script happens by calling
AddEventScript with the object the script is
to be run on (and on which the data about the
script is stored on), an EVENT_* constant
determining the event that the script is to be
run on and the name of the script to be run.
In addition to these, there is a parameter to
control whether the script will be just during
the next invocation of the event, or during all
invocations from now on until the script is
explicitly descheduled.
This feature only automatically works when using
ExecuteAllScriptsHookedToEvent(). That is, merely
viewing the eventscript list does not trigger the
effect.
See the comments in function prototype section for
more details.
Added event constants to be used with items. For
example, now you can define a script to be fired
for The Sword of Foo every time someone equips it.
NOTE: Persistence of scripts hooked to non-creatures
over module boundaries is not guaranteed. ie, if
the player takes abovementioned Sword of Foo to
another module, it most likely will lose the locals
defining the script hooked into it.
@author Ordedan
@date Created - 28.02.2005
@date Modified - 26.05.2005
@date Modified - 04.09.2005
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Constant defintions */
//////////////////////////////////////////////////
// Module events
/// Module event - On Acquire Item
const int EVENT_ONACQUIREITEM = 1;
/// Module event - On Activate Item
const int EVENT_ONACTIVATEITEM = 2;
/// Module event - On Client Enter
const int EVENT_ONCLIENTENTER = 3;
/// Module event - On Client Leave
const int EVENT_ONCLIENTLEAVE = 4;
/// Module event - On Cutscene Abort
const int EVENT_ONCUTSCENEABORT = 5;
/// Module event - On Heartbeat
const int EVENT_ONHEARTBEAT = 6;
/// Module event - On Player Death
const int EVENT_ONPLAYERDEATH = 9;
/// Module event - On Player Dying
const int EVENT_ONPLAYERDYING = 10;
/// Module event - On Player Equip Item
const int EVENT_ONPLAYEREQUIPITEM = 11;
/// Module event - On Player Level Up
const int EVENT_ONPLAYERLEVELUP = 12;
/// Module event - On Player Rest Cancelled
const int EVENT_ONPLAYERREST_CANCELLED = 13;
/// Module event - On Player Rest Started
const int EVENT_ONPLAYERREST_STARTED = 14;
/// Module event - On Player Rest Finished
const int EVENT_ONPLAYERREST_FINISHED = 15;
/// Module event - On Player Unequip Item
const int EVENT_ONPLAYERUNEQUIPITEM = 16;
/// Module event - On Player Respawn
const int EVENT_ONPLAYERRESPAWN = 17;
/// Module event - On Unacquire Item
const int EVENT_ONUNAQUIREITEM = 18;
/// Module event - On Player Chat
const int EVENT_ONPLAYERCHAT = 49;
/**
* Module Event - On Userdefined
* This has special handling
* @see prc_onuserdef.nss
*/
const int EVENT_ONUSERDEFINED = 19;
// Other events
/// Virtual event - On Hit
/// Requires OnHitCastSpell: Unique on the weapon used
const int EVENT_ONHIT = 20;
/// Virtual event - On Spell Cast
//const int EVENT_ONSPELLCAST = 21;
/// Virtual event - On Power Manifest
//const int EVENT_ONPOWERMANIFEST = 22;
/// Virtual event - On Player Level Down
/// WARNING: Event detection is slightly inaccurate
const int EVENT_ONPLAYERLEVELDOWN = 35;
/// Virtual event - On Physically Attacked
/// WARNING: Event detection is highly inaccurate
const int EVENT_VIRTUAL_ONPHYSICALATTACKED = 36;
/// Virtual event - On Blocked
/// WARNING: Event detection is inaccurate
const int EVENT_VIRTUAL_ONBLOCKED = 37;
/// Virtual event - On Combat Round End
/// WARNING: Event detection is inaccurate
const int EVENT_VIRTUAL_ONCOMBATROUNDEND = 38;
/// Virtual event - On Conversation
/// Does not work on PCs!
const int EVENT_VIRTUAL_ONCONVERSATION = 39;
/// Virtual event - On Damaged
/// WARNING: Event detection is slightly inaccurate
const int EVENT_VIRTUAL_ONDAMAGED = 40;
/// Virtual event - On Disturbed
/// WARNING: Event detection may be inaccurate
const int EVENT_VIRTUAL_ONDISTURBED = 41;
/// Virtual event - On Perception
/// WARNING: Event detection may be inaccurate
const int EVENT_VIRTUAL_ONPERCEPTION = 42;
/// Virtual event - On Spawned
const int EVENT_VIRTUAL_ONSPAWNED = 43;
/// Virtual event - On Spell Cast At
/// WARNING: Event detection may be inaccurate
const int EVENT_VIRTUAL_ONSPELLCASTAT = 44;
/// Virtual event - On Death
/// WARNING: Event detection may be inaccurate
const int EVENT_VIRTUAL_ONDEATH = 45;
/// Virtual event - On Rested
/// WARNING: Event detection may be inaccurate
const int EVENT_VIRTUAL_ONRESTED = 46;
/// Virtual event - On User Defined
/// WARNING: Event detection may be inaccurate
const int EVENT_VIRTUAL_ONUSERDEFINED = 47;
/// Virtual event - On Heartbeat
/// WARNING: Event detection may be inaccurate
const int EVENT_VIRTUAL_ONHEARTBEAT = 48;
/// Virtual event - On Player Chat
/// WARNING: Event detection may be inaccurate
const int EVENT_VIRTUAL_ONPLAYERCHAT = 50;
// NPC events
/// NPC event - On Blocked
const int EVENT_NPC_ONBLOCKED = 23;
/// NPC event - On Combat Round End
const int EVENT_NPC_ONCOMBATROUNDEND = 24;
/// NPC event - On Conversation
const int EVENT_NPC_ONCONVERSATION = 25;
/// NPC event - On Damaged
const int EVENT_NPC_ONDAMAGED = 26;
/// NPC event - On Death
const int EVENT_NPC_ONDEATH = 27;
/// NPC event - On Disturbed
const int EVENT_NPC_ONDISTURBED = 28;
/// NPC event - On Heartbeat
const int EVENT_NPC_ONHEARTBEAT = 29;
/// NPC event - On Perception
const int EVENT_NPC_ONPERCEPTION = 30;
/// NPC event - On Physically Attacked
const int EVENT_NPC_ONPHYSICALATTACKED = 31;
/// NPC event - On Rested
const int EVENT_NPC_ONRESTED = 32;
/// NPC event - On Spell Cast At
const int EVENT_NPC_ONSPELLCASTAT = 34;
/* Item events */
/// Virtual item event - On Acquire Item
const int EVENT_ITEM_ONACQUIREITEM = 1000;
/// Virtual item event - On Activate Item
const int EVENT_ITEM_ONACTIVATEITEM = 1001;
/// Virtual item event - On Player Equip Item
const int EVENT_ITEM_ONPLAYEREQUIPITEM = 1002;
/// Virtual item event - On Player Unequip Item
const int EVENT_ITEM_ONPLAYERUNEQUIPITEM = 1003;
/// Virtual item event - On Acquire Item
const int EVENT_ITEM_ONUNAQUIREITEM = 1004;
/// Virtual item event - On Hit
/// Requires OnHitCastSpell: Unique on the item used to hit
const int EVENT_ITEM_ONHIT = 1005;
/* Placeable events */
//Note these will only fire for placeables using the
//prc_plc_* scriptset
// Placeable event - OnClick (1.67 or later only)
const int EVENT_PLACEABLE_ONCLICK = 3001;
// Placeable event - OnClose
const int EVENT_PLACEABLE_ONCLOSE = 3002;
// Placeable event - OnDamaged
const int EVENT_PLACEABLE_ONDAMAGED = 3003;
// Placeable event - OnDeath
const int EVENT_PLACEABLE_ONDEATH = 3004;
// Placeable event - OnHeartbeat
const int EVENT_PLACEABLE_ONHEARTBEAT = 3005;
// Placeable event - OnDisturbed
const int EVENT_PLACEABLE_ONDISTURBED = 3006;
// Placeable event - OnLock
const int EVENT_PLACEABLE_ONLOCK = 3007;
// Placeable event - OnPhysicalAttacked
const int EVENT_PLACEABLE_ONATTACKED = 3008;
// Placeable event - OnOpen
const int EVENT_PLACEABLE_ONOPEN = 3009;
// Placeable event - OnSpellCastAt
const int EVENT_PLACEABLE_ONSPELL = 3010;
// Placeable event - OnUnLock
const int EVENT_PLACEABLE_ONUNLOCK = 3011;
// Placeable event - OnUsed
const int EVENT_PLACEABLE_ONUSED = 3012;
// Placeable event - OnUserDefined
const int EVENT_PLACEABLE_ONUSERDEFINED = 3013;
/* Door events */
//Note these will only fire for doors using the
//Note that placeable doors use the placeable set
//prc_door_* scriptset
// Door event - OnAreaTransitionClick
const int EVENT_DOOR_ONTRANSITION = 4001;
// Door event - OnClose
const int EVENT_DOOR_ONCLOSE = 4002;
// Door event - OnDamaged
const int EVENT_DOOR_ONDAMAGED = 4003;
// Door event - OnDeath
const int EVENT_DOOR_ONDEATH = 4004;
// Door event - OnFailToOpen
const int EVENT_DOOR_ONFAILTOOPEN = 4005;
// Door event - OnHeartbeat
const int EVENT_DOOR_ONHEARTBEAT = 4006;
// Door event - OnLock
const int EVENT_DOOR_ONLOCK = 4007;
// Door event - OnPhysicalAttacked
const int EVENT_DOOR_ONATTACKED = 4008;
// Door event - OnOpen
const int EVENT_DOOR_ONOPEN = 4009;
// Door event - OnSpellCastAt
const int EVENT_DOOR_ONSPELL = 4010;
// Door event - OnUnLock
const int EVENT_DOOR_ONUNLOCK = 4011;
// Door event - OnUserDefined
const int EVENT_DOOR_ONUSERDEFINED = 4012;
/* Callback hooks */
/// Callback hook - Unarmed evaluation
const int CALLBACKHOOK_UNARMED = 2000;
/// When TRUE, ExecuteAllScriptsHookedToEvent() will print a list of the scripts it executes.
/// Disabling DEBUG will disablet this, too.
const int PRINT_EVENTHOOKS = FALSE;
/////////////////////////
// Internal constants //
/////////////////////////
const string PERMANENCY_SUFFIX = "_permanent";
// Unused events
//const int EVENT_ONMODULELOAD = 7; // Not included, since anything that would be hooked to this event
//const string NAME_ONMODULELOAD = "prc_event_array_onmoduleload"; // should be directly in the eventscript anyway.
//const int EVENT_NPC_ONSPAWN = 33; // No way to add script to the hook for a creature before this fires
//const string NAME_NPC_ONSPAWN = "prc_event_array_npc_onspawn";
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Adds the given script to be fired when the event next occurs for the given object.
* NOTE! Do not add a script that calls ExecuteAllScriptsHookedToEvent() to an eventhook.
* It will result in recursive infinite loop.
*
* @param oObject The object that the script is to be fired for
* @param nEvent One of the EVENT_* constants defined in "inc_eventhook",
* (or any number, but then need to be a bit more careful, since the system won't complain if you typo it)
* @param sScript The script to be fired on the event. Special case: "" will not be stored.
* @param bPermanent Unless this is set, the script will be only fired once, after which it
* is removed from the list
*
* @param bAllowDuplicate This being set makes the function first check if a script with
* the same name is already queued for the event and avoids adding a
* duplicate. This will not remove duplicates already present, though.
*/
int AddEventScript(object oObject, int nEvent, string sScript, int bPermanent = FALSE, int bAllowDuplicate = TRUE);
/**
* Removes all instances of the given script from the given eventhook
*
* @param oObject The object that the script is to be removed from the list for.
* @param nEvent One of the EVENT_* constants defined in "inc_eventhook"
* @param sScript The script to be removed from the event
*
* @param bPermanent Depending on the state of this switch, the script is either removed
* from the one-shot or permanent list.
*
* @param bIgnorePermanency Setting this to true will make the function clear the script from
* both one-shot and permanent lists, regardless of the value of bPermanent
*/
void RemoveEventScript(object oObject, int nEvent, string sScript, int bPermanent = FALSE, int bIgnorePermanency = FALSE);
/**
* Removes all scripts in the given eventhook
*
* @param oObject The object to clear script list for.
* @param nEvent One of the EVENT_* constants defined in "inc_eventhook"
*
* @param bPermanent Depending on the state of this switch, the scripts are either removed
* from the one-shot or permanent list.
*
* @param bIgnorePermanency Setting this to true will make the function clear both one-shot and
* permanent lists, regardless of the value of bPermanent
*/
void ClearEventScriptList(object oObject, int nEvent, int bPermanent = FALSE, int bIgnorePermanency = FALSE);
/**
* Gets the first script hooked to the given event.
* This must be called before any calls to GetNextEventScript() are made.
*
* @param oObject The object to get a script for.
* @param nEvent One of the EVENT_* constants defined in "inc_eventhook"
* @param bPermanent Which list to get the first script from.
*
* @return The name of the first script stored, or "" if one was not found.
*/
string GetFirstEventScript(object oObject, int nEvent, int bPermanent);
/**
* Gets the next script hooked to the given event.
* You should call GetFirstEventScript before calling this.
*
* @param oObject The object to get a script for.
* @param nEvent One of the EVENT_* constants defined in "inc_eventhook"
* @param bPermanent Which list to get the first script from.
*
* @return The name of the next script in the list, or "" if there are no more scripts
* left. Also returns "" if GetFirstEventScript hasn't been called.
*/
string GetNextEventScript(object oObject, int nEvent, int bPermanent);
/**
* Executes all scripts in both the one-shot and permanent hooks and
* clears scripts off the one-shot hook afterwards.
* It is recommended this be used instead of manually going through
* the script lists with Get(First|Next)EventScript.
*
* All the scripts will be ExecuteScripted on OBJECT_SELF, so they will
* behave as if being in the script slot for that event.
*
* @param oObject The object to execute listed scripts for.
* @param nEvent One of the EVENT_* constants defined in "inc_eventhook"
*/
void ExecuteAllScriptsHookedToEvent(object oObject, int nEvent);
/**
* Gets the event currently being run via ExecuteAllScriptsHookedToEvent
*
* @return One of the EVENT_* constants if an ExecuteAllScriptsHookedToEvent
* is being run, FALSE otherwise.
*/
int GetRunningEvent();
//////////////////////////////////////////////////
/* Include section */
//////////////////////////////////////////////////
//#include "inc_utility"
//#include "prc_inc_array"
#include "inc_pers_array" // link higher than prc_inc_array
///////////////////////////////////////////////////////////////////////
/* Private function prototypes - Move on people, nothing to see here */
///////////////////////////////////////////////////////////////////////
/// Internal function. Returns the name matching the given integer constant
string EventTypeIdToName(int nEvent);
string _GetMarkerLocalName(string sScript, string sArrayName);
/// Internal function - Array wrapper
int wrap_array_create(object store, string name);
/// Internal function - Array wrapper
int wrap_array_set_string(object store, string name, int i, string entry);
/// Internal function - Array wrapper
string wrap_array_get_string(object store, string name, int i);
/// Internal function - Array wrapper
int wrap_array_shrink(object store, string name, int size_new);
/// Internal function - Array wrapper
int wrap_array_get_size(object store, string name);
/// Internal function - Array wrapper
int wrap_array_exists(object store, string name);
//////////////////////////////////////////////////
/* Function defintions */
//////////////////////////////////////////////////
int AddEventScript(object oObject, int nEvent, string sScript, int bPermanent = FALSE, int bAllowDuplicate = TRUE){
// If an eventhook is running, place the call into queue
if(GetLocalInt(GetModule(), "prc_eventhook_running")){
int nQueue = GetLocalInt(GetModule(), "prc_eventhook_pending_queue") + 1;
SetLocalInt(GetModule(), "prc_eventhook_pending_queue", nQueue);
SetLocalInt(GetModule(), "prc_eventhook_pending_queue_" + IntToString(nQueue) + "_operation", 1);
SetLocalObject(GetModule(), "prc_eventhook_pending_queue_" + IntToString(nQueue) + "_target", oObject);
SetLocalInt(GetModule(), "prc_eventhook_pending_queue_" + IntToString(nQueue) + "_event", nEvent);
SetLocalString(GetModule(), "prc_eventhook_pending_queue_" + IntToString(nQueue) + "_script", sScript);
SetLocalInt(GetModule(), "prc_eventhook_pending_queue_" + IntToString(nQueue) + "_flags", ((!(!bPermanent)) << 1) | (!(!bAllowDuplicate)));
return FALSE; //TODO: What should this really be?
}
string sArrayName = EventTypeIdToName(nEvent);
// Abort if the object given / event / script isn't valid
if(!GetIsObjectValid(oObject) || sArrayName == "" || sScript == "") return FALSE;
sArrayName += bPermanent ? PERMANENCY_SUFFIX : "";
// Create the array if necessary
if(!wrap_array_exists(oObject, sArrayName)){
wrap_array_create(oObject, sArrayName);
}
// Check for duplicates if necessary
int bAdd = TRUE;
if(!bAllowDuplicate){
// Check if a marker is present.
if(GetLocalInt(oObject, _GetMarkerLocalName(sScript, sArrayName)))
bAdd = FALSE;
// Since this might be the first time it is looked up, loop through the whole list anyway
else
{
int i, nMax = wrap_array_get_size(oObject, sArrayName);
for(i = 0; i < nMax; i++){
if(wrap_array_get_string(oObject, sArrayName, i) == sScript){
// Add a marker that the script is present
SetLocalInt(oObject, _GetMarkerLocalName(sScript, sArrayName), TRUE);
bAdd = FALSE;
break;
} } } }
// Add to the array if needed
if(bAdd)
{
wrap_array_set_string(oObject, sArrayName, wrap_array_get_size(oObject, sArrayName), sScript);
// Add a marker that the script is present
SetLocalInt(oObject, _GetMarkerLocalName(sScript, sArrayName), TRUE);
}
return bAdd;
}
void RemoveEventScript(object oObject, int nEvent, string sScript, int bPermanent = FALSE, int bIgnorePermanency = FALSE){
// If an eventhook is running, place the call into queue
if(GetLocalInt(GetModule(), "prc_eventhook_running")){
int nQueue = GetLocalInt(GetModule(), "prc_eventhook_pending_queue") + 1;
SetLocalInt(GetModule(), "prc_eventhook_pending_queue", nQueue);
SetLocalInt(GetModule(), "prc_eventhook_pending_queue_" + IntToString(nQueue) + "_operation", 2);
SetLocalObject(GetModule(), "prc_eventhook_pending_queue_" + IntToString(nQueue) + "_target", oObject);
SetLocalInt(GetModule(), "prc_eventhook_pending_queue_" + IntToString(nQueue) + "_event", nEvent);
SetLocalString(GetModule(), "prc_eventhook_pending_queue_" + IntToString(nQueue) + "_script", sScript);
SetLocalInt(GetModule(), "prc_eventhook_pending_queue_" + IntToString(nQueue) + "_flags", ((!(!bPermanent)) << 1) | (!(!bIgnorePermanency)));
return;
}
string sArrayNameBase = EventTypeIdToName(nEvent),
sArrayName;
// Abort if the object given / event / script isn't valid
if(!GetIsObjectValid(oObject) || sArrayNameBase == "" || sScript == "") return;
// Go through one-shot array
if(!bPermanent || bIgnorePermanency){
sArrayName = sArrayNameBase;
// First, check if there is an array to look through at all and that the script is in the array
if(wrap_array_exists(oObject, sArrayName)/* &&
GetLocalInt(oObject, _GetMarkerLocalName(sScript, sArrayName))*/
){
int nMoveBackBy = 0;
int i = 0;
int nArraySize = wrap_array_get_size(oObject, sArrayName);
// Loop through the array elements
for(; i < nArraySize; i++){
// See if we have an entry to remove
if(wrap_array_get_string(oObject, sArrayName, i) == sScript){
nMoveBackBy++;
}
// Move the entries in the array back by an amount great enough to overwrite entries containing sScript
else if(nMoveBackBy){
wrap_array_set_string(oObject, sArrayName, i - nMoveBackBy,
wrap_array_get_string(oObject, sArrayName, i));
} }
// Shrink the array by the number of entries removed, if any
if(nMoveBackBy)
wrap_array_shrink(oObject, sArrayName, wrap_array_get_size(oObject, sArrayName) - nMoveBackBy);
// Remove the script presence marker
DeleteLocalInt(oObject, _GetMarkerLocalName(sScript, sArrayName));
} }
// Go through the permanent array
if(bPermanent || bIgnorePermanency){
sArrayName = sArrayNameBase + PERMANENCY_SUFFIX;
// First, check if there is an array to look through at all and that the script is in the array
if(wrap_array_exists(oObject, sArrayName)/* &&
GetLocalInt(oObject, _GetMarkerLocalName(sScript, sArrayName))*/
){
int nMoveBackBy = 0;
int i = 0;
int nArraySize = wrap_array_get_size(oObject, sArrayName);
// Loop through the array elements
for(; i < nArraySize; i++){
// See if we have an entry to remove
if(wrap_array_get_string(oObject, sArrayName, i) == sScript){
nMoveBackBy++;
}
// Move the entries in the array back by an amount great enough to overwrite entries containing sScript
else if(nMoveBackBy){
wrap_array_set_string(oObject, sArrayName, i - nMoveBackBy,
wrap_array_get_string(oObject, sArrayName, i));
} }
// Shrink the array by the number of entries removed, if any
if(nMoveBackBy)
wrap_array_shrink(oObject, sArrayName, wrap_array_get_size(oObject, sArrayName) - nMoveBackBy);
// Remove the script presence marker
DeleteLocalInt(oObject, _GetMarkerLocalName(sScript, sArrayName));
} }
}
void ClearEventScriptList(object oObject, int nEvent, int bPermanent = FALSE, int bIgnorePermanency = FALSE){
// If an eventhook is running, place the call into queue
if(GetLocalInt(GetModule(), "prc_eventhook_running")){
int nQueue = GetLocalInt(GetModule(), "prc_eventhook_pending_queue") + 1;
SetLocalInt(GetModule(), "prc_eventhook_pending_queue", nQueue);
SetLocalInt(GetModule(), "prc_eventhook_pending_queue_" + IntToString(nQueue) + "_operation", 3);
SetLocalObject(GetModule(), "prc_eventhook_pending_queue_" + IntToString(nQueue) + "_target", oObject);
SetLocalInt(GetModule(), "prc_eventhook_pending_queue_" + IntToString(nQueue) + "_event", nEvent);
SetLocalInt(GetModule(), "prc_eventhook_pending_queue_" + IntToString(nQueue) + "_flags", ((!(!bPermanent)) << 1) | (!(!bIgnorePermanency)));
return;
}
string sArrayNameBase = EventTypeIdToName(nEvent),
sArrayName;
// Abort if the object given / event isn't valid
if(!GetIsObjectValid(oObject) || sArrayNameBase == "") return;
// Go through one-shot array
if(!bPermanent || bIgnorePermanency){
sArrayName = sArrayNameBase;
// First, check if there is an array present
if(wrap_array_exists(oObject, sArrayName)){
// Remove all markers
int i = 0;
for(; i <= wrap_array_get_size(oObject, sArrayName); i++){
DeleteLocalInt(oObject, _GetMarkerLocalName(wrap_array_get_string(oObject, sArrayName, i), sArrayName));
}
// Shrink the array to 0
wrap_array_shrink(oObject, sArrayName, 0);
} }
// Go through the permanent array
if(bPermanent || bIgnorePermanency){
sArrayName = sArrayNameBase + PERMANENCY_SUFFIX;
// First, check if there is an array present
if(wrap_array_exists(oObject, sArrayName)){
// Remove all markers
int i = 0;
for(; i <= wrap_array_get_size(oObject, sArrayName); i++){
DeleteLocalInt(oObject, _GetMarkerLocalName(wrap_array_get_string(oObject, sArrayName, i), sArrayName));
}
// Shrink the array to 0
wrap_array_shrink(oObject, sArrayName, 0);
} }
}
string GetFirstEventScript(object oObject, int nEvent, int bPermanent){
string sArrayName = EventTypeIdToName(nEvent);
// Abort if the object given / event isn't valid
if(!GetIsObjectValid(oObject) || sArrayName == "") return "";
sArrayName += bPermanent ? PERMANENCY_SUFFIX : "";
// DelayCommand is somewhat expensive, so do this bit only if there is actually an array to iterate over
if(wrap_array_exists(oObject, sArrayName)) {
SetLocalInt(oObject, sArrayName + "_index", 1);
DelayCommand(0.0f, DeleteLocalInt(oObject, sArrayName + "_index"));
}
return wrap_array_get_string(oObject, sArrayName, 0);
}
string GetNextEventScript(object oObject, int nEvent, int bPermanent){
string sArrayName = GetLocalInt(GetModule(), "prc_eventhook_running") ?
GetLocalString(GetModule(), "prc_eventhook_running_sArrayName") :
EventTypeIdToName(nEvent);
// Abort if the object given / event isn't valid
if(!GetIsObjectValid(oObject) || sArrayName == "") return "";
sArrayName += bPermanent ? PERMANENCY_SUFFIX : "";
int nIndex = GetLocalInt(oObject, sArrayName + "_index");
if(nIndex)
SetLocalInt(oObject, sArrayName + "_index", nIndex + 1);
else{
WriteTimestampedLogEntry("GetNextEventScript called without first calling GetFirstEventScript");
return "";
}
return wrap_array_get_string(oObject, sArrayName, nIndex);
}
void ExecuteAllScriptsHookedToEvent(object oObject, int nEvent){
// Mark that an eventhook is being run, so calls to modify the
// scripts listed are delayd until the eventhook is done.
SetLocalInt(GetModule(), "prc_eventhook_running", nEvent);
SetLocalString(GetModule(), "prc_eventhook_running_sArrayName", EventTypeIdToName(nEvent));
if(PRINT_EVENTHOOKS && DEBUG)
DoDebug("Executing eventhook for event " + IntToString(nEvent) + "; object = " + DebugObject2Str(oObject) + ". Hooked scripts:");
// Loop through the scripts to be fired only once
string sScript = GetFirstEventScript(oObject, nEvent, FALSE);
int bNeedClearing = FALSE;
while(sScript != ""){
bNeedClearing = TRUE;
if(PRINT_EVENTHOOKS && DEBUG)
DoDebug("\nOneshot: '" + sScript + "'");
ExecuteScript(sScript, OBJECT_SELF);
sScript = GetNextEventScript(oObject, nEvent, FALSE);
}
// Clear the one-shot script list
if(bNeedClearing)
ClearEventScriptList(oObject, nEvent, FALSE, FALSE);
// Loop through the persistent scripts
sScript = GetFirstEventScript(oObject, nEvent, TRUE);
while(sScript != ""){
if(PRINT_EVENTHOOKS && DEBUG)
DoDebug("\nPermanent: '" + sScript + "'");
ExecuteScript(sScript, OBJECT_SELF);
sScript = GetNextEventScript(oObject, nEvent, TRUE);
}
// Remove the lock on modifying the script lists
DeleteLocalInt(GetModule(), "prc_eventhook_running");
DeleteLocalString(GetModule(), "prc_eventhook_running_sArrayName");
// Run the delayed commands
int nQueued = GetLocalInt(GetModule(), "prc_eventhook_pending_queue"),
nOperation, nFlags, i;
object oTarget;
for(i = 1; i <= nQueued; i++){
nOperation = GetLocalInt(GetModule(), "prc_eventhook_pending_queue_" + IntToString(i) + "_operation");
oTarget = GetLocalObject(GetModule(), "prc_eventhook_pending_queue_" + IntToString(i) + "_target");
nEvent = GetLocalInt(GetModule(), "prc_eventhook_pending_queue_" + IntToString(i) + "_event");
sScript = GetLocalString(GetModule(), "prc_eventhook_pending_queue_" + IntToString(i) + "_script");
nFlags = GetLocalInt(GetModule(), "prc_eventhook_pending_queue_" + IntToString(i) + "_flags");
switch(nOperation){
case 1:
AddEventScript(oTarget, nEvent, sScript, nFlags >>> 1, nFlags & 1);
break;
case 2:
RemoveEventScript(oTarget, nEvent, sScript, nFlags >>> 1, nFlags & 1);
break;
case 3:
ClearEventScriptList(oTarget, nEvent, nFlags >>> 1, nFlags & 1);
break;
default:
WriteTimestampedLogEntry("Invalid value in delayed eventhook manipulation operation queue");
}
DeleteLocalInt (GetModule(), "prc_eventhook_pending_queue_" + IntToString(i) + "_operation");
DeleteLocalObject(GetModule(), "prc_eventhook_pending_queue_" + IntToString(i) + "_target");
DeleteLocalInt (GetModule(), "prc_eventhook_pending_queue_" + IntToString(i) + "_event");
DeleteLocalString(GetModule(), "prc_eventhook_pending_queue_" + IntToString(i) + "_script");
DeleteLocalInt (GetModule(), "prc_eventhook_pending_queue_" + IntToString(i) + "_flags");
}
DeleteLocalInt(GetModule(), "prc_eventhook_pending_queue");
}
int GetRunningEvent(){
return GetLocalInt(GetModule(), "prc_eventhook_running");
}
string EventTypeIdToName(int nEvent){
/*
switch(nEvent){
// Module events
case EVENT_ONACQUIREITEM:
return NAME_ONACQUIREITEM;
case EVENT_ONACTIVATEITEM:
return NAME_ONACTIVATEITEM;
case EVENT_ONCLIENTENTER:
return NAME_ONCLIENTENTER;
case EVENT_ONCLIENTLEAVE:
return NAME_ONCLIENTLEAVE;
case EVENT_ONCUTSCENEABORT:
return NAME_ONCUTSCENEABORT;
case EVENT_ONHEARTBEAT:
return NAME_ONHEARTBEAT;
// case EVENT_ONMODULELOAD:
// return NAME_ONMODULELOAD;
case EVENT_ONPLAYERDEATH:
return NAME_ONPLAYERDEATH;
case EVENT_ONPLAYERDYING:
return NAME_ONPLAYERDYING;
case EVENT_ONPLAYEREQUIPITEM:
return NAME_ONPLAYEREQUIPITEM;
case EVENT_ONPLAYERLEVELUP:
return NAME_ONPLAYERLEVELUP;
case EVENT_ONPLAYERREST_CANCELLED:
return NAME_ONPLAYERREST_CANCELLED;
case EVENT_ONPLAYERREST_STARTED:
return NAME_ONPLAYERREST_STARTED;
case EVENT_ONPLAYERREST_FINISHED:
return NAME_ONPLAYERREST_FINISHED;
case EVENT_ONPLAYERUNEQUIPITEM:
return NAME_ONPLAYERUNEQUIPITEM;
case EVENT_ONPLAYERRESPAWN:
return NAME_ONPLAYERRESPAWN;
case EVENT_ONUNAQUIREITEM:
return NAME_ONUNAQUIREITEM;
case EVENT_ONUSERDEFINED:
return NAME_ONUSERDEFINED;
case EVENT_ONPLAYERLEVELDOWN:
return NAME_ONPLAYERLEVELDOWN;
// NPC events
case EVENT_NPC_ONBLOCKED:
return NAME_NPC_ONBLOCKED;
case EVENT_NPC_ONCOMBATROUNDEND:
return NAME_NPC_ONCOMBATROUNDEND;
case EVENT_NPC_ONCONVERSATION:
return NAME_NPC_ONCONVERSATION;
case EVENT_NPC_ONDAMAGED:
return NAME_NPC_ONDAMAGED;
case EVENT_NPC_ONDEATH:
return NAME_NPC_ONDEATH;
case EVENT_NPC_ONDISTURBED:
return NAME_NPC_ONDISTURBED;
case EVENT_NPC_ONHEARTBEAT:
return NAME_NPC_ONHEARTBEAT;
case EVENT_NPC_ONPERCEPTION:
return NAME_NPC_ONPERCEPTION;
case EVENT_NPC_ONPHYSICALATTACKED:
return NAME_NPC_ONPHYSICALATTACKED;
case EVENT_NPC_ONRESTED:
return NAME_NPC_ONRESTED;
// case EVENT_NPC_ONSPAWN:
// return NAME_NPC_ONSPAWN;
case EVENT_NPC_ONSPELLCASTAT:
return NAME_NPC_ONSPELLCASTAT;
// Other events
case EVENT_ONHIT:
return NAME_ONHIT;
case EVENT_ONSPELLCAST:
return NAME_ONSPELLCAST;
case EVENT_ONPOWERMANIFEST:
return NAME_ONPOWERMANIFEST;
// Item events
case EVENT_ITEM_ONACQUIREITEM:
return NAME_ITEM_ONACQUIREITEM;
case EVENT_ITEM_ONACTIVATEITEM:
return NAME_ITEM_ONACTIVATEITEM;
case EVENT_ITEM_ONPLAYEREQUIPITEM:
return NAME_ITEM_ONPLAYEREQUIPITEM;
case EVENT_ITEM_ONPLAYERUNEQUIPITEM:
return NAME_ITEM_ONPLAYERUNEQUIPITEM;
case EVENT_ITEM_ONUNAQUIREITEM:
return NAME_ITEM_ONUNAQUIREITEM;
case EVENT_ITEM_ONHIT:
return NAME_ITEM_ONHIT;
// Callbackhooks
case CALLBACKHOOK_UNARMED:
return NAME_CALLBACKHOOK_UNARMED;
default:
WriteTimestampedLogEntry("Unknown event id passed to EventTypeIdToName: " + IntToString(nEvent) + "\nAdding a name constant for it recommended.");
return "prc_event_array_" + IntToString(nEvent);
}
*/
return "prc_event_array_" + IntToString(nEvent);
//return ""; // Never going to reach this, but the compiler doesn't realize that :P
}
string _GetMarkerLocalName(string sScript, string sArrayName)
{
return "prc_eventhook_script:" + sScript + ";array:" + sArrayName;
}
int wrap_array_create(object store, string name){
if(GetIsPC(store))
return persistant_array_create(store, name);
else
return array_create(store, name);
}
int wrap_array_set_string(object store, string name, int i, string entry){
if(GetIsPC(store))
return persistant_array_set_string(store, name, i, entry);
else
return array_set_string(store, name, i, entry);
}
string wrap_array_get_string(object store, string name, int i){
if(GetIsPC(store))
return persistant_array_get_string(store, name, i);
else
return array_get_string(store, name, i);
}
int wrap_array_shrink(object store, string name, int size_new){
if(GetIsPC(store))
return persistant_array_shrink(store, name, size_new);
else
return array_shrink(store, name, size_new);
}
int wrap_array_get_size(object store, string name){
if(GetIsPC(store))
return persistant_array_get_size(store, name);
else
return array_get_size(store, name);
}
int wrap_array_exists(object store, string name){
if(GetIsPC(store))
return persistant_array_exists(store, name);
else
return array_exists(store, name);
}

592
src/include/inc_heap.nss Normal file
View File

@@ -0,0 +1,592 @@
//::///////////////////////////////////////////////
//:: Heap include
//:: inc_heap
//:://////////////////////////////////////////////
/** @file
A simple maxheap, backed by an array.
Insertion priority is determined by an interger
parameter, data stored may be anything.
Heap element indices begin at one, for convenience.
For optimization, I use binary search instead of
switches. Result: It's fugly
Return values are similar to the ones in
Mr. Figglesworth's sdl_array
@author Ornedan
@date Created - 16.03.2005
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Constant defintions */
//////////////////////////////////////////////////
/*
const int SDL_SUCCESS = 1;
const int SDL_ERROR_ALREADY_EXISTS = 1001;
const int SDL_ERROR_DOES_NOT_EXIST = 1002;
const int SDL_ERROR_OUT_OF_BOUNDS = 1003;
const int SDL_ERROR_NO_ZERO_SIZE = 1004;
const int SDL_ERROR_NOT_VALID_OBJECT = 1005;
*/
/// Heap entity type - float
const int ENTITY_TYPE_FLOAT = 1;
/// Heap entity type - integer
const int ENTITY_TYPE_INTEGER = 2;
/// Heap entity type - object
const int ENTITY_TYPE_OBJECT = 3;
/// Heap entity type - string
const int ENTITY_TYPE_STRING = 4;
// Internal constants
const string HEAP_PREFIX = "heap_";
const string KEY_SUFFIX = "_key";
const string ELEMENT_SUFFIX = "_element";
const string TYPE_SUFFIX = "_type";
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Initializes heap variables on the storage object.
*
* @param oStore object that the heap will be stored as locals on
* @param sName the name of the heap
* @return SDL_* constant
*/
int heap_create(object oStore, string sName);
/**
* Deletes the heap and all it's entries.
*
* @param oStore object the heap is stored on
* @param sName the name of the heap
* @return SDL_* constant
*/
int heap_delete(object oStore, string sName);
/**
* Checks to see if a heap exists.
*
* @param oStore object the heap is stored on
* @param sName the name of the heap
* @return TRUE if a heap with the given name is stored on oStore.
* FALSE otherwise.
*/
int heap_exists(object oStore, string sName);
/**
* Gets the number of elements in the heap
*
* @param oStore object the heap is stored on
* @param sName the name of the heap
* @return the number of elements in the heap, or -1 on error.
*/
int heap_get_size(object oStore, string sName);
/**
* Heap insertion functions - float.
* Inserts the given key & element pair at a location in the heap
* determined by the key.
* Return order of elements inserted with the same key is not defined.
*
* @param oStore object the heap to be used is stored on
* @param sName the name of the heap
* @param nKey integer value used to determine insertion location
* @param fEntry element to be insterted
* @return SDL_* constant
*/
int heap_put_float(object oStore, string sName, int nKey, float fEntry);
/**
* Heap insertion functions - integer.
* Inserts the given key & element pair at a location in the heap
* determined by the key.
* Return order of elements inserted with the same key is not defined.
*
* @param oStore object the heap to be used is stored on
* @param sName the name of the heap
* @param nKey integer value used to determine insertion location
* @param nEntry element to be insterted
* @return SDL_* constant
*/
int heap_put_int(object oStore, string sName, int nKey, int nEntry);
/**
* Heap insertion functions - object.
* Inserts the given key & element pair at a location in the heap
* determined by the key.
* Return order of elements inserted with the same key is not defined.
*
* @param oStore object the heap to be used is stored on
* @param sName the name of the heap
* @param nKey integer value used to determine insertion location
* @param oEntry element to be insterted
* @return SDL_* constant
*/
int heap_put_object(object oStore, string sName, int nKey, object oEntry);
/**
* Heap insertion functions - string
.
* Inserts the given key & element pair at a location in the heap
* determined by the key.
* Return order of elements inserted with the same key is not defined.
*
* @param oStore object the heap to be used is stored on
* @param sName the name of the heap
* @param nKey integer value used to determine insertion location
* @param sEntry element to be insterted
* @return SDL_* constant
*/
int heap_put_string(object oStore, string sName, int nKey, string sEntry);
/**
* Checks the type of the element at the top of the heap. Errors if
* heap does not exist or is empty.
*
* @param oStore object the heap to be used is stored on
* @param sName the name of the heap
* @return one of the ENTITY_TYPE_* constants, or 0 on error.
*/
int heap_get_type(object oStore, string sName);
/**
* Gets the top element of the heap as float.
*
* @param oStore object the heap to be used is stored on
* @param sName the name of the heap
* @return top element of the heap as float. If the type
* of the top element was not float, returns 0.0f
*/
float heap_get_float(object oStore, string sName);
/**
* Gets the top element of the heap as integer.
*
* @param oStore object the heap to be used is stored on
* @param sName the name of the heap
* @return top element of the heap as integer. If the type
* of the top element was not integer, returns 0
*/
int heap_get_int(object oStore, string sName);
/**
* Gets the top element of the heap as object.
*
* @param oStore object the heap to be used is stored on
* @param sName the name of the heap
* @return top element of the heap as object. If the type
* of the top element was not object, returns OBJECT_INVALID
*/
object heap_get_object(object oStore, string sName);
/**
* Gets the top element of the heap as string.
*
* @param oStore object the heap to be used is stored on
* @param sName the name of the heap
* @return top element of the heap as string. If the type
* of the top element was not string, returns ""
*/
string heap_get_string(object oStore, string sName);
/**
* Deletes the top element of the heap and reorders the heap to
* preserve the heap conditions.
*
* @param oStore object the heap to be used is stored on
* @param sName the name of the heap
* @return one of the SDL_* constants
*/
int heap_remove(object oStore, string sName);
//////////////////////////////////////////////////
/* Include section */
//////////////////////////////////////////////////
//#include "inc_utility"
#include "prc_inc_array" //The only part of inc_utility it needs
//////////////////////////////////////////////////
/* Function defintions */
//////////////////////////////////////////////////
int heap_create(object oStore, string sName){
// Validity checks
if(!GetIsObjectValid(oStore))
return SDL_ERROR_NOT_VALID_OBJECT;
if(GetLocalInt(oStore, sName))
return SDL_ERROR_ALREADY_EXISTS;
// Initialize the size (always one greater than the actual size)
SetLocalInt(oStore, HEAP_PREFIX + sName, 1);
return SDL_SUCCESS;
}
int heap_delete(object oStore, string sName){
// Validity checks
int nSize = GetLocalInt(oStore, HEAP_PREFIX + sName);
if(!nSize)
return SDL_ERROR_DOES_NOT_EXIST;
nSize -= 1;
int nTempType;
for(; nSize >= 0; nSize--){
// Delete the storage values
nTempType = GetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nSize) + TYPE_SUFFIX);
DeleteLocalInt (oStore, HEAP_PREFIX + sName + "_" + IntToString(nSize) + TYPE_SUFFIX);
DeleteLocalInt (oStore, HEAP_PREFIX + sName + "_" + IntToString(nSize) + KEY_SUFFIX);
if(nTempType > ENTITY_TYPE_INTEGER){
if(nTempType > ENTITY_TYPE_OBJECT)
DeleteLocalString(oStore, HEAP_PREFIX + sName + "_" + IntToString(nSize) + ELEMENT_SUFFIX);
else
DeleteLocalObject(oStore, HEAP_PREFIX + sName + "_" + IntToString(nSize) + ELEMENT_SUFFIX);
}else{
if(nTempType > ENTITY_TYPE_FLOAT)
DeleteLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nSize) + ELEMENT_SUFFIX);
else
DeleteLocalFloat(oStore, HEAP_PREFIX + sName + "_" + IntToString(nSize) + ELEMENT_SUFFIX);
}
}
// Delete the size variable
DeleteLocalInt(oStore, HEAP_PREFIX + sName);
return SDL_SUCCESS;
}
int heap_exists(object oStore, string sName){
if(GetLocalInt(oStore, HEAP_PREFIX + sName))
return TRUE;
else
return FALSE;
}
int heap_get_size(object oStore, string sName){
return GetLocalInt(oStore, HEAP_PREFIX + sName) - 1;
}
/* Some functions for simulating the element links */
int heap_parent(int nIndex){ return (nIndex - 1) / 2; }
int heap_lchild(int nIndex){ return (nIndex * 2) + 1; }
int heap_rchild(int nIndex){ return (nIndex * 2) + 2; }
/* An element swapper */
void heap_swap(object oStore, string sName, int nInd1, int nInd2){
int nTempKey = GetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd1) + KEY_SUFFIX);
int nTempType = GetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd1) + TYPE_SUFFIX);
float fTemp;
int nTemp;
object oTemp;
string sTemp;
// Grab the element from index1
if(nTempType > ENTITY_TYPE_INTEGER){
if(nTempType > ENTITY_TYPE_OBJECT){
sTemp = GetLocalString(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd1) + ELEMENT_SUFFIX);
DeleteLocalString(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd1) + ELEMENT_SUFFIX);
}else{
oTemp = GetLocalObject(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd1) + ELEMENT_SUFFIX);
DeleteLocalObject(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd1) + ELEMENT_SUFFIX);
}}else{
if(nTempType > ENTITY_TYPE_FLOAT){
nTemp = GetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd1) + ELEMENT_SUFFIX);
DeleteLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd1) + ELEMENT_SUFFIX);
}else{
fTemp = GetLocalFloat(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd1) + ELEMENT_SUFFIX);
DeleteLocalFloat(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd1) + ELEMENT_SUFFIX);
}}
// Start moving from index2
int nTempType2 = GetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd2) + TYPE_SUFFIX);
SetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd1) + TYPE_SUFFIX,
nTempType2);
SetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd1) + KEY_SUFFIX,
GetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd2) + KEY_SUFFIX));
// Illegal use of enumerations. Don't do this at home :p
if(nTempType2 > ENTITY_TYPE_INTEGER){
if(nTempType2 > ENTITY_TYPE_OBJECT){
SetLocalString(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd1) + ELEMENT_SUFFIX,
GetLocalString(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd2) + ELEMENT_SUFFIX));
DeleteLocalString(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd2) + ELEMENT_SUFFIX);
}else{
SetLocalObject(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd1) + ELEMENT_SUFFIX,
GetLocalObject(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd2) + ELEMENT_SUFFIX));
DeleteLocalObject(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd2) + ELEMENT_SUFFIX);
}}else{
if(nTempType2 > ENTITY_TYPE_FLOAT){
SetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd1) + ELEMENT_SUFFIX,
GetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd2) + ELEMENT_SUFFIX));
DeleteLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd2) + ELEMENT_SUFFIX);
}else{
SetLocalFloat(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd1) + ELEMENT_SUFFIX,
GetLocalFloat(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd2) + ELEMENT_SUFFIX));
DeleteLocalFloat(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd2) + ELEMENT_SUFFIX);
}}
// Place the stuff copied to temporary variables to their new place
SetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd2) + TYPE_SUFFIX,
nTempType);
SetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd2) + KEY_SUFFIX,
nTempKey);
if(nTempType > ENTITY_TYPE_INTEGER){
if(nTempType > ENTITY_TYPE_OBJECT)
SetLocalString(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd2) + ELEMENT_SUFFIX,
sTemp);
else
SetLocalObject(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd2) + ELEMENT_SUFFIX,
oTemp);
}else{
if(nTempType > ENTITY_TYPE_FLOAT)
SetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd2) + ELEMENT_SUFFIX,
nTemp);
else
SetLocalFloat(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInd2) + ELEMENT_SUFFIX,
fTemp);
}
}
/* A function that gets the location where the given
* key should be inserted. Moves other elements around
* to clear the location
*/
int heap_get_insert_location(object oStore, string sName, int nKey){
// Insert into position just beyond the end of current elements
int nIndex = heap_get_size(oStore, sName);
int nTempType;
while(nIndex > 0 && GetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(heap_parent(nIndex)) + KEY_SUFFIX) < nKey){
// Move the parent entry down
nTempType = GetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(heap_parent(nIndex)) + TYPE_SUFFIX);
SetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nIndex) + TYPE_SUFFIX,
nTempType);
SetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nIndex) + KEY_SUFFIX,
GetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(heap_parent(nIndex)) + KEY_SUFFIX));
// Illegal use of enumerations. Don't do this at home :p
// The old entry is deleted, since the entry to be inserted might not be of the same type
if(nTempType > ENTITY_TYPE_INTEGER){
if(nTempType > ENTITY_TYPE_OBJECT){
SetLocalString(oStore, HEAP_PREFIX + sName + "_" + IntToString(nIndex) + ELEMENT_SUFFIX,
GetLocalString(oStore, HEAP_PREFIX + sName + "_" + IntToString(heap_parent(nIndex)) + ELEMENT_SUFFIX));
DeleteLocalString(oStore, HEAP_PREFIX + sName + "_" + IntToString(heap_parent(nIndex)) + ELEMENT_SUFFIX);
}else{
SetLocalObject(oStore, HEAP_PREFIX + sName + "_" + IntToString(nIndex) + ELEMENT_SUFFIX,
GetLocalObject(oStore, HEAP_PREFIX + sName + "_" + IntToString(heap_parent(nIndex)) + ELEMENT_SUFFIX));
DeleteLocalObject(oStore, HEAP_PREFIX + sName + "_" + IntToString(heap_parent(nIndex)) + ELEMENT_SUFFIX);
}}else{
if(nTempType > ENTITY_TYPE_FLOAT){
SetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nIndex) + ELEMENT_SUFFIX,
GetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(heap_parent(nIndex)) + ELEMENT_SUFFIX));
DeleteLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(heap_parent(nIndex)) + ELEMENT_SUFFIX);
}else{
SetLocalFloat(oStore, HEAP_PREFIX + sName + "_" + IntToString(nIndex) + ELEMENT_SUFFIX,
GetLocalFloat(oStore, HEAP_PREFIX + sName + "_" + IntToString(heap_parent(nIndex)) + ELEMENT_SUFFIX));
DeleteLocalFloat(oStore, HEAP_PREFIX + sName + "_" + IntToString(heap_parent(nIndex)) + ELEMENT_SUFFIX);
}}
nIndex = heap_parent(nIndex);
}
return nIndex;
}
/*if(a > 2){
if(a > 3)
b = ENTITY_TYPE_STRING;
else
b = ENTITY_TYPE_OBJECT;
}else{
if(a > 1)
b = ENTITY_TYPE_INTEGER;
else
b = ENTITY_TYPE_FLOAT;
}*/
int heap_put_float(object oStore, string sName, int nKey, float fEntry){
// Validity checks
if(!GetLocalInt(oStore, HEAP_PREFIX + sName))
return SDL_ERROR_DOES_NOT_EXIST;
// Get the location to insert to
int nInsert = heap_get_insert_location(oStore, sName, nKey);
// Insert the new element
SetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInsert) + TYPE_SUFFIX, ENTITY_TYPE_FLOAT);
SetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInsert) + KEY_SUFFIX, nKey);
SetLocalFloat(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInsert) + ELEMENT_SUFFIX, fEntry);
// Mark the insertion
SetLocalInt(oStore, HEAP_PREFIX + sName, GetLocalInt(oStore, HEAP_PREFIX + sName) + 1);
return SDL_SUCCESS;
}
int heap_put_int(object oStore, string sName, int nKey, int nEntry){
// Validity checks
if(!GetLocalInt(oStore, HEAP_PREFIX + sName))
return SDL_ERROR_DOES_NOT_EXIST;
// Get the location to insert to
int nInsert = heap_get_insert_location(oStore, sName, nKey);
// Insert the new element
SetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInsert) + KEY_SUFFIX, nKey);
SetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInsert) + TYPE_SUFFIX, ENTITY_TYPE_INTEGER);
SetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInsert) + ELEMENT_SUFFIX, nEntry);
// Mark the insertion
SetLocalInt(oStore, HEAP_PREFIX + sName, GetLocalInt(oStore, HEAP_PREFIX + sName) + 1);
return SDL_SUCCESS;
}
int heap_put_string(object oStore, string sName, int nKey, string sEntry){
// Validity checks
if(!GetLocalInt(oStore, HEAP_PREFIX + sName))
return SDL_ERROR_DOES_NOT_EXIST;
// Get the location to insert to
int nInsert = heap_get_insert_location(oStore, sName, nKey);
// Insert the new element
SetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInsert) + KEY_SUFFIX, nKey);
SetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInsert) + TYPE_SUFFIX, ENTITY_TYPE_STRING);
SetLocalString(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInsert) + ELEMENT_SUFFIX, sEntry);
// Mark the insertion
SetLocalInt(oStore, HEAP_PREFIX + sName, GetLocalInt(oStore, HEAP_PREFIX + sName) + 1);
return SDL_SUCCESS;
}
int heap_put_object(object oStore, string sName, int nKey, object oEntry){
// Validity checks
if(!GetLocalInt(oStore, HEAP_PREFIX + sName))
return SDL_ERROR_DOES_NOT_EXIST;
// Get the location to insert to
int nInsert = heap_get_insert_location(oStore, sName, nKey);
// Insert the new element
SetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInsert) + KEY_SUFFIX, nKey);
SetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInsert) + TYPE_SUFFIX, ENTITY_TYPE_OBJECT);
SetLocalObject(oStore, HEAP_PREFIX + sName + "_" + IntToString(nInsert) + ELEMENT_SUFFIX, oEntry);
// Mark the insertion
SetLocalInt(oStore, HEAP_PREFIX + sName, GetLocalInt(oStore, HEAP_PREFIX + sName) + 1);
return SDL_SUCCESS;
}
int heap_remove(object oStore, string sName){
// Validity checks
if(!GetLocalInt(oStore, HEAP_PREFIX + sName))
return SDL_ERROR_DOES_NOT_EXIST;
int nSize = heap_get_size(oStore, sName);
if(!nSize)
return SDL_ERROR_OUT_OF_BOUNDS;
// Move the bottommost element over the max
nSize--;
heap_swap(oStore, sName, 0, nSize);
// Delete the bottommost element
int nTempType = GetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nSize) + TYPE_SUFFIX);
DeleteLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nSize) + TYPE_SUFFIX);
DeleteLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nSize) + KEY_SUFFIX);
if(nTempType > ENTITY_TYPE_INTEGER){
if(nTempType > ENTITY_TYPE_OBJECT)
DeleteLocalString(oStore, HEAP_PREFIX + sName + "_" + IntToString(nSize) + ELEMENT_SUFFIX);
else
DeleteLocalObject(oStore, HEAP_PREFIX + sName + "_" + IntToString(nSize) + ELEMENT_SUFFIX);
}else{
if(nTempType > ENTITY_TYPE_FLOAT)
DeleteLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nSize) + ELEMENT_SUFFIX);
else
DeleteLocalFloat(oStore, HEAP_PREFIX + sName + "_" + IntToString(nSize) + ELEMENT_SUFFIX);
}
// Mark the heapsize as reduced
SetLocalInt(oStore, HEAP_PREFIX + sName, nSize + 1);
// Move nSize to point at the new last entry
nSize--;
// Re-assert the heap conditions
int nLeft, nRight, nMax, nIndex = 0;
int bContinue = TRUE;
while(bContinue){
bContinue = FALSE;
nLeft = heap_lchild(nIndex);
nRight = heap_rchild(nIndex);
if(nRight <= nSize){
if(GetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nLeft) + KEY_SUFFIX)
>
GetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nLeft) + KEY_SUFFIX))
nMax = nLeft;
else
nMax = nRight;
if(GetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nIndex) + KEY_SUFFIX)
<
GetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nMax) + KEY_SUFFIX)){
heap_swap(oStore, sName, nIndex, nMax);
bContinue = TRUE;
}
}
else if(nLeft == nSize &&
GetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nIndex) + KEY_SUFFIX)
<
GetLocalInt(oStore, HEAP_PREFIX + sName + "_" + IntToString(nLeft) + KEY_SUFFIX))
heap_swap(oStore, sName, nIndex, nLeft);
}
return SDL_SUCCESS;
}
int heap_get_type(object oStore, string sName){
// Validity checks
if(!GetLocalInt(oStore, HEAP_PREFIX + sName))
return SDL_ERROR_DOES_NOT_EXIST;
// Return the heap top element's type
return GetLocalInt(oStore, HEAP_PREFIX + sName + "_0" + TYPE_SUFFIX);
}
float heap_get_float(object oStore, string sName){
return GetLocalInt(oStore, HEAP_PREFIX + sName + "_0" + TYPE_SUFFIX) == ENTITY_TYPE_FLOAT ?
GetLocalFloat(oStore, HEAP_PREFIX + sName + "_0" + ELEMENT_SUFFIX) :
0.0f;
}
int heap_get_int(object oStore, string sName){
return GetLocalInt(oStore, HEAP_PREFIX + sName + "_0" + TYPE_SUFFIX) == ENTITY_TYPE_INTEGER ?
GetLocalInt(oStore, HEAP_PREFIX + sName + "_0" + ELEMENT_SUFFIX) :
0;
}
object heap_get_object(object oStore, string sName){
return GetLocalInt(oStore, HEAP_PREFIX + sName + "_0" + TYPE_SUFFIX) == ENTITY_TYPE_OBJECT ?
GetLocalObject(oStore, HEAP_PREFIX + sName + "_0" + ELEMENT_SUFFIX) :
OBJECT_INVALID;
}
string heap_get_string(object oStore, string sName){
return GetLocalInt(oStore, HEAP_PREFIX + sName + "_0" + TYPE_SUFFIX) == ENTITY_TYPE_STRING ?
GetLocalString(oStore, HEAP_PREFIX + sName + "_0" + ELEMENT_SUFFIX) :
"";
}
//void main(){}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,689 @@
/** @file
Log Message 1.06 - versatile send message wrapper function
by OldManWhistler
This script is available as a individual download on NWN Vault:
http://nwvault.ign.com/Files/scripts/data/1057281729727.shtml
Also check out my portfolio:
http://nwvault.ign.com/portfolios/data/1054937958.shtml
It is easiest to think of it as a wrapper for SendMessageToPC,
SendMessageToAllDMs, FloatingTextStringOnCreature, ActionSpeakString,
PrintString, and WriteTimeStampedLogEntry. You can use log message instead
of any of those functions.
The name is a misnomer, it is not a tool for "logging" text, rather a tool
for "sending" text. In retrospect I should have called it SendMessage instead
of LogMessage. My bad.
LogMessage is a generic function for sending a message to a target (PC, DM,
Party, Server log file). There is a parameter that controls how the function
will behave.
ie:
LogMessage (LOG_DISABLED, oPC, "Do nothing");
LogMessage (LOG_PC, oPC, "Send only to the oPC who activated it (floating text)");
LogMessage (LOG_PARTY, oPC, "Send to the oPC and all of their party members (floating text)");
LogMessage (LOG_PC | LOG_DM_ALL, oPC, "Send only to the oPC who activated it (floating text) and the DM channel");
LogMessage (LOG_DM_ALL, oPC, "Send to all the DMs on the server");
LogMessage (LOG_DM_20, oPC, "Send to all DMs within distance 20' of oPC");
LogMessage (LOG_TO_SERVER_LOG | LOG_PC, oPC, "Send only to the oPC who activated it (floating text) and the server log file");
LogMessage (LOG_TO_SERVER_LOG, oPC, "Send only to the server log file");
LogMessage (LOG_PARTY_PERC, oPC, "Send to oPC and all of their party members who can see them (floating text)");
LogMessage (LOG_PC_ALL, oPC, "Send to all players who have a local variable called 'Filter' with value 3", "Filter", 3);
I prefer using LogMessage because then I only have to remember one interface
for how to send a message instead of five. It is also useful because I can
make a message go multiple places just by bit wise ORing several constants
together. See more on bit wise operators:
http://www.reapers.org/nwn/reference/compiled/primer.BitwiseOperators.html
Note: Through one LogMessage function call you can send a string in any
combination of 30 different ways.
It is useful when you want to build a script that could either be used with a
persistent world or might be used with a single party and only one DM.
Say you write a script with several lines sending messages to the PCs using
SendMessageToPC and copying it on the DM channel using SendMessageToAllDMs.
Modifying your script would be a really big headache for the person trying to
use it with their PW, since the DM channel would be flooded by the actions of
the various players.
Instead of using SendMessageToPC and SendMessageToAllDMs you could write
your messages as:
LogMessage (MY_LOG, oPC, "blah blah blah");
and then have a section in your main include file that has:
#include "inc_LogMessage"
int MY_LOG = LOGPC | LOG_DM_40;
That way the person who is running a persistent world could set
MY_LOG as LOG_PC | LOG_DM_20 while the person who is running a single
party DMed game could set MY_LOG as LOG_PC | LOG_DM_ALL.
All they would have to do is change that value of the constant you used and
recompile the scripts and then it would work the way they wanted it to with
very little hassle.
The other benefit is when the person modifying your script wants to find
a specific string to change. All they have to do is do a FindInFiles and
search for LogMessage. FindInFiles will then generate a complete list of all
your strings and the filename/line number the string is generated on.
Using SetLocalInt to create filters:
There are optional parameters to the LogMessage function called sLocalFilter
and iLocalValue. The way these work is that they require the recipient of the
message to have a LocalInt called sLocalFilter with a value of iLocalValue.
ie:
I could put a local int on specific players with SetLocalInt(oPC, "Filter1", 4);
Then LogMessage(LOG_PC_ALL, "This is a filtered message.", "", "Filter1", 4)
would send that message only to the players who have
GetLocalInt(oPC, "Filter1") == 4.
The filter does not work for the following types of logs. They will always
work irregardless of the setting of the filter variable.
LOG_DM_ALL
LOG_TO_SERVER_LOG
LOG_TIME_SERVER_LOG
LOG_PARTY_30
Changelog:
1.01 -> 1.02
Changed LOG_TO_SERVER_LOG so it has no time stamp
Added LOG_PC_ALL, LOG_TIME_SERVER_LOG
Changed so that one LogMessage call could send several messages using
the bitwise OR operator.
1.02 -> 1.03
Added another parameter to LogMessage for a DM only message that is only
added to the DM channels and the server log channels.
1.03 -> 1.04
Fixed a bug with LOG_PARTY_SERVER that was sending all the messages to only
one player in the party instead of the entire party.
1.04 -> 1.05
Added local int filters to control who gets the message and who doesn't.
Added some more log types:
LOG_PARTY_10, LOG_PARTY_20, LOG_PARTY_40, LOG_PARTY_80
- like LOG_PARTY_30 except floating text is over the head of the person
- receiving the message.
LOG_DM_10_SERVER, LOG_DM_20_SERVER, LOG_DM_40_SERVER, LOG_DM_80_SERVER
- like LOG_DM_XX but with server messages instead of floating text.
LOG_PARTY_PERC, LOG_PARTY_PERC_SERVER
- like LOG_PARTY except it does a perception check to see if the party
member can see oPC.
1.05 -> 1.06
Added LOG_DM_ALL_SERVER
- like LOG_DM_ALL except it is sent as a server message instead of on DM channel
Added LOG_PARTY_ONLY
- Sends a server message to everyone in the party EXCEPT for the person who
triggered the message (oPC)
Added LOG_PARTY_PERC_ONLY
- Sends a server message to everyone in the party EXCEPT for the person who
triggered the message (oPC) and the members of the party who cannot perceive oPC
*/
// ****************************************************************************
// ** CONSTANTS
// ****************************************************************************
// Logging Level Constants - Do not change these values!
// Note: every constant is a multiple of 2. If you want to send something to
// multiple log locations then use the bitwise OR operator.
// ie: using "LOG_PC | LOG_DM_ALL" will send the message to the player and to
// the DM channel.
/// Do not send a message.
const int LOG_DISABLED = 0x0;
/// Send only to the oPC who activated it (floating text)
const int LOG_PC = 0x1;
/// Send only to the oPC who activated it (server message window)
const int LOG_PC_SERVER = 0x2;
/// Send to all players on the server (server message window)
const int LOG_PC_ALL = 0x4;
/// Send to the oPC and all of their party members (floating text)
const int LOG_PARTY = 0x8;
/// Send to the oPC and all of their party members (server message window)
const int LOG_PARTY_SERVER = 0x10;
/// Send to the oPC and their nearby (30m) party members (floating text)
const int LOG_PARTY_30 = 0x20;
/// Send to the DM channel (DM channel)
const int LOG_DM_ALL = 0x40;
/// Send to all DMs within distance 10m of oPC (floating text)
const int LOG_DM_10 = 0x80;
/// Send to all DMs within distance 20m of oPC (floating text)
const int LOG_DM_20 = 0x100;
/// Send to all DMs within distance 40m of oPC (floating text)
const int LOG_DM_40 = 0x200;
/// Send to all DMs within distance 80m of oPC (floating text)
const int LOG_DM_80 = 0x400;
/// Make oPC whisper the message (chat message window)
const int LOG_WHISPER = 0x800;
/// Make oPC talk the message (chat message window)
const int LOG_TALK = 0x1000;
/// Make oPC shout the message (chat message window)
const int LOG_SHOUT = 0x2000;
/// Send to the server log file
const int LOG_TO_SERVER_LOG = 0x4000;
/// Send to the server log file with time stamp
const int LOG_TIME_SERVER_LOG = 0x8000;
/// Send to all DMs within distance 10m of oPC (server message window)
const int LOG_DM_10_SERVER = 0x10000;
/// Send to all DMs within distance 20m of oPC (server message window)
const int LOG_DM_20_SERVER = 0x20000;
/// Send to all DMs within distance 40m of oPC (server message window)
const int LOG_DM_40_SERVER = 0x40000;
/// Send to all DMs within distance 80m of oPC (server message window)
const int LOG_DM_80_SERVER = 0x80000;
/// Send to the oPC and all of their party members who percieve oPC (floating text)
const int LOG_PARTY_PERC = 0x100000;
/// Send to the oPC and all of their party members who percieve oPC (server message window)
const int LOG_PARTY_PERC_SERVER = 0x200000;
/// Send to the oPC and their nearby (10m) party members (floating text)
const int LOG_PARTY_10 = 0x400000;
/// Send to the oPC and their nearby (20m) party members (floating text)
const int LOG_PARTY_20 = 0x800000;
/// Send to the oPC and their nearby (40m) party members (floating text)
const int LOG_PARTY_40 = 0x1000000;
/// Send to the oPC and their nearby (80m) party members (floating text)
const int LOG_PARTY_80 = 0x2000000;
/// Send to all DMs as a server message
const int LOG_DM_ALL_SERVER = 0x4000000;
/// Send to all party EXCEPT for the player who triggered as a server message
const int LOG_PARTY_ONLY = 0x8000000;
/// Send to all party EXCEPT for the player *and people who can't see the player) who triggered as a server message
const int LOG_PARTY_PERC_ONLY = 0x10000000;
// ****************************************************************************
// ** BACKWARDS COMPATIBILITY
// ****************************************************************************
// These globals exist purely for backwards compatibility with older versions
// of LogMessage. They aren't recommended.
/// Send only to the oPC who activated it (floating text) and the server log file
int LOG_FILE_PC = LOG_TO_SERVER_LOG | LOG_PC;
/// Send only to the oPC who activated it (server message window) and the server log file
int LOG_FILE_PC_SERVER = LOG_TO_SERVER_LOG | LOG_PC_SERVER;
/// Send to the oPC and all of their party members (floating text) and the server log file
int LOG_FILE_PARTY = LOG_TO_SERVER_LOG | LOG_PARTY;
/// Send to the oPC and all of their party members (server message window) and the server log file
int LOG_FILE_PARTY_SERVER = LOG_TO_SERVER_LOG | LOG_PARTY_SERVER;
/// Send to the oPC and their nearby (30m) faction members (floating text) and the server log file
int LOG_FILE_PARTY_30 = LOG_TO_SERVER_LOG | LOG_PARTY_30;
/// Send to the DM channel and the server log file
int LOG_FILE_DM_ALL = LOG_TO_SERVER_LOG | LOG_DM_ALL;
/// Send to all DMs within distance 10m of oPC and the server log file
int LOG_FILE_DM_10 = LOG_TO_SERVER_LOG | LOG_DM_10;
/// Send to all DMs within distance 20m of oPC and the server log file
int LOG_FILE_DM_20 = LOG_TO_SERVER_LOG | LOG_DM_20;
/// Send to all DMs within distance 40m of oPC and the server log file
int LOG_FILE_DM_40 = LOG_TO_SERVER_LOG | LOG_DM_40;
/// Send to all DMs within distance 80m of oPC and the server log file
int LOG_FILE_DM_80 = LOG_TO_SERVER_LOG | LOG_DM_80;
/// Make oPC whisper the message (chat message window) and the server log file
int LOG_FILE_WHISPER = LOG_TO_SERVER_LOG | LOG_WHISPER;
/// Make oPC talk the message (chat message window) and the server log file
int LOG_FILE_TALK = LOG_TO_SERVER_LOG | LOG_TALK;
/// Make oPC shout the message (chat message window) and the server log file
int LOG_FILE_SHOUT = LOG_TO_SERVER_LOG | LOG_SHOUT;
// ****************************************************************************
// ** CONSTANTS
// ****************************************************************************
// Set this to FALSE to include henchmen as part of the party for sending messages.
// Useful when trying to test MP messages when in SP.
const int LOG_MESSAGE_PARTY_PLAYERS_ONLY = TRUE;
// Set this to TRUE to debug how messages are being decoded.
const int LOG_MESSAGE_DEBUG = FALSE;
// Set this to TRUE to debug where messages are coming from.
const int LOG_MESSAGE_SOURCE_DEBUG = FALSE;
// This can be used to display which version of LogMessage you are using.
const string LOG_MESSAGE_VERSION = "LogMessage v1.06";
// ****************************************************************************
// ** FUNCTION DECLARATIONS
// ****************************************************************************
/**
* This function is used to a log a message in several different ways depending
* the value of iLogType.
*
* @param iLogType This is the level of logging to use. It should be one of the
* LOG_* constants.
* @param oPC This is the player who is triggering the log message.
* @param sMessage This is the message to be logged.
* @param sDMMessage This a message to be appended only for DM/log file messages.
* @param sLocalFilter The message will only be sent to people who have
* a LocalInt with this name and a specified value.
* @param iLocalValue The value the LocalInt must have.
*/
void LogMessage (int iLogType, object oPC, string sMessage, string sDMMessage = "", string sLocalFilter = "", int iLocalValue = 0);
/**
*
* This function is used to send a message to every player on the server using the
* server message window.
*
* @param oPC A member of the party to send the message to.
* @param sMessage The message to send.
* @param sLocalFilter The message will only be sent to people who have
* a LocalInt with this name and a specified value.
* @param iLocalValue The value the LocalInt must have.
*/
void SendMessageToAllPCs (string sMessage, string sLocalFilter = "", int iLocalValue = 0);
/**
* This function is used to send a message to every player in a party using the
* server message window.
*
* @param oPC A member of the party to send the message to.
* @param sMessage The message to send.
* @param bSkipOrigin Skip the player who originated the message.
* @param bPerceptionCheck If this is true, only send the message if the party member can see oPC.
* @param sLocalFilter The message will only be sent to people who have
* a LocalInt with this name and a specified value.
* @param iLocalValue The value the LocalInt must have.
*/
void SendMessageToParty (object oPC, string sMessage, int bSkipOrigin = FALSE, int bPerceptionCheck = FALSE, string sLocalFilter = "", int iLocalValue = 0);
/**
* This function is used to send a message to every player in a party using
* floating text.
*
* @param oPC A member of the party to send the message to.
* @param sMessage The message to send.
* @param bPerceptionCheck If this is true, only send the message if the party member can see oPC.
* @param sLocalFilter The message will only be sent to people who have
* a LocalInt with this name and a specified value.
* @param iLocalValue The value the LocalInt must have.
void FloatingTextStringOnParty (object oPC, string sMessage, int bPerceptionCheck = FALSE, string sLocalFilter = "", int iLocalValue = 0);
/**
* This function is used to send a message to every player in a party using
* floating text.
*
* @param oPC A member of the party to send the message to.
* @param iDistance The maximum distance the party member can be from oPC.
* @param sMessage The message to send.
* @param sLocalFilter The message will only be sent to people who have
* a LocalInt with this name and a specified value.
* @param iLocalValue The value the LocalInt must have.
*/
void FloatingTextStringOnPartyByDistance (object oPC, int iDistance, string sMessage, string sLocalFilter = "", int iLocalValue = 0);
/**
* This function is used to send a message to all of the DMs near a particular
* location.
*
* @param lLocation The center of the sphere to search for DMs.
* @param iDistance The maximum distance the DM can be from lLocation.
* @param sMessage The message to send.
* @param bFloating If TRUE, send as a floating text string, if FALSE, send as a server message.
* @param sLocalFilter The message will only be sent to people who have
* a LocalInt with this name and a specified value.
* @param iLocalValue The value the LocalInt must have.
*/
void SendMessageToDMsByDistance (location lLocation, int iDistance, string sMessage, int bFloating = TRUE, string sLocalFilter = "", int iLocalValue = 0);
// ****************************************************************************
// ** FUNCTION DEFINITIONS
// ****************************************************************************
void SendMessageToAllPCs (string sMessage, string sLocalFilter = "", int iLocalValue = 0)
{
object oPC = GetFirstPC();
while (GetIsObjectValid(oPC))
{
if ((sLocalFilter == "") ||
(GetLocalInt(oPC, sLocalFilter) == iLocalValue))
{
// Check for DM possessed NPCs.
if (!GetIsDM(GetMaster(oPC)))
SendMessageToPC(oPC, sMessage);
}
oPC = GetNextPC();
}
}
void SendMessageToParty (object oPC, string sMessage, int bSkipOrigin = FALSE, int bPerceptionCheck = FALSE, string sLocalFilter = "", int iLocalValue = 0)
{
object oParty = GetFirstFactionMember(oPC, LOG_MESSAGE_PARTY_PLAYERS_ONLY);
while ( GetIsObjectValid(oParty) )
{
if (
// if filter is not set, or filter is true
((sLocalFilter == "") ||
(GetLocalInt(oParty, sLocalFilter) == iLocalValue)) &&
// if perception check not set, or perception is true
((bPerceptionCheck == FALSE) ||
(GetObjectSeen(oPC, oParty) == TRUE)) &&
// if bSkipOrigin is not set, or this is not the originating player
((bSkipOrigin == FALSE) ||
(oPC != oParty))
)
{
SendMessageToPC(oParty, sMessage);
}
oParty = GetNextFactionMember(oPC, LOG_MESSAGE_PARTY_PLAYERS_ONLY);
}
return;
}
void FloatingTextStringOnParty (object oPC, string sMessage, int bPerceptionCheck = FALSE, string sLocalFilter = "", int iLocalValue = 0)
{
object oParty = GetFirstFactionMember(oPC, LOG_MESSAGE_PARTY_PLAYERS_ONLY);
while ( GetIsObjectValid(oParty) )
{
if (
// if filter is not set, or filter is true
((sLocalFilter == "") ||
(GetLocalInt(oParty, sLocalFilter) == iLocalValue)) &&
// if perception check not set, or perception is true
((bPerceptionCheck == FALSE) ||
(GetObjectSeen(oPC, oParty) == TRUE))
) {
FloatingTextStringOnCreature(sMessage, oParty, FALSE);
}
oParty = GetNextFactionMember(oPC, LOG_MESSAGE_PARTY_PLAYERS_ONLY);
}
return;
}
void FloatingTextStringOnPartyByDistance (object oPC, int iDistance, string sMessage, string sLocalFilter = "", int iLocalValue = 0)
{
float fMaxDist = IntToFloat(iDistance);
object oParty = GetFirstFactionMember(oPC, LOG_MESSAGE_PARTY_PLAYERS_ONLY);
while ( GetIsObjectValid(oParty) )
{
float fDistance = GetDistanceBetween(oPC, oParty);
if (
// if filter is not set, or filter is true
( (sLocalFilter == "") ||
(GetLocalInt(oParty, sLocalFilter) == iLocalValue) ) &&
// Check that the party member is close enough to the player
( (oParty == oPC) ||
( (fDistance > 0.0) && (fDistance <= fMaxDist) ) )
)
{
FloatingTextStringOnCreature(sMessage, oParty, FALSE);
}
oParty = GetNextFactionMember(oPC, LOG_MESSAGE_PARTY_PLAYERS_ONLY);
}
}
void SendMessageToDMsByDistance (location lLocation, int iDistance, string sMessage, int bFloating = TRUE, string sLocalFilter = "", int iLocalValue = 0)
{
object oDM;
// If distance is zero, then send the message to all DMs on the server
if (iDistance == 0)
{
oDM = GetFirstPC();
while (GetIsObjectValid(oDM))
{
if ((sLocalFilter == "") ||
(GetLocalInt(oDM, sLocalFilter) == iLocalValue))
{
// Note: DM possessed NPCs do not return TRUE for GetIsPC anymore.
if ( GetIsDM(oDM) || GetIsDMPossessed(oDM) )
{
if (bFloating) FloatingTextStringOnCreature(sMessage, oDM, FALSE);
else SendMessageToPC(oDM, sMessage);
}
}
oDM = GetNextPC();
}
return;
}
// Normal operation
float fSize = IntToFloat(iDistance);
// Using ObjectInShape with CREATURE only catches DMs possessing NPCs but not DM avatars.
oDM = GetFirstObjectInShape (SHAPE_SPHERE, fSize, lLocation, FALSE, OBJECT_TYPE_ALL);
while ( GetIsObjectValid(oDM) )
{
if ((sLocalFilter == "") ||
(GetLocalInt(oDM, sLocalFilter) == iLocalValue))
{
if ( GetIsDM(oDM) || GetIsDMPossessed(oDM) )
{
if (bFloating) FloatingTextStringOnCreature(sMessage, oDM, FALSE);
else SendMessageToPC(oDM, sMessage);
}
}
oDM = GetNextObjectInShape (SHAPE_SPHERE, fSize, lLocation, FALSE, OBJECT_TYPE_ALL);
}
return;
}
void LogMessage (int iLogType, object oPC, string sMessage, string sDMMessage = "", string sLocalFilter = "", int iLocalValue = 0)
{
object oParty;
object oArea;
object oDM;
int iDistance = 0;
if (LOG_MESSAGE_SOURCE_DEBUG) SpeakString("Debug: "+GetName(OBJECT_SELF)+" in area: "+GetName(GetArea(OBJECT_SELF))+" is originating "+IntToHexString(iLogType)+" type log message: "+sMessage, TALKVOLUME_SHOUT);
// Handle the various different types of log levels.
// Messages that do not require oPC to be valid.
if (iLogType & LOG_DISABLED)
return;
if (iLogType & LOG_PC_ALL)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_PC_ALL");
// Does not use the sLocalFilter because oPC does not have to
// be valid.
SendMessageToAllPCs(sMessage, sLocalFilter, iLocalValue);
}
if (iLogType & LOG_DM_ALL)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_DM_ALL");
// Does not use the sLocalFilter because oPC does not have to
// be valid.
SendMessageToAllDMs(sMessage + " " + sDMMessage);
}
if (iLogType & LOG_DM_ALL_SERVER)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_DM_ALL_SERVER");
// Does not use the sLocalFilter because oPC does not have to
// be valid.
SendMessageToDMsByDistance (GetLocation(OBJECT_SELF), 0, sMessage + " " + sDMMessage, FALSE, sLocalFilter, iLocalValue);
}
if (iLogType & LOG_TO_SERVER_LOG)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_TO_SERVER_LOG");
// Does not use the sLocalFilter because oPC does not have to
// be valid.
PrintString(sMessage + " " + sDMMessage);
}
if (iLogType & LOG_TIME_SERVER_LOG)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_TIME_SERVER_LOG");
// Does not use the sLocalFilter because oPC does not have to
// be valid.
WriteTimestampedLogEntry(sMessage + " " + sDMMessage);
}
// Messages that do require oPC to be valid.
if (GetIsObjectValid(oPC))
{
if (iLogType & LOG_PC)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_PC");
if ((sLocalFilter == "") ||
(GetLocalInt(oPC, sLocalFilter) == iLocalValue))
{
FloatingTextStringOnCreature(sMessage, oPC, FALSE);
}
}
if (iLogType & LOG_PC_SERVER)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_PC_SERVER");
if ((sLocalFilter == "") ||
(GetLocalInt(oPC, sLocalFilter) == iLocalValue))
{
SendMessageToPC(oPC, sMessage);
}
}
if (iLogType & LOG_PARTY)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_PARTY");
FloatingTextStringOnParty(oPC, sMessage, FALSE, sLocalFilter, iLocalValue);
}
if (iLogType & LOG_PARTY_ONLY)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_PARTY_ONLY");
SendMessageToParty(oPC, sMessage, TRUE, FALSE, sLocalFilter, iLocalValue);
}
if (iLogType & LOG_PARTY_10)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_PARTY_10");
FloatingTextStringOnPartyByDistance(oPC, 10, sMessage, sLocalFilter, iLocalValue);
}
if (iLogType & LOG_PARTY_20)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_PARTY_20");
FloatingTextStringOnPartyByDistance(oPC, 20, sMessage, sLocalFilter, iLocalValue);
}
if (iLogType & LOG_PARTY_40)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_PARTY_40");
FloatingTextStringOnPartyByDistance(oPC, 40, sMessage, sLocalFilter, iLocalValue);
}
if (iLogType & LOG_PARTY_80)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_PARTY_80");
FloatingTextStringOnPartyByDistance(oPC, 80, sMessage, sLocalFilter, iLocalValue);
}
if (iLogType & LOG_PARTY_SERVER)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_PARTY_SERVER");
SendMessageToParty(oPC, sMessage, FALSE, FALSE, sLocalFilter, iLocalValue);
}
if (iLogType & LOG_PARTY_PERC)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_PARTY_PERC");
FloatingTextStringOnParty(oPC, sMessage, TRUE, sLocalFilter, iLocalValue);
}
if (iLogType & LOG_PARTY_PERC_ONLY)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_PARTY_ONLY_PERC");
SendMessageToParty(oPC, sMessage, TRUE, TRUE, sLocalFilter, iLocalValue);
}
if (iLogType & LOG_PARTY_PERC_SERVER)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_PARTY_PERC_SERVER");
SendMessageToParty(oPC, sMessage, FALSE, TRUE, sLocalFilter, iLocalValue);
}
if (iLogType & LOG_PARTY_30)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_PARTY_30");
// Note: does not use sLocalFilter
FloatingTextStringOnCreature(sMessage, oPC, TRUE);
}
if (iLogType & LOG_DM_10)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_DM_10");
SendMessageToDMsByDistance(GetLocation(oPC), 10, sMessage + " " + sDMMessage, TRUE, sLocalFilter, iLocalValue);
}
if (iLogType & LOG_DM_20)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_DM_20");
SendMessageToDMsByDistance(GetLocation(oPC), 20, sMessage + " " + sDMMessage, TRUE, sLocalFilter, iLocalValue);
}
if (iLogType & LOG_DM_40)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_DM_40");
SendMessageToDMsByDistance(GetLocation(oPC), 40, sMessage + " " + sDMMessage, TRUE, sLocalFilter, iLocalValue);
}
if (iLogType & LOG_DM_80)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_DM_80");
SendMessageToDMsByDistance(GetLocation(oPC), 80, sMessage + " " + sDMMessage, TRUE, sLocalFilter, iLocalValue);
}
if (iLogType & LOG_DM_10_SERVER)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_DM_10_SERVER");
SendMessageToDMsByDistance(GetLocation(oPC), 10, sMessage + " " + sDMMessage, FALSE, sLocalFilter, iLocalValue);
}
if (iLogType & LOG_DM_20_SERVER)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_DM_20_SERVER");
SendMessageToDMsByDistance(GetLocation(oPC), 20, sMessage + " " + sDMMessage, FALSE, sLocalFilter, iLocalValue);
}
if (iLogType & LOG_DM_40_SERVER)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_DM_40_SERVER");
SendMessageToDMsByDistance(GetLocation(oPC), 40, sMessage + " " + sDMMessage, FALSE, sLocalFilter, iLocalValue);
}
if (iLogType & LOG_DM_80_SERVER)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_DM_80_SERVER");
SendMessageToDMsByDistance(GetLocation(oPC), 80, sMessage + " " + sDMMessage, FALSE, sLocalFilter, iLocalValue);
}
if (iLogType & LOG_WHISPER)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_WHISPER");
if ((sLocalFilter == "") ||
(GetLocalInt(oPC, sLocalFilter) == iLocalValue))
{
AssignCommand(oPC, ActionSpeakString(sMessage, TALKVOLUME_WHISPER));
}
}
if (iLogType & LOG_TALK)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_TALK");
if ((sLocalFilter == "") ||
(GetLocalInt(oPC, sLocalFilter) == iLocalValue))
{
AssignCommand(oPC, ActionSpeakString(sMessage, TALKVOLUME_TALK));
}
}
if (iLogType & LOG_SHOUT)
{
if (LOG_MESSAGE_DEBUG) SendMessageToPC(oPC, "LOG_SHOUT");
if ((sLocalFilter == "") ||
(GetLocalInt(oPC, sLocalFilter) == iLocalValue))
{
AssignCommand(oPC, ActionSpeakString(sMessage, TALKVOLUME_SHOUT));
}
}
}
return;
}

598
src/include/inc_lookups.nss Normal file
View File

@@ -0,0 +1,598 @@
/*
This file is used for lookup functions for psionics and newspellbooks
It is supposed to reduce the need for large loops that may result in
TMI errors.
It does this by creating arrays in advance and the using those as direct
lookups.
*/
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
void MakeLookupLoop(int nClass, string sFile, int nMin, int nMax, int nLoopSize = 100, string sTemp = "");
void SetupLookupStage(object oMod, int n);
//this returns the real SpellID of "wrapper" spells cast by psionic or the new spellbooks
int GetPowerFromSpellID(int nSpellID);
/**
* Maps spells.2da rows of the class-specific entries to corresponding cls_psipw_*.2da rows.
*
* @param nSpellID Spells.2da row to determine cls_psipw_*.2da row for
* @return The mapped value
*/
int GetPowerfileIndexFromSpellID(int nSpellID);
/**
* Maps spells.2da rows of the real entries to corresponding cls_psipw_*.2da rows.
*
* @param nSpellID Spells.2da row to determine cls_psipw_*.2da row for
* @return The mapped value
*/
int GetPowerfileIndexFromRealSpellID(int nRealSpellID);
//this retuns the featID of the class-specific feat for a spellID
//useful for psionics GetHasPower function
int GetClassFeatFromPower(int nPowerID, int nClass);
/**
* Determines cls_spell_*.2da index from a given new spellbook class-specific
* spell spells.2da index.
*
* @param nSpell The class-specific spell to find cls_spell_*.2da index for
* @return The cls_spell_*.2da index in whichever class's file that the
* given spell belongs to.
* If the spell at nSpell isn't a newspellbook class-specific spell,
* returns -1 instead.
*/
int SpellToSpellbookID(int nSpell);
/**
* Determines cls_spell_*.2da index from a given spells.2da index.
*
* @param nClass The class in whose spellbook to search in
* @param nSpell The spell to search for
* @return The cls_spell_*.2da index in whichever class's file that the
* given spell belongs to.
* If nSpell does not exist within the spellbook,
* returns -1 instead.
*/
int RealSpellToSpellbookID(int nClass, int nSpell);
/**
* Determines number of metamagics from a given spells.2da index.
*
* @param nClass The class in whose spellbook to search in
* @param nSpell The spell to search for
* @return The number of metamagics in cls_spell_*.2da
* for a particular spell.
*/
int RealSpellToSpellbookIDCount(int nClass, int nSpell);
/**
* Determines the name of the 2da file that defines the number of alternate magic
* system powers/spells/whathaveyou known, maximum level of such known and
* number of uses at each level of the given class. And possibly related things
* that apply to that specific system.
*
* @param nClass CLASS_TYPE_* of the class to determine the powers known 2da name of
* @return The name of the given class's powers known 2da
*/
string GetAMSKnownFileName(int nClass);
/**
* Determines the name of the 2da file that lists the powers/spells/whathaveyou
* on the given class's list of such.
*
* @param nClass CLASS_TYPE_* of the class to determine the power list 2da name of
* @return The name of the given class's power list 2da
*/
string GetAMSDefinitionFileName(int nClass);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
#include "inc_2dacache"
#include "prc_inc_array"
#include "prc_class_const"
//////////////////////////////////////////////////
/* Internal functions */
//////////////////////////////////////////////////
object _inc_lookups_GetCacheObject(string sTag)
{
object oWP = GetObjectByTag(sTag);
if(!GetIsObjectValid(oWP))
{
object oChest = GetObjectByTag("Bioware2DACache");
if(!GetIsObjectValid(oChest))
{
//has to be an object, placeables cant go through the DB
oChest = CreateObject(OBJECT_TYPE_CREATURE, "prc_2da_cache",
GetLocation(GetObjectByTag("HEARTOFCHAOS")), FALSE, "Bioware2DACache");
}
if(!GetIsObjectValid(oChest))
{
//has to be an object, placeables cant go through the DB
oChest = CreateObject(OBJECT_TYPE_CREATURE, "prc_2da_cache",
GetStartingLocation(), FALSE, "Bioware2DACache");
}
int nContainer = 0;
string sContainerName = "Bio2DACacheTokenContainer_Lkup_";
object oContainer = GetObjectByTag(sContainerName + IntToString(nContainer));
// Find last existing container
if(GetIsObjectValid(oContainer))
{
nContainer = GetLocalInt(oContainer, "ContainerCount");
oContainer = GetObjectByTag(sContainerName + IntToString(nContainer));
// Make sure it's not full
if(GetLocalInt(oContainer, "NumTokensInside") >= 34) // Container has 35 slots. Attempt to not use them all, just in case
{
oContainer = OBJECT_INVALID;
++nContainer; // new container is 1 higher than last one
}
}
// We need to create a container
if(!GetIsObjectValid(oContainer))
{
oContainer = CreateObject(OBJECT_TYPE_ITEM, "nw_it_contain001", GetLocation(oChest), FALSE, sContainerName + IntToString(nContainer));
DestroyObject(oContainer);
oContainer = CopyObject(oContainer, GetLocation(oChest), oChest, sContainerName + IntToString(nContainer));
// store the new number of containers in this series
if(nContainer)
SetLocalInt(GetObjectByTag(sContainerName + "0"), "ContainerCount", nContainer);
// else this is the first container - do nothing as this is the same as storing 0 on it.
// Also here we still have 2 objects with the same tag so above code may get
// the object destroyed at the end of the function if this is the first container.
}
// Create the new token
oWP = CreateItemOnObject("hidetoken", oContainer, 1, sTag);
// Increment token count tracking variable
SetLocalInt(oContainer, "NumTokensInside", GetLocalInt(oContainer, "NumTokensInside") + 1);
}
if(!GetIsObjectValid(oWP))
{
DoDebug("ERROR: Failed to create lookup storage token for " + sTag);
return OBJECT_INVALID;
}
return oWP;
}
void SetLkupStage(int nStage, object oModule, int nClass, string sFile)
{
SetLocalInt(oModule, "PRCLookup_Stage", nStage + 1);
SetLocalInt(oModule, "PRCLookup_Class", nClass);
SetLocalString(oModule, "PRCLookup_File", sFile);
}
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
void RunLookupLoop()
{
// check if we run lookup before
if(GetXP(GetObjectByTag("Bioware2DACache")) & 0x01)
{
if (DEBUG) DoDebug("RunLookupLoop() - marker found - exiting");
return;
}
object oModule = GetModule();
SetupLookupStage(oModule, 1);
int nClass = GetLocalInt(oModule, "PRCLookup_Class");
string sFile = GetLocalString(oModule, "PRCLookup_File");
if (DEBUG) DoDebug("RunLookupLoop(): Looking in "+sFile+" for nClass "+IntToString(nClass));
MakeLookupLoop(nClass, sFile, 1, PRCGetDynamicFileEnd(sFile));
}
void RunNextLoop()
{
object oModule = GetModule();
int nStage = GetLocalInt(oModule, "PRCLookup_Stage");
SetupLookupStage(oModule, nStage);
int nClass = GetLocalInt(oModule, "PRCLookup_Class");
if(nClass)
{
string sFile = GetLocalString(oModule, "PRCLookup_File");
if (DEBUG) DoDebug("RunNextLoop(): Looking in "+sFile+" for nClass "+IntToString(nClass));
MakeLookupLoop(nClass, sFile, 1, PRCGetDynamicFileEnd(sFile));
}
else
{
DeleteLocalInt(oModule, "PRCLookup_Stage");
DeleteLocalInt(oModule, "PRCLookup_Class");
DeleteLocalString(oModule, "PRCLookup_File");
//mark lookup as done, tell hb to save the DB
object oCache = GetObjectByTag("Bioware2DACache");
SetXP(oCache, GetXP(oCache) | 0x01);
SetLocalInt(oModule, "Bioware2dacacheCount", GetPRCSwitch(PRC_USE_BIOWARE_DATABASE) - 5);
}
}
void SetupLookupStage(object oMod, int n)
{
switch(n)
{
case 1: SetLkupStage(n, oMod, CLASS_TYPE_PSION, "cls_psipw_psion"); break;
case 2: SetLkupStage(n, oMod, CLASS_TYPE_PSYWAR, "cls_psipw_psywar"); break;
case 3: SetLkupStage(n, oMod, CLASS_TYPE_WILDER, "cls_psipw_wilder"); break;
case 4: SetLkupStage(n, oMod, CLASS_TYPE_FIST_OF_ZUOKEN, "cls_psipw_foz"); break;
case 5: SetLkupStage(n, oMod, CLASS_TYPE_WARMIND, "cls_psipw_warmnd"); break;
case 6: SetLkupStage(n, oMod, CLASS_TYPE_TRUENAMER, "cls_true_utter"); break;
case 7: SetLkupStage(n, oMod, CLASS_TYPE_CRUSADER, "cls_move_crusdr"); break;
case 8: SetLkupStage(n, oMod, CLASS_TYPE_SWORDSAGE, "cls_move_swdsge"); break;
case 9: SetLkupStage(n, oMod, CLASS_TYPE_WARBLADE, "cls_move_warbld"); break;
case 10: SetLkupStage(n, oMod, CLASS_TYPE_DRAGONFIRE_ADEPT, "cls_inv_dfa"); break;
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 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;
//case 29: SetLkupStage(n, oMod, CLASS_TYPE_SLAYER_OF_DOMIEL, "cls_spell_sod"); break;
//case 29: SetLkupStage(n, oMod, CLASS_TYPE_SOHEI, "cls_spell_sohei"); break;
//case 33: SetLkupStage(n, oMod, CLASS_TYPE_VASSAL, "cls_spell_vassal"); break;
//case 17: SetLkupStage(n, oMod, CLASS_TYPE_BLACKGUARD, "cls_spell_blkgrd"); break;
//case 24: SetLkupStage(n, oMod, CLASS_TYPE_KNIGHT_CHALICE, "cls_spell_kchal"); break;
//case 25: SetLkupStage(n, oMod, CLASS_TYPE_KNIGHT_MIDDLECIRCLE, "cls_spell_kotmc"); break;
//case 26: SetLkupStage(n, oMod, CLASS_TYPE_SOLDIER_OF_LIGHT, "cls_spell_sol"); break;
//case 24: SetLkupStage(n, oMod, CLASS_TYPE_OCULAR, "cls_spell_ocu"); break;
//case 30: SetLkupStage(n, oMod, CLASS_TYPE_BLIGHTER, "cls_spell_blight"); break;
//case 21: SetLkupStage(n, oMod, CLASS_TYPE_HEALER, "cls_spell_healer"); break;
//case 23: SetLkupStage(n, oMod, CLASS_TYPE_SHAMAN, "cls_spell_shaman"); break;
default: SetLkupStage(n, oMod, 0, ""); break;
}
}
/*
void LookupSpells(int nRealSpellID, string sClass, string sLevel);
{
int nDescriptor = Get2DACache("prc_spells", "Descriptor", nRealSpellID);//should already be in cache, just read the value
DESCRIPTOR_ACID
DESCRIPTOR_AIR
DESCRIPTOR_COLD
DESCRIPTOR_LIGHT
DESCRIPTOR_ELECTRICITY
DESCRIPTOR_DARKNESS
DESCRIPTOR_FIRE
DESCRIPTOR_SONIC
SUBSCHOOL_HEALING
SUBSCHOOL_SUMMONING
SUBSCHOOL_POLYMORPH
SPELL_SCHOOL_ENCHANTMENT
SPELL_SCHOOL_NECROMANCY
SPELL_SCHOOL_ABJURATION
string sLevel = Get2DACache("spells", "Cleric", nRealSpellID);
if(sLevel != "")
{
oLevelToken = _inc_lookups_GetCacheObject("SpellLvl_2_Level_"+sLevel);
// check if array exist, if not create one
if(!array_exists(oLevelToken, "Lkup"))
array_create(oLevelToken, "Lkup");
array_set_int(oLevelToken, "Lkup", array_get_size(oLevelToken, "Lkup"), i);
}
sLevel = Get2DACache("spells", "Druid", nRealSpellID);
if(sLevel != "")
{
oLevelToken = _inc_lookups_GetCacheObject("SpellLvl_3_Level_"+sLevel);
// check if array exist, if not create one
if(!array_exists(oLevelToken, "Lkup"))
array_create(oLevelToken, "Lkup");
array_set_int(oLevelToken, "Lkup", array_get_size(oLevelToken, "Lkup"), i);
}
sLevel = Get2DACache("spells", "Paladin", nRealSpellID);
if(sLevel != "")
{
oLevelToken = _inc_lookups_GetCacheObject("SpellLvl_6_Level_"+sLevel);
// check if array exist, if not create one
if(!array_exists(oLevelToken, "Lkup"))
array_create(oLevelToken, "Lkup");
array_set_int(oLevelToken, "Lkup", array_get_size(oLevelToken, "Lkup"), i);
}
sLevel = Get2DACache("spells", "Ranger", nRealSpellID);
if(sLevel != "")
{
oLevelToken = _inc_lookups_GetCacheObject("SpellLvl_7_Level_"+sLevel);
// check if array exist, if not create one
if(!array_exists(oLevelToken, "Lkup"))
array_create(oLevelToken, "Lkup");
array_set_int(oLevelToken, "Lkup", array_get_size(oLevelToken, "Lkup"), i);
}
sLevel = Get2DACache("spells", "Wiz_Sorc", nRealSpellID);
if(sLevel != "")
{
oLevelToken = _inc_lookups_GetCacheObject("SpellLvl_10_Level_"+sLevel);
// check if array exist, if not create one
if(!array_exists(oLevelToken, "Lkup"))
array_create(oLevelToken, "Lkup");
array_set_int(oLevelToken, "Lkup", array_get_size(oLevelToken, "Lkup"), i);
}
*/
void MakeLookupLoop(int nClass, string sFile, int nMin, int nMax, int nLoopSize = 100, string sTemp = "")
{
// Tell the function to skip before reaching nMax
int bSkipLoop = FALSE;
int i;
if(DEBUG) DoDebug("MakeLookupLoop("
+IntToString(nClass)+", "
+sFile+", "
+IntToString(nMin)+", "
+IntToString(nMax)+", "
+IntToString(nLoopSize)+", "
+") : sTemp = "+sTemp);
// psionic, tob, truenameing and ivocation using classes have slightly different handling
// new AMS classes should be added here
int bAMS = FALSE;
if(nClass == CLASS_TYPE_PSION
|| nClass == CLASS_TYPE_PSYWAR
|| nClass == CLASS_TYPE_PSYCHIC_ROGUE
|| nClass == CLASS_TYPE_WILDER
|| nClass == CLASS_TYPE_FIST_OF_ZUOKEN
|| nClass == CLASS_TYPE_WARMIND
|| nClass == CLASS_TYPE_CRUSADER
|| nClass == CLASS_TYPE_SWORDSAGE
|| nClass == CLASS_TYPE_WARBLADE
|| nClass == CLASS_TYPE_TRUENAMER
|| nClass == CLASS_TYPE_SHADOWCASTER
|| nClass == CLASS_TYPE_SHADOWSMITH
|| nClass == CLASS_TYPE_DRAGONFIRE_ADEPT
|| nClass == CLASS_TYPE_DRAGON_SHAMAN
|| nClass == CLASS_TYPE_WARLOCK)
bAMS = TRUE;
object oSpellIDToken = bAMS ? _inc_lookups_GetCacheObject("PRC_SpellIDToClsPsipw"):
_inc_lookups_GetCacheObject("PRC_GetRowFromSpellID");
// Failed to obtain a valid token - nothing to store on
if(!GetIsObjectValid(oSpellIDToken))
bSkipLoop = TRUE;
// Starting a new run and the data is present already. Assume the whole thing is present and abort
if(nMin == 1
&& GetLocalInt(oSpellIDToken, Get2DACache(sFile, "SpellID", 1)))
{
if(DEBUG) DoDebug("MakeLookupLoop("+sFile+") restored from database");
bSkipLoop = TRUE;
}
if(!bSkipLoop)
{
string sClass = IntToString(nClass);
object oLevelToken;
object oPowerToken = _inc_lookups_GetCacheObject("PRC_GetPowerFromSpellID");
object oRealSpellIDToken = bAMS ? _inc_lookups_GetCacheObject("PRC_GetClassFeatFromPower_"+sClass):
_inc_lookups_GetCacheObject("PRC_GetRowFromRealSpellID");
int nRealSpellID, nFeatID, nCount;
string sSpellID, sRealSID;
for(i = nMin; i < nMin + nLoopSize; i++)
{
// None of the relevant 2da files have blank Label entries on rows other than 0. We can assume i is greater than 0 at this point
if(Get2DAString(sFile, "Label", i) == "") // Using Get2DAString() instead of Get2DACache() to avoid caching useless data
{
bSkipLoop = TRUE;
break;// exit the loop
}
sSpellID = Get2DACache(sFile, "SpellID", i);
sRealSID = Get2DACache(sFile, "RealSpellID", i);
nRealSpellID = StringToInt(sRealSID);
//GetPowerfileIndexFromSpellID
//SpellToSpellbookID
SetLocalInt(oSpellIDToken, sSpellID, i);
//GetPowerfileIndexFromRealSpellID
SetLocalInt(oSpellIDToken, sRealSID, i);
//GetPowerFromSpellID
SetLocalInt(oPowerToken, sSpellID, nRealSpellID);
//Spell level lookup
if(!bAMS || nClass == CLASS_TYPE_WARLOCK)
{
string sReqFt = bAMS ? "" : Get2DACache(sFile, "ReqFeat", i);// Only new spellbooks have the ReqFeat column. No sense in caching it for other stuff
if(sReqFt == "")
{
string sLevel = Get2DACache(sFile, "Level", i);
oLevelToken = _inc_lookups_GetCacheObject("SpellLvl_"+sClass+"_Level_"+sLevel);
// check if array exist, if not create one
if(!array_exists(oLevelToken, "Lkup"))
array_create(oLevelToken, "Lkup");
array_set_int(oLevelToken, "Lkup", array_get_size(oLevelToken, "Lkup"), i);
//LookupSpellDescriptor(nRealSpellID, sClass, sLevel);
}
}
//GetClassFeatFromPower
if(bAMS)
{
nFeatID = StringToInt(Get2DACache(sFile, "FeatID", i));
if(nFeatID != 0)
{
SetLocalInt(oRealSpellIDToken, sRealSID, nFeatID);
}
}
//RealSpellToSpellbookID
//RealSpellToSpellbookIDCount
else
{
if(sRealSID == sTemp)
{
nCount += 1;
continue;
}
else
{
SetLocalInt(oRealSpellIDToken, sClass+"_"+sTemp+"_Count", nCount);
SetLocalInt(oRealSpellIDToken, sClass+"_"+sRealSID+"_Start", i);
sTemp = sRealSID;
nCount = 0;
}
}
}
}
// And delay continuation to avoid TMI
if(i < nMax && !bSkipLoop)
DelayCommand(0.0, MakeLookupLoop(nClass, sFile, i, nMax, nLoopSize, sTemp));
else
DelayCommand(0.0, RunNextLoop());
}
int GetPowerFromSpellID(int nSpellID)
{
object oWP = GetObjectByTag("PRC_GetPowerFromSpellID");
int nPower = GetLocalInt(oWP, /*"PRC_GetPowerFromSpellID_" + */IntToString(nSpellID));
if(nPower == 0)
nPower = -1;
return nPower;
}
int GetPowerfileIndexFromSpellID(int nSpellID)
{
object oWP = GetObjectByTag("PRC_SpellIDToClsPsipw");
int nIndex = GetLocalInt(oWP, /*"PRC_SpellIDToClsPsipw_" + */IntToString(nSpellID));
return nIndex;
}
int GetPowerfileIndexFromRealSpellID(int nRealSpellID)
{
object oWP = GetObjectByTag("PRC_SpellIDToClsPsipw");
int nIndex = GetLocalInt(oWP, /*"PRC_SpellIDToClsPsipw_" + */IntToString(nRealSpellID));
return nIndex;
}
int GetClassFeatFromPower(int nPowerID, int nClass)
{
string sLabel = "PRC_GetClassFeatFromPower_" + IntToString(nClass);
object oWP = GetObjectByTag(sLabel);
int nPower = GetLocalInt(oWP, /*sLabel+"_" + */IntToString(nPowerID));
if(nPower == 0)
nPower = -1;
return nPower;
}
int SpellToSpellbookID(int nSpell)
{
object oWP = GetObjectByTag("PRC_GetRowFromSpellID");
int nOutSpellID = GetLocalInt(oWP, /*"PRC_GetRowFromSpellID_" + */IntToString(nSpell));
if(nOutSpellID == 0)
nOutSpellID = -1;
//if(DEBUG) DoDebug("SpellToSpellbookID(" + IntToString(nSpell) + ", " + sFile + ") = " + IntToString(nOutSpellID));
return nOutSpellID;
}
int RealSpellToSpellbookID(int nClass, int nSpell)
{
object oWP = GetObjectByTag("PRC_GetRowFromRealSpellID");
int nOutSpellID = GetLocalInt(oWP, IntToString(nClass) + "_" + IntToString(nSpell) + "_Start");
if(nOutSpellID == 0)
nOutSpellID = -1;
return nOutSpellID;
}
int RealSpellToSpellbookIDCount(int nClass, int nSpell)
{
return GetLocalInt(GetObjectByTag("PRC_GetRowFromRealSpellID"), IntToString(nClass) + "_" + IntToString(nSpell) + "_Count");
}
string GetAMSKnownFileName(int nClass)
{
// Get the class-specific base
string sFile = Get2DACache("classes", "FeatsTable", nClass);
// Various naming schemes based on system
if(nClass == CLASS_TYPE_TRUENAMER)
sFile = "cls_true_known";
// ToB
else if(nClass == CLASS_TYPE_CRUSADER || nClass == CLASS_TYPE_SWORDSAGE || nClass == CLASS_TYPE_WARBLADE)
sFile = "cls_mvkn" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061210
// Shadowcasting
else if(nClass == CLASS_TYPE_SHADOWCASTER || nClass == CLASS_TYPE_SHADOWSMITH)
sFile = "cls_mykn" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061210
// Invocations
else if(nClass == CLASS_TYPE_DRAGONFIRE_ADEPT || nClass == CLASS_TYPE_WARLOCK || nClass == CLASS_TYPE_DRAGON_SHAMAN)
sFile = "cls_invkn" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061210
// Assume psionics if no other match
else
sFile = "cls_psbk" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061210
return sFile;
}
string GetAMSDefinitionFileName(int nClass)
{
// Get the class-specific base
string sFile = Get2DACache("classes", "FeatsTable", nClass);
// Various naming schemes based on system
if(nClass == CLASS_TYPE_TRUENAMER)
sFile = "cls_true_utter";
// ToB
else if(nClass == CLASS_TYPE_CRUSADER || nClass == CLASS_TYPE_SWORDSAGE || nClass == CLASS_TYPE_WARBLADE)
sFile = "cls_move" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061210
// Shadowcasting
else if(nClass == CLASS_TYPE_SHADOWCASTER || nClass == CLASS_TYPE_SHADOWSMITH)
sFile = "cls_myst" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061210
// Invoc
else if(nClass == CLASS_TYPE_DRAGONFIRE_ADEPT || nClass == CLASS_TYPE_WARLOCK || nClass == CLASS_TYPE_DRAGON_SHAMAN)
sFile = "cls_inv" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061210
// Assume psionics if no other match
else
sFile = "cls_psipw" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061210
return sFile;
}
// Test main
//void main(){}

View File

@@ -0,0 +1,618 @@
//::///////////////////////////////////////////////
//:: Metalocation include
//:: inc_metalocation
//:://////////////////////////////////////////////
/** @file
A metalocation is intended for reliable (independent
of object locations in memory) storage of location
data across module boundaries for possible eventual
re-entry to the same module. For example, to
carry location data over server resets.
This file specifies the metalocation structure,
which contains data equivalent to a standard
location, and in addition name of the module the
metalocation resides in and, if defined, the name
of the metalocation.
The area reference is built of two strings and
two integers instead of a memory pointer.
First string specifies the tag of the area containing
the metalocation. The second string specifies the name
of the area and the integers specify it's height and
width. They are used obtain exact match in cases where
there are several areas with the same tag.
The metalocation invariant:
All valid metalocations are such that they may be
uniquely matched to a location.
That is, a valid metalocation is one where the area
can be identified will full certainty using the
tag, name, height and width of the area.
In addition, this file contains a group of functions
for abstracted handling of metalocation data.
@author Ornedan
@date Created - 23.05.2005
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* A dismantled version of location with some metadata attached.
* Intended for use of persistent storage of location data over
* module boundaries. For example over server resets
*/
struct metalocation{
/// Tag of the area the location is in.
string sAreaTag;
/*
/// Resref of the area the location is in. Used to differentiate between
/// areas with the same tag.
string sAreaResRef;
*/
/// Name of the area. Used to differentiate between areas with the same tag.
string sAreaName;
/// Height of the area, in tiles. Used if tag and name are not enough to
/// uniquely identify an area.
int nAreaHeight;
/// Width of the area, in tiles. Used if tag and name are not enough to
/// uniquely identify an area.
int nAreaWidth;
/// The X coordinate of the location within the area.
float fX;
/// The Y coordinate of the location within the area.
float fY;
/// The Z coordinate of the location within the area.
float fZ;
/// The direction the location is facing.
float fFacing;
/// The metalocation may be named and the name is stored in this member.
string sName;
/// Name of the module containing the location.
string sModule;
};
/**
* Converts a standard location to equivalent metalocation. If area of the
* location cannot be uniquely identified using it's tag, name, height and
* width, a null metalocation is returned to preserve invariant of all
* valid metalocations being uniquely identifiable.
*
* @param locL The location to convert.
* @param sName The name of the created metalocation, if any.
* @return The metalocation created from locL. Or a null
* metalocation on failure.
*/
struct metalocation LocationToMetalocation(location locL, string sName = "");
/**
* Convert a metalocation to equivalent standard location.
*
* NOTE!
* If the metalocation is not in current module, the current module's starting
* location will be returned. As such, it is recommended that you run
* GetIsMetalocationInModule() on the metalocation before using this.
*
* If the metalocation is not valid, the returned location will also
* not be valid.
*
* @param mlocL The metalocation to convert.
* @return The location created from mlocL.
*/
location MetalocationToLocation(struct metalocation mlocL);
/**
* Checks whether the given metalocation is in the module currently being run.
*
* @param mlocL The metalocation to test.
* @return TRUE if mlocL refers to a location within current module,
* FALSE otherwise.
*/
int GetIsMetalocationInModule(struct metalocation mlocL);
/**
* Extracts an area reference from the given metalocation. If the metalocation
* is not in the current module, does not refere to a valid area, or the area
* cannot be uniquely identified, OBJECT_INVALID is returned.
*
* @param mlocL The metalocation from which to extract the area reference.
* @return An object reference to the area containing the metalocation or
* OBJECT_INVALID in case of error.
*/
object GetAreaFromMetalocation(struct metalocation mlocL);
/**
* Stores the given metalocation on the given object. Behaves as other normal
* local variables do.
*
* @param oObject The object to store the metalocation on.
* @param sName The local variable name the metalocation will be stored as.
* @param mlocL The metalocation to store.
*/
void SetLocalMetalocation(object oObject, string sName, struct metalocation mlocL);
/**
* Stores the given metalocation persistantly, so that it will remain in the
* character data over character exports.
*
* @param oCreature The creature to store the metalocation on.
* @param sName The local variable name the metalocation will be stored as.
* @param mlocL The metalocation to store.
*
* @see inc_persist_loca
*/
void SetPersistantLocalMetalocation(object oCreature, string sName, struct metalocation mlocL);
/**
* Retrieves the metalocation stored on the given object under the given name.
* NOTE! If there was no metalocation stored with the given name, the returned
* value will have all it's fields contain null-equivalents.
*
* @param oObject The object the metalocation was stored on.
* @param sName The name the metalocation was stored under.
* @return A copy of the stored metalocation.
*/
struct metalocation GetLocalMetalocation(object oObject, string sName);
/**
* Retrieves the metalocation persistantly stored on the given creature under
* the given name.
* NOTE! If there was no metalocation stored with the given name, the returned
* value will have all it's fields contain null-equivalents.
*
* @param oCreature The creature the metalocation was stored on.
* @param sName The name the metalocation was stored under.
* @return A copy of the stored metalocation.
*
* @see inc_persist_loca
*/
struct metalocation GetPersistantLocalMetalocation(object oCreature, string sName);
/**
* Deletes the metalocation stored with the given name on the given object.
*
* @param oObject The object the metalocation was stored on.
* @param sName The name the metalocation was stored under.
*/
void DeleteLocalMetalocation(object oObject, string sName);
/**
* Deletes the metalocation persistantly stored with the given name on
* the given creature.
*
* @param oCreature The creature the metalocation was stored on.
* @param sName The name the metalocation was stored under.
*
* @see inc_persist_loca
*/
void DeletePersistantLocalMetalocation(object oCreature, string sName);
/**
* Creates a map pin based on the given metalocation. It will be created at the
* end of the map pin array, with name equal to the metalocation's.
*
* @param mlocL The metalocation to create a map pin from.
* @param oPC The player character in whose map pin array to create the map pin in.
*/
void CreateMapPinFromMetalocation(struct metalocation mlocL, object oPC);
/**
* Creates a metalocation based on the given map pin.
*
* @param oPC The player character in whose map pin array to use
* @param nPinNo The position of the map pin to use
*/
struct metalocation CreateMetalocationFromMapPin(object oPC, int nPinNo);
/**
* Creates a metalocation with all constituents having null-equivalent values.
* Used when there is a need to return an invalid metalocation.
*
* @return A metalocation that has a null-equivalent in each field.
*/
struct metalocation GetNullMetalocation();
/**
* Checks whether the given metalocation is valid. That is, not null and
* in the current module.
*
* @param mlocL The metalocation to test.
* @return TRUE if the metalocation is valid, FALSE otherwise.
*/
int GetIsMetalocationValid(struct metalocation mlocL);
/**
* Gets the size of a players map pin array
*
* @param oPC The player character in whose map pin array to get the size of.
*/
int GetNumberOfMapPins(object oPC);
/**
* Gets the area of a players specific map pin
*
* @param oPC The player character in whose map pin array to get the area of.
* @param nPinNo The number of the map pin to remove.
*/
object GetAreaOfMapPin(object oPC, int nPinNo);
/**
* Deletes a players specific map pin
*
* @param oPC The player character in whose map pin array to get the size of.
*/
void DeleteMapPin(object oPC, int nPinNo);
/**
* Creates a string from a metalocation that is of the following format:
* NameOfMetalocation - NameOfMetalocationArea (Xcoord, Ycoord)
*
* @param mlocL The metalocation to make a string from.
* @return The created string.
*/
string MetalocationToString(struct metalocation mlocL);
//////////////////////////////////////////////////
/* Include section */
//////////////////////////////////////////////////
//#include "inc_utility"
#include "inc_area" // Area functions seperated from inc_itility
#include "inc_persist_loca" // changed include as these are the only other
// functions required from inc_utilities
//////////////////////////////////////////////////
/* Function defintions */
//////////////////////////////////////////////////
struct metalocation LocationToMetalocation(location locL, string sName = "")
{
struct metalocation mlocL;
object oArea = GetAreaFromLocation(locL);
vector vCoords = GetPositionFromLocation(locL);
mlocL.sAreaTag = GetTag(oArea);
mlocL.sAreaName = GetName(oArea);
mlocL.nAreaHeight = GetAreaHeight(oArea);
mlocL.nAreaWidth = GetAreaWidth(oArea);
mlocL.fX = vCoords.x;
mlocL.fY = vCoords.y;
mlocL.fZ = vCoords.z;
mlocL.fFacing = GetFacingFromLocation(locL);
mlocL.sName = sName;
mlocL.sModule = GetName(GetModule());
// Check that the area can be uniquely identified.
if(GetAreaFromMetalocation(mlocL) == OBJECT_INVALID)
return GetNullMetalocation(); // It can't, return null.
return mlocL;
}
location MetalocationToLocation(struct metalocation mlocL)
{
// Check whether the metalocation is in this module
if(!GetIsMetalocationInModule(mlocL))
return GetStartingLocation(); // Must return a valid location, so return starting location.
// Get the area
object oArea = GetAreaFromMetalocation(mlocL);
// Construct and return the location
return Location(oArea, Vector(mlocL.fX, mlocL.fY, mlocL.fZ), mlocL.fFacing);
}
int GetIsMetalocationInModule(struct metalocation mlocL)
{
return GetName(GetModule()) == mlocL.sModule;
}
object GetAreaFromMetalocation(struct metalocation mlocL)
{
if(!GetIsMetalocationInModule(mlocL)) return OBJECT_INVALID;
object oArea = GetObjectByTag(mlocL.sAreaTag, 0);
// Multiple areas with same tag?
if(GetName(oArea) != mlocL.sAreaName)
{
int i = 1;
oArea = GetObjectByTag(mlocL.sAreaTag, i);
while(GetIsObjectValid(oArea) &&
GetName(oArea) != mlocL.sAreaName &&
GetAreaHeight(oArea) != mlocL.nAreaHeight &&
GetAreaWidth(oArea) != mlocL.nAreaWidth
)
oArea = GetObjectByTag(mlocL.sAreaTag, ++i);
// Make sure that if the object reference is not valid, it is OBJECT_INVALID
if(!GetIsObjectValid(oArea)) return OBJECT_INVALID;
// We have a valid area reference. Now check that it is the only one matching the parameters.
object oAreaCheck = GetObjectByTag(mlocL.sAreaTag, ++i);
while(GetIsObjectValid(oAreaCheck))
{
if(GetName(oAreaCheck) == mlocL.sAreaName &&
GetAreaHeight(oAreaCheck) == mlocL.nAreaHeight &&
GetAreaWidth(oAreaCheck) == mlocL.nAreaWidth
)
return OBJECT_INVALID; // Found a second match, return OBJECT_INVALID to preserve invariant
}
}
return oArea;
}
void SetLocalMetalocation(object oObject, string sName, struct metalocation mlocL)
{
SetLocalString(oObject, "Metalocation_" + sName + "_AreaTag", mlocL.sAreaTag);
//SetLocalString(oObject, "Metalocation_" + sName + "_AreaResRef", mlocL.sAreaResRef);
SetLocalString(oObject, "Metalocation_" + sName + "_AreaName", mlocL.sAreaName);
SetLocalInt (oObject, "Metalocation_" + sName + "_AreaHeight", mlocL.nAreaHeight);
SetLocalInt (oObject, "Metalocation_" + sName + "_AreaWidth", mlocL.nAreaWidth);
SetLocalFloat (oObject, "Metalocation_" + sName + "_X", mlocL.fX);
SetLocalFloat (oObject, "Metalocation_" + sName + "_Y", mlocL.fY);
SetLocalFloat (oObject, "Metalocation_" + sName + "_Z", mlocL.fZ);
SetLocalFloat (oObject, "Metalocation_" + sName + "_Facing", mlocL.fFacing);
SetLocalString(oObject, "Metalocation_" + sName + "_Name", mlocL.sName);
SetLocalString(oObject, "Metalocation_" + sName + "_Module", mlocL.sModule);
}
void SetPersistantLocalMetalocation(object oCreature, string sName, struct metalocation mlocL)
{
// Persistant operations fail on non-creatures.
if(GetObjectType(oCreature) != OBJECT_TYPE_CREATURE) return;
SetPersistantLocalString(oCreature, "Metalocation_" + sName + "_AreaTag", mlocL.sAreaTag);
//SetPersistantLocalString(oCreature, "Metalocation_" + sName + "_AreaResRef", mlocL.sAreaResRef);
SetPersistantLocalString(oCreature, "Metalocation_" + sName + "_AreaName", mlocL.sAreaName);
SetPersistantLocalInt (oCreature, "Metalocation_" + sName + "_AreaHeight", mlocL.nAreaHeight);
SetPersistantLocalInt (oCreature, "Metalocation_" + sName + "_AreaWidth", mlocL.nAreaWidth);
SetPersistantLocalFloat (oCreature, "Metalocation_" + sName + "_X", mlocL.fX);
SetPersistantLocalFloat (oCreature, "Metalocation_" + sName + "_Y", mlocL.fY);
SetPersistantLocalFloat (oCreature, "Metalocation_" + sName + "_Z", mlocL.fZ);
SetPersistantLocalFloat (oCreature, "Metalocation_" + sName + "_Facing", mlocL.fFacing);
SetPersistantLocalString(oCreature, "Metalocation_" + sName + "_Name", mlocL.sName);
SetPersistantLocalString(oCreature, "Metalocation_" + sName + "_Module", mlocL.sModule);
}
struct metalocation GetLocalMetalocation(object oObject, string sName)
{
struct metalocation mlocL;
mlocL.sAreaTag = GetLocalString(oObject, "Metalocation_" + sName + "_AreaTag");
//mlocL.sAreaResRef = GetLocalString(oObject, "Metalocation_" + sName + "_AreaResRef");
mlocL.sAreaName = GetLocalString(oObject, "Metalocation_" + sName + "_AreaName");
mlocL.nAreaHeight = GetLocalInt (oObject, "Metalocation_" + sName + "_AreaHeight");
mlocL.nAreaWidth = GetLocalInt (oObject, "Metalocation_" + sName + "_AreaWidth");
mlocL.fX = GetLocalFloat (oObject, "Metalocation_" + sName + "_X");
mlocL.fY = GetLocalFloat (oObject, "Metalocation_" + sName + "_Y");
mlocL.fZ = GetLocalFloat (oObject, "Metalocation_" + sName + "_Z");
mlocL.fFacing = GetLocalFloat (oObject, "Metalocation_" + sName + "_Facing");
mlocL.sName = GetLocalString(oObject, "Metalocation_" + sName + "_Name");
mlocL.sModule = GetLocalString(oObject, "Metalocation_" + sName + "_Module");
return mlocL;
}
struct metalocation GetPersistantLocalMetalocation(object oCreature, string sName)
{
// Persistant operations fail on non-creatures.
if(GetObjectType(oCreature) != OBJECT_TYPE_CREATURE) return GetNullMetalocation();
struct metalocation mlocL;
mlocL.sAreaTag = GetPersistantLocalString(oCreature, "Metalocation_" + sName + "_AreaTag");
//mlocL.sAreaResRef = GetPersistantLocalString(oCreature, "Metalocation_" + sName + "_AreaResRef");
mlocL.sAreaName = GetPersistantLocalString(oCreature, "Metalocation_" + sName + "_AreaName");
mlocL.nAreaHeight = GetPersistantLocalInt (oCreature, "Metalocation_" + sName + "_AreaHeight");
mlocL.nAreaWidth = GetPersistantLocalInt (oCreature, "Metalocation_" + sName + "_AreaWidth");
mlocL.fX = GetPersistantLocalFloat (oCreature, "Metalocation_" + sName + "_X");
mlocL.fY = GetPersistantLocalFloat (oCreature, "Metalocation_" + sName + "_Y");
mlocL.fZ = GetPersistantLocalFloat (oCreature, "Metalocation_" + sName + "_Z");
mlocL.fFacing = GetPersistantLocalFloat (oCreature, "Metalocation_" + sName + "_Facing");
mlocL.sName = GetPersistantLocalString(oCreature, "Metalocation_" + sName + "_Name");
mlocL.sModule = GetPersistantLocalString(oCreature, "Metalocation_" + sName + "_Module");
return mlocL;
}
void DeleteLocalMetalocation(object oObject, string sName)
{
DeleteLocalString(oObject, "Metalocation_" + sName + "_AreaTag");
//DeleteLocalString(oObject, "Metalocation_" + sName + "_AreaResRef");
DeleteLocalString(oObject, "Metalocation_" + sName + "_AreaName");
DeleteLocalInt (oObject, "Metalocation_" + sName + "_AreaHeight");
DeleteLocalInt (oObject, "Metalocation_" + sName + "_AreaWidth");
DeleteLocalFloat (oObject, "Metalocation_" + sName + "_X");
DeleteLocalFloat (oObject, "Metalocation_" + sName + "_Y");
DeleteLocalFloat (oObject, "Metalocation_" + sName + "_Z");
DeleteLocalFloat (oObject, "Metalocation_" + sName + "_Facing");
DeleteLocalString(oObject, "Metalocation_" + sName + "_Name");
DeleteLocalString(oObject, "Metalocation_" + sName + "_Module");
}
void DeletePersistantLocalMetalocation(object oCreature, string sName)
{
// Persistant operations fail on non-creatures.
if(GetObjectType(oCreature) != OBJECT_TYPE_CREATURE) return;
DeletePersistantLocalString(oCreature, "Metalocation_" + sName + "_AreaTag");
//DeletePersistantLocalString(oCreature, "Metalocation_" + sName + "_AreaResRef");
DeletePersistantLocalString(oCreature, "Metalocation_" + sName + "_AreaName");
DeletePersistantLocalInt (oCreature, "Metalocation_" + sName + "_AreaHeight");
DeletePersistantLocalInt (oCreature, "Metalocation_" + sName + "_AreaWidth");
DeletePersistantLocalFloat (oCreature, "Metalocation_" + sName + "_X");
DeletePersistantLocalFloat (oCreature, "Metalocation_" + sName + "_Y");
DeletePersistantLocalFloat (oCreature, "Metalocation_" + sName + "_Z");
DeletePersistantLocalFloat (oCreature, "Metalocation_" + sName + "_Facing");
DeletePersistantLocalString(oCreature, "Metalocation_" + sName + "_Name");
DeletePersistantLocalString(oCreature, "Metalocation_" + sName + "_Module");
}
/*
Map pin data:
Local int "NW_TOTAL_MAP_PINS"
- Number of existing map pins.
Local string "NW_MAP_PIN_NRTY_#"
- Name of the nth map pin.
- # is string representation of the map pin's index number, base 1.
Local float "NW_MAP_PIN_XPOS_#"
- The map pin's X coordinate in the area.
- # is string representation of the map pin's index number, base 1.
Local float "NW_MAP_PIN_YPOS_#"
- The map pin's Y coordinate in the area.
- # is string representation of the map pin's index number, base 1.
Local object "NW_MAP_PIN_AREA_#"
- Object reference to the area where the map pin is located.
- # is string representation of the map pin's index number, base 1.
*/
void CreateMapPinFromMetalocation(struct metalocation mlocL, object oPC)
{
if(!GetIsObjectValid(oPC))
return;
//check no other map pins at that location
int nPinCount = GetNumberOfMapPins(oPC);
int i;
for(i=1;i<nPinCount;i++)
{
struct metalocation mlocTest = CreateMetalocationFromMapPin(oPC, i);
if(mlocTest == mlocL)
return;//duplicate detected, abort
}
//create that map pin
int nID = GetLocalInt(oPC, "NW_TOTAL_MAP_PINS") + 1;
SetLocalInt(oPC, "NW_TOTAL_MAP_PINS", nID);
SetLocalString(oPC, "NW_MAP_PIN_NRTY_" + IntToString(nID), mlocL.sName);
SetLocalFloat( oPC, "NW_MAP_PIN_XPOS_" + IntToString(nID), mlocL.fX);
SetLocalFloat( oPC, "NW_MAP_PIN_YPOS_" + IntToString(nID), mlocL.fY);
SetLocalObject(oPC, "NW_MAP_PIN_AREA_" + IntToString(nID), GetAreaFromLocation(MetalocationToLocation(mlocL)));
}
struct metalocation CreateMetalocationFromMapPin(object oPC, int nPinNo)
{
//sanity checks
if(!GetIsObjectValid(oPC))
return GetNullMetalocation();
if(nPinNo < 1)
return GetNullMetalocation();
int nPinCount = GetNumberOfMapPins(oPC);
if(nPinCount < 1)
return GetNullMetalocation();
if(nPinCount < nPinNo)
return GetNullMetalocation();
//variables
struct metalocation mlocReturn;
string sID = IntToString(nPinNo);
location lLoc;
object oArea = GetLocalObject(oPC,"NW_MAP_PIN_AREA_"+sID);
float fX = GetLocalFloat( oPC,"NW_MAP_PIN_XPOS_"+sID);
float fY = GetLocalFloat( oPC,"NW_MAP_PIN_YPOS_"+sID);
string sName = GetLocalString(oPC,"NW_MAP_PIN_NRTY_"+sID);
lLoc = Location(oArea, Vector(fX, fY, 0.0), 0.0);
mlocReturn = LocationToMetalocation(lLoc, sName);
return mlocReturn;
}
int GetNumberOfMapPins(object oPC)
{
return GetLocalInt(oPC, "NW_TOTAL_MAP_PINS");
}
object GetAreaOfMapPin(object oPC, int nPinNo)
{
return GetLocalObject(oPC, "NW_MAP_PIN_AREA_"+IntToString(nPinNo));
}
void DeleteMapPin(object oPC, int nPinNo)
{
//sanity checks
if(nPinNo < 1)
return;
if(!GetIsObjectValid(oPC))
return;
int nPinCount = GetNumberOfMapPins(oPC);
if(nPinCount < 1)
return;
if(nPinCount < nPinNo)
return;
//delete the pin
DeleteLocalString(oPC, "NW_MAP_PIN_NRTY_"+IntToString(nPinNo));
DeleteLocalFloat( oPC, "NW_MAP_PIN_XPOS_"+IntToString(nPinNo));
DeleteLocalFloat( oPC, "NW_MAP_PIN_YPOS_"+IntToString(nPinNo));
DeleteLocalObject(oPC, "NW_MAP_PIN_AREA_"+IntToString(nPinNo));
//move the other ones up
int i = nPinNo+1;
for (i=nPinNo+1;i<nPinCount;i++)
{
SetLocalString(oPC, "NW_MAP_PIN_NRTY_"+IntToString(i), GetLocalString(oPC, "NW_MAP_PIN_NRTY_"+IntToString(i+1)));
SetLocalFloat( oPC, "NW_MAP_PIN_XPOS_"+IntToString(i), GetLocalFloat (oPC, "NW_MAP_PIN_XPOS_"+IntToString(i+1)));
SetLocalFloat( oPC, "NW_MAP_PIN_YPOS_"+IntToString(i), GetLocalFloat (oPC, "NW_MAP_PIN_YPOS_"+IntToString(i+1)));
SetLocalObject(oPC, "NW_MAP_PIN_AREA_"+IntToString(i), GetLocalObject(oPC, "NW_MAP_PIN_AREA_"+IntToString(i+1)));
}
//delete the last pin, since the list is shorter now
DeleteLocalString(oPC, "NW_MAP_PIN_NRTY_"+IntToString(nPinCount));
DeleteLocalFloat( oPC, "NW_MAP_PIN_XPOS_"+IntToString(nPinCount));
DeleteLocalFloat( oPC, "NW_MAP_PIN_YPOS_"+IntToString(nPinCount));
DeleteLocalObject(oPC, "NW_MAP_PIN_AREA_"+IntToString(nPinCount));
//fix the overall count
SetLocalInt(oPC, "NW_TOTAL_MAP_PINS", nPinCount-1);
}
struct metalocation GetNullMetalocation()
{
struct metalocation mlocL;
mlocL.sAreaTag = "";
//mlocL.sAreaResRef = "";
mlocL.sAreaName = "";
mlocL.nAreaHeight = 0;
mlocL.nAreaWidth = 0;
mlocL.fX = 0.0f;
mlocL.fY = 0.0f;
mlocL.fZ = 0.0f;
mlocL.fFacing = 0.0f;
mlocL.sName = "";
mlocL.sModule = "";
return mlocL;
}
int GetIsMetalocationValid(struct metalocation mlocL)
{
/* SendMessageToPC(GetFirstPC(), "mlocL.sAreaTag " + IntToString(mlocL.sAreaTag != ""));
SendMessageToPC(GetFirstPC(), "mlocL.sAreaResRef " + IntToString(mlocL.sAreaResRef != ""));
SendMessageToPC(GetFirstPC(), "mlocL.sModule " + IntToString(mlocL.sModule != ""));
SendMessageToPC(GetFirstPC(), "GetIsMetalocationInModule(mlocL): " + IntToString(GetIsMetalocationInModule(mlocL)));
*/
return mlocL.sAreaTag != "" &&
// mlocL.sAreaResRef != "" &&
mlocL.sAreaName != "" &&
mlocL.nAreaWidth != 0 &&
mlocL.nAreaHeight != 0 &&
mlocL.sModule != "" &&
GetIsMetalocationInModule(mlocL);
}
string MetalocationToString(struct metalocation mlocL)
{
object oArea = GetAreaFromMetalocation(mlocL);
return mlocL.sName + " - " + GetName(oArea)
+ " (" + IntToString(FloatToInt(mlocL.fX)) + ", " + IntToString(FloatToInt(mlocL.fY)) + ", " + IntToString(FloatToInt(mlocL.fZ)) + ")"
+ ((GetIsAreaNatural(oArea) && !GetIsAreaInterior(oArea)) ? "<c <20> >*</c>": "")
+ (GetIsMetalocationInModule(mlocL) ? "" : (" " + GetStringByStrRef(16825269)/*" Not in module "*/));
}
//void main(){} // Test main

File diff suppressed because it is too large Load Diff

223
src/include/inc_npc.nss Normal file
View File

@@ -0,0 +1,223 @@
//::///////////////////////////////////////////////
//:: NPC associate include
//:: inc_npc
//:://////////////////////////////////////////////
/*
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
// Get the master of oAssociate.
object GetMasterNPC(object oAssociate=OBJECT_SELF);
// Returns the associate type of the specified creature.
// - Returns ASSOCIATE_TYPE_NONE if the creature is not the associate of anyone.
int GetAssociateTypeNPC( object oAssociate );
// Get the henchman belonging to oMaster.
// * Return OBJECT_INVALID if oMaster does not have a henchman.
// -nNth: Which henchman to return.
object GetHenchmanNPC(object oMaster=OBJECT_SELF,int nNth=1);
// Get the associate of type nAssociateType belonging to oMaster.
// - nAssociateType: ASSOCIATE_TYPE_*
// - nMaster
// - nTh: Which associate of the specified type to return
// * Returns OBJECT_INVALID if no such associate exists.
object GetAssociateNPC(int nAssociateType, object oMaster=OBJECT_SELF, int nTh=1);
// Returns TRUE if the specified condition flag is set on
// the associate.
int GetAssociateStateNPC(int nCondition, object oAssoc=OBJECT_SELF);
// Determine if this henchman is currently dying
int GetIsHenchmanDyingNPC(object oHench=OBJECT_SELF);
// Determine if Should I Heal My Master
int GetAssociateHealMasterNPC();
// Create the next AssociateType creature
object CreateLocalNextNPC(object oMaster,int nAssociateType,string sTemplate,location loc,string sTag="");
// Create a AssociateType creature
object CreateLocalNPC(object oMaster,int nAssociateType,string sTemplate,location loc,int Nth=1,string sTag="");
#include "prc_inc_function"
#include "x0_i0_assoc"
void SetLocalNPC(object oMaster,object oAssociate,int nAssociateType ,int nNth=1)
{
SetLocalObject(oAssociate, "oMaster", oMaster);
SetLocalInt(oAssociate, "iAssocType", nAssociateType);
SetLocalObject(oMaster, IntToString(nAssociateType)+"oHench"+IntToString(nNth), oAssociate);
SetLocalInt(oAssociate, "iAssocNth", nNth);
}
void DeleteLocalNPC(object oAssociate=OBJECT_SELF)
{
int nType = GetLocalInt(oAssociate, "iAssocType");
object oMaster = GetMasterNPC(oAssociate);
int Nth = GetLocalInt(oAssociate, "iAssocNth");
DeleteLocalInt(oMaster, IntToString(nType)+"oHench"+IntToString(Nth));
DeleteLocalInt(oAssociate, "iAssocNth");
DeleteLocalObject(oAssociate, "oMaster");
DeleteLocalInt(oAssociate, "iAssocType");
}
void DestroySummon(object oSummon)
{
effect eVis = EffectVisualEffect(VFX_IMP_UNSUMMON);
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetLocation(oSummon));
DeleteLocalNPC(oSummon);
DestroyObject(oSummon);
}
object CreateLocalNPC(object oMaster,int nAssociateType,string sTemplate,location loc,int Nth=1,string sTag="")
{
object oSummon=CreateObject(OBJECT_TYPE_CREATURE,sTemplate,loc,FALSE,sTag);
SetLocalNPC(oMaster,oSummon,nAssociateType ,Nth);
SetAssociateState(NW_ASC_HAVE_MASTER,TRUE,oSummon);
SetAssociateState(NW_ASC_DISTANCE_2_METERS);
SetAssociateState(NW_ASC_DISTANCE_4_METERS, FALSE);
SetAssociateState(NW_ASC_DISTANCE_6_METERS, FALSE);
if (nAssociateType == ASSOCIATE_TYPE_FAMILIAR) SetLocalInt(oMaster, "FamiliarToTheDeath", 100);
if (nAssociateType == ASSOCIATE_TYPE_ANIMALCOMPANION) SetLocalInt(oMaster, "AniCompToTheDeath", 100);
effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD);
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, GetLocation(oSummon));
return oSummon;
}
object CreateLocalNextNPC(object oMaster,int nAssociateType,string sTemplate,location loc,string sTag="")
{
object oSummon=CreateObject(OBJECT_TYPE_CREATURE,sTemplate,loc,FALSE,sTag);
int nCount=1;
while (GetIsObjectValid(GetAssociateNPC(ASSOCIATE_TYPE_SUMMONED,OBJECT_SELF,nCount)))
{
nCount++;
SendMessageToPC(OBJECT_SELF," nCount:"+IntToString(nCount));
}
SetLocalObject(oSummon, "oMaster", oMaster);
SetLocalInt(oSummon, "iAssocType", nAssociateType);
SetLocalObject(oMaster, IntToString(nAssociateType)+"oHench"+IntToString(nCount), oSummon);
SetLocalInt(oSummon, "iAssocNth", nCount);
SetAssociateState(NW_ASC_HAVE_MASTER,TRUE,oSummon);
SetAssociateState(NW_ASC_DISTANCE_2_METERS);
SetAssociateState(NW_ASC_DISTANCE_4_METERS, FALSE);
SetAssociateState(NW_ASC_DISTANCE_6_METERS, FALSE);
if (nAssociateType ==ASSOCIATE_TYPE_FAMILIAR) SetLocalInt(oMaster, "FamiliarToTheDeath", 100);
if (nAssociateType ==ASSOCIATE_TYPE_ANIMALCOMPANION) SetLocalInt(oMaster, "AniCompToTheDeath", 100);
return oSummon;
}
object GetMasterNPC(object oAssociate=OBJECT_SELF)
{
object oMaster = GetLocalObject(oAssociate, "oMaster");
if (GetIsObjectValid(oMaster))
return oMaster;
else
return GetMaster(oAssociate);
}
int GetAssociateTypeNPC( object oAssociate )
{
int iType = GetLocalInt(oAssociate, "iAssocType");
if (iType)
return iType;
else
return GetAssociateType(oAssociate);
}
object GetHenchmanNPC(object oMaster=OBJECT_SELF,int nNth=1)
{
object oAssociate = GetLocalObject(oMaster,IntToString(ASSOCIATE_TYPE_HENCHMAN)+"oHench"+IntToString(nNth));
if (GetIsObjectValid(oAssociate))
return oAssociate;
else
return GetHenchman(oMaster,nNth);
}
object GetAssociateNPC(int nAssociateType, object oMaster=OBJECT_SELF, int nTh=1)
{
object oAssociate = GetLocalObject(oMaster,IntToString(nAssociateType)+"oHench"+IntToString(nTh));
if (GetIsObjectValid(oAssociate))
return oAssociate;
else
return GetAssociate(nAssociateType,oMaster,nTh);
}
int GetAssociateStateNPC(int nCondition, object oAssoc=OBJECT_SELF)
{
//SpawnScriptDebugger();
if(nCondition == NW_ASC_HAVE_MASTER)
{
if(GetIsObjectValid(GetMasterNPC(oAssoc)))
return TRUE;
}
else
{
int nPlot = GetLocalInt(oAssoc, sAssociateMasterConditionVarname);
if(nPlot & nCondition)
return TRUE;
}
return FALSE;
}
int GetIsHenchmanDyingNPC(object oHench=OBJECT_SELF)
{
int bHenchmanDying = GetAssociateStateNPC(NW_ASC_MODE_DYING, oHench);
if (bHenchmanDying == TRUE)
{
return TRUE;
}
else
{
return FALSE;
}
}
int GetAssociateHealMasterNPC()
{
if(GetAssociateStateNPC(NW_ASC_HAVE_MASTER))
{
object oMaster = GetMasterNPC();
int nLoss = GetPercentageHPLoss(oMaster);
if(!GetIsDead(oMaster))
{
if(GetAssociateStateNPC(NW_ASC_HEAL_AT_75) && nLoss <= 75)
{
return TRUE;
}
else if(GetAssociateStateNPC(NW_ASC_HEAL_AT_50) && nLoss <= 50)
{
return TRUE;
}
else if(GetAssociateStateNPC(NW_ASC_HEAL_AT_25) && nLoss <= 25)
{
return TRUE;
}
}
}
return FALSE;
}

View File

@@ -0,0 +1,284 @@
////////////////////////////////////////////////////////////////////////////////////
/* Combined wrappers for both Win32 and Linux NWNX funcs */
////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
// Used in OnModuleLoad event to auto-detect if NWNX_Funcs plugin is enabled
void PRC_Funcs_Init(object oModule);
// Sets the amount of hitpoints oObject has currently to nHP
void PRC_Funcs_SetCurrentHitPoints(object oCreature, int nHP);
// Sets the amount of hitpoints oObject can maximally have to nHP
void PRC_Funcs_SetMaxHitPoints(object oCreature, int nHP);
// Changes the skill ranks for nSkill on oObject by iValue
void PRC_Funcs_ModSkill(object oCreature, int nSkill, int nValue);
// Sets a base ability score nAbility (ABILITY_STRENGTH, ABILITY_DEXTERITY, etc) to nValue
// The range of nValue is 3 to 255
void PRC_Funcs_SetAbilityScore(object oCreature, int nAbility, int nValue);
// Changes a base ability score nAbility (ABILITY_STRENGTH, ABILITY_DEXTERITY, etc) by nValue
void PRC_Funcs_ModAbilityScore(object oCreature, int nAbility, int nValue);
// Adds a feat to oObject's general featlist
// If nLevel is greater than 0 the feat is also added to the featlist for that level
void PRC_Funcs_AddFeat(object oCreature, int nFeat, int nLevel=0);
// Checks if oCreature inherently knows a feat (as opposed to a feat given from an equipped item)
// Returns FALSE if oCreature does not know the feat, TRUE if the feat is known
// The return value (if greater than 0) also denotes the position of the feat in the general feat list offset by +1
int PRC_Funcs_GetFeatKnown(object oCreature, int nFeat);
// Changes the saving throw bonus nSavingThrow of oObject by nValue;
void PRC_Funcs_ModSavingThrowBonus(object oCreature, int nSavingThrow, int nValue);
// Sets the base natural AC
void PRC_Funcs_SetBaseNaturalAC(object oCreature, int nValue);
// Returns the base natural AC
int PRC_Funcs_GetBaseNaturalAC(object oCreature);
// Sets the specialist spell school of a Wizard
void PRC_Funcs_SetWizardSpecialization(object oCreature, int iSpecialization);
// Returns the specialist spell school of a Wizard
int PRC_Funcs_GetWizardSpecialization(object oCreature);
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
int _PRC_NWNXFuncsZero(object oObject, string sFunc) {
int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS");
if (nVersion == 1)
SetLocalString(oObject, sFunc, "-");
else if (nVersion == 2)
SetLocalString(oObject, sFunc, " ");
int nResult = StringToInt(GetLocalString(oObject, sFunc));
DeleteLocalString(oObject, sFunc);
return nResult;
}
int _PRC_NWNXFuncsOne(object oObject, string sFunc, int nVal1) {
int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS");
if (nVersion == 1)
SetLocalString(oObject, sFunc, IntToString(nVal1));
else if (nVersion == 2)
SetLocalString(oObject, sFunc, IntToString(nVal1) + " ");
int nResult = StringToInt(GetLocalString(oObject, sFunc));
DeleteLocalString(oObject, sFunc);
return nResult;
}
int _PRC_NWNXFuncsTwo(object oObject, string sFunc, int nVal1, int nVal2) {
int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS");
if (nVersion == 1)
SetLocalString(oObject, sFunc, IntToString(nVal1) + " " + IntToString(nVal2));
else if (nVersion == 2)
SetLocalString(oObject, sFunc, IntToString(nVal1) + " " + IntToString(nVal2) + " ");
int nResult = StringToInt(GetLocalString(oObject, sFunc));
DeleteLocalString(oObject, sFunc);
return nResult;
}
int _PRC_NWNXFuncsThree(object oObject, string sFunc, int nVal1, int nVal2, int nVal3) {
int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS");
if (nVersion == 1)
SetLocalString(oObject, sFunc, IntToString(nVal1) + " " + IntToString(nVal2) + " " + IntToString(nVal3));
else if (nVersion == 2)
SetLocalString(oObject, sFunc, IntToString(nVal1) + " " + IntToString(nVal2) + " " + IntToString(nVal3) + " ");
int nResult = StringToInt(GetLocalString(oObject, sFunc));
DeleteLocalString(oObject, sFunc);
return nResult;
}
int _PRC_NWNXFuncsFour(object oObject, string sFunc, int nVal1, int nVal2, int nVal3, int nVal4) {
int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS");
if (nVersion == 1)
SetLocalString(oObject, sFunc, IntToString(nVal1) + " " + IntToString(nVal2) + " " + IntToString(nVal3) + " " + IntToString(nVal4));
else if (nVersion == 2)
SetLocalString(oObject, sFunc, IntToString(nVal1) + " " + IntToString(nVal2) + " " + IntToString(nVal3) + " " + IntToString(nVal4) + " ");
int nResult = StringToInt(GetLocalString(oObject, sFunc));
DeleteLocalString(oObject, sFunc);
return nResult;
}
void PRC_Funcs_Init(object oModule)
{
//Only NWNX for Win32 implements GetHasLocalVariable, so if this succeeds, that's what we're using
string sTestVariable = "PRC_TEST_NWNX_FUNCS";
SetLocalString(oModule, sTestVariable, "1");
SetLocalString(oModule, "NWNX!FUNCS!GETHASLOCALVARIABLE", sTestVariable + " 3"); //3 is the variable type
//NOTE: don't use _PRC_NWNXFuncsX functions here; they depend on the PRC_NWNX_FUNCS that we haven't set yet
int iTest = StringToInt(GetLocalString(oModule, "NWNX!FUNCS!GETHASLOCALVARIABLE"));
DeleteLocalString(oModule, "NWNX!FUNCS!GETHASLOCALVARIABLE");
DeleteLocalString(oModule, sTestVariable);
if (iTest)
SetLocalInt(oModule, "PRC_NWNX_FUNCS", 1); //1 == win32
else
{
//NWNX GetLocalVariableCount behaves differently for win32 and linux,
//but we know we're not using the win32 version (because the above check failed),
//so try the linux version of GetLocalVariableCount.
//Since PRC_VERSION is a module-level variable, and we know it's defined
//by OnLoad before it calls this function, the variable count will be at
//least 1 if we're using NWNX. If not, 0 will be returned to indicate that
//the call failed because NWNX funcs is not present.
string sFunc = "NWNX!FUNCS!GETLOCALVARIABLECOUNT";
SetLocalString(oModule, sFunc, " ");
//NOTE: don't use _PRC_NWNXFuncsX functions here; they depend on the PRC_NWNX_FUNCS that we haven't set yet
//NOTE: the number being returned by GetLocalVariableCount() on Linux seems bogus to me (it's huge, e.g. 294,654,504),
//but it does seem to be reliably zero when NWNX funcs is not present, and so far has been reliably non-zero
//when it is present. That's all we need here.
//Info: on win32, GetLocalVariableCount() is returning much more reasonable numbers (e.g. 1707).
int nVariables = StringToInt(GetLocalString(oModule, sFunc));
DeleteLocalString(oModule, sFunc);
if (nVariables)
SetLocalInt(oModule, "PRC_NWNX_FUNCS", 2); //2 == linux
}
}
void PRC_Funcs_SetMaxHitPoints(object oCreature, int nHP)
{
int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS");
if (nVersion == 1 || nVersion == 2)
{
_PRC_NWNXFuncsOne(oCreature, "NWNX!FUNCS!SETMAXHITPOINTS", nHP);
DeleteLocalString(oCreature, "NWNX!FUNCS!SETMAXHITPOINTS");
}
}
void PRC_Funcs_ModSkill(object oCreature, int nSkill, int nValue)
{
int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS");
if (nVersion == 1)
_PRC_NWNXFuncsThree(oCreature, "NWNX!FUNCS!SETSKILL", nSkill, nValue, 1); //The 1 is a flag specifying modify instead of set
else if (nVersion == 2)
_PRC_NWNXFuncsTwo(oCreature, "NWNX!FUNCS!MODIFYSKILLRANK", nSkill, nValue);
}
void PRC_Funcs_SetAbilityScore(object oCreature, int nAbility, int nValue)
{
int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS");
if (nVersion == 1)
_PRC_NWNXFuncsFour(oCreature, "NWNX!FUNCS!SETABILITYSCORE", nAbility, nValue, 0, 0); //The first 0 is a flag specifying set instead of modify
else if (nVersion == 2)
_PRC_NWNXFuncsTwo(oCreature, "NWNX!FUNCS!SETABILITYSCORE", nAbility, nValue);
}
void PRC_Funcs_ModAbilityScore(object oCreature, int nAbility, int nValue)
{
int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS");
if (nVersion == 1)
_PRC_NWNXFuncsFour(oCreature, "NWNX!FUNCS!SETABILITYSCORE", nAbility, nValue, 1, 0); //The 1 is a flag specifying modify instead of set
else if (nVersion == 2)
_PRC_NWNXFuncsTwo(oCreature, "NWNX!FUNCS!MODIFYABILITYSCORE", nAbility, nValue);
}
void PRC_Funcs_AddFeat(object oCreature, int nFeat, int nLevel=0)
{
int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS");
if (nVersion == 1)
{
if (!nLevel)
_PRC_NWNXFuncsOne(oCreature, "NWNX!FUNCS!ADDFEAT", nFeat);
else if(nLevel > 0)
_PRC_NWNXFuncsTwo(oCreature, "NWNX!FUNCS!ADDFEATATLEVEL", nLevel, nFeat);
}
else if (nVersion == 2)
{
if (!nLevel)
_PRC_NWNXFuncsOne(oCreature, "NWNX!FUNCS!ADDKNOWNFEAT", nFeat);
else if(nLevel > 0)
_PRC_NWNXFuncsTwo(oCreature, "NWNX!FUNCS!ADDKNOWNFEATATLEVEL", nLevel, nFeat);
}
}
int PRC_Funcs_GetFeatKnown(object oCreature, int nFeatIndex)
{
int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS");
if (nVersion == 1)
return _PRC_NWNXFuncsOne(oCreature, "NWNX!FUNCS!GETFEATKNOWN", nFeatIndex);
else if (nVersion == 2)
return _PRC_NWNXFuncsOne(oCreature, "NWNX!FUNCS!GETKNOWNFEAT", nFeatIndex);
return 0;
}
void PRC_Funcs_ModSavingThrowBonus(object oCreature, int nSavingThrow, int nValue)
{
int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS");
if (nVersion == 1)
_PRC_NWNXFuncsThree(oCreature, "NWNX!FUNCS!SETSAVINGTHROWBONUS", nSavingThrow, nValue, 1); //The 1 is a flag specifying modify instead of set
else if (nVersion == 2)
{
int nNewValue = _PRC_NWNXFuncsOne(oCreature, "NWNX!FUNCS!GETSAVINGTHROWBONUS", nSavingThrow) + nValue;
if (nNewValue < 0)
nNewValue = 0;
else if (nNewValue > 127)
nNewValue = 127;
_PRC_NWNXFuncsTwo(oCreature, "NWNX!FUNCS!SETSAVINGTHROWBONUS", nSavingThrow, nNewValue);
}
}
void PRC_Funcs_SetBaseNaturalAC(object oCreature, int nValue)
{
int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS");
if (nVersion == 1)
_PRC_NWNXFuncsTwo(oCreature, "NWNX!FUNCS!SETBASEAC", nValue, AC_NATURAL_BONUS);
else if (nVersion == 2)
_PRC_NWNXFuncsOne(oCreature, "NWNX!FUNCS!SETACNATURALBASE", nValue);
}
int PRC_Funcs_GetBaseNaturalAC(object oCreature)
{
int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS");
if (nVersion == 1)
return _PRC_NWNXFuncsOne(oCreature, "NWNX!FUNCS!GETBASEAC", AC_NATURAL_BONUS);
else if (nVersion == 2)
return _PRC_NWNXFuncsZero(oCreature, "NWNX!FUNCS!GETACNATURALBASE");
return 0;
}
void PRC_Funcs_SetCurrentHitPoints(object oCreature, int nHP)
{
int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS");
if (nVersion == 1 || nVersion == 2)
_PRC_NWNXFuncsOne(oCreature, "NWNX!FUNCS!SETCURRENTHITPOINTS", nHP);
}
void PRC_Funcs_SetCreatureSize (object oCreature, int nSize)
{
int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS");
if (nVersion == 1 || nVersion == 2)
_PRC_NWNXFuncsOne(oCreature, "NWNX!FUNCS!SETCREATURESIZE", nSize);
}
void PRC_Funcs_SetRace(object oCreature, int nRace)
{
int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS");
if (nVersion == 1)
_PRC_NWNXFuncsOne(oCreature, "NWNX!FUNCS!SETRACE", nRace);
else if (nVersion == 2)
_PRC_NWNXFuncsOne(oCreature, "NWNX!FUNCS!SETRACIALTYPE", nRace);
}
void PRC_Funcs_SetWizardSpecialization(object oCreature, int iSpecialization)
{
int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS");
if (nVersion == 1 || nVersion == 2)
_PRC_NWNXFuncsOne(oCreature, "NWNX!FUNCS!SETWIZARDSPECIALIZATION", iSpecialization);
}
int PRC_Funcs_GetWizardSpecialization(object oCreature)
{
int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS");
if (nVersion == 1 || nVersion == 2)
return _PRC_NWNXFuncsZero(oCreature, "NWNX!FUNCS!GETWIZARDSPECIALIZATION");
return 0;
}

View File

@@ -0,0 +1,340 @@
//::///////////////////////////////////////////////
//:: Persistant array simulation include
//:: inc_pers_array
//:://////////////////////////////////////////////
/** @file
Persistant array simulation include
This file defines a set of functions for creating
and manipulating persistant arrays, which are
implemented as persistant local variables on some
holder creature.
Notes:
* Arrays are dynamic and may be increased in size by just _set_'ing a new
element
* There are no restrictions on what is in the array (can have multiple
types in the same array)
* Arrays start at index 0
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
/////////////////////////////////////
// Functions
/////////////////////////////////////
/**
* Creates a new persistant array on the given storage creature.
* If an array with the same name already exists, the function
* errors.
*
* @param store The creature to use as holder for the array
* @param name The name of the array
* @return SDL_SUCCESS if the array was successfully created,
* one of SDL_ERROR_* on error.
*/
int persistant_array_create(object store, string name);
/**
* Deletes a persistant array, erasing all it's entries.
*
* @param store The creature which holds the array to delete
* @param name The name of the array
* @return SDL_SUCCESS if the array was successfully deleted,
* one of SDL_ERROR_* on error
*/
int persistant_array_delete(object store, string name);
/**
* Stores a string in a persistant array.
*
* @param store The creature holding the array
* @param name The name of the array
* @param i The index to store the string at
* @param entry The string to store
* @return SDL_SUCCESS if the store was successfull, SDL_ERROR_* on error.
*/
int persistant_array_set_string(object store, string name, int i, string entry);
/**
* Stores an integer in a persistant array.
*
* @param store The creature holding the array
* @param name The name of the array
* @param i The index to store the integer at
* @param entry The integer to store
* @return SDL_SUCCESS if the store was successfull, SDL_ERROR_* on error.
*/
int persistant_array_set_int(object store, string name, int i, int entry);
/**
* Stores a float in a persistant array.
*
* @param store The creature holding the array
* @param name The name of the array
* @param i The index to store the float at
* @param entry The float to store
* @return SDL_SUCCESS if the store was successfull, SDL_ERROR_* on error.
*/
int persistant_array_set_float(object store, string name, int i, float entry);
/**
* Stores an object in a persistant array.
*
* @param store The creature holding the array
* @param name The name of the array
* @param i The index to store the object at
* @param entry The object to store
* @return SDL_SUCCESS if the store was successfull, SDL_ERROR_* on error.
*/
int persistant_array_set_object(object store, string name, int i, object entry);
/**
* Gets a string from a persistant array.
*
* @param store The creature holding the array
* @param name The name of the array
* @param i The index to retrieve the string from
* @return The value contained at the index on success,
* "" on error
*/
string persistant_array_get_string(object store, string name, int i);
/**
* Gets an integer from a persistant array.
*
* @param store The creature holding the array
* @param name The name of the array
* @param i The index to retrieve the integer from
* @return The value contained at the index on success,
* 0 on error
*/
int persistant_array_get_int(object store, string name, int i);
/**
* Gets a float from a persistant array.
*
* @param store The creature holding the array
* @param name The name of the array
* @param i The index to retrieve the float from
* @return The value contained at the index on success,
* 0.0f on error
*/
float persistant_array_get_float(object store, string name, int i);
/**
* Gets an object from a persistant array.
*
* @param store The creature holding the array
* @param name The name of the array
* @param i The index to retrieve the object from
* @return The value contained at the index on success,
* OBJECT_INVALID on error
*/
object persistant_array_get_object(object store, string name, int i);
/**
* Removes all entries in the array with indexes greater than or equal to
* the new size and sets the array size to be equal to the new size.
*
* @param store The creature holding the array
* @param name The name of the array
* @param size_new The new number of entries in the array
* @return SDL_SUCCESS on successful resize, SDL_ERROR_* on
* error
*/
int persistant_array_shrink(object store, string name, int size_new);
/**
* Gets the current size of the array. This is one greater
* than the index of highest indexed element the array
* has contained since the last array_shrink or the new size
* specified by the last array_shrink, whichever is greater.
*
* @param store The creature holding the array
* @param name The name of the array
* @return The size of the array, or -1 if the specified
* array does not exist.
*/
int persistant_array_get_size(object store, string name);
/**
* Checks whether the given persistant array exists.
*
* @param store The creature holding the array
* @param name The name of the array
* @return TRUE if the array exists, FALSE otherwise.
*/
int persistant_array_exists(object store, string name);
/////////////////////////////////////
// Includes
/////////////////////////////////////
#include "inc_persist_loca"
#include "prc_inc_array" // yes this is also got via inc_persist_loca if rather indirectly
/////////////////////////////////////
// Implementation
/////////////////////////////////////
int persistant_array_create(object store, string name)
{
// error checking
if(!GetIsObjectValid(store))
return SDL_ERROR_NOT_VALID_OBJECT;
else if(persistant_array_exists(store,name))
return SDL_ERROR_ALREADY_EXISTS;
else
{
// Initialize the size (always one greater than the actual size)
SetPersistantLocalInt(store,name,1);
return SDL_SUCCESS;
}
}
void persistant_array_delete_loop(object store, string name, int nMin, int nMax)
{
int i = nMin;
while(i < nMin + 250 && i < nMax)
{
DeletePersistantLocalString(store,name+"_"+IntToString(i));
// just in case, delete possible object names
DeletePersistantLocalObject(store,name+"_"+IntToString(i)+"_OBJECT");
i++;
}
// delay continuation to avoid TMI
if(i < nMax)
DelayCommand(0.0, persistant_array_delete_loop(store, name, i, nMax));
}
int persistant_array_delete(object store, string name)
{
// error checking
int size=GetPersistantLocalInt(store,name);
if (size==0)
return SDL_ERROR_DOES_NOT_EXIST;
persistant_array_delete_loop(store, name, 0, size+5);
DeletePersistantLocalInt(store,name);
return SDL_SUCCESS;
}
int persistant_array_set_string(object store, string name, int i, string entry)
{
int size=GetPersistantLocalInt(store,name);
if(size == 0)
return SDL_ERROR_DOES_NOT_EXIST;
if(i < 0)
return SDL_ERROR_OUT_OF_BOUNDS;
SetPersistantLocalString(store,name+"_"+IntToString(i),entry);
// save size if we've enlarged it
if (i+2>size)
SetPersistantLocalInt(store,name,i+2);
return SDL_SUCCESS;
}
int persistant_array_set_int(object store, string name, int i, int entry)
{
return persistant_array_set_string(store,name,i,IntToString(entry));
}
int persistant_array_set_float(object store, string name, int i, float entry)
{
return persistant_array_set_string(store,name,i,FloatToString(entry));
}
int persistant_array_set_object(object store, string name, int i, object entry)
{
// object is a little more complicated.
// we want to create an object as a local variable too
if (!GetIsObjectValid(entry))
return SDL_ERROR_NOT_VALID_OBJECT;
int results = persistant_array_set_string(store,name,i,"OBJECT");
if (results==SDL_SUCCESS)
SetPersistantLocalObject(store,name+"_"+IntToString(i)+"_OBJECT",entry);
return results;
}
string persistant_array_get_string(object store, string name, int i)
{
// error checking
int size=GetPersistantLocalInt(store,name);
if (size==0 || i>size || i < 0)
return "";
return GetPersistantLocalString(store,name+"_"+IntToString(i));
}
int persistant_array_get_int(object store, string name, int i)
{
return StringToInt(persistant_array_get_string(store,name,i));
}
float persistant_array_get_float(object store, string name, int i)
{
return StringToFloat(persistant_array_get_string(store,name,i));
}
object persistant_array_get_object(object store, string name, int i)
{
if(persistant_array_get_string(store, name, i) == "OBJECT")
return GetPersistantLocalObject(store,name+"_"+IntToString(i)+"_OBJECT");
else
return OBJECT_INVALID;
}
int persistant_array_shrink(object store, string name, int size_new)
{
// Get the current size value
int size = GetPersistantLocalInt(store, name);
// Error check - non-existent array
if(size == 0)
return SDL_ERROR_DOES_NOT_EXIST;
// If the new number of elements is equal to or greater than the current number of elements, autosuccess
if((size - 1) <= size_new)
return SDL_SUCCESS;
// Delete entries that are outside the new array bounds
int i;
for(i = size_new; i < size; i++)
{
DeletePersistantLocalString(store, name+"_"+IntToString(i));
// just in case, delete possible object names
DeletePersistantLocalObject(store, name+"_"+IntToString(i)+"_OBJECT");
}
// Store the new size, with the +1 existence marker
SetPersistantLocalInt(store, name, size_new + 1);
return SDL_SUCCESS;
}
int persistant_array_get_size(object store, string name)
{
return GetPersistantLocalInt(store,name)-1;
}
int persistant_array_exists(object store, string name)
{
if (GetPersistantLocalInt(store,name))
return TRUE;
else
return FALSE;
}
// Test main
//void main(){}

View File

@@ -0,0 +1,436 @@
//::///////////////////////////////////////////////
//:: Persistant local variables include
//:: inc_persist_loca
//:://////////////////////////////////////////////
/** @file
A set of functions for storing local variables
on a token item stored in the creature's skin.
Since local variables on items within containers
are not stripped during serialization, these
variables persist across module changes and
server resets.
These functions work on NPCs in addition to PCs,
but the persitence is mostly useless for them,
since NPCs are usually not serialized in a way
that would remove normal locals from them, if
they are serialized at all.
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//:: Adapted by ebonfowl to fix the Beamdog local variable bug
//:: Functions all still intuitively work the same way
//:: Only difference is the variables all run through SQL rather than via the hide token
//:: Dedicated to Edgar, the real Ebonfowl
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Gets the token item inside the given creature's hide, on which the persistant
* variables are stored on.
* If a token does not exist already, one is created.
* WARNING: If called on a non-creature object, returns the object itself.
*
* @param oPC The creature whose storage token to get
* @param bAMS - TRUE will return special token for alternate magic system buckup info
* @return The creature's storage token
*
* GetNSBToken - special token for New Spellbook System information
*/
//object GetHideToken(object oPC, int bAMS = FALSE);
/**
* Set a local string variable on the creature's storage token.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
* @param sValue The value to set the string local to
*/
void SetPersistantLocalString(object oPC, string sName, string sValue);
/**
* Set a local integer variable on the creature's storage token.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
* @param nValue The value to set the integer local to
*/
void SetPersistantLocalInt(object oPC, string sName, int nValue);
/**
* Set a local float variable on the creature's storage token.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
* @param nValue The value to set the float local to
*/
void SetPersistantLocalFloat(object oPC, string sName, float fValue);
/**
* Set a local location variable on the creature's storage token.
*
* CAUTION! See note in SetPersistantLocalObject(). Location also contains an
* object reference, though it will only break across changes to the module,
* not across server resets.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
* @param nValue The value to set the location local to
*/
void SetPersistantLocalLocation(object oPC, string sName, location lValue);
/**
* Set a local object variable on the creature's storage token.
*
* CAUTION! Object references are likely (and in some cases, certain) to break
* when transferring across modules or upon server reset. This means that
* persistantly stored local objects may not refer to the same object after such
* a change, if they refer to a valid object at all.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
* @param nValue The value to set the object local to
*/
void SetPersistantLocalObject(object oPC, string sName, object oValue);
/**
* Get a local string variable from the creature's storage token.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
* @return The string local specified. On error, returns ""
*/
string GetPersistantLocalString(object oPC, string sName);
/**
* Get a local integer variable from the creature's storage token.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
* @return The integer local specified. On error, returns 0
*/
int GetPersistantLocalInt(object oPC, string sName);
/**
* Get a local float variable from the creature's storage token.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
* @return The float local specified. On error, returns 0.0
*/
float GetPersistantLocalFloat(object oPC, string sName);
/**
* Get a local location variable from the creature's storage token.
*
* CAUTION! See note in SetPersistantLocalLocation()
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
* @return The location local specified. Return value on error is unknown
*/
location GetPersistantLocalLocation(object oPC, string sName);
/**
* Get a local object variable from the creature's storage token.
*
* CAUTION! See note in SetPersistantLocalObject()
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
* @return The object local specified. On error, returns OBJECT_INVALID
*/
object GetPersistantLocalObject(object oPC, string sName);
/**
* Delete a local string variable on the creature's storage token.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
*/
void DeletePersistantLocalString(object oPC, string sName);
/**
* Delete a local integer variable on the creature's storage token.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
*/
void DeletePersistantLocalInt(object oPC, string sName);
/**
* Delete a local float variable on the creature's storage token.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
*/
void DeletePersistantLocalFloat(object oPC, string sName);
/**
* Delete a local location variable on the creature's storage token.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
*/
void DeletePersistantLocalLocation(object oPC, string sName);
/**
* Delete a local object variable on the creature's storage token.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
*/
void DeletePersistantLocalObject(object oPC, string sName);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
#include "prc_inc_skin"
// SQL include
#include "inc_persistsql"
//////////////////////////////////////////////////
/* Function defintions */
//////////////////////////////////////////////////
object GetHideToken(object oPC, int bAMS = FALSE)
{
string sCache = bAMS ? "PRC_AMSTokenCache" : "PRC_HideTokenCache";
string sTag = bAMS ? "AMS_Token" : "HideToken";
// Creatureness check - non-creatures don't get persistent storage from here
if(!(GetObjectType(oPC) == OBJECT_TYPE_CREATURE))
return oPC; // Just return a reference to the object itself
object oHide = GetPCSkin(oPC);
object oToken = GetLocalObject(oPC, sCache);
if(!GetIsObjectValid(oToken))
{
object oTest = GetFirstItemInInventory(oHide);
while(GetIsObjectValid(oTest))
{
if(GetTag(oTest) == sTag)
{
oToken = oTest;
break;//exit while loop
}
oTest = GetNextItemInInventory(oHide);
}
if(!GetIsObjectValid(oToken))
{
oToken = GetItemPossessedBy(oPC, sTag);
// Move the token to hide's inventory
if(GetIsObjectValid(oToken))
AssignCommand(oHide, ActionTakeItem(oToken, oPC)); // Does this work? - Ornedan
else
{
//oToken = CreateItemOnObject("hidetoken", oPC);
//AssignCommand(oHide, ActionTakeItem(oToken, oPC));
oToken = CreateItemOnObject("hidetoken", oHide, 1, sTag);
}
}
AssignCommand(oToken, SetIsDestroyable(FALSE));
// Cache the token so that there needn't be multiple loops over an inventory
SetLocalObject(oPC, sCache, oToken);
//- If the cache reference is found to break under any conditions, uncomment this.
//looks like logging off then back on without the server rebooting breaks it
//I guess because the token gets a new ID, but the local still points to the old one
//Ive changed it to delete the local in OnClientEnter. Primogenitor
//DelayCommand(1.0f, DeleteLocalObject(oPC, "PRC_HideTokenCache"));
}
return oToken;
}
void SetPersistantLocalString(object oPC, string sName, string sValue)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
SQLocalsPlayer_SetString(oPC, sName, sValue);
}
else
{
SetLocalString(oPC, sName, sValue);
}
}
/* void SetPersistantLocalString(object oPC, string sName, string sValue)
{
if(GetIsPC(oPC))
{
SQLocalsPlayer_SetString(oPC, sName, sValue);
}
else
{
SetLocalString(oPC, sName, sValue);
}
} */
void SetPersistantLocalInt(object oPC, string sName, int nValue)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
SQLocalsPlayer_SetInt(oPC, sName, nValue);
}
else
{
SetLocalInt(oPC, sName, nValue);
}
}
void SetPersistantLocalFloat(object oPC, string sName, float fValue)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
SQLocalsPlayer_SetFloat(oPC, sName, fValue);
}
else
{
SetLocalFloat(oPC, sName, fValue);
}
}
void SetPersistantLocalLocation(object oPC, string sName, location lValue)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
SQLocalsPlayer_SetLocation(oPC, sName, lValue);
}
else
{
SetLocalLocation(oPC, sName, lValue);
}
}
void SetPersistantLocalObject(object oPC, string sName, object oValue)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
SQLocalsPlayer_SetObject(oPC, sName, oValue);
}
else
{
SetLocalObject(oPC, sName, oValue);
}
}
string GetPersistantLocalString(object oPC, string sName)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
return SQLocalsPlayer_GetString(oPC, sName);
}
return GetLocalString(oPC, sName);
}
int GetPersistantLocalInt(object oPC, string sName)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
return SQLocalsPlayer_GetInt(oPC, sName);
}
return GetLocalInt(oPC, sName);
}
float GetPersistantLocalFloat(object oPC, string sName)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
return SQLocalsPlayer_GetFloat(oPC, sName);
}
return GetLocalFloat(oPC, sName);
}
location GetPersistantLocalLocation(object oPC, string sName)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
return SQLocalsPlayer_GetLocation(oPC, sName);
}
return GetLocalLocation(oPC, sName);
}
object GetPersistantLocalObject(object oPC, string sName)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
// Additional check since the OID returned may be invalid, but not actually OBJECT_INVALID
object oReturn = SQLocalsPlayer_GetObject(oPC, sName);
if(GetIsObjectValid(oReturn)) return oReturn;
return OBJECT_INVALID;
}
return GetLocalObject(oPC, sName);
}
void DeletePersistantLocalString(object oPC, string sName)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
SQLocalsPlayer_DeleteString(oPC, sName);
}
else
{
DeleteLocalString(oPC, sName);
}
}
void DeletePersistantLocalInt(object oPC, string sName)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
SQLocalsPlayer_DeleteInt(oPC, sName);
}
else
{
DeleteLocalInt(oPC, sName);
}
}
void DeletePersistantLocalFloat(object oPC, string sName)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
SQLocalsPlayer_DeleteFloat(oPC, sName);
}
else
{
DeleteLocalFloat(oPC, sName);
}
}
void DeletePersistantLocalLocation(object oPC, string sName)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
SQLocalsPlayer_DeleteLocation(oPC, sName);
}
else
{
DeleteLocalLocation(oPC, sName);
}
}
void DeletePersistantLocalObject(object oPC, string sName)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
SQLocalsPlayer_DeleteObject(oPC, sName);
}
else
{
DeleteLocalObject(oPC, sName);
}
}
// Test main
// void main() {}

View File

@@ -0,0 +1,688 @@
//::///////////////////////////////////////////////
//:: Utility Include: SQLocalsPlayer
//:: inc_persistsql.nss
//:://////////////////////////////////////////////
/*
Daz wrote these library functions to act as replacements for the usual local
functions:
* GetLocalInt / SetLocalInt / DeleteLocalInt
* GetLocalFloat / SetLocalFloat / DeleteLocalFloat
* GetLocalString / SetLocalString / DeleteLocalString
* GetLocalObject / SetLocalObject / DeleteLocalObject (NB: remember these are references NOT serialised objects)
* GetLocalLocation / SetLocalLocation / DeleteLocalLocation
* Plus a new function for saving just a vector by itself.
Since sometimes iterating over many locals is slow, this might be an excellent way to
speed up large amounts of access, or for debugging, or using regex or whatever else.
These are functions for PC Object persistence only. See utl_i_sqlocals.nss for
the module saved version.
*/
//:://////////////////////////////////////////////
//:: Based off of the nwscript_utility_scripts project; see for dates/creator info
//:: https://github.com/Finaldeath/nwscript_utility_scripts
//:://////////////////////////////////////////////
const string SQLOCALSPLAYER_TABLE_NAME = "sqlocalsplayer_table";
const int SQLOCALSPLAYER_TYPE_ALL = 0;
const int SQLOCALSPLAYER_TYPE_INT = 1;
const int SQLOCALSPLAYER_TYPE_FLOAT = 2;
const int SQLOCALSPLAYER_TYPE_STRING = 4;
const int SQLOCALSPLAYER_TYPE_OBJECT = 8;
const int SQLOCALSPLAYER_TYPE_VECTOR = 16;
const int SQLOCALSPLAYER_TYPE_LOCATION = 32;
// Returns an integer stored on oPlayer, or 0 on error
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
int SQLocalsPlayer_GetInt(object oPlayer, string sVarName);
// Sets an integer stored on oPlayer to the given value
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
// * nValue - Value to store
void SQLocalsPlayer_SetInt(object oPlayer, string sVarName, int nValue);
// Deletes an integer stored on oPlayer
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to delete
void SQLocalsPlayer_DeleteInt(object oPlayer, string sVarName);
// Returns a float stored on oPlayer, or 0.0 on error
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
float SQLocalsPlayer_GetFloat(object oPlayer, string sVarName);
// Sets a float stored on oPlayer to the given value
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
// * fValue - Value to store
void SQLocalsPlayer_SetFloat(object oPlayer, string sVarName, float fValue);
// Deletes a float stored on oPlayer
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to delete
void SQLocalsPlayer_DeleteFloat(object oPlayer, string sVarName);
// Returns an string stored on oPlayer, or "" on error
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
string SQLocalsPlayer_GetString(object oPlayer, string sVarName);
// Sets a string stored on oPlayer to the given value
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
// * sValue - Value to store
void SQLocalsPlayer_SetString(object oPlayer, string sVarName, string sValue);
// Deletes a string stored on oPlayer
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to delete
void SQLocalsPlayer_DeleteString(object oPlayer, string sVarName);
// Returns an object identifier stored on oPlayer
// If this is used on a player it might return a "once valid" OID, so check
// with GetIsObjectValid, do not compare to OBJECT_INVALID.
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
object SQLocalsPlayer_GetObject(object oPlayer, string sVarName);
// Sets an object identifier stored on oPlayer to the given value
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
// * oValue - Value to store
void SQLocalsPlayer_SetObject(object oPlayer, string sVarName, object oValue);
// Deletes an object identifier stored on oPlayer
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to delete
void SQLocalsPlayer_DeleteObject(object oPlayer, string sVarName);
// Returns a vector stored on oPlayer, or [0.0, 0.0, 0.0] on error
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
vector SQLocalsPlayer_GetVector(object oPlayer, string sVarName);
// Sets a vector stored on oPlayer to the given value
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
// * vValue - Value to store
void SQLocalsPlayer_SetVector(object oPlayer, string sVarName, vector vValue);
// Deletes a vector stored on oPlayer
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to delete
void SQLocalsPlayer_DeleteVector(object oPlayer, string sVarName);
// Returns a location stored on oPlayer, or the starting location of the module on error
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
location SQLocalsPlayer_GetLocation(object oPlayer, string sVarName);
// Sets a location stored on oPlayer to the given value
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
// * lValue - Value to store
void SQLocalsPlayer_SetLocation(object oPlayer, string sVarName, location lValue);
// Deletes a location stored on oPlayer
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to delete
void SQLocalsPlayer_DeleteLocation(object oPlayer, string sVarName);
// Deletes a set of locals stored on oPlayer matching the given criteria
// * oPlayer - a player object to save the variable on
// * nType - The SQLOCALSPLAYER_TYPE_* you wish to remove (default: SQLOCALSPLAYER_TYPE_ALL)
// * sLike - The string to compare with the SQL "like" comparison
// * sEscape - The escape character to use with the SQL "escape" keyword
void SQLocalsPlayer_Delete(object oPlayer, int nType = SQLOCALSPLAYER_TYPE_ALL, string sLike = "", string sEscape = "");
// Counts a set of locals stored on oPlayer matching the given criteria
// * oPlayer - a player object to save the variable on
// * nType - The SQLOCALSPLAYER_TYPE_* you wish to count (default: SQLOCALSPLAYER_TYPE_ALL)
// * sLike - The string to compare with the SQL "like" comparison
// * sEscape - The escape character to use with the SQL "escape" keyword
int SQLocalsPlayer_Count(object oPlayer, int nType = SQLOCALSPLAYER_TYPE_ALL, string sLike = "", string sEscape = "");
// Checks a locals stored on oPlayer is set
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
// * nType - The SQLOCALSPLAYER_TYPE_* you wish to check
int SQLocalsPlayer_IsSet(object oPlayer, string sVarName, int nType);
// Returns the last Unix time the given variable was updated
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
// * nType - The SQLOCALSPLAYER_TYPE_* you wish to check
int SQLocalsPlayer_GetLastUpdated_UnixEpoch(object oPlayer, string sVarName, int nType);
// Returns the last UTC time the given variable was updated
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
// * nType - The SQLOCALSPLAYER_TYPE_* you wish to check
string SQLocalsPlayer_GetLastUpdated_UTC(object oPlayer, string sVarName, int nType);
/* INTERNAL */
void SQLocalsPlayer_CreateTable(object oPlayer)
{
sqlquery sql = SqlPrepareQueryObject(oPlayer,
"CREATE TABLE IF NOT EXISTS " + SQLOCALSPLAYER_TABLE_NAME + " (" +
"type INTEGER, " +
"varname TEXT, " +
"value TEXT, " +
"timestamp INTEGER, " +
"PRIMARY KEY(type, varname));");
SqlStep(sql);
}
sqlquery SQLocalsPlayer_PrepareSelect(object oPlayer, int nType, string sVarName)
{
SQLocalsPlayer_CreateTable(oPlayer);
sqlquery sql = SqlPrepareQueryObject(oPlayer,
"SELECT value FROM " + SQLOCALSPLAYER_TABLE_NAME + " " +
"WHERE type = @type AND varname = @varname;");
SqlBindInt(sql, "@type", nType);
SqlBindString(sql, "@varname", sVarName);
return sql;
}
sqlquery SQLocalsPlayer_PrepareInsert(object oPlayer, int nType, string sVarName)
{
SQLocalsPlayer_CreateTable(oPlayer);
sqlquery sql = SqlPrepareQueryObject(oPlayer,
"INSERT INTO " + SQLOCALSPLAYER_TABLE_NAME + " " +
"(type, varname, value, timestamp) VALUES (@type, @varname, @value, strftime('%s','now')) " +
"ON CONFLICT (type, varname) DO UPDATE SET value = @value, timestamp = strftime('%s','now');");
SqlBindInt(sql, "@type", nType);
SqlBindString(sql, "@varname", sVarName);
return sql;
}
sqlquery SQLocalsPlayer_PrepareDelete(object oPlayer, int nType, string sVarName)
{
SQLocalsPlayer_CreateTable(oPlayer);
sqlquery sql = SqlPrepareQueryObject(oPlayer,
"DELETE FROM " + SQLOCALSPLAYER_TABLE_NAME + " " +
"WHERE type = @type AND varname = @varname;");
SqlBindInt(sql, "@type", nType);
SqlBindString(sql, "@varname", sVarName);
return sql;
}
string SQLocalsPlayer_LocationToString(location locLocation)
{
string sAreaId = ObjectToString(GetAreaFromLocation(locLocation));
vector vPosition = GetPositionFromLocation(locLocation);
float fFacing = GetFacingFromLocation(locLocation);
return "#A#" + sAreaId +
"#X#" + FloatToString(vPosition.x, 0, 5) +
"#Y#" + FloatToString(vPosition.y, 0, 5) +
"#Z#" + FloatToString(vPosition.z, 0, 5) +
"#F#" + FloatToString(fFacing, 0, 5) + "#";
}
location SQLocalsPlayer_StringToLocation(string sLocation)
{
location locLocation;
int nLength = GetStringLength(sLocation);
if(nLength > 0)
{
int nPos, nCount;
nPos = FindSubString(sLocation, "#A#") + 3;
nCount = FindSubString(GetSubString(sLocation, nPos, nLength - nPos), "#");
object oArea = StringToObject(GetSubString(sLocation, nPos, nCount));
nPos = FindSubString(sLocation, "#X#") + 3;
nCount = FindSubString(GetSubString(sLocation, nPos, nLength - nPos), "#");
float fX = StringToFloat(GetSubString(sLocation, nPos, nCount));
nPos = FindSubString(sLocation, "#Y#") + 3;
nCount = FindSubString(GetSubString(sLocation, nPos, nLength - nPos), "#");
float fY = StringToFloat(GetSubString(sLocation, nPos, nCount));
nPos = FindSubString(sLocation, "#Z#") + 3;
nCount = FindSubString(GetSubString(sLocation, nPos, nLength - nPos), "#");
float fZ = StringToFloat(GetSubString(sLocation, nPos, nCount));
vector vPosition = Vector(fX, fY, fZ);
nPos = FindSubString(sLocation, "#F#") + 3;
nCount = FindSubString(GetSubString(sLocation, nPos, nLength - nPos), "#");
float fOrientation = StringToFloat(GetSubString(sLocation, nPos, nCount));
if (GetIsObjectValid(oArea))
locLocation = Location(oArea, vPosition, fOrientation);
else
locLocation = GetStartingLocation();
}
return locLocation;
}
/* **** */
/* INT */
// Returns an integer stored on oPlayer, or 0 on error
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
int SQLocalsPlayer_GetInt(object oPlayer, string sVarName)
{
if (!GetIsPC(oPlayer) || sVarName == "") return 0;
sqlquery sql = SQLocalsPlayer_PrepareSelect(oPlayer, SQLOCALSPLAYER_TYPE_INT, sVarName);
if (SqlStep(sql))
return SqlGetInt(sql, 0);
else
return 0;
}
// Sets an integer stored on oPlayer to the given value
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
// * nValue - Value to store
void SQLocalsPlayer_SetInt(object oPlayer, string sVarName, int nValue)
{
if (!GetIsPC(oPlayer) || sVarName == "") return;
sqlquery sql = SQLocalsPlayer_PrepareInsert(oPlayer, SQLOCALSPLAYER_TYPE_INT, sVarName);
SqlBindInt(sql, "@value", nValue);
SqlStep(sql);
}
// Deletes an integer stored on oPlayer
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to delete
void SQLocalsPlayer_DeleteInt(object oPlayer, string sVarName)
{
if (!GetIsPC(oPlayer) || sVarName == "") return;
sqlquery sql = SQLocalsPlayer_PrepareDelete(oPlayer, SQLOCALSPLAYER_TYPE_INT, sVarName);
SqlStep(sql);
}
/* **** */
/* FLOAT */
// Returns a float stored on oPlayer, or 0.0 on error
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
float SQLocalsPlayer_GetFloat(object oPlayer, string sVarName)
{
if (!GetIsPC(oPlayer) || sVarName == "") return 0.0f;
sqlquery sql = SQLocalsPlayer_PrepareSelect(oPlayer, SQLOCALSPLAYER_TYPE_FLOAT, sVarName);
if (SqlStep(sql))
return SqlGetFloat(sql, 0);
else
return 0.0f;
}
// Sets a float stored on oPlayer to the given value
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
// * fValue - Value to store
void SQLocalsPlayer_SetFloat(object oPlayer, string sVarName, float fValue)
{
if (!GetIsPC(oPlayer) || sVarName == "") return;
sqlquery sql = SQLocalsPlayer_PrepareInsert(oPlayer, SQLOCALSPLAYER_TYPE_FLOAT, sVarName);
SqlBindFloat(sql, "@value", fValue);
SqlStep(sql);
}
// Deletes a float stored on oPlayer
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to delete
void SQLocalsPlayer_DeleteFloat(object oPlayer, string sVarName)
{
if (!GetIsPC(oPlayer) || sVarName == "") return;
sqlquery sql = SQLocalsPlayer_PrepareDelete(oPlayer, SQLOCALSPLAYER_TYPE_FLOAT, sVarName);
SqlStep(sql);
}
/* **** */
/* STRING */
// Returns an string stored on oPlayer, or "" on error
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
string SQLocalsPlayer_GetString(object oPlayer, string sVarName)
{
if (!GetIsPC(oPlayer) || sVarName == "") return "";
sqlquery sql = SQLocalsPlayer_PrepareSelect(oPlayer, SQLOCALSPLAYER_TYPE_STRING, sVarName);
if (SqlStep(sql))
return SqlGetString(sql, 0);
else
return "";
}
// Sets a string stored on oPlayer to the given value
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
// * sValue - Value to store
void SQLocalsPlayer_SetString(object oPlayer, string sVarName, string sValue)
{
if (!GetIsPC(oPlayer) || sVarName == "") return;
sqlquery sql = SQLocalsPlayer_PrepareInsert(oPlayer, SQLOCALSPLAYER_TYPE_STRING, sVarName);
SqlBindString(sql, "@value", sValue);
SqlStep(sql);
}
// Deletes a string stored on oPlayer
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to delete
void SQLocalsPlayer_DeleteString(object oPlayer, string sVarName)
{
if (!GetIsPC(oPlayer) || sVarName == "") return;
sqlquery sql = SQLocalsPlayer_PrepareDelete(oPlayer, SQLOCALSPLAYER_TYPE_STRING, sVarName);
SqlStep(sql);
}
/* **** */
/* OBJECT */
// Returns an object identifier stored on oPlayer
// If this is used on a player it might return a "once valid" OID, so check
// with GetIsObjectValid, do not compare to OBJECT_INVALID.
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
object SQLocalsPlayer_GetObject(object oPlayer, string sVarName)
{
if (!GetIsPC(oPlayer) || sVarName == "") return OBJECT_INVALID;
sqlquery sql = SQLocalsPlayer_PrepareSelect(oPlayer, SQLOCALSPLAYER_TYPE_OBJECT, sVarName);
if (SqlStep(sql))
return StringToObject(SqlGetString(sql, 0));
else
return OBJECT_INVALID;
}
// Sets an object identifier stored on oPlayer to the given value
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
// * oValue - Value to store
void SQLocalsPlayer_SetObject(object oPlayer, string sVarName, object oValue)
{
if (!GetIsPC(oPlayer) || sVarName == "") return;
sqlquery sql = SQLocalsPlayer_PrepareInsert(oPlayer, SQLOCALSPLAYER_TYPE_OBJECT, sVarName);
SqlBindString(sql, "@value", ObjectToString(oValue));
SqlStep(sql);
}
// Deletes an object identifier stored on oPlayer
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to delete
void SQLocalsPlayer_DeleteObject(object oPlayer, string sVarName)
{
if (!GetIsPC(oPlayer) || sVarName == "") return;
sqlquery sql = SQLocalsPlayer_PrepareDelete(oPlayer, SQLOCALSPLAYER_TYPE_OBJECT, sVarName);
SqlStep(sql);
}
/* **** */
/* VECTOR */
// Returns a vector stored on oPlayer, or [0.0, 0.0, 0.0] on error
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
vector SQLocalsPlayer_GetVector(object oPlayer, string sVarName)
{
if (!GetIsPC(oPlayer) || sVarName == "") return [0.0f, 0.0f, 0.0f];
sqlquery sql = SQLocalsPlayer_PrepareSelect(oPlayer, SQLOCALSPLAYER_TYPE_VECTOR, sVarName);
if (SqlStep(sql))
return SqlGetVector(sql, 0);
else
return [0.0f, 0.0f, 0.0f];
}
// Sets a vector stored on oPlayer to the given value
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
// * vValue - Value to store
void SQLocalsPlayer_SetVector(object oPlayer, string sVarName, vector vValue)
{
if (!GetIsPC(oPlayer) || sVarName == "") return;
sqlquery sql = SQLocalsPlayer_PrepareInsert(oPlayer, SQLOCALSPLAYER_TYPE_VECTOR, sVarName);
SqlBindVector(sql, "@value", vValue);
SqlStep(sql);
}
// Deletes a vector stored on oPlayer
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to delete
void SQLocalsPlayer_DeleteVector(object oPlayer, string sVarName)
{
if (!GetIsPC(oPlayer) || sVarName == "") return;
sqlquery sql = SQLocalsPlayer_PrepareDelete(oPlayer, SQLOCALSPLAYER_TYPE_VECTOR, sVarName);
SqlStep(sql);
}
/* **** */
/* LOCATION */
// Returns a location stored on oPlayer, or the starting location of the module on error
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
location SQLocalsPlayer_GetLocation(object oPlayer, string sVarName)
{
if (!GetIsPC(oPlayer) || sVarName == "") return GetStartingLocation();
sqlquery sql = SQLocalsPlayer_PrepareSelect(oPlayer, SQLOCALSPLAYER_TYPE_LOCATION, sVarName);
if (SqlStep(sql))
return SQLocalsPlayer_StringToLocation(SqlGetString(sql, 0));
else
return GetStartingLocation();
}
// Sets a location stored on oPlayer to the given value
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
// * lValue - Value to store
void SQLocalsPlayer_SetLocation(object oPlayer, string sVarName, location lValue)
{
if (!GetIsPC(oPlayer) || sVarName == "") return;
sqlquery sql = SQLocalsPlayer_PrepareInsert(oPlayer, SQLOCALSPLAYER_TYPE_LOCATION, sVarName);
SqlBindString(sql, "@value", SQLocalsPlayer_LocationToString(lValue));
SqlStep(sql);
}
// Deletes a location stored on oPlayer
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to delete
void SQLocalsPlayer_DeleteLocation(object oPlayer, string sVarName)
{
if (!GetIsPC(oPlayer) || sVarName == "") return;
sqlquery sql = SQLocalsPlayer_PrepareDelete(oPlayer, SQLOCALSPLAYER_TYPE_LOCATION, sVarName);
SqlStep(sql);
}
/* **** */
/* UTILITY */
// Deletes a set of locals stored on oPlayer matching the given criteria
// * oPlayer - a player object to save the variable on
// * nType - The SQLOCALSPLAYER_TYPE_* you wish to remove (default: SQLOCALSPLAYER_TYPE_ALL)
// * sLike - The string to compare with the SQL "like" comparison
// * sEscape - The escape character to use with the SQL "escape" keyword
// Note if it is TYPE_ALL and sLike is "" then it will delete all values
void SQLocalsPlayer_Delete(object oPlayer, int nType = SQLOCALSPLAYER_TYPE_ALL, string sLike = "", string sEscape = "")
{
if (!GetIsPC(oPlayer) || nType < 0) return;
SQLocalsPlayer_CreateTable(oPlayer);
sqlquery sql;
if(nType == SQLOCALSPLAYER_TYPE_ALL && sLike == "")
{
sql = SqlPrepareQueryObject(oPlayer,
"DELETE FROM " + SQLOCALSPLAYER_TABLE_NAME + ";");
}
else
{
sql = SqlPrepareQueryObject(oPlayer,
"DELETE FROM " + SQLOCALSPLAYER_TABLE_NAME + " " +
"WHERE TRUE " +
(nType != SQLOCALSPLAYER_TYPE_ALL ? "AND type & @type " : " ") +
(sLike != "" ? "AND varname LIKE @like " + (sEscape != "" ? "ESCAPE @escape" : "") : "") +
";");
if (nType != SQLOCALSPLAYER_TYPE_ALL)
SqlBindInt(sql, "@type", nType);
if (sLike != "")
{
SqlBindString(sql, "@like", sLike);
if (sEscape != "")
SqlBindString(sql, "@escape", sEscape);
}
}
SqlStep(sql);
}
// Counts a set of locals stored on oPlayer matching the given criteria
// * oPlayer - a player object to save the variable on
// * nType - The SQLOCALSPLAYER_TYPE_* you wish to count (default: SQLOCALSPLAYER_TYPE_ALL)
// * sLike - The string to compare with the SQL "like" comparison
// * sEscape - The escape character to use with the SQL "escape" keyword
int SQLocalsPlayer_Count(object oPlayer, int nType = SQLOCALSPLAYER_TYPE_ALL, string sLike = "", string sEscape = "")
{
if (!GetIsPC(oPlayer) || nType < 0) return 0;
SQLocalsPlayer_CreateTable(oPlayer);
sqlquery sql;
if(nType == SQLOCALSPLAYER_TYPE_ALL && sLike == "")
{
sql = SqlPrepareQueryObject(oPlayer,
"SELECT COUNT(*) FROM " + SQLOCALSPLAYER_TABLE_NAME + ";");
}
else if(nType != SQLOCALSPLAYER_TYPE_ALL && sLike == "")
{
sql = SqlPrepareQueryObject(oPlayer,
"SELECT COUNT(*) FROM " + SQLOCALSPLAYER_TABLE_NAME + " " +
"WHERE type & @type;");
SqlBindInt(sql, "@type", nType);
}
else if(nType == SQLOCALSPLAYER_TYPE_ALL && sLike != "")
{
sql = SqlPrepareQueryObject(oPlayer,
"SELECT COUNT(*) FROM " + SQLOCALSPLAYER_TABLE_NAME + " " +
"varname LIKE @like " + (sEscape != "" ? "ESCAPE @escape" : "") +
";");
SqlBindString(sql, "@like", sLike);
if (sEscape != "")
SqlBindString(sql, "@escape", sEscape);
}
else
{
sql = SqlPrepareQueryObject(oPlayer,
"SELECT COUNT(*) FROM " + SQLOCALSPLAYER_TABLE_NAME + " " +
"WHERE type & @type " +
"AND varname LIKE @like " + (sEscape != "" ? "ESCAPE @escape" : "") +
";");
SqlBindInt(sql, "@type", nType);
SqlBindString(sql, "@like", sLike);
if (sEscape != "")
SqlBindString(sql, "@escape", sEscape);
}
if (SqlStep(sql))
return SqlGetInt(sql, 0);
else
return 0;
}
// Checks a locals stored on oPlayer is set
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
// * nType - The SQLOCALSPLAYER_TYPE_* you wish to check (default: SQLOCALSPLAYER_TYPE_ALL)
int SQLocalsPlayer_IsSet(object oPlayer, string sVarName, int nType)
{
if (!GetIsPC(oPlayer) || nType < 0) return 0;
SQLocalsPlayer_CreateTable(oPlayer);
sqlquery sql = SqlPrepareQueryObject(oPlayer,
"SELECT * FROM " + SQLOCALSPLAYER_TABLE_NAME + " " +
"WHERE AND varname = @varname" +
(nType != SQLOCALSPLAYER_TYPE_ALL ? "AND type & @type " : " ") +
";");
if (nType != SQLOCALSPLAYER_TYPE_ALL)
SqlBindInt(sql, "@type", nType);
SqlBindString(sql, "@varname", sVarName);
return SqlStep(sql);
}
// Returns the last Unix time the given variable was updated
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
// * nType - The SQLOCALSPLAYER_TYPE_* you wish to check (default: SQLOCALSPLAYER_TYPE_ALL)
int SQLocalsPlayer_GetLastUpdated_UnixEpoch(object oPlayer, string sVarName, int nType)
{
if (!GetIsPC(oPlayer) || nType <= 0) return 0;
SQLocalsPlayer_CreateTable(oPlayer);
sqlquery sql = SqlPrepareQueryObject(oPlayer,
"SELECT timestamp FROM " + SQLOCALSPLAYER_TABLE_NAME + " " +
"WHERE type = @type " +
"AND varname = @varname;");
SqlBindInt(sql, "@type", nType);
SqlBindString(sql, "@varname", sVarName);
if (SqlStep(sql))
return SqlGetInt(sql, 0);
else
return 0;
}
// Returns the last UTC time the given variable was updated
// * oPlayer - a player object to save the variable on
// * sVarName - name of the variable to retrieve
// * nType - The SQLOCALSPLAYER_TYPE_* you wish to check (default: SQLOCALSPLAYER_TYPE_ALL)
string SQLocalsPlayer_GetLastUpdated_UTC(object oPlayer, string sVarName, int nType)
{
if (!GetIsPC(oPlayer) || nType <= 0) return "";
SQLocalsPlayer_CreateTable(oPlayer);
sqlquery sql = SqlPrepareQueryObject(oPlayer,
"SELECT datetime(timestamp, 'unixepoch') FROM " + SQLOCALSPLAYER_TABLE_NAME + " " +
"WHERE type = @type " +
"AND varname = @varname;");
SqlBindInt(sql, "@type", nType);
SqlBindString(sql, "@varname", sVarName);
if (SqlStep(sql))
return SqlGetString(sql, 0);
else
return "";
}

113
src/include/inc_poison.nss Normal file
View File

@@ -0,0 +1,113 @@
//::///////////////////////////////////////////////
//:: Poison System includes
//:: inc_poison
//::///////////////////////////////////////////////
//:://////////////////////////////////////////////
//:: Created By: Ornedan
//:: Created On: 12.12.2004
//:: Updated On: 09.01.2005
//:://////////////////////////////////////////////
const int POISONED_WEAPON_CASTERLEVEL = 1;
const int STRREF_POISON_WORN_OFF = 16826227;
const int STRREF_POISON_APPLY_SUCCESS = 16826228;
const int STRREF_POISON_APPLY_FAILURE = 16826230;
const int STRREF_POISON_CLEAN_OFF_WEAPON = 16826229;
const int STRREF_POISON_NOT_VALID_FOR_WEAPON = 16826231;
const int STRREF_SHATTER_HARMLESS = 16826234;
const int STRREF_POISON_ITEM_USE_1 = 16826236;
const int STRREF_POISON_ITEM_USE_2 = 16826237;
const int STRREF_POISON_FOOD_USE_1 = 16826239;
const int STRREF_POISON_FOOD_USE_2 = 16826240;
const int STRREF_CLEAN_ITEM_SUCCESS = 16826242;
const int STRREF_CLEAN_ITEM_FAIL_1 = 16826243;
const int STRREF_CLEAN_ITEM_FAIL_2 = 16826244;
const int STRREF_INVALID_TARGET = 16826245;
const int STRREF_NOT_CONTACT_POISON = 16826246;
const int STRREF_TARGET_ALREADY_POISONED = 16826247;
const int STRREF_NOT_INGESTED_POISON = 16826251;
const int STRREF_TARGET_NOT_FOOD = 16826252;
const int STRREF_ACQUIRE_SPOT_SUCCESS1 = 16826253;
const int STRREF_ACQUIRE_SPOT_SUCCESS2 = 16826254;
const int STRREF_ONEQUIP_CLEAN_ITEM = 16826255;
const int POISON_TYPE_CONTACT = 0;
const int POISON_TYPE_INGESTED = 1;
const int POISON_TYPE_INHALED = 2;
const int POISON_TYPE_INJURY = 3;
/**
* Gets the type of the given poison.
*
* @param nPoison POISON_* constant
* @return POISON_TYPE_* constant
*/
int GetPoisonType(int nPoison);
// Poison removal handlers
void DoPoisonRemovalFromWeapon(object oWeapon);
void DoPoisonRemovalFromItem(object oItem);
//#include "inc_utility"
//#include "inc_poison_const"
#include "prc_inc_spells"
#include "prc_ipfeat_const"
/****************************************************
************** The implementations ******************
****************************************************/
int GetPoisonType(int nPoison)
{
return StringToInt(Get2DACache("poison", "Poison_Type", nPoison));
}
// Handles removing of itemproperties and locals on a poisoned weapon
void DoPoisonRemovalFromWeapon(object oWeapon)
{
DeleteLocalInt(oWeapon, "pois_wpn_idx");
DeleteLocalInt(oWeapon, "pois_wpn_uses");
RemoveEventScript(oWeapon, EVENT_ITEM_ONHIT, "poison_wpn_onhit", TRUE, TRUE);
// Remove the UniquePower only if poisoning the weapon added it.
if(GetLocalInt(oWeapon, "PoisonedWeapon_DoDelete"))
RemoveSpecificProperty(oWeapon,
ITEM_PROPERTY_ONHITCASTSPELL,
IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER,
0,
1,
"",
-1,
DURATION_TYPE_PERMANENT);
}
// Handles removing of itemproperties and locals on a poisoned item
void DoPoisonRemovalFromItem(object oItem)
{
DeleteLocalInt(oItem, "pois_itm_idx");
DeleteLocalInt(oItem, "pois_itm_uses");
DeleteLocalInt(oItem, "pois_itm_trap_dc");
DeleteLocalObject(oItem, "pois_itm_poisoner");
int nSafeCount = GetLocalInt(oItem, "pois_itm_safecount");
DeleteLocalInt(oItem, "pois_itm_safecount");
int i;
for(i = 1; i <= nSafeCount; i++)
DeleteLocalObject(oItem, "pois_itm_safe_" + IntToString(i));
RemoveSpecificProperty(oItem,
ITEM_PROPERTY_CAST_SPELL,
IP_CONST_CASTSPELL_CLEAN_POISON_OFF,
IP_CONST_CASTSPELL_NUMUSES_UNLIMITED_USE,
1,
"",
-1,
DURATION_TYPE_PERMANENT);
RemoveEventScript(oItem, EVENT_ITEM_ONACQUIREITEM, "poison_onaquire", TRUE, TRUE);
RemoveEventScript(oItem, EVENT_ITEM_ONPLAYEREQUIPITEM, "poison_onequip", TRUE, TRUE);
}

181
src/include/inc_prc_npc.nss Normal file
View File

@@ -0,0 +1,181 @@
//::///////////////////////////////////////////////
//:: NPC event wrapper include
//:: inc_prc_npc
//:://////////////////////////////////////////////
/** @file
Wrapper functions for getters used in module
events. Used to make the PRC evaluations
happening in events to work for NPCs, too.
Event currently supported:
OnEquip
OnUnequip
OnDeath
OnRest
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* A heartbeat function for NPCs. Checks if their equipped items have changed.
* Simulates OnEquip / OnUnEquip firing
* Since this should be fired from an NPCs hearbeat, OBJECT_SELF is assumed to
* be the NPC.
*/
void DoEquipTest();
/* On(Un)Equip wrappers */
/**
* Wrapper for GetPCItemLastEquipped
*/
object GetItemLastEquipped();
/**
* Wrapper for GetPCItemLastEquippedBy
*/
object GetItemLastEquippedBy();
/**
* Wrapper for GetItemLastUnequipped
*/
object GetItemLastUnequipped();
/**
* Wrapper for GetPCItemLastUnequippedBy
*/
object GetItemLastUnequippedBy();
/* OnDeath wrappers */
/**
* Wrapper for GetLastHostileActor and GetLastKiller
*/
object MyGetLastKiller();
/**
* Wrapper for GetLastPlayerDied
*/
object GetLastBeingDied();
/* OnRest wrapper */
/**
* Wrapper for GetLastPCRested
*/
object GetLastBeingRested();
/**
* Wrapper for GetLastRestEventType
*/
int MyGetLastRestEventType();
//////////////////////////////////////////////////
/* Function defintions */
//////////////////////////////////////////////////
object GetItemLastEquippedBy()
{
if(GetModule() == OBJECT_SELF || GetIsPC(OBJECT_SELF)) // prc_inc_function runs the class scripts on the PC instead of the module
return GetPCItemLastEquippedBy();
else
return OBJECT_SELF;
}
object GetItemLastUnequippedBy()
{
if(GetModule() == OBJECT_SELF || GetIsPC(OBJECT_SELF))
return GetPCItemLastUnequippedBy();
else
return OBJECT_SELF;
}
object GetItemLastEquipped()
{
if(GetModule() == OBJECT_SELF || GetIsPC(OBJECT_SELF))
return GetPCItemLastEquipped();
else
return GetLocalObject(OBJECT_SELF, "oLastEquipped");
}
object GetItemLastUnequipped()
{
if(GetModule() == OBJECT_SELF || GetIsPC(OBJECT_SELF))
return GetPCItemLastUnequipped();
else
return GetLocalObject(OBJECT_SELF, "oLastUnequipped");
}
void DoEquipTest()
{
int i;
object oTest;
object oItem;
for(i=1; i<NUM_INVENTORY_SLOTS;i++)
{
oItem = GetItemInSlot(i, OBJECT_SELF);
oTest = GetLocalObject(OBJECT_SELF, "oSlotItem"+IntToString(i));
if(oTest != oItem)
{
if(GetIsObjectValid(oItem))
{
SetLocalObject(OBJECT_SELF, "oLastEquipped", oItem);
ExecuteScript("prc_equip", OBJECT_SELF);
}
if(GetIsObjectValid(oTest))
{
SetLocalObject(OBJECT_SELF, "oLastUnequipped", oTest);
ExecuteScript("prc_unequip", OBJECT_SELF);
}
SetLocalObject(OBJECT_SELF, "oSlotItem"+IntToString(i), oItem);
// to avoid lag, only run this on 1 item per HB
// so we abort this now and prc_npc_hb will run it again in 6 seconds
return;
}
}
}
object MyGetLastKiller(){
if(GetModule() == OBJECT_SELF || GetIsPC(OBJECT_SELF))
return GetLastHostileActor();
else
return GetLastKiller();
}
object GetLastBeingDied(){
if(GetModule() == OBJECT_SELF || GetIsPC(OBJECT_SELF))
return GetLastPlayerDied();
else
return OBJECT_SELF;
}
object GetLastBeingRested(){
if(GetModule() == OBJECT_SELF || GetIsPC(OBJECT_SELF))
{
// Account for the PRCForceRest() wrapper
if(GetLocalInt(OBJECT_SELF, "PRC_ForceRested"))
return OBJECT_SELF;
else
return GetLastPCRested();
}
else
return OBJECT_SELF;
}
int MyGetLastRestEventType(){
if(GetModule() == OBJECT_SELF || GetIsPC(OBJECT_SELF))
return GetLastRestEventType();
else
return GetLocalInt(OBJECT_SELF, "prc_rest_eventtype");
}

View File

@@ -0,0 +1,167 @@
//include file for new polymorph like functions using the pnp shifters shifting code
//created by paradox_42 - 2005/07/01
// used to shift by resref
// oPC = PC to shift/polymorph
// sResRef = ResRef of Target to shift/polymorph into
// iExtraAbilitys = gives epic shifter orb with target spell-like abilitys on it (TRUE = extra; FALSE = non)
int PRC_Polymorph_ResRef(object oPC, string sResRef, int iExtraAbilitys);
// used to shift by Object
// oPC = PC to shift/polymorph
// oTarget = Target object to shift/polymorph into
// iExtraAbilitys = gives epic shifter orb with target spell-like abilitys on it (TRUE = extra; FALSE = non)
// iDeleteTarget = delete the target object after shift done (TRUE = delete; FALSE = leave)
// iUseClone = use the ResRef of the target object to create a clone to shift into (TRUE = use clone; FALSE = use target object)
int PRC_Polymorph_Object(object oPC, object oTarget, int iExtraAbilitys, int iDeleteTarget, int iUseClone);
// used to check for shifted
// oPC = PC to check if shifted or not
// returns TRUE if shifted
int PRC_Polymorph_Check(object oPC);
// used to unshift the PC
// oPC = PC to unshift/unpolymorph
void PRC_UnPolymorph(object oPC);
#include "pnp_shft_main"
int PRC_Polymorph_ResRef(object oPC, string sResRef, int iExtraAbilitys)
{
StoreAppearance(oPC);
if (!CanShift(oPC))
{
return FALSE;
}
int i = 0;
object oLimbo = GetObjectByTag("Limbo", i);
location lLimbo;
while (i < 100)
{
if (GetIsObjectValid(oLimbo))
{
if (GetName(oLimbo) == "Limbo")
{
i = 2000;
vector vLimbo = Vector(0.0f, 0.0f, 0.0f);
lLimbo = Location(oLimbo, vLimbo, 0.0f);
}
}
i++;
object oLimbo = GetObjectByTag("Limbo", i);
}
object oTarget;
if (i>=2000)
{
oTarget = CreateObject(OBJECT_TYPE_CREATURE,sResRef,lLimbo);
}
else
{
oTarget = CreateObject(OBJECT_TYPE_CREATURE,sResRef,GetLocation(oPC));
}
if (!GetIsObjectValid(oTarget))
{
SendMessageToPC(oPC, "Not a valid creature.");
// Remove the temporary creature
AssignCommand(oTarget,SetIsDestroyable(TRUE,FALSE,FALSE));
SetPlotFlag(oTarget,FALSE);
SetImmortal(oTarget,FALSE);
DestroyObject(oTarget);
return FALSE;
}
else
{
//get the appearance before changing it
SetLocalInt(oTarget,"Appearance",GetAppearanceType(oTarget));
//set appearance to invis so it dont show up when scripts run thro
SetCreatureAppearanceType(oTarget,APPEARANCE_TYPE_INVISIBLE_HUMAN_MALE);
//set oTarget for deletion
SetLocalInt(oTarget,"pnp_shifter_deleteme",1);
//Shift the PC to it
if (iExtraAbilitys == TRUE)
SetShiftEpic(oPC, oTarget);
else
SetShift(oPC, oTarget);
return TRUE;
}
}
int PRC_Polymorph_Object(object oPC, object oTarget, int iExtraAbilitys, int iDeleteTarget, int iUseClone)
{
StoreAppearance(oPC);
if (!CanShift(oPC))
{
return FALSE;
}
if (iUseClone == TRUE)
{
string sResRef = GetResRef(oTarget);
int i = 0;
object oLimbo = GetObjectByTag("Limbo", i);
location lLimbo;
while (i < 100)
{
if (GetIsObjectValid(oLimbo))
{
if (GetName(oLimbo) == "Limbo")
{
i = 2000;
vector vLimbo = Vector(0.0f, 0.0f, 0.0f);
lLimbo = Location(oLimbo, vLimbo, 0.0f);
}
}
i++;
object oLimbo = GetObjectByTag("Limbo", i);
}
if (i>=2000)
{
oTarget = CreateObject(OBJECT_TYPE_CREATURE,sResRef,lLimbo);
}
else
{
oTarget = CreateObject(OBJECT_TYPE_CREATURE,sResRef,GetLocation(oPC));
}
}
if (!GetIsObjectValid(oTarget))
{
SendMessageToPC(oPC, "Not a valid creature.");
// Remove the temporary creature
AssignCommand(oTarget,SetIsDestroyable(TRUE,FALSE,FALSE));
SetPlotFlag(oTarget,FALSE);
SetImmortal(oTarget,FALSE);
DestroyObject(oTarget);
return FALSE;
}
else
{
SetLocalInt(oTarget,"Appearance",GetAppearanceType(oTarget));
if (iDeleteTarget == TRUE)
{
//set oTarget for deletion
SetLocalInt(oTarget,"pnp_shifter_deleteme",1);
}
//Shift the PC to it
if (iExtraAbilitys == TRUE)
SetShiftEpic(oPC, oTarget);
else
SetShift(oPC, oTarget);
return TRUE;
}
}
int PRC_Polymorph_Check(object oPC)
{
return GetPersistantLocalInt(oPC, "nPCShifted");
}
void PRC_UnPolymorph(object oPC)
{
ExecuteScript("pnp_shft_true", oPC);
}
// Test main
//void main(){}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
//::///////////////////////////////////////////////
//:: Poison System includes for Ravages
//:: inc_ravage
//::///////////////////////////////////////////////
//:://////////////////////////////////////////////
//:: Created By: Ornedan
//:: Created On: 10.01.2005
//:://////////////////////////////////////////////
#include "prc_alterations"
// Calculates the amount of extra ability damage ravages cause:
// Charisma bonus, if any
// +1 if undead
// +1 if elemental
// +2 if outsider
// +2 if cleric
int GetRavageExtraDamage(object oTarget)
{
int nRacial = MyPRCGetRacialType(oTarget);
int nExtra = GetAbilityModifier(ABILITY_CHARISMA, oTarget);
nExtra = (nExtra > 0) ? nExtra : 0;
if ( nRacial == RACIAL_TYPE_UNDEAD) nExtra++;
if ( nRacial == RACIAL_TYPE_ELEMENTAL) nExtra++;
if ( nRacial == RACIAL_TYPE_OUTSIDER) nExtra+=2;
if ( GetLevelByClass(CLASS_TYPE_CLERIC,oTarget)) nExtra+=2;
return nExtra;
}
// Creates the VFX common to all ravages.
// This is used when they deal their damage
effect GetRavageVFX()
{
//effect eReduce = EffectVisualEffect(VFX_IMP_REDUCE_ABILITY_SCORE);
effect eHoly = EffectVisualEffect(VFX_IMP_SUNSTRIKE);
//effect eHoly = EffectVisualEffect(VFX_IMP_HEAD_HOLY);
return eHoly;//EffectLinkEffects(eReduce, eHoly);
}

237
src/include/inc_rend.nss Normal file
View File

@@ -0,0 +1,237 @@
//::///////////////////////////////////////////////
//:: Rend OnHit include
//:: inc_rend
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//:: Created By: Ornedan
//:: Created On: 23.01.2005
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Constant defintions */
//////////////////////////////////////////////////
const string REND_1ST_HIT_DONE = "RendingHit1stHit";
const string REND_DONE = "RendingHitDone";
const string FROST_1ST_HIT_DONE = "FrostRendHit1stHit";
const string FROST_DONE = "FrostRendHitDone";
const string SPINE_1ST_HIT_DONE = "SpineRendHit1stHit";
const string SPINE_DONE = "SpineRendHitDone";
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
void DoRend(object oTarget, object oAttacker, object oWeapon);
int GetDamageFromConstant(int nIPConst);
void DoFrostRend(object oTarget, object oAttacker, object oWeapon);
#include "moi_inc_moifunc"
//////////////////////////////////////////////////
/* Function defintions */
//////////////////////////////////////////////////
void DoRend(object oTarget, object oAttacker, object oWeapon)
{
if (DEBUG) DoDebug("DoRend running");
// Only one rend allowed per round for the sake of clearness
if(GetLocalInt(oAttacker, REND_DONE))
return;
if(GetLocalObject(oAttacker, REND_1ST_HIT_DONE) == oTarget)
{
if (DEBUG) DoDebug("DoRend second hit");
// First, find the weapon base damage
int nIPConst;
itemproperty ipCheck = GetFirstItemProperty(oWeapon);
while(GetIsItemPropertyValid(ipCheck))
{
if(GetItemPropertyType(ipCheck) == ITEM_PROPERTY_MONSTER_DAMAGE)
{
nIPConst = GetItemPropertyCostTableValue(ipCheck);
break;
}
ipCheck = GetNextItemProperty(oWeapon);
}
int nDamage = GetDamageFromConstant(nIPConst);
int nStrBon = GetAbilityModifier(ABILITY_STRENGTH, oAttacker);
nStrBon = nStrBon < 0 ? 0 : nStrBon;
nDamage += nStrBon;
if (GetLevelByClass(CLASS_TYPE_BLACK_BLOOD_CULTIST, oAttacker) >= 6) nDamage *= 2;
if (GetIsMeldBound(oAttacker, MELD_GIRALLON_ARMS) == CHAKRA_ARMS) nDamage *= 2;
if (GetHasSpellEffect(VESTIGE_IPOS, oAttacker) >= 6) nDamage *= 2;
int nDamageType;
switch(GetBaseItemType(oWeapon))
{
case BASE_ITEM_CBLUDGWEAPON:
nDamageType = DAMAGE_TYPE_BLUDGEONING;
break;
case BASE_ITEM_CPIERCWEAPON:
nDamageType = DAMAGE_TYPE_PIERCING;
break;
// Both slashing and slashing & piercing weapons do slashing damage from rend
// because it's not possible to make the damage be of both types in any
// elegant way
case BASE_ITEM_CSLASHWEAPON:
case BASE_ITEM_CSLSHPRCWEAP:
nDamageType = DAMAGE_TYPE_SLASHING;
break;
default:
WriteTimestampedLogEntry("Unexpected weapon type in DoRend()!");
return;
}
// Apply damage and VFX
effect eDamage = EffectDamage(nDamage, nDamageType);
effect eLink = EffectLinkEffects(eDamage, EffectVisualEffect(VFX_COM_BLOOD_CRT_RED));
ApplyEffectToObject(DURATION_TYPE_INSTANT, eLink, oTarget);
// Tell people what happened
// * AttackerName rends TargetName *
FloatingTextStringOnCreature("* " + GetName(oAttacker) + " " + GetStringByStrRef(0x01000000 + 51197) + " " + GetName(oTarget) + " *", oAttacker, TRUE);
// Note the rend having happened in the locals
SetLocalInt(oAttacker, REND_DONE, TRUE);
DelayCommand(4.5, DeleteLocalInt(oAttacker, REND_DONE));
}// end if - the target had a local signifying that rend is possible
else
{
SetLocalObject(oAttacker, REND_1ST_HIT_DONE, oTarget);
if (DEBUG) DoDebug("DoRend first hit");
}
}
void DoFrostRend(object oTarget, object oAttacker, object oWeapon)
{
// Only one rend allowed per round for the sake of clearness
if(GetLocalInt(oAttacker, FROST_DONE))
return;
float fDelay1 = 6.0 - (6.0 / GetMainHandAttacks(oAttacker));
float fDelay2 = 6.0 - 2 * (6.0 - fDelay1);
if(GetLocalObject(oAttacker, FROST_1ST_HIT_DONE) == oTarget)
{
// First, find the weapon base damage
int nIPConst;
itemproperty ipCheck = GetFirstItemProperty(oWeapon);
while(GetIsItemPropertyValid(ipCheck))
{
if(GetItemPropertyType(ipCheck) == ITEM_PROPERTY_MONSTER_DAMAGE)
{
nIPConst = GetItemPropertyCostTableValue(ipCheck);
break;
}
ipCheck = GetNextItemProperty(oWeapon);
}
int nDamage = GetDamageFromConstant(nIPConst);
int nStrBon = GetAbilityModifier(ABILITY_STRENGTH, oAttacker);
nStrBon = nStrBon < 0 ? 0 : nStrBon;
// nDamage += nStrBon;
// nDamage += FloatToInt(nStrBon/2); //1.5x Strength damage
nDamage += FloatToInt(nStrBon * 1.5);
int nDamageType = DAMAGE_TYPE_BLUDGEONING; // It's an unarmed strike, so always bludgeoning for this
// Apply damage and VFX
effect eDamage = EffectDamage(nDamage, nDamageType);
effect eLink = EffectLinkEffects(eDamage, EffectVisualEffect(VFX_IMP_FROST_L));
eLink = EffectLinkEffects(eLink, EffectDamage(d6(), DAMAGE_TYPE_COLD));
ApplyEffectToObject(DURATION_TYPE_INSTANT, eLink, oTarget);
// Tell people what happened
// * AttackerName rends TargetName *
FloatingTextStringOnCreature("* " + GetName(oAttacker) + " " + GetStringByStrRef(0x01000000 + 51197) + " " + GetName(oTarget) + " *",
oAttacker,
TRUE);
// Note the rend having happened in the locals
SetLocalInt(oAttacker, FROST_DONE, TRUE);
DelayCommand(fDelay2, DeleteLocalInt(oAttacker, FROST_DONE));
}// end if - the target had a local signifying that rend is possible
else
{
SetLocalObject(oAttacker, FROST_1ST_HIT_DONE, oTarget);
DelayCommand(fDelay1, DeleteLocalObject(oAttacker, FROST_1ST_HIT_DONE));
}
}
void DoSpineRend(object oTarget, object oAttacker, object oWeapon)
{
// Only one rend allowed per round for the sake of clearness
if(GetLocalInt(oAttacker, SPINE_DONE))
return;
float fDelay1 = 6.0 - (6.0 / GetMainHandAttacks(oAttacker));
float fDelay2 = 6.0 - 2 * (6.0 - fDelay1);
if(GetLocalObject(oAttacker, SPINE_1ST_HIT_DONE) == oTarget)
{
int nStrBon = GetAbilityModifier(ABILITY_STRENGTH, oAttacker);
nStrBon = nStrBon < 0 ? 0 : nStrBon;
int nDamage = FloatToInt(nStrBon * 1.5);
// Apply damage and VFX
effect eDamage = EffectDamage(nDamage + d6(2), DAMAGE_TYPE_PIERCING);
effect eLink = EffectLinkEffects(eDamage, EffectVisualEffect(VFX_COM_BLOOD_SPARK_MEDIUM));
ApplyEffectToObject(DURATION_TYPE_INSTANT, eLink, oTarget);
// Tell people what happened
// * AttackerName rends TargetName *
FloatingTextStringOnCreature("* " + GetName(oAttacker) + " " + GetStringByStrRef(0x01000000 + 51197) + " " + GetName(oTarget) + " *", oAttacker, TRUE);
// Note the rend having happened in the locals
SetLocalInt(oAttacker, SPINE_DONE, TRUE);
DelayCommand(fDelay2, DeleteLocalInt(oAttacker, SPINE_DONE));
}// end if - the target had a local signifying that rend is possible
else
{
SetLocalObject(oAttacker, SPINE_1ST_HIT_DONE, oTarget);
DelayCommand(fDelay1, DeleteLocalObject(oAttacker, SPINE_1ST_HIT_DONE));
}
}
int GetDamageFromConstant(int nIPConst)
{
// First, handle the values outside the main series
switch(nIPConst)
{
case IP_CONST_MONSTERDAMAGE_1d2: return d2(1);
case IP_CONST_MONSTERDAMAGE_1d3: return d3(1);
case IP_CONST_MONSTERDAMAGE_1d4: return d4(1);
case IP_CONST_MONSTERDAMAGE_2d4: return d4(2);
case IP_CONST_MONSTERDAMAGE_3d4: return d4(3);
case IP_CONST_MONSTERDAMAGE_4d4: return d4(4);
case IP_CONST_MONSTERDAMAGE_5d4: return d4(5);
case IP_CONST_MONSTERDAMAGE_7d4: return d4(7);
}
int nDieNum = ((nIPConst - 8) % 10) + 1;
switch((nIPConst - 8) / 10)
{
case 0: return d6(nDieNum);
case 1: return d8(nDieNum);
case 2: return d10(nDieNum);
case 3: return d12(nDieNum);
case 4: return d20(nDieNum);
}
WriteTimestampedLogEntry("Unknown IP_CONST_MONSTERDAMAGE_* constant passed to GetDamageFromConstant()!");
return 0;
}
//:: void main (){}

View File

@@ -0,0 +1,227 @@
/*
Supply Based Rest System: Version 1.2
Created by: Demetrious and OldManWhistler
For questions or comments, or to get the latest version please visit:
http://nwvault.ign.com/Files/scripts/data/1055903555000.shtml
****************************************************************************
CONTENTS
****************************************************************************
Placeables>>Misc Interior - restful bed, restful bed (invisible object), restful cot, restful bedroll, restful campsite.
Items>>Misc>>kits - Supply kit, Woodland kit, DM Rest Widget.
Supply Kit weighs 30 lbs, costs 100gp and can be used by anyone to create a restful object.
Supply Kit weighs 15 lbs, costs 75gp and can only be used by rangers/druids.
Scripts - sbr_onrest, sbr_restful_obj, sbr_onactivate, sbr_onacquire, sbr_include, logmessage
****************************************************************************
DESCRIPTION
****************************************************************************
This is a supply based rest system. There are three methods of resting in this system:
1) Restful beds, cots, bedrolls - I personally place these in towns or cities and maybe rarely in dungeons where it is assumed that there are sufficient supplies to rest (ie food, water, bed). These objects will ALWAYS allow a player to rest.
2) Supply kit resting (or woodland kit resting) - Using this item will create a campfire that players may use to rest. For roleplaying, the kit contains all supplies needed to rest and these are used while the players rest. It is removed after a time delay of several minutes.
3) DM Controlled rest widget - DM can turn resting on/off for the entire module, a specific area, or a specific player.
This is an attempt create a rest system closer to the resting that I remember from PnP. This system encourages players to rest as a group and forces them to ration supplies. Finally it forces the players to guard the campfire because how bad would it be if a bear destroyed the campfire before they could all rest.
The kits are purposefully heavy. This is to encourage appropriate rationing of supplies.
If player rest is restricted by a BW trigger or by your widget, you will receive a message stating the reason rest was restricted and the message will include the player name and area and level that restricted rest. Both the player and the DM will receive a message that indicates the reason for rest being canceled.
****************************************************************************
INSTALLATION
****************************************************************************
// SupplyBasedRest.erf contains the base scripts, the placeables and the items.
// sbr_acttag.erf is only needed if you use an activate item system
// where you execute the item's tag as a script
// (ie: you use X0_ONITEMACTV as your OnActivateItem script).
// #1: Modify OnAcquiredItem module event script (create if it does not exist).
// Add the following line to somewhere in the void main function. If you do
// not have an OnAcquiredItem script then you can use 'sbr_onacquire' as your
// OnAcquiredItem script.
ExecuteScript("sbr_onacquire", OBJECT_SELF);
// #2: Set your module OnPlayerRest script to "sbr_onrest".
// #3: Modify OnActivateItem module event script. You can skip this step if you use an activate item script
// that executes a script with the same name as the item tag and you have imported sbr_acttag.erf.
ExecuteScript("sbr_onactivate", OBJECT_SELF);
// #4: Add the kits to some stores and place restful objects in your inns.
// #5: (optional) Create a journal entry that explains the rest system and give
// it to players when they enter the module. A sample journal entry is provided
// in this documentation.
// #6: (optional) You can extend the rest system by handling the SBR_EVENT_REST
// in the module OnUserDefined event. You could easily add a wandering monster system,
// a "dream plane" or have cutscenes play when resting in specific areas.
// Read more about the OnUserDefined event at:
// http://www.reapers.org/nwn/reference/compiled/event.OnUserDefined.html
// SBR_EVENT_REST is defined in the sbr_include script.
****************************************************************************
CONFIGURATION
****************************************************************************
Configuration settings can be found in 'sbr_include'.
Always recompile your module after modifying sbr_include because it is an include file.
#1: Select "Build" from the toolset menu and then choose "Build Module".
#2: Click the "Advanced Controls" box to bring up the advanced options.
#3: Make sure that the only boxes that are selected are "Compile" and "Scripts".
#4: Click the "Build" button.
#5: Remember to always make sure you are using the options you want to use when running "Build Module"!
// The variable below sets up how the DM Rest widget is configured.
// Change this to true to only toggle rest module wide rather
// than using the 3 different level options.
// If this is TRUE clicking the ground, yourself or a player will
// toggle the Module level rest restriction.
// If FALSE, then you have 3 options.
// Target yourself = Module level toggle.
// Target ground (ie the area) = Area level toggle.
// Target player = Party level toggle.
//
// In either mode, targeting an NPC or other placeable will report
// all pertinent rest system information to you.
const int SBR_MAKE_IT_SIMPLE = FALSE;
// This is the maximum distance the player can be from a "restful object" to
// automatically use it when they hit rest. *****BUILDERS remember that this does NOT
// account for walls so be careful at inns with bed placement******
const float SBR_DISTANCE = 5.0;
// This is the event number that will be signalled to your module OnUserDefined Event
// when a player rests. This user defined event is how you should extend the system
// so that specific things happen on rest. IE: create some wandering monsters,
// play a cutscene, teleport them to a "dream" area, etc.
const int SBR_EVENT_REST = 2000;
****************************************************************************
PLAYER DOCUMENTATION
****************************************************************************
This module uses Supply Based Rest.
In order to rest you must be near a "Restful Object". These objects have "Restful" in their name: a Restful Bed or a Restful Campsite, for example. You can use a restful object by clicking on it or by pressing the rest button while you are near it.
If you are not near a restful object then you must use a supply kit to build one. Using a supply kit will create a temporary Restful Campsite that will last several minutes. There are two ways to use a supply kit. You can either right click on the kit and activate the item, or you can hit the rest button (or press 'r') twice in rapid succession.
There are two kinds of supply kits: regular kits that anyone can use and woodland kits that are lighter/cheaper but can only be carried by rangers or druids. You cannot carry a woodland kit unless you are a ranger or druid.
Supply kits are quite heavy and quite expensive. This is to encourage players to rest as a group and to encourage players to ration the how often they rest.
Sometimes you will encounter areas that are not secure for rest. This means you must find a safe area (an enclosed room for example) before you can rest.
****************************************************************************
BUILDER NOTES
****************************************************************************
This version will allow you to use the new BioWare rest restriction triggers "on top of" these restrictions. For example, the rules above will still apply, but you can go the extra step and make players close the door to the room (like the BioWare trigger) just by laying down the standard trigger - all code is included and integrated into the system. For discussion on this new trigger - see bottom of document.
LogMessage is used for displaying text to players and DMs. It is scripting package designed by OldManWhistler. You can configure who receives feedback to almost anything imaginable. See the actual script for details and see the sbr_include file to see the multitude of options available to you.
****************************************************************************
DM FUNCTIONS
****************************************************************************
1) DM Rest Widget. Allows you to have total control over rest in your module. There are 2 modes: standard and "MAKEITSIMPLE". In standard mode, if you target your avatar it will toggle rest enable/disable on a module level. Targeting the ground will toggle rest enable/disable on an area level and targeting a player will toggle rest enable/disable on a party level. In "MAKEITSIMPLE" mode, targeting the ground, yourself or a player will toggle the module level rest restriction. Finally, targeting an NPC or placeable will report the rest settings just like clicking a restful bed (see below).
Toggling the module level rest will NOT remove area, or party rest restrictions you set with the widget. The same goes for area and party restrictions. They are all INDEPENDENT and ALL must be OFF to allow the player to rest. You will receive a message why they can't but you could have 3 separate settings to clear if in standard mode. I included the feature with extra flexibility due to the huge varieties of server set-ups using NWN. For single party, classic DM adventure - "MAKEITSIMPLE" is the easiest.
To change modes: Open the sbr_include file and change the "MAKEITSIMPLE" variable to either TRUE or FALSE. Default is FALSE. BUILD YOUR MODULE IF YOU CHANGE ANY INCLUDE FILE - at least compile all scripts using the build function.
2) Rest settings report. The report has a lot of pertinent information to you to help you keep track of exactly what is the status of the rest system. You will receive the following information if you use the DM Rest Widget on an NPC/placeable OR if you click on any restful object, :
- Module Rest Setting
- Area Rest Setting
- BW trigger information: is there a Bioware rest trigger in the current area.
The following information is reported based on the nearest player. NOTE: It uses GetNearestCreature function and therefore will return "No valid player found" if the "nearest" player is in a different area transition. This is a good feature for PW or other situations with multiple parties.
- Player Rest Setting
- Number of party kits (both woodland and supply kit information).
****************************************************************************
QUESTIONS AND COMMENTS
****************************************************************************
Q: What is the difference between the supply kit and the woodland kit?
A: The woodland kit can be used by rangers and druids. It attempts to simulate the fact that these classes can find many resources from the land. Therefore, woodland kits are significantly lighter as these classes will supplement the kit with things from the woods. The woodlands kits are medium size item and the supply kits are a large item. Woodland kits are a little bit cheaper too.
NOTE: If you are NOT a druid or a ranger, the OnAcquire code will drop any woodland kit you attempt to hold or purchase. This is to avoid other players acting as pack mules for the druid or ranger so that they can use the cheaper kits. Not exactly "realistic" but forces them to play fair.
If you don't like this added feature of the woodland kit - don't add any to stores and then you do NOT need the sbr_onacquire script.
Q: What do the kits cost?
A: 100 for supply kit and 75 for woodland kit. This is a pretty hefty price tag for a brand new level 1 adventures and therefore you may need to adjust the starting money value (or just give out a few supply kits for "free" when you begin the adventure). Another option would be to make the players rest in a town or inn until they gain enough money to begin traveling and camping out in the wilderness.
Q: How does this affect game play balance?
A: The number of kits the players carry ARE the only limit to resting so be careful with not only how much money the players have, but use caution with store inventories and with magical bag or bags of holding. The kits are large so that only 3 supply kits or 6 woodland kits can fit into a bag of holding but as a designer, it may be important to further ration the kits (The are "rationed" in a sense of the weight and price tag). I initially had the weight at 50lb for the supply kit but decided that this was too heavy for non-fighter based parties and so I backed the weight down. You can adjust the weight or price by editing the price in the toolset and then restocking any stores that you have created.
**BW Rest Trigger Commentary and Answers**
Q: What is the deal with the new BW rest triggers?
First off, much of this is opinion, much is fact. They are not simple and they are not easy to integrate into a module. They are poorly documented and the documentation contains errors. In the official campaign there are 2 checks that are performed to rest. One is area specific and one looks for this trigger. There are subroutines for both of these checks. If you do NOT have rest script - the trigger does nothing despite what the comment says. You should also NOT have the area level "No rest" box checked like it says. All this being said you can use the idea but it takes custom work on your end as a builder.
How do they work in this system? Closer to what I expected :) . In this system, if you lay down a BW rest trigger that ENTIRE AREA becomes a region where the players MUST find a secure region. It will NOT affect other areas (this is a coding change I made to the trigger subroutine - by default one BW trigger negated resting throughout the entire module without adding more code other places). That is it. The trigger must contain one door. You could still use the "no rest" box in the area properties to disallow rest everywhere in the area at all times.
I hated to have to include this long explanation but thought it would save me time and effort in the long run of answering a lot of questions related to this system.
****************************************************************************
CONCLUSION
****************************************************************************
As a builder, I find the system easy to install and very flexible. I think it is straightforward for players and functions to limit rest in a way that allows the players to decide when, where, and how they want it to happen while the final decision to "how many times" is left to the builder when they place the objects and supplies.
Special thanks to Mogney, Dick Nervous, and JohhnyB for play testing, feedback, and fine tuning of the concept.
Demetrious
****************************************************************************
CHANGELOG
****************************************************************************
v1.1 to v1.2
- Cosmetic module changes: made the signs, door and merchants plot so they couldn't be destroyed and screw up the tutorial.
- Revamped the documentation and installation instructions.
- Changed "IsDM" checks to check for DMPossessed creatures. The system will treat DM possessed creatures the same as DMs.
- Added a module OnUserDefined event for players resting so that you can easily extend the rest system without touching the code.
- Changed interface so that players have to hit 'r' or the rest button twice to enable the "automatically use supply" feature. In live play some players would accidently hit R because they forgot to press enter before they started typing. This solves that issue.
- Hitting the rest button when you are near a "restful" object will automatically use that restful object instead of a kit. In live play some players who were not used to the system would try a normal rest and accidently use another kit. This solves that issue.
- Changed it so that woodland kits are not destroyed when picked up by non-ranger/druids. Now they will be dropped. In live play some players would accidently destroy woodland kits by picking them up. This solves that issue.
- Modified the store conversations to reflect the changes.
- Version 1.1 was tagged as requiring SoU. Version 1.2 can be used by anyone -- regardless of whether they have SoU.
*/

667
src/include/inc_set.nss Normal file
View File

@@ -0,0 +1,667 @@
//::///////////////////////////////////////////////
//:: Set-like storage data type include
//:: inc_set
//:://////////////////////////////////////////////
/** @file
This file defines a "data type" that behaves
like a set. It is implemented as an extension
of the arrays defined in prc_inc_array.
Operations:
- Get number of entities in the set. O(1)
- Store an entity in the set. O(1)
- Remove an entity from the set. O(n)
- Determine if the set contains a given entity. O(1)
- Get operations on the underlying array
The memory complexity is O(n), specifically 2n(m + c), where
n is the number of entities stored in the set, m is the memory
taken up the local variable store of a member entity and c is
a constant overhead from disambiguation strings.
Note that a set can contain only contain one instance
of any specific entity. Any attempts to add an entity to
a set that is already a member of will return with success,
but do nothing.
For example, if a set contains {"Foo", "Bar, 123, OBJECT_INVALID}
calling set_add_string(container, setname, "Foo") will return
SDL_SUCCESS, but not modify the contents of the set.
@author Ornedan
@date Created - 2006.09.16
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Creates a new set on the given storage object. If a set with
* the same name already exists, the function fails.
*
* @param store The object to use as holder for the set
* @param name The name of the set
* @return SDL_SUCCESS if the set was successfully created,
* one of SDL_ERROR_* on error.
*/
int set_create(object store, string name);
/**
* Deletes a set, deleting all local variables it consists of.
*
* @param store The object which holds the set to delete
* @param name The name of the set
* @return SDL_SUCCESS if the set was successfully deleted,
* one of SDL_ERROR_* on error
*/
int set_delete(object store, string name);
/**
* Adds a string to the set.
*
* @param store The object holding the set
* @param name The name of the set
* @param entry The string to add
* @return SDL_SUCCESS if the addition was successfull, SDL_ERROR_* on error.
*/
int set_add_string(object store, string name, string entry);
/**
* Adds a integer to the set.
*
* @param store The object holding the set
* @param name The name of the set
* @param entry The integer to add
* @return SDL_SUCCESS if the addition was successfull, SDL_ERROR_* on error.
*/
int set_add_int(object store, string name, int entry);
/**
* Adds a float to the set.
*
* @param store The object holding the set
* @param name The name of the set
* @param entry The float to add
* @return SDL_SUCCESS if the addition was successfull, SDL_ERROR_* on error.
*/
int set_add_float(object store, string name, float entry);
/**
* Adds a object to the set.
*
* @param store The object holding the set
* @param name The name of the set
* @param entry The object to add
* @return SDL_SUCCESS if the addition was successfull, SDL_ERROR_* on error.
*/
int set_add_object(object store, string name, object entry);
/**
* Determines whether the set contains the given string.
*
* @param store The object holding the set
* @param name The name of the set
* @param entity The string to test
* @return TRUE if the set contains entry, FALSE otherwise
*/
int set_contains_string(object store, string name, string entity);
/**
* Determines whether the set contains the given integer.
*
* @param store The object holding the set
* @param name The name of the set
* @param entity The integer to test
* @return TRUE if the set contains entry, FALSE otherwise
*/
int set_contains_int(object store, string name, int entity);
/**
* Determines whether the set contains the given float.
*
* @param store The object holding the set
* @param name The name of the set
* @param entity The float to test
* @return TRUE if the set contains entry, FALSE otherwise
*/
int set_contains_float(object store, string name, float entity);
/**
* Determines whether the set contains the given object.
*
* @param store The object holding the set
* @param name The name of the set
* @param entity The object to test
* @return TRUE if the set contains entry, FALSE otherwise
*/
int set_contains_object(object store, string name, object entity);
/**
* Removes the given string from the set, if it is a member.
*
* @param store The object holding the set
* @param name The name of the set
* @param entity The string to remove
*/
void set_remove_string(object store, string name, string entity);
/**
* Removes the given integer from the set, if it is a member.
*
* @param store The object holding the set
* @param name The name of the set
* @param entity The integer to remove
*/
void set_remove_int(object store, string name, int entity);
/**
* Removes the given float from the set, if it is a member.
*
* @param store The object holding the set
* @param name The name of the set
* @param entity The float to remove
*/
void set_remove_float(object store, string name, float entity);
/**
* Removes the given object from the set, if it is a member.
*
* @param store The object holding the set
* @param name The name of the set
* @param entity The object to remove
*/
void set_remove_object(object store, string name, object entity);
/**
* Gets the type of the i:th member of the set.
*
* @param store The object holding the set
* @param name The name of the set
* @param i The index of the member the type of which to retrieve
* @return One of the ENTITY_TYPE_* defined in inc_heap, or 0 in case of error
*/
int set_get_member_type(object store, string name, int i);
/**
* Gets the i:th member of the set as a string.
*
* NOTE: If the member is actually not a string, the return
* value in undefined. As such, always check the real
* type of the member first using set_get_member_type().
*
* @param store The object holding the set
* @param name The name of the set
* @param i The index to retrieve the string from
* @return The value contained at the index on success,
* "" on error
*/
string set_get_string(object store, string name, int i);
/**
* Gets the i:th member of the set as an integer.
*
* NOTE: If the member is actually not an integer, the return
* value in undefined. As such, always check the real
* type of the member first using set_get_member_type().
*
* @param store The object holding the set
* @param name The name of the set
* @param i The index to retrieve the string from
* @return The value contained at the index on success,
* 0 on error
*/
int set_get_int(object store, string name, int i);
/**
* Gets the i:th member of the set as an float.
*
* NOTE: If the member is actually not an float, the return
* value in undefined. As such, always check the real
* type of the member first using set_get_member_type().
*
* @param store The object holding the set
* @param name The name of the set
* @param i The index to retrieve the string from
* @return The value contained at the index on success,
* 0.0 on error
*/
float set_get_float(object store, string name, int i);
/**
* Gets the i:th member of the set as an object.
*
* NOTE: If the member is actually not an object, the return
* value in undefined. As such, always check the real
* type of the member first using set_get_member_type().
*
* @param store The object holding the set
* @param name The name of the set
* @param i The index to retrieve the string from
* @return The value contained at the index on success,
* OBJECT_INVALID on error
*/
object set_get_object(object store, string name, int i);
/**
* Gets the number of members in the set
*
* @param store The object holding the set
* @param name The name of the set
* @return The size of the set, or -1 if the specified
* set does not exist.
*/
int set_get_size(object store, string name);
/**
* Checks whether the given set exists.
*
* @param store The object holding the set
* @param name The name of the set
* @return TRUE if the set exists, FALSE otherwise.
*/
int set_exists(object store, string name);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
// prc_inc_array access is via inc_heap
//#include "prc_inc_array"
#include "inc_debug"
#include "inc_heap"
//////////////////////////////////////////////////
/* Internal Constants */
//////////////////////////////////////////////////
const string _PRC_SET_PREFIX = "@@@set";
//////////////////////////////////////////////////
/* Internal functions */
//////////////////////////////////////////////////
/** Internal function.
* Performs the real addition operation.
*
* @param store The object holding the set
* @param name The name of the set
* @param entry String form of the entity to be stored in the set
* @param isobject Whether the entity being stored is an object. Objects need special handling
* @param obj The object being stored, if any
*/
int _inc_set_set_add_aux(object store, string name, string entry, int isobject = FALSE, object obj = OBJECT_INVALID)
{
// Sanity checks
if(!set_exists(store, name))
return SDL_ERROR_DOES_NOT_EXIST;
// Generate real name for accessing array functions
name = _PRC_SET_PREFIX + name;
// Set the presence marker to be the index where the entity will be stored + 1 to avoid storing a 0
int index = array_get_size(store, name);
SetLocalInt(store, name + entry, index + 1);
// Store the member's value in the array
if(isobject)
{
if(DEBUG)
{
Assert(array_set_object(store, name, index, obj) == SDL_SUCCESS,
"array_set_object(store, name, index, obj) == SDL_SUCCESS",
"", "inc_set", "_inc_set_set_add_aux"
);
return SDL_SUCCESS;
}
else
{
return array_set_object(store, name, index, obj);
}
}
else
{
if(DEBUG)
{
Assert(array_set_string(store, name, index, entry) == SDL_SUCCESS,
"array_set_string(store, name, index, entry) == SDL_SUCCESS",
"", "inc_set", "_inc_set_set_add_aux"
);
return SDL_SUCCESS;
}
else
{
return array_set_string(store, name, index, entry);
}
}
}
/** Internal function.
* Determines whether the set contains the given entity.
*
* @param store The object holding the set
* @param name The name of the set
* @param entity The presence string for the entity to test
* @return TRUE if the set contains the entity, FALSE otherwise
*/
int _inc_set_set_contains_aux(object store, string name, string entity)
{
// Sanity check
if(!set_exists(store, name))
return FALSE;
// Get the value of the presence marker and normalise to TRUE / FALSE
return GetLocalInt(store, _PRC_SET_PREFIX + name + entity) != 0;
}
/** Internal function.
* Removes the given entity from the set.
*
* @param store The object holding the set
* @param name The name of the set
* @param entity The presence string for the entity to remove
*/
void _inc_set_set_remove_aux(object store, string name, string entity)
{
// Set does not exist or exists, but does not contain the given entity. Nothing to do
if(!_inc_set_set_contains_aux(store, name, entity))
return;
// Generate real name for accessing array functions
name = _PRC_SET_PREFIX + name;
// Get the index where the entity is stored and the size of the underlying array
int index = GetLocalInt(store, name + entity) - 1;
int size = array_get_size(store, name);
string raw;
object obj;
// Move each element in the array after the one being removed back by one
for(index = index + 1; index < size; index++)
{
// Determine what's stored here
raw = array_get_string(store, name, index);
// Different handling for objects vs everything else
if(raw == "OBJECT")
{
obj = array_get_object(store, name, index);
// Move back
array_set_object(store, name, index - 1, obj);
// Update the marker value
SetLocalInt(store, name + "O" + ObjectToString(obj), index/* - 1 + 1 */);
}
else
{
// Move back
array_set_string(store, name, index - 1, raw);
// Update the marker value
SetLocalInt(store, name + raw, index/* - 1 + 1 */);
}
}
// Delete the marker local
DeleteLocalInt(store, name + entity);
// Shrink the array
array_shrink(store, name, size - 1);
}
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
int set_create(object store, string name)
{
// Sanity checks
if(!GetIsObjectValid(store))
return SDL_ERROR_NOT_VALID_OBJECT;
if(name == "")
return SDL_ERROR_INVALID_PARAMETER;
if(set_exists(store, name))
return SDL_ERROR_ALREADY_EXISTS;
// Generate real name for accessing array functions
name = _PRC_SET_PREFIX + name;
// All OK, create the underlying array
return array_create(store, name);
}
int set_delete(object store, string name)
{
// Sanity check
if(!set_exists(store, name))
return SDL_ERROR_DOES_NOT_EXIST;
// Generate real name for accessing array functions
name = _PRC_SET_PREFIX + name;
// Loop over all members, getting deleting the presence indicator local
int size = array_get_size(store, name);
int i;
string raw, member;
for(i = 0; i < size; i++)
{
// Get the raw data stored in the array.
// NOTE: This relies on internal details of the array implementation. Specifically, objects having a string containing "OBJECT"
// stored in their position
raw = array_get_string(store, name, i);
// Construct the presence marker name. Special handling for objects
if(raw == "OBJECT")
member = name + "O" + ObjectToString(array_get_object(store, name, i));
else
member = name + raw;
// Delete the marker
DeleteLocalInt(store, member);
}
// Clean up the underlying array
if(DEBUG)
{
Assert(array_delete(store, name) == SDL_SUCCESS, "array_delete(store, name) == SDL_SUCCESS", "", "inc_set", "set_delete");
return SDL_SUCCESS;
}
else
{
return array_delete(store, name);
}
}
int set_add_string(object store, string name, string entry)
{
// Convert the entry to the storable string form
entry = "S" + entry;
// If the set already contains the entry being added, nothing happens
if(_inc_set_set_contains_aux(store, name, entry))
return SDL_SUCCESS;
return _inc_set_set_add_aux(store, name, entry);
}
int set_add_int(object store, string name, int entry)
{
// Convert the entry to the storable string form
string strentry = "I" + IntToString(entry);
// If the set already contains the entry being added, nothing happens
if(_inc_set_set_contains_aux(store, name, strentry))
return SDL_SUCCESS;
return _inc_set_set_add_aux(store, name, strentry);
}
int set_add_float(object store, string name, float entry)
{
// Convert the entry to the storable string form
string strentry = "F" + FloatToString(entry);
// If the set already contains the entry being added, nothing happens
if(_inc_set_set_contains_aux(store, name, strentry))
return SDL_SUCCESS;
return _inc_set_set_add_aux(store, name, strentry);
}
int set_add_object(object store, string name, object entry)
{
// Convert the entry to the storable string form
string strentry = "O" + ObjectToString(entry);
// If the set already contains the entry being added, nothing happens
if(_inc_set_set_contains_aux(store, name, strentry))
return SDL_SUCCESS;
return _inc_set_set_add_aux(store, name, strentry, TRUE, entry);
}
int set_get_member_type(object store, string name, int i)
{
// Sanity check
if(!set_exists(store, name) || i >= set_get_size(store, name))
return 0;
// Generate real name for accessing array functions
name = _PRC_SET_PREFIX + name;
// Grab the first character of the raw string, it determines type
string type = GetSubString(array_get_string(store, name, i), 0, 1);
// First character in the string determines type
if (type == "F")
return ENTITY_TYPE_FLOAT;
else if(type == "I")
return ENTITY_TYPE_INTEGER;
else if(type == "O")
return ENTITY_TYPE_OBJECT;
else if(type == "S")
return ENTITY_TYPE_STRING;
else
return 0;
}
int set_contains_string(object store, string name, string entity)
{
return _inc_set_set_contains_aux(store, name, "S" + entity);
}
int set_contains_int(object store, string name, int entity)
{
return _inc_set_set_contains_aux(store, name, "I" + IntToString(entity));
}
int set_contains_float(object store, string name, float entity)
{
return _inc_set_set_contains_aux(store, name, "F" + FloatToString(entity));
}
int set_contains_object(object store, string name, object entity)
{
return _inc_set_set_contains_aux(store, name, "O" + ObjectToString(entity));
}
void set_remove_string(object store, string name, string entity)
{
_inc_set_set_remove_aux(store, name, "S" + entity);
}
void set_remove_int(object store, string name, int entity)
{
_inc_set_set_remove_aux(store, name, "I" + IntToString(entity));
}
void set_remove_float(object store, string name, float entity)
{
_inc_set_set_remove_aux(store, name, "F" + FloatToString(entity));
}
void set_remove_object(object store, string name, object entity)
{
_inc_set_set_remove_aux(store, name, "O" + ObjectToString(entity));
}
string set_get_string(object store, string name, int i)
{
// Sanity check
if(!set_exists(store, name) || i >= set_get_size(store, name))
return "";
// Generate real name for accessing array functions
name = _PRC_SET_PREFIX + name;
// Chop off the first character from the raw string and return the rest
string raw = array_get_string(store, name, i);
return GetSubString(raw, 1, GetStringLength(raw));
}
int set_get_int(object store, string name, int i)
{
// Sanity check
if(!set_exists(store, name) || i >= set_get_size(store, name))
return 0;
// Generate real name for accessing array functions
name = _PRC_SET_PREFIX + name;
// Chop off the first character from the raw string and return the rest
string raw = array_get_string(store, name, i);
return StringToInt(GetSubString(raw, 1, GetStringLength(raw)));
}
float set_get_float(object store, string name, int i)
{
// Sanity check
if(!set_exists(store, name) || i >= set_get_size(store, name))
return 0.0f;
// Generate real name for accessing array functions
name = _PRC_SET_PREFIX + name;
// Chop off the first character from the raw string and return the rest
string raw = array_get_string(store, name, i);
return StringToFloat(GetSubString(raw, 1, GetStringLength(raw)));
}
object set_get_object(object store, string name, int i)
{
// Sanity check
if(!set_exists(store, name) || i >= set_get_size(store, name))
return OBJECT_INVALID;
// Generate real name for accessing array functions
name = _PRC_SET_PREFIX + name;
return array_get_object(store, name, i);
}
int set_get_size(object store, string name)
{
// Generate real name for accessing array functions
name = _PRC_SET_PREFIX + name;
return array_get_size(store, name);
}
int set_exists(object store, string name)
{
// Generate real name for accessing array functions
name = _PRC_SET_PREFIX + name;
return array_exists(store, name);
}
// Test main
//void main() {}

View File

@@ -0,0 +1,366 @@
//:://////////////////////////////////////////////
//:: Name: new spellbook spellgain / spell memorization include
//:: File: inc_sp_gain_mem.nss
//:://////////////////////////////////////////////
/**
contains helper functions for the two dynamic conversation scripts
- prc_s_spellb.nss
- prc_s_spellgain.nss
that handle learning / gaining new spells at level up (prc_s_spellgain)
or preparing what spells to learn at next rest (prc_s_spellb)
Author: motu99
Created: May 1, 2008
*/
//#include "prc_inc_core" //granted access via parent (inc_newspellbook)
//:: Updated for .35 by Jaysyn 2023/03/11
//:: Test Void
//void main (){}
//:://////////////////////////////////////////////
//:: Constants
//:://////////////////////////////////////////////
// max. number of classes a PC (or creature) can take (8 for NWN, 4 for NWN2)
const int MAX_CLASSES = 8;
//////////////////////////////////////////////////
/* Aid functions */
//////////////////////////////////////////////////
string GetNSBDefinitionFileName(int nClass);
int GetCasterLevelByClass(int nClass, object oPC);
int GetSpellsKnown_MaxCount(int nCasterLevel, int nClass, int nSpellLevel, object oPC);
int GetSpellsInClassSpellbook_Count(int nClass, int nSpellLevel);
string GetClassString(int nClass);
int GetMaxSpellLevelForCasterLevel(int nClass, int nCasterLevel);
int GetMinSpellLevelForCasterLevel(int nClass, int nCasterLevel);
void WipeSpellFromHide(int nIPFeatID, object oPC);
string GetSpellsKnown_Array(int nClass, int nSpellLevel = -1);
object GetSpellsOfClass_Token(int nClass, int nSpellLevel);
string GetSpellsOfClass_Array();
string GetSpellsMemorized_Array(int nClass);
string GetSpellsToBeMemorized_Array(int nClass, int nSpellSlotLevel);
void array_set_size(object oPC, string sArrayName, int nSize);
int array_has_string(object oPC, string sArrayName, string sValue, int nFirst = 0, int nSize = 0);
int array_has_int(object oPC, string sArrayName, int nValue, int nFirst = 0, int nSize = 0);
int persistant_array_has_string(object oPC, string sArrayName, string sValue, int nFirst = 0, int nSize = 0);
int persistant_array_has_int(object oPC, string sArrayName, int nValue, int nFirst = 0, int nSize = 0);
int array_extract_string(object oPC, string sArrayName, string sValue, int nFirst = 0);
int array_extract_int(object oPC, string sArrayName, int nValue, int nFirst = 0);
int persistant_array_extract_string(object oPC, string sArrayName, string sValue, int nFirst = 0);
int persistant_array_extract_int(object oPC, string sArrayName, int nValue, int nFirst = 0);
string GetMetaMagicString_Short(int nMetaMagic);
string GetMetaMagicString(int nMetaMagic);
int GetMetaMagicFromFeat(int nFeat);
int GetMetaMagicOfCaster(object oPC = OBJECT_SELF);
// name of the new spellbook file (cls_spell_*)
string GetNSBDefinitionFileName(int nClass)
{
return GetFileForClass(nClass);
}
// gets the caster level (without special modifications due to feats), by which the max spell slot level is determined
int GetCasterLevelByClass(int nClass, object oPC)
{
return GetSpellslotLevel(nClass, oPC);
// return GetPrCAdjustedCasterLevel(nClass, oPC, TRUE);
}
// gets the maximum nr of spells that oPC can know with a given nCasterLevel, nClass and nSpellLevel
int GetSpellsKnown_MaxCount(int nCasterLevel, int nClass, int nSpellLevel, object oPC)
{
return GetSpellKnownMaxCount(nCasterLevel, nSpellLevel, nClass, oPC);
}
// gets the total nr of spells available at nSpellLevel for nClass
int GetSpellsInClassSpellbook_Count(int nClass, int nSpellLevel)
{
return persistant_array_get_size(GetSpellsOfClass_Token(nClass, nSpellLevel), GetSpellsOfClass_Array());
}
string GetClassString(int nClass)
{
// get the name of the feats table 2da
string sClass = Get2DACache("classes", "FeatsTable", nClass);
// truncate the first 8 characters (the "cls_feat" part), leaving the "_<class>" part
sClass = GetStringRight(sClass, GetStringLength(sClass) - 8);
return sClass;
}
// gets the maximum spell level that nClass can cast at nCasterLevel
int GetMaxSpellLevelForCasterLevel(int nClass, int nCasterLevel)
{
string sFile;
// Bioware casters use their classes.2da-specified tables
//if(GetIsBioSpellCastClass(nClass))
//{
sFile = Get2DACache("classes", "SpellGainTable", nClass);
//}
//else
//{
// sFile = "cls_spbk" + GetClassString(nClass);
//}
// row nr in the files is nCasterLevel minus 1
nCasterLevel--;
int nSpellLevel;
if (Get2DACache(sFile, "NumSpellLevels", 9) != "")
{
string sTemp = Get2DACache(sFile, "NumSpellLevels", nCasterLevel);
if (sTemp != "")
{
nSpellLevel = StringToInt(sTemp)-1;
if (nSpellLevel <= 0) nSpellLevel = 0;
}
}
else
{
for (nSpellLevel=9; nSpellLevel >= 0; nSpellLevel--)
{
string sTemp = Get2DACache(sFile, "SpellLevel" + IntToString(nSpellLevel), nCasterLevel);
if (sTemp != "")
{
break;
}
}
}
return nSpellLevel;
}
// gets the minimum spell level that nClass can cast at nCasterLevel
int GetMinSpellLevelForCasterLevel(int nClass, int nCasterLevel)
{
string sFile;
// Bioware casters use their classes.2da-specified tables
//if(GetIsBioSpellCastClass(nClass))
//{
sFile = Get2DACache("classes", "SpellGainTable", nClass);
//}
//else
//{
// sFile = "cls_spbk" + GetClassString(nClass);
//}
// row nr in the files is nCasterLevel minus 1
nCasterLevel--;
int bFound = 0;
int nSpellLevel;
for (nSpellLevel=0; nSpellLevel <= 9; nSpellLevel++)
{
string sTemp = Get2DACache(sFile, "SpellLevel" + IntToString(nSpellLevel), nCasterLevel);
if (sTemp != "")
{
bFound = TRUE;
break;
}
}
if (!bFound) nSpellLevel = -1;
return nSpellLevel;
}
// wipes the IPbonusfeat from the hide
void WipeSpellFromHide(int nIPFeatID, object oPC)
{
// go through all item properties on the hide
object oHide = GetPCSkin(oPC);
itemproperty ipTest = GetFirstItemProperty(oHide);
while(GetIsItemPropertyValid(ipTest))
{
// is it a bonus feat?
if(GetItemPropertyType(ipTest) == ITEM_PROPERTY_BONUS_FEAT)
{
// get the row nr of the bonus feat in iprp_feat.2da
// is it the ipfeat to delete?
if (GetItemPropertySubType(ipTest) == nIPFeatID)
{
RemoveItemProperty(oHide, ipTest);
if(DEBUG) DoDebug("WipeSpellFromHide: Removing item property " + DebugIProp2Str(ipTest));
}
}
ipTest = GetNextItemProperty(oHide);
}
}
// one array for each class (array holds all spell levels, but only non-metamagicked masterspells)
string GetSpellsKnown_Array(int nClass, int nSpellLevel = -1)
{
int nSpellbookType = GetSpellbookTypeForClass(nClass);
if(nSpellbookType == SPELLBOOK_TYPE_PREPARED)
return "Spellbook_Known_" + IntToString(nClass) + "_" + IntToString(nSpellLevel);
return "Spellbook" + IntToString(nClass);
}
// class spellbook (one storage token for each spell level and class)
object GetSpellsOfClass_Token(int nClass, int nSpellLevel)
{
return GetObjectByTag("SpellLvl_" + IntToString(nClass) + "_Level_" + IntToString(nSpellLevel));
}
string GetSpellsOfClass_Array()
{
return "Lkup";
}
string GetSpellsMemorized_Array(int nClass)
{
return "NewSpellbookMem_" + IntToString(nClass);
}
string GetSpellsToBeMemorized_Array(int nClass, int nSpellSlotLevel)
{
return "Spellbook" + IntToString(nSpellSlotLevel) + "_" + IntToString(nClass);
}
void array_set_size(object oPC, string sArrayName, int nSize)
{
SetPersistantLocalInt(oPC, sArrayName, nSize+1);
}
int array_has_string(object oPC, string sArrayName, string sValue, int nFirst = 0, int nSize = 0)
{
// get array size, if size not already supplied
if (nSize == 0) nSize = GetPersistantLocalInt(oPC, sArrayName) -1;
int i;
for (i = nFirst; i < nSize; i++)
{
if (sValue == GetPersistantLocalString(oPC, sArrayName + "_" + IntToString(i)))
return i;
}
return -1;
}
int array_has_int(object oPC, string sArrayName, int nValue, int nFirst = 0, int nSize = 0)
{
// array values are stored as strings, so convert nValue to a string
return array_has_string(oPC, sArrayName, IntToString(nValue), nFirst, nSize);
}
int persistant_array_has_string(object oPC, string sArrayName, string sValue, int nFirst = 0, int nSize = 0)
{
return array_has_string(oPC, sArrayName, sValue, nFirst, nSize);
}
int persistant_array_has_int(object oPC, string sArrayName, int nValue, int nFirst = 0, int nSize = 0)
{
return array_has_string(oPC, sArrayName, IntToString(nValue), nFirst, nSize);
}
int array_extract_string(object oPC, string sArrayName, string sValue, int nFirst = 0)
{
// get array size
int nSize = GetPersistantLocalInt(oPC, sArrayName)-1;
if (nSize <= nFirst) return -1;
// position of the first found; -1 if not found
int nPos = array_has_string(oPC, sArrayName, sValue, nFirst, nSize);
if (nPos < 0) return -1;
// Is is not the last element?
if (nPos < nSize-1)
{
// then swap nPos (or rather nPos-1) with the last element (nSize-1)
string sTemp = GetPersistantLocalString(oPC, sArrayName + "_" + IntToString(nSize-1));
SetPersistantLocalString(oPC, sArrayName + "_" + IntToString(nPos), sTemp);
}
// now decrement the array size (note that we already subtracted one in the beginning)
SetPersistantLocalInt(oPC, sArrayName, nSize);
return nPos;
}
// extracts the integer value nValue from a persistant sArray on oPC
// extracts the first instance of nValue that it finds
// extracts it by swapping the last array element to the position of the extracted element and reducing the array size by one
// returns the position where the extracted element was found
int array_extract_int(object oPC, string sArrayName, int nValue, int nFirst = 0)
{
// array values are stored as strings, so convert nValue to a string
return array_extract_string(oPC, sArrayName, IntToString(nValue), nFirst);
}
int persistant_array_extract_string(object oPC, string sArrayName, string sValue, int nFirst = 0)
{
return array_extract_string(oPC, sArrayName, sValue, nFirst);
}
int persistant_array_extract_int(object oPC, string sArrayName, int nValue, int nFirst = 0)
{
// array values are stored as strings, so convert nValue to a string
return array_extract_string(oPC, sArrayName, IntToString(nValue), nFirst);
}
string GetMetaMagicString_Short(int nMetaMagic)
{
string s;
if (nMetaMagic == 0) return s;
if (nMetaMagic & METAMAGIC_EXTEND) s += "ext ";
if (nMetaMagic & METAMAGIC_SILENT) s += "sil ";
if (nMetaMagic & METAMAGIC_STILL) s += "sti ";
if (nMetaMagic & METAMAGIC_EMPOWER) s += "emp ";
if (nMetaMagic & METAMAGIC_MAXIMIZE) s += "max ";
if (nMetaMagic & METAMAGIC_QUICKEN) s += "qui ";
return GetStringLeft(s, GetStringLength(s)-1);
}
string GetMetaMagicString(int nMetaMagic)
{
string s;
if (nMetaMagic == 0) return s;
if (nMetaMagic & METAMAGIC_EXTEND) s += "extend ";
if (nMetaMagic & METAMAGIC_SILENT) s += "silent ";
if (nMetaMagic & METAMAGIC_STILL) s += "still ";
if (nMetaMagic & METAMAGIC_EMPOWER) s += "empower ";
if (nMetaMagic & METAMAGIC_MAXIMIZE) s += "maximize ";
if (nMetaMagic & METAMAGIC_QUICKEN) s += "quicken ";
return GetStringLeft(s, GetStringLength(s)-1);
}
int GetMetaMagicFromFeat(int nFeat)
{
switch(nFeat)
{
case FEAT_EMPOWER_SPELL: return METAMAGIC_EMPOWER;
case FEAT_EXTEND_SPELL: return METAMAGIC_EXTEND;
case FEAT_MAXIMIZE_SPELL: return METAMAGIC_MAXIMIZE;
case FEAT_QUICKEN_SPELL: return METAMAGIC_QUICKEN;
case FEAT_SILENCE_SPELL: return METAMAGIC_SILENT;
case FEAT_STILL_SPELL: return METAMAGIC_STILL;
}
return METAMAGIC_NONE;
}
int GetMetaMagicOfCaster(object oPC = OBJECT_SELF)
{
int nMetaMagic;
if (GetHasFeat(FEAT_EMPOWER_SPELL, oPC)) nMetaMagic |= METAMAGIC_EMPOWER;
if (GetHasFeat(FEAT_EXTEND_SPELL, oPC)) nMetaMagic |= METAMAGIC_EXTEND;
if (GetHasFeat(FEAT_MAXIMIZE_SPELL, oPC)) nMetaMagic |= METAMAGIC_MAXIMIZE;
if (GetHasFeat(FEAT_QUICKEN_SPELL, oPC)) nMetaMagic |= METAMAGIC_QUICKEN;
if (GetHasFeat(FEAT_SILENCE_SPELL, oPC)) nMetaMagic |= METAMAGIC_SILENT;
if (GetHasFeat(FEAT_STILL_SPELL, oPC)) nMetaMagic |= METAMAGIC_STILL;
return nMetaMagic;
}

File diff suppressed because it is too large Load Diff

316
src/include/inc_sql.nss Normal file
View File

@@ -0,0 +1,316 @@
/**
* @file
* All the functions dealing with the NWNx database. Based on the APS include
* with optimisations, renamed to avoid naming clashes with the APS system.
* @author Primogenitor, motu99, fluffyamoeba
* @date created on 2009-01-25
*/
#include "prc_inc_switch"
const int PRC_SQL_ERROR = 0;
const int PRC_SQL_SUCCESS = 1;
const string XCHST_DB = "xchst_db";
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
// creates and stores a 1024 Byte string for database-fetches on the module
void PRC_SQLInit();
// executes an SQL command direclty
void PRC_SQLExecDirect(string sSQL);
// fetches data from a previous SQL fetch request; returns TRUE is fetch was successful
int PRC_SQLFetch();
// gets the actual data from a fetch; if a table with more than 1 column was requested, return the table element at column iCol
string PRC_SQLGetData(int iCol);
// SQLite and MYSQL use different syntaxes
string PRC_SQLGetTick();
// Problems can arise with SQL commands if variables or values have single quotes
// in their names. These functions are a replace these quote with the tilde character
string ReplaceSingleChars(string sString, string sTarget, string sReplace);
// only needed for SQLite; commits (actually stores) the changed to the database
void PRC_SQLiteCommit();
// starts the pseudo heartbeat for committing SQLite DB
void StartSQLiteCommitHB();
// pseudo heartbeat for committing SQLite DB; interval given in switch PRC_DB_SQLITE_INTERVAL
// default is 600 seconds (= 10 min)
void SQLiteCommitHB();
// Set oObject's persistent object with sVarName to sValue
// Optional parameters:
// iExpiration: Number of days the persistent variable should be kept in database (default: 0=forever)
// sTable: Name of the table where variable should be stored (default: pwobjdata)
void PRC_SetPersistentObject(object oObject, string sVarName, object oObject2, int iExpiration = 0, string sTable = "pwobjdata");
// Get oObject's persistent object sVarName
// Optional parameters:
// sTable: Name of the table where object is stored (default: pwobjdata)
// * Return value on error: 0
object PRC_GetPersistentObject(object oObject, string sVarName, object oOwner = OBJECT_INVALID, string sTable = "pwobjdata");
// Portable presistent chest system (X-Chest) nwnx database support
//
void CreateXChestDB_SQLite();
void CreateXChestDB_MySQL();
void DeleteXChestDB();
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
void PRC_SQLInit()
{
int i;
// Placeholder for ODBC persistence
string sMemory;
for (i = 0; i < 8; i++) // reserve 8*128 bytes
sMemory +=
"................................................................................................................................";
SetLocalString(GetModule(), "NWNX!ODBC!SPACER", sMemory);
}
void PRC_SQLExecDirect(string sSQL)
{
SetLocalString(GetModule(), "NWNX!ODBC!EXEC", sSQL);
}
int PRC_SQLFetch()
{
string sRow;
object oModule = GetModule();
// initialize the fetch string to a large 1024 Byte string; this will also trigger the fetch operation in NWNX
SetLocalString(oModule, "NWNX!ODBC!FETCH", GetLocalString(oModule, "NWNX!ODBC!SPACER"));
// get the result from the fetch
sRow = GetLocalString(oModule, "NWNX!ODBC!FETCH");
if (GetStringLength(sRow) > 0)
{
// store the result on the module and signal success
SetLocalString(oModule, "NWNX_ODBC_CurrentRow", sRow);
return PRC_SQL_SUCCESS;
}
else
{
// set the result string on the module to empty and signal failure
SetLocalString(oModule, "NWNX_ODBC_CurrentRow", "");
return PRC_SQL_ERROR;
}
}
/** @todo check mySQL manual, not sure if this is needed - fluffyamoeba */
string PRC_SQLGetTick()
{
if(GetPRCSwitch(PRC_DB_SQLITE))
{
return "";
}
else
{
return "`";
}
}
string PRC_SQLGetData(int iCol)
{
string sResultSet = GetLocalString(GetModule(), "NWNX_ODBC_CurrentRow");
int iPos = FindSubString(sResultSet, "<22>");
if (iCol == 1)
{
// only one column returned ? Then we are finished
if (iPos == -1) return sResultSet;
// more than one column returned ? Then return first column
else return GetStringLeft(sResultSet, iPos);
}
// more than one column requested, but only one returned ? Something went wrong; return empty string
else if (iPos == -1) return "";
// find column in current row
int iCount = 0;
int nLength = GetStringLength(sResultSet);
// loop through columns until found
while (iCount++ != iCol)
{
if (iCount == iCol)
return GetStringLeft(sResultSet, iPos);
// pull off the previous column and find new column marker
nLength -= (iPos + 1);
sResultSet = GetStringRight(sResultSet, nLength);
iPos = FindSubString(sResultSet, "<22>");
// special case: last column in row
if (iPos == -1) return sResultSet;
}
return sResultSet;
}
string ReplaceSingleChars(string sString, string sTarget, string sReplace)
{
if (FindSubString(sString, sTarget) == -1) // not found
return sString;
int i;
string sReturn = "";
string sChar;
// Loop over every character and replace special characters
for (i = 0; i < GetStringLength(sString); i++)
{
sChar = GetSubString(sString, i, 1);
if (sChar == sTarget)
sReturn += sReplace;
else
sReturn += sChar;
}
return sReturn;
}
// only needed for SQLite; commits (actually stores) the changed to the database
void PRC_SQLiteCommit()
{
PRC_SQLExecDirect("COMMIT");
PRC_SQLExecDirect("BEGIN IMMEDIATE");
}
// starts the pseudo heartbeat for committing SQLite DB
void StartSQLiteCommitHB()
{
if (GetPRCSwitch(PRC_DB_SQLITE))
{
int nInterval = GetPRCSwitch(PRC_DB_SQLITE_INTERVAL);
DelayCommand(nInterval ? IntToFloat(nInterval) : 600.0f, SQLiteCommitHB());
}
}
// pseudo heartbeat for committing SQLite DB; interval given in switch PRC_DB_SQLITE_INTERVAL
// default is 600 seconds (= 10 min)
void SQLiteCommitHB()
{
// check if we are still using SQLite
if (GetPRCSwitch(PRC_DB_SQLITE))
{
// do the commit
PRC_SQLExecDirect("COMMIT");
PRC_SQLExecDirect("BEGIN IMMEDIATE");
// continue pseudo heartbeat
int nInterval = GetPRCSwitch(PRC_DB_SQLITE_INTERVAL);
DelayCommand(nInterval ? IntToFloat(nInterval) : 600.0f, SQLiteCommitHB());
}
}
void PRC_SetPersistentObject(object oOwner, string sVarName, object oObject, int iExpiration = 0, string sTable = "pwobjdata")
{
string sPlayer;
string sTag;
if (GetIsPC(oOwner))
{
sPlayer = ReplaceSingleChars(GetPCPlayerName(oOwner), "'", "~");
sTag = ReplaceSingleChars(GetName(oOwner), "'", "~");
}
else
{
sPlayer = "~";
sTag = GetTag(oOwner);
}
sVarName = ReplaceSingleChars(sVarName, "'", "~");
string sSQL = "SELECT player FROM " + sTable + " WHERE player='" + sPlayer +
"' AND tag='" + sTag + "' AND name='" + sVarName + "'";
PRC_SQLExecDirect(sSQL);
if (PRC_SQLFetch() == PRC_SQL_SUCCESS)
{
// row exists
sSQL = "UPDATE " + sTable + " SET val=%s,expire=" + IntToString(iExpiration) +
" WHERE player='" + sPlayer + "' AND tag='" + sTag + "' AND name='" + sVarName + "'";
SetLocalString(GetModule(), "NWNX!ODBC!SETSCORCOSQL", sSQL);
StoreCampaignObject ("NWNX", "-", oObject);
}
else
{
// row doesn't exist
sSQL = "INSERT INTO " + sTable + " (player,tag,name,val,expire) VALUES" +
"('" + sPlayer + "','" + sTag + "','" + sVarName + "',%s," + IntToString(iExpiration) + ")";
SetLocalString(GetModule(), "NWNX!ODBC!SETSCORCOSQL", sSQL);
StoreCampaignObject ("NWNX", "-", oObject);
}
}
object PRC_GetPersistentObject(object oObject, string sVarName, object oOwner = OBJECT_INVALID, string sTable = "pwobjdata")
{
string sPlayer;
string sTag;
object oModule;
if (GetIsPC(oObject))
{
sPlayer = ReplaceSingleChars(GetPCPlayerName(oObject), "'", "~");
sTag = ReplaceSingleChars(GetName(oObject), "'", "~");
}
else
{
sPlayer = "~";
sTag = GetTag(oObject);
}
sVarName = ReplaceSingleChars(sVarName, "'", "~");
string sSQL = "SELECT val FROM " + sTable + " WHERE player='" + sPlayer +
"' AND tag='" + sTag + "' AND name='" + sVarName + "'";
SetLocalString(GetModule(), "NWNX!ODBC!SETSCORCOSQL", sSQL);
if (!GetIsObjectValid(oOwner))
oOwner = oObject;
return RetrieveCampaignObject ("NWNX", "-", GetLocation(oOwner), oOwner);
}
//////////////////////////////////////////////////
/* Functions for portable persistent chest */
//////////////////////////////////////////////////
void DeleteXChestDB()
{
PRC_SQLExecDirect("DROP TABLE "+XCHST_DB);
}
void CreateXChestDB_SQLite()
{
PRC_SQLExecDirect("CREATE TABLE "+XCHST_DB+" (" +
"player varchar(64) NOT NULL default '~'," +
"tag varchar(64) NOT NULL default '~'," +
"name varchar(64) NOT NULL default '~'," +
"val blob," +
"expire int(11) default NULL," +
"last timestamp NOT NULL default current_timestamp," +
"PRIMARY KEY (player,tag,name)" +
")");
}
void CreateXChestDB_MySQL()
{
PRC_SQLExecDirect("CREATE TABLE "+XCHST_DB+" (" +
"player varchar(64) NOT NULL default '~'," +
"tag varchar(64) NOT NULL default '~'," +
"name varchar(64) NOT NULL default '~'," +
"val blob," +
"expire int(11) default NULL," +
"last timestamp NOT NULL default CURRENT_TIMESTAMP," +
"PRIMARY KEY (player,tag,name)" +
") ENGINE=MyISAM DEFAULT CHARSET=latin1;");
}
//:: void main (){}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,239 @@
//::///////////////////////////////////////////////
//:: Target list management functions include
//:: inc_target_list
//::///////////////////////////////////////////////
/** @file
This is a set of functions intended to be used in
spellscripts for getting a set of targets according
to CR.
The list is built on the objects making up the list,
so it should be extracted from this system if it is
to be used for longer than the duration of a single
spellscript.
This is because the system cleans up after itself
and the object references from which the list is
built up of are deleted when current script execution
ends.
Also, do not manipulate the list structure with means
other than the functions provided here.
Any particular list should be built using only a signle
bias and ordering direction.
Behavior in circumstances other than the recommended
is non-deterministic. In other words, you've been warned :D
One can utilise the insertion bias constants to change
the ordering of the creatures in the list.
All orders are descending by default.
@author Ornedan
@date Created - 18.01.2005
@date Modified - 26.06.2005
@date Modified - 21.01.2006
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Public constants */
//////////////////////////////////////////////////
/// Inserts based on Challenge Rating
const int INSERTION_BIAS_CR = 1;
/// Inserts based on Hit Dice
const int INSERTION_BIAS_HD = 2;
/// Inserts based on the ratio of CurrentHP / MaxHP
const int INSERTION_BIAS_HP_RATIO = 3;
/// Inserts based on distance from the object list is being built on
const int INSERTION_BIAS_DISTANCE = 4;
/// Inserts based on the current amount of HP
const int INSERTION_BIAS_HP = 5;
//////////////////////////////////////////////////
/* Public functions */
//////////////////////////////////////////////////
/**
* Adds the given object to a list. If no list exists when this is called,
* it is created.
* If either oInsert or oCaster is not valid, nothing happens.
*
* @param oInsert The object to insert into the list
* @param oCaster The object that holds the head of the list.
* This should be whatever object is casting the
* spell that uses the list.
* @param nInsertionBias The insertion bias to use, one of the
* INSERTION_BIAS_* constants
* @param bDescendingOrder Whether to sort the targets into ascending or
* descending order.
*/
void AddToTargetList(object oInsert, object oCaster, int nInsertionBias = INSERTION_BIAS_CR, int bDescendingOrder = TRUE);
/**
* Gets the head a target list.
* Returns the head of the list built on oCaster and removes it
* from the list. If there are no more entries in the list,
* return OBJECT_INVALID.
*
* @param oCaster An object a target list has been built on.
* @return The current head of the target list, which
* is then removed from the list. Or
* OBJECT_INVALID when no more objects remain
* in the list.
*/
object GetTargetListHead(object oCaster);
//////////////////////////////////////////////////
/* Private constants */
//////////////////////////////////////////////////
const string TARGET_LIST_HEAD = "TargetListHead";
const string TARGET_LIST_NEXT = "TargetListNext_";
const string TARGET_LIST_PURGE_CALLED = "TargetListPurgeCalled";
//////////////////////////////////////////////////
/* Private functions */
//////////////////////////////////////////////////
int GetIsInsertPosition(object oInsert, object oCompare, object oCaster, int nInsertionBias, int bDescendingOrder);
void PurgeTargetList(object oCaster);
//////////////////////////////////////////////////
/* function definitions */
//////////////////////////////////////////////////
void AddToTargetList(object oInsert, object oCaster, int nInsertionBias = INSERTION_BIAS_CR, int bDescendingOrder = TRUE)
{
if(!GetIsObjectValid(oInsert) ||
!GetIsObjectValid(oCaster))
{
WriteTimestampedLogEntry("AddToTargetList called with an invalid parameter");
return;
}
object oCurrent = GetLocalObject(oCaster, TARGET_LIST_HEAD);
// If the queue is empty, or the insertable just happens to belong at the head
if(GetIsInsertPosition(oInsert, oCurrent, oCaster, nInsertionBias, bDescendingOrder))
{
SetLocalObject(oCaster, TARGET_LIST_HEAD, oInsert);
SetLocalObject(oCaster, TARGET_LIST_NEXT + ObjectToString(oInsert), oCurrent);
}// end if - insertable is the new head of the list
else
{
object oNext = GetLocalObject(oCaster, TARGET_LIST_NEXT + ObjectToString(oCurrent));
int bDone = FALSE;
while(!bDone)
{
if(GetIsInsertPosition(oInsert, oNext, oCaster, nInsertionBias, bDescendingOrder))
{
SetLocalObject(oCaster, TARGET_LIST_NEXT + ObjectToString(oCurrent), oInsert);
// Some paranoia to make sure the last element of the list always points
// to invalid
if(GetIsObjectValid(oNext)){
SetLocalObject(oCaster, TARGET_LIST_NEXT + ObjectToString(oInsert), oNext);
}
else
DeleteLocalObject(oCaster, TARGET_LIST_NEXT + ObjectToString(oInsert));
bDone = TRUE;
}// end if - this is the place to insert
else
{
oCurrent = oNext;
oNext = GetLocalObject(oCaster, TARGET_LIST_NEXT + ObjectToString(oCurrent));
}// end else - get next object in the list
}// end while - loop through the list, looking for the position to insert this creature
}// end else - the insertable creature is to be in a position other than the head
// Schedule clearing the list away once the current script has finished if it hasn't been done already
if(!GetLocalInt(oCaster, TARGET_LIST_PURGE_CALLED))
{
DelayCommand(0.0f, PurgeTargetList(oCaster));
SetLocalInt(oCaster, TARGET_LIST_PURGE_CALLED, TRUE);
}
}
object GetTargetListHead(object oCaster)
{
object oReturn = GetLocalObject(oCaster, TARGET_LIST_HEAD);
SetLocalObject(oCaster, TARGET_LIST_HEAD, GetLocalObject(oCaster, TARGET_LIST_NEXT + ObjectToString(oReturn)));
DeleteLocalObject(oCaster, TARGET_LIST_NEXT + ObjectToString(oReturn));
return oReturn;
}
/* Removes the list of target objects held by oCaster
* This should be called once the list is no longer used by the script that needed it
* Failure to do so may cause problems
*/
void PurgeTargetList(object oCaster)
{
object oCurrent = GetLocalObject(oCaster, TARGET_LIST_HEAD);
DeleteLocalObject(oCaster, TARGET_LIST_HEAD);
object oNext;
while(GetIsObjectValid(oCurrent))
{
oNext = GetLocalObject(oCaster, TARGET_LIST_NEXT + ObjectToString(oCurrent));
DeleteLocalObject(oCaster, TARGET_LIST_NEXT + ObjectToString(oCurrent));
oCurrent = oNext;
}// end while - loop through the list erasing the links
DeleteLocalInt(oCaster, TARGET_LIST_PURGE_CALLED);
}
// This is an internal function intended only for use in inc_target_list.nss
int GetIsInsertPosition(object oInsert, object oCompare, object oCaster, int nInsertionBias, int bDescendingOrder)
{
// Special case - A valid object is always inserted before an invalid one
if(!GetIsObjectValid(oCompare))
return TRUE;
int bReturn;
switch(nInsertionBias)
{
case INSERTION_BIAS_CR:
bReturn = GetChallengeRating(oInsert) > GetChallengeRating(oCompare);
break;
case INSERTION_BIAS_HD:
bReturn = GetHitDice(oInsert) > GetHitDice(oCompare);
break;
case INSERTION_BIAS_HP_RATIO:// A bit of trickery to avoid possible division by zero, which would happen if a non-creature got passed for insertion
bReturn = (IntToFloat(GetCurrentHitPoints(oInsert)) / ((GetMaxHitPoints(oInsert) > 0) ? IntToFloat(GetMaxHitPoints(oInsert)) : 0.001f))
>
(IntToFloat(GetCurrentHitPoints(oCompare)) / ((GetMaxHitPoints(oCompare) > 0) ? IntToFloat(GetMaxHitPoints(oCompare)) : 0.001f));
break;
case INSERTION_BIAS_DISTANCE:
bReturn = GetDistanceBetween(oInsert, oCaster) > GetDistanceBetween(oCompare, oCaster);
break;
case INSERTION_BIAS_HP:
bReturn = GetCurrentHitPoints(oInsert) > GetCurrentHitPoints(oCompare);
break;
default:
WriteTimestampedLogEntry("Invalid target selection bias given. Value: " + IntToString(nInsertionBias));
return TRUE;
}
return bDescendingOrder ? bReturn : !bReturn;
}

405
src/include/inc_threads.nss Normal file
View File

@@ -0,0 +1,405 @@
//:://////////////////////////////////////////////
//:: Thread include
//:: inc_threads
//:://////////////////////////////////////////////
/** @file
A simple set of functions for creating,
controlling and destroying threads that
repeatedly run a given script.
A thread is implemented as a pseudo-hb that
executes a given script on each of it's
beats.
Threads may be in one of 3 states:
THREAD_STATE_DEAD:
Equivalent to the thread not existing at
all.
THREAD_STATE_RUNNING:
The thread is alive, and will execute it's
script on each of the underlying pseudo-hb's
beats.
THREAD_STATE_SLEEPING:
The thread is alive, but will not execute
it's script on the pseudo-hb's beats.
The thread's script will be ExecuteScripted on
the object that the thread is running on. This
is the same object that also stores the
thread's state (all of 3 local variables).
@author Ornedan
@date Created - 14.03.2005
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Constant declarations */
//////////////////////////////////////////////////
// Thread state constants
/// Thread state - Dead or non-existent
const int THREAD_STATE_DEAD = 0;
/// Thread state - Running at the moment
const int THREAD_STATE_RUNNING = 1;
/// Thread state - Sleeping
const int THREAD_STATE_SLEEPING = 2;
// Internal constants. Nothing to see here. <.< >.>
const string PREFIX = "prc_thread_";
const string SUFFIX_SCRIPT = "_script";
const string SUFFIX_INTERVAL = "_interval";
const string SUFFIX_ITERATION = "_iteration";
const string CUR_THREAD = "current_thread";
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Creates a new thread.
*
* @param sName Name of thread to create. Must be non-empty
* @param sScript Name of script to run. Must be non-empty
* @param fExecutionInterval Amount of time that passes between executions of sScript.
* Only values > 0.0 allowed
* @param oToRunOn Object that stores the thread state values, and that
* sScript will be ExecuteScripted on.
* If this is OBJECT_INVALID, the module will be used to hold
* the thread
*
* @return TRUE if the thread creation was successfull. Possible reasons of failure:
* - One or more parameters were invalid
* - A thread by the given name was already running on oToRunOn
*/
int SpawnNewThread(string sName, string sScript, float fExecutionInterval = 6.0f, object oToRunOn = OBJECT_INVALID);
/**
* Inspects the state of the given thread.
*
* @param sName Name of thread to inspect. Must be non-empty
* @param oRunningOn Object that the thread is running on. If this
* is OBJECT_INVALID, the module will be used.
*
* @return One of the THREAD_STATE_* constants. Inspecting a non-
* existent thread, or thread that was running on an object that
* was destroyed will return THREAD_STATE_DEAD
*/
int GetThreadState(string sName, object oRunningOn = OBJECT_INVALID);
/**
* Gets the name of the script the given thread is running.
*
* @param sName Name of thread to inspect. Must be non-empty
* @param oRunningOn Object that the thread is running on. If this
* is OBJECT_INVALID, the module will be used.
*
* @return The name of the the given thread executes on success, ""
* on failure (querying with invalid parameters, or on a dead thread)
*/
string GetThreadScript(string sName, object oRunningOn = OBJECT_INVALID);
/** Gets the execution interval for the given thread
*
* @param sName Name of thread to inspect. Must be non-empty
* @param oRunningOn Object that the thread is running on. If this
* is OBJECT_INVALID, the module will be used.
*
* @return The time between the given thread executing it's script.
* On failure, 0.0f is returned.
*/
float GetThreadExecutionInterval(string sName, object oRunningOn = OBJECT_INVALID);
/**
* Gets the name of the thread whose script is currently being executed.
*
* @return The name of the thread being executed at the time of the call,
* or "" if no thread is being executed when this is called.
*/
string GetCurrentThread();
/**
* Gets the object currently running thread is executing on
*
* @return The object the currently executing thread is being executed on
* or OBJECT_INVALID if no thread is being executed when this is called.
*/
object GetCurrentThreadObject();
/**
* Stops further execution of the given thread and removes it's data
* from the object it was running on.
*
* @param sName Name of thread to terminate. Must be non-empty
* @param oRunningOn Object that the thread is running on. If this
* is OBJECT_INVALID, the module will be used.
*/
void TerminateThread(string sName, object oRunningOn = OBJECT_INVALID);
/**
* Stops further execution of the thread currently being executed.
* A convenience wrapper for TerminateThread to be called from a
* threadscript.
*/
void TerminateCurrentThread();
/**
* Sets the stae of the given thread to sleeping.
*
* @param sName Name of thread to set sleeping. Must be non-empty
* @param oRunningOn Object that the thread is running on. If this
* is OBJECT_INVALID, the module will be used.
*
* @return Whether the operation was successfull. Failure indicates
* that the thread was dead.
*/
int SleepThread(string sName, object oRunningOn = OBJECT_INVALID);
/**
* Awakens the given thread.
*
* @param sName Name of thread to set back running. Must be non-empty
* @param oRunningOn Object that the thread is running on. If this
* is OBJECT_INVALID, the module will be used.
*
* @return Whether the operation was successfull. Failure indicates
* that the thread was dead.
*/
int AwakenThread(string sName, object oRunningOn = OBJECT_INVALID);
/**
* Changes the execution interval of the given thread.
*
* @param sName Name of thread to set back running. Must be non-empty
* @param oRunningOn Object that the thread is running on. If this
* is OBJECT_INVALID, the module will be used.
* @param fNewInterval The amount of time between executions of the
* threadscript that will used from next execution
* onwards.
*
* @return Returns whether the operation was successfull. Failure indicates
* that the thread was dead.
*/
int ChangeExecutionInterval(string sName, float fNewInterval, object oRunningOn = OBJECT_INVALID);
/*
* Internal function. This is the pseudo-hb function that calls itself.
*
* @param sName name of the thread to run. Used to build local variable names
* @param oRunningOn object that stores the variables, and the one that will
* be passed to ExecuteScript
*/
void RunThread(string sName, object oRunningOn, int iIteration);
//////////////////////////////////////////////////
/* Function defintions */
//////////////////////////////////////////////////
int SpawnNewThread(string sName, string sScript, float fExecutionInterval = 6.0f, object oToRunOn = OBJECT_INVALID){
if(oToRunOn == OBJECT_INVALID)
oToRunOn = GetModule();
// Check paramaeters for correctness
if(sName == "" ||
sScript == "" ||
fExecutionInterval <= 0.0f ||
!GetIsObjectValid(oToRunOn))
return FALSE;
// Make sure there is no thread by this name already running
// if(GetLocalInt(oToRunOn, PREFIX + sName))
// return FALSE;
// use iterations in place of the above to make it more reliable in case of a PC thread timing out while not logged in
int iIteration = GetLocalInt(oToRunOn, PREFIX + sName + SUFFIX_ITERATION);
// Set the thread variables
SetLocalInt(oToRunOn, PREFIX + sName, THREAD_STATE_RUNNING);
SetLocalString(oToRunOn, PREFIX + sName + SUFFIX_SCRIPT, sScript);
SetLocalFloat(oToRunOn, PREFIX + sName + SUFFIX_INTERVAL, fExecutionInterval);
// Start thread execution
DelayCommand(fExecutionInterval, RunThread(sName, oToRunOn, iIteration));
// All done successfully
return TRUE;
}
int GetThreadState(string sName, object oRunningOn = OBJECT_INVALID){
if(oRunningOn == OBJECT_INVALID)
oRunningOn = GetModule();
// Check paramaeters for correctness
if(sName == "" ||
!GetIsObjectValid(oRunningOn))
return FALSE;
// Return the local determining if the thread exists
return GetLocalInt(oRunningOn, PREFIX + sName);
}
string GetThreadScript(string sName, object oRunningOn = OBJECT_INVALID){
if(oRunningOn == OBJECT_INVALID)
oRunningOn = GetModule();
// Check paramaeters for correctness
if(sName == "" ||
!GetIsObjectValid(oRunningOn))
return "";
return GetLocalString(oRunningOn, PREFIX + sName + SUFFIX_SCRIPT);
}
float GetThreadExecutionInterval(string sName, object oRunningOn = OBJECT_INVALID){
if(oRunningOn == OBJECT_INVALID)
oRunningOn = GetModule();
// Check paramaeters for correctness
if(sName == "" ||
!GetIsObjectValid(oRunningOn))
return 0.0f;
return GetLocalFloat(oRunningOn, PREFIX + sName + SUFFIX_INTERVAL);
}
string GetCurrentThread(){
return GetLocalString(GetModule(), PREFIX + CUR_THREAD);
}
object GetCurrentThreadObject(){
return GetIsObjectValid(GetLocalObject(GetModule(), PREFIX + CUR_THREAD)) ?
GetLocalObject(GetModule(), PREFIX + CUR_THREAD) :
OBJECT_INVALID;
}
void TerminateThread(string sName, object oRunningOn = OBJECT_INVALID){
if(oRunningOn == OBJECT_INVALID)
oRunningOn = GetModule();
// Check paramaeters for correctness. Just an optimization here, since
// if either of these were not valid, nothing would happen.
if(sName == "" ||
!GetIsObjectValid(oRunningOn))
return;
// Remove the thread variables
DeleteLocalInt(oRunningOn, PREFIX + sName);
DeleteLocalString(oRunningOn, PREFIX + sName + SUFFIX_SCRIPT);
DeleteLocalFloat(oRunningOn, PREFIX + sName + SUFFIX_INTERVAL);
// Increase the iteration so that any lingering runthread fail to fire if the thread is restarted
int iExpectedIteration = GetLocalInt(oRunningOn, PREFIX + sName + SUFFIX_ITERATION);
iExpectedIteration++;
SetLocalInt(oRunningOn, PREFIX + sName + SUFFIX_ITERATION, iExpectedIteration);
}
void TerminateCurrentThread(){
TerminateThread(GetLocalString(GetModule(), PREFIX + CUR_THREAD),
GetLocalObject(GetModule(), PREFIX + CUR_THREAD)
);
}
int SleepThread(string sName, object oRunningOn = OBJECT_INVALID){
if(oRunningOn == OBJECT_INVALID)
oRunningOn = GetModule();
// Check paramaeters for correctness
if(sName == "" ||
!GetIsObjectValid(oRunningOn))
return FALSE;
// Change thread state
SetLocalInt(oRunningOn, PREFIX + sName, THREAD_STATE_SLEEPING);
return TRUE;
}
int AwakenThread(string sName, object oRunningOn = OBJECT_INVALID){
if(oRunningOn == OBJECT_INVALID)
oRunningOn = GetModule();
// Check paramaeters for correctness
if(sName == "" ||
!GetIsObjectValid(oRunningOn))
return FALSE;
// Change thread state
SetLocalInt(oRunningOn, PREFIX + sName, THREAD_STATE_RUNNING);
return TRUE;
}
int ChangeExecutionInterval(string sName, float fNewInterval, object oRunningOn = OBJECT_INVALID){
if(oRunningOn == OBJECT_INVALID)
oRunningOn = GetModule();
// Check paramaeters for correctness
if(!GetThreadState(sName, oRunningOn) ||
fNewInterval <= 0.0f)
return FALSE;
SetLocalFloat(oRunningOn, PREFIX + sName + SUFFIX_INTERVAL, fNewInterval);
return TRUE;
}
void RunThread(string sName, object oRunningOn, int iIteration){
// Abort if we're on the wrong iteration, this allows us to
// be liberal about spawning threads in case they've timed
// out while a PC was logged out
int iExpectedIteration = GetLocalInt(oRunningOn, PREFIX + sName + SUFFIX_ITERATION);
if(iIteration != iExpectedIteration)
return;
iExpectedIteration++;
SetLocalInt(oRunningOn, PREFIX + sName + SUFFIX_ITERATION, iExpectedIteration);
// Abort if the object we're running on has ceased to exist
// or if the thread has been terminated
int nThreadState = GetThreadState(sName, oRunningOn);
if(nThreadState == THREAD_STATE_DEAD)
return;
// Mark this thread as running
SetLocalString(GetModule(), PREFIX + CUR_THREAD, sName);
SetLocalObject(GetModule(), PREFIX + CUR_THREAD, oRunningOn);
// Execute the threadscript if the thread is running atm
if(nThreadState == THREAD_STATE_RUNNING){
string sScript = GetLocalString(oRunningOn, PREFIX + sName + SUFFIX_SCRIPT);
ExecuteScript(sScript, oRunningOn);
}
// Schedule next execution, unless we've been terminated
if(GetThreadState(sName, oRunningOn) != THREAD_STATE_DEAD){
DelayCommand(GetLocalFloat(oRunningOn, PREFIX + sName + SUFFIX_INTERVAL), RunThread(sName, oRunningOn, iExpectedIteration));
}
// Clean up the module variables
DeleteLocalString(GetModule(), PREFIX + CUR_THREAD);
DeleteLocalObject(GetModule(), PREFIX + CUR_THREAD);
}
// Test main
//void main(){}

501
src/include/inc_time.nss Normal file
View File

@@ -0,0 +1,501 @@
/** @file
This set of functions controlls time for players.
When recalculate time is called, the clock advances to that of the most behind player.
This system works best with single party modules. If you have multiple parties and player
you may find that when the server catches up it may disorent players for a time.
This is disabled unless the switch PRC_PLAYER_TIME is true
Also in this include is a time struct and various functions for expressing time
As part of this, there is some custom tokens that can be setup
//82001 part of day
//82002 date
//82003 month
//82004 year
//82005 hour
//82006 minutes
//82007 seconds
@author Primogenitor
*/
//////////////////////////////////////////////////
/* Function Prototypes */
//////////////////////////////////////////////////
struct time
{
int nYear;
int nMonth;
int nDay;
int nHour;
int nMinute;
int nSecond;
int nMillisecond;
};
struct time TimeCheck(struct time tTime);
struct time GetLocalTime(object oObject, string sName);
void SetLocalTime(object oObject, string sName, struct time tTime);
void DeleteLocalTime(object oObject, string sName);
struct time GetPersistantLocalTime(object oObject, string sName);
void SetPersistantLocalTime(object oObject, string sName, struct time tTime);
string TimeToString(struct time tTime);
struct time StringToTime(string sIn);
void SetTimeAndDate(struct time tTime);
int GetIsTimeAhead(struct time tTime1, struct time tTime2);
void RecalculateTime(int nMaxStep = 6);
void AdvanceTimeForPlayer(object oPC, float fSeconds);
//////////////////////////////////////////////////
/* Include section */
//////////////////////////////////////////////////
//#include "prc_inc_switch"
#include "inc_persist_loca"
//////////////////////////////////////////////////
/* Function Definitions */
//////////////////////////////////////////////////
struct time TimeAdd(struct time tTime1, struct time tTime2)
{
tTime1 = TimeCheck(tTime1);
tTime2 = TimeCheck(tTime2);
tTime1.nYear += tTime2.nYear;
tTime1.nMonth += tTime2.nMonth;
tTime1.nDay += tTime2.nDay;
tTime1.nHour += tTime2.nHour;
tTime1.nMinute += tTime2.nMinute;
tTime1.nSecond += tTime2.nSecond;
tTime1.nMillisecond += tTime2.nMillisecond;
tTime1 = TimeCheck(tTime1);
return tTime1;
}
struct time TimeSubtract(struct time tTime1, struct time tTime2)
{
tTime1 = TimeCheck(tTime1);
tTime2 = TimeCheck(tTime2);
tTime1.nYear -= tTime2.nYear;
tTime1.nMonth -= tTime2.nMonth;
tTime1.nDay -= tTime2.nDay;
tTime1.nHour -= tTime2.nHour;
tTime1.nMinute -= tTime2.nMinute;
tTime1.nSecond -= tTime2.nSecond;
tTime1.nMillisecond -= tTime2.nMillisecond;
tTime1 = TimeCheck(tTime1);
return tTime1;
}
struct time GetLocalTime(object oObject, string sName)
{
struct time tTime;
tTime.nYear = GetLocalInt(oObject, sName+".nYear");
tTime.nMonth = GetLocalInt(oObject, sName+".nMonth");
tTime.nDay = GetLocalInt(oObject, sName+".nDay");
tTime.nHour = GetLocalInt(oObject, sName+".nHour");
tTime.nMinute = GetLocalInt(oObject, sName+".nMinute");
tTime.nSecond = GetLocalInt(oObject, sName+".nSecond");
tTime.nMillisecond = GetLocalInt(oObject, sName+".nMillisecond");
tTime = TimeCheck(tTime);
return tTime;
}
void SetLocalTime(object oObject, string sName, struct time tTime)
{
tTime = TimeCheck(tTime);
SetLocalInt(oObject, sName+".nYear", tTime.nYear);
SetLocalInt(oObject, sName+".nMonth", tTime.nMonth);
SetLocalInt(oObject, sName+".nDay", tTime.nDay);
SetLocalInt(oObject, sName+".nHour", tTime.nHour);
SetLocalInt(oObject, sName+".nMinute", tTime.nMinute);
SetLocalInt(oObject, sName+".nSecond", tTime.nSecond);
SetLocalInt(oObject, sName+".nMillisecond", tTime.nMillisecond);
}
void DeleteLocalTime(object oObject, string sName)
{
DeleteLocalInt(oObject, sName+".nYear");
DeleteLocalInt(oObject, sName+".nMonth");
DeleteLocalInt(oObject, sName+".nDay");
DeleteLocalInt(oObject, sName+".nHour");
DeleteLocalInt(oObject, sName+".nMinute");
DeleteLocalInt(oObject, sName+".nSecond");
DeleteLocalInt(oObject, sName+".nMillisecond");
}
struct time GetPersistantLocalTime(object oObject, string sName)
{
struct time tTime;
tTime.nYear = GetPersistantLocalInt(oObject, sName+".nYear");
tTime.nMonth = GetPersistantLocalInt(oObject, sName+".nMonth");
tTime.nDay = GetPersistantLocalInt(oObject, sName+".nDay");
tTime.nHour = GetPersistantLocalInt(oObject, sName+".nHour");
tTime.nMinute = GetPersistantLocalInt(oObject, sName+".nMinute");
tTime.nSecond = GetPersistantLocalInt(oObject, sName+".nSecond");
tTime.nMillisecond = GetPersistantLocalInt(oObject, sName+".nMillisecond");
tTime = TimeCheck(tTime);
return tTime;
}
void SetPersistantLocalTime(object oObject, string sName, struct time tTime)
{
tTime = TimeCheck(tTime);
SetPersistantLocalInt(oObject, sName+".nYear", tTime.nYear);
SetPersistantLocalInt(oObject, sName+".nMonth", tTime.nMonth);
SetPersistantLocalInt(oObject, sName+".nDay", tTime.nDay);
SetPersistantLocalInt(oObject, sName+".nHour", tTime.nHour);
SetPersistantLocalInt(oObject, sName+".nMinute", tTime.nMinute);
SetPersistantLocalInt(oObject, sName+".nSecond", tTime.nSecond);
SetPersistantLocalInt(oObject, sName+".nMillisecond", tTime.nMillisecond);
}
string TimeToString(struct time tTime)
{
string sReturn;
sReturn += IntToString(tTime.nYear)+"|";
sReturn += IntToString(tTime.nMonth)+"|";
sReturn += IntToString(tTime.nDay)+"|";
sReturn += IntToString(tTime.nHour)+"|";
sReturn += IntToString(tTime.nMinute)+"|";
sReturn += IntToString(tTime.nSecond)+"|";
sReturn += IntToString(tTime.nMillisecond);
return sReturn;
}
struct time StringToTime(string sIn)
{
struct time tTime;
int nPos;
string sID;
nPos = FindSubString(sIn, "|");
tTime.nYear = StringToInt(GetStringLeft(sIn, nPos));
sIn = GetStringRight(sIn, GetStringLength(sIn)-nPos-1);
nPos = FindSubString(sIn, "|");
tTime.nMonth = StringToInt(GetStringLeft(sIn, nPos));
sIn = GetStringRight(sIn, GetStringLength(sIn)-nPos-1);
nPos = FindSubString(sIn, "|");
tTime.nDay = StringToInt(GetStringLeft(sIn, nPos));
sIn = GetStringRight(sIn, GetStringLength(sIn)-nPos-1);
nPos = FindSubString(sIn, "|");
tTime.nHour = StringToInt(GetStringLeft(sIn, nPos));
sIn = GetStringRight(sIn, GetStringLength(sIn)-nPos-1);
nPos = FindSubString(sIn, "|");
tTime.nMinute = StringToInt(GetStringLeft(sIn, nPos));
sIn = GetStringRight(sIn, GetStringLength(sIn)-nPos-1);
nPos = FindSubString(sIn, "|");
tTime.nSecond = StringToInt(GetStringLeft(sIn, nPos));
sIn = GetStringRight(sIn, GetStringLength(sIn)-nPos-1);
nPos = FindSubString(sIn, "|");
tTime.nMillisecond = StringToInt(GetStringLeft(sIn, nPos));
sIn = GetStringRight(sIn, GetStringLength(sIn)-nPos-1);
return tTime;
}
struct time TimeCheck(struct time tTime)
{
while(tTime.nMillisecond > 1000)
{
tTime.nSecond += 1;
tTime.nMillisecond -= 1000;
}
while(tTime.nSecond > 60)
{
tTime.nMinute += 1;
tTime.nSecond -= 60;
}
while(tTime.nMinute > FloatToInt(HoursToSeconds(1))/60)
{
tTime.nHour += 1;
tTime.nMinute -= FloatToInt(HoursToSeconds(1))/60;
}
while(tTime.nHour > 24)
{
tTime.nDay += 1;
tTime.nHour -= 24;
}
while(tTime.nDay > 28)
{
tTime.nMonth += 1;
tTime.nDay -= 28;
}
while(tTime.nMonth > 12)
{
tTime.nYear += 1;
tTime.nMonth -= 12;
}
//decreases
while(tTime.nMillisecond < 1)
{
tTime.nSecond -= 1;
tTime.nMillisecond += 1000;
}
while(tTime.nSecond < 1)
{
tTime.nMinute -= 1;
tTime.nSecond += 60;
}
while(tTime.nMinute < 1)
{
tTime.nHour -= 1;
tTime.nMinute += FloatToInt(HoursToSeconds(1))/60;
}
while(tTime.nHour < 1)
{
tTime.nDay -= 1;
tTime.nHour += 24;
}
while(tTime.nDay < 1)
{
tTime.nMonth -= 1;
tTime.nDay += 28;
}
while(tTime.nMonth < 1)
{
tTime.nYear -= 1;
tTime.nMonth += 12;
}
return tTime;
}
struct time GetTimeAndDate()
{
struct time tTime;
tTime.nYear = GetCalendarYear();
tTime.nMonth = GetCalendarMonth();
tTime.nDay = GetCalendarDay();
tTime.nHour = GetTimeHour();
tTime.nMinute = GetTimeMinute();
tTime.nSecond = GetTimeSecond();
tTime.nMillisecond = GetTimeMillisecond();
tTime = TimeCheck(tTime);
return tTime;
}
void SetTimeAndDate(struct time tTime)
{
tTime = TimeCheck(tTime);
SetCalendar(tTime.nYear, tTime.nMonth, tTime.nDay);
SetTime(tTime.nHour, tTime.nMinute, tTime.nSecond, tTime.nMillisecond);
}
int GetIsTimeAhead(struct time tTime1, struct time tTime2)
{
if(tTime1.nYear > tTime2.nYear)
return TRUE;
else if(tTime1.nYear < tTime2.nYear)
return FALSE;
//equal
if(tTime1.nMonth > tTime2.nMonth)
return TRUE;
else if(tTime1.nMonth < tTime2.nMonth)
return FALSE;
//equal
if(tTime1.nDay > tTime2.nDay)
return TRUE;
else if(tTime1.nDay < tTime2.nDay)
return FALSE;
//equal
if(tTime1.nHour > tTime2.nHour)
return TRUE;
else if(tTime1.nHour < tTime2.nHour)
return FALSE;
//equal
if(tTime1.nMinute > tTime2.nMinute)
return TRUE;
else if(tTime1.nMinute < tTime2.nMinute)
return FALSE;
//equal
if(tTime1.nSecond > tTime2.nSecond)
return TRUE;
else if(tTime1.nSecond < tTime2.nSecond)
return FALSE;
//equal
if(tTime1.nMillisecond > tTime2.nMillisecond)
return TRUE;
else if(tTime1.nMillisecond < tTime2.nMillisecond)
return FALSE;
//must be exactly the same
return FALSE;
}
void RecalculateTime(int nMaxStep = 6)
{
if(!GetPRCSwitch(PRC_PLAYER_TIME))
return;
//get the earliest time ahead of all PCs
object oPC = GetFirstPC();
struct time tTimeAhead = GetLocalTime(oPC, "TimeAhead");
while(GetIsObjectValid(oPC))
{
struct time tTest = GetLocalTime(oPC, "TimeAhead");
if(!GetIsTimeAhead(tTimeAhead, tTest))
tTimeAhead = tTest;
oPC = GetNextPC();
}
//if its zero, abort
struct time tNULL;
if(tNULL == tTimeAhead)
return;
//if its not zero, recalulate it till it is
DelayCommand(0.01, RecalculateTime());//do it again until caught up
//create the steps to use
struct time tStep;
tStep.nSecond = nMaxStep;
//make sure you dont skip more than a step at a time
if(GetIsTimeAhead(tTimeAhead, tStep))
tTimeAhead = tStep;
//set the new real time
struct time tNewTime = GetTimeAndDate();
tNewTime = TimeAdd(tNewTime, tTimeAhead);
SetTimeAndDate(tNewTime);
//update the stored values
oPC = GetFirstPC();
while(GetIsObjectValid(oPC))
{
struct time tTest = GetLocalTime(oPC, "TimeAhead");
tTest = TimeSubtract(tTest, tTimeAhead);
SetLocalTime(oPC, "TimeAhead", tTest);
oPC = GetNextPC();
}
}
void AdvanceTimeForPlayer(object oPC, float fSeconds)
{
struct time tTime = GetLocalTime(oPC, "TimeAhead");
tTime.nSecond += FloatToInt(fSeconds);
SetLocalTime(oPC, "TimeAhead", tTime);
DelayCommand(0.01, RecalculateTime());
}
void AssembleTokens(struct time tTime)
{
tTime = TimeCheck(tTime);
//setup time tokens
//82001 part of day
//82002 date
//82003 month
//82004 year
//82005 hour
//82006 minutes
//82007 seconds
//82008 24 hour clock
//82009 timer
//this assumes default time settings
//Dawn, 06:00
//Dusk, 18:00
if(tTime.nHour == 6)
SetCustomToken(82001, "dawn");
else if(tTime.nHour == 18)
SetCustomToken(82001, "dusk");
else if(tTime.nHour >= 19 || tTime.nHour <= 5)
SetCustomToken(82001, "night");
else if(tTime.nHour >= 7 && tTime.nHour < 13)
SetCustomToken(82001, "morning");
else if(tTime.nHour >= 13 && tTime.nHour < 18)
SetCustomToken(82001, "afternoon");
string sDay = IntToString(tTime.nDay);
if(tTime.nDay == 1
//|| tTime.nDay == 11 //this is 11th
|| tTime.nDay == 21)
sDay += "st";
else if(tTime.nDay == 2
//|| tTime.nDay == 12 //this is 12th
|| tTime.nDay == 22)
sDay += "nd";
else if(tTime.nDay == 3
//|| tTime.nDay == 13 //this is 13th
|| tTime.nDay == 23)
sDay += "rd";
else
sDay += "th";
SetCustomToken(82002, sDay);
string sMonth;
switch(tTime.nMonth)
{
case 1: sMonth = "January"; break;
case 2: sMonth = "Febuary"; break;
case 3: sMonth = "March"; break;
case 4: sMonth = "April"; break;
case 5: sMonth = "May"; break;
case 6: sMonth = "June"; break;
case 7: sMonth = "July"; break;
case 8: sMonth = "August"; break;
case 9: sMonth = "September"; break;
case 10: sMonth = "October"; break;
case 11: sMonth = "November"; break;
case 12: sMonth = "December"; break;
}
SetCustomToken(82003, sMonth);
SetCustomToken(82004, IntToString(tTime.nYear));
SetCustomToken(82005, IntToString(tTime.nHour));
SetCustomToken(82006, IntToString(tTime.nMinute));
SetCustomToken(82007, IntToString(tTime.nSecond));
SetCustomToken(82008, IntToString(tTime.nHour)+":"+IntToString(tTime.nMinute));
string sTimer;
if(!tTime.nYear)
{
if(tTime.nYear > 1)
sTimer += IntToString(tTime.nYear)+" years";
else
sTimer += IntToString(tTime.nYear)+" year";
}
if(!tTime.nMonth)
{
if(sTimer != "")
sTimer += ", ";
if(tTime.nMonth > 1)
sTimer += IntToString(tTime.nMonth)+" months";
else
sTimer += IntToString(tTime.nMonth)+" month";
}
if(!tTime.nDay)
{
if(sTimer != "")
sTimer += ", ";
if(tTime.nDay > 1)
sTimer += IntToString(tTime.nDay)+" days";
else
sTimer += IntToString(tTime.nMonth)+" day";
}
if(!tTime.nHour)
{
if(sTimer != "")
sTimer += ", ";
if(tTime.nHour > 1)
sTimer += IntToString(tTime.nHour)+" hours";
else
sTimer += IntToString(tTime.nMonth)+" hour";
}
if(!tTime.nMinute)
{
if(sTimer != "")
sTimer += ", ";
if(tTime.nMinute > 1)
sTimer += IntToString(tTime.nMinute)+" minutes";
else
sTimer += IntToString(tTime.nMonth)+" minute";
}
SetCustomToken(82009, sTimer);
}

View File

@@ -0,0 +1,83 @@
void DoTimestopEquip(object oPC, object oItem);
void DoTimestopUnEquip(object oPC, object oItem);
void ApplyTSToObject(object oTarget);
void RemoveTSFromObject(object oTarget);
#include "prc_x2_itemprop"
#include "prc_inc_switch"
#include "inc_prc_npc"
//#include "inc_utility"
void RemoveTimestopEquip()
{
int i;
for (i=0;i<18;i++)
{
IPRemoveMatchingItemProperties(GetItemInSlot(i), ITEM_PROPERTY_NO_DAMAGE, DURATION_TYPE_TEMPORARY);
}
}
void DoTimestopEquip(object oPC, object oItem)
{
if(GetPRCSwitch(PRC_TIMESTOP_NO_HOSTILE))
{
if(GetHasSpellEffect(SPELL_TIME_STOP, oPC)
|| GetHasSpellEffect(4032, oPC)
|| GetHasSpellEffect(14236, oPC))
AddItemProperty(DURATION_TYPE_TEMPORARY, ItemPropertyNoDamage(), oItem, 9999.0);
/*else if(GetHasSpellEffect(POWER_ID, oPC))
{
AddItemProperty(DURATION_TYPE_TEMPORARY, ItemPropertyNoDamage(), oItem, 9999.0);
//stuff for AC negation
}*/
}
}
void DoTimestopUnEquip(object oPC, object oItem)
{
if(GetPRCSwitch(PRC_TIMESTOP_NO_HOSTILE))
{
if(GetHasSpellEffect(SPELL_TIME_STOP, oPC)
|| GetHasSpellEffect(4032, oPC)
|| GetHasSpellEffect(14236, oPC))
IPRemoveMatchingItemProperties(oItem, ITEM_PROPERTY_NO_DAMAGE, DURATION_TYPE_TEMPORARY);
/*else if(GetHasSpellEffect(POWER_ID, oPC))
{
AddItemProperty(DURATION_TYPE_TEMPORARY, ItemPropertyNoDamage(), oItem, 9999.0);
//stuff for AC negation removal
}*/
}
}
void ApplyTSToObject(object oTarget)
{
effect eTS = EffectVisualEffect(VFX_DUR_FREEZE_ANIMATION);
effect eCSP = EffectCutsceneParalyze();
effect eLink = EffectLinkEffects(eTS, eCSP);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oTarget);
if(GetIsPC(oTarget) && GetPRCSwitch(PRC_TIMESTOP_BLANK_PC))
BlackScreen(oTarget);
AssignCommand(oTarget, ClearAllActions(FALSE));
SetCommandable(FALSE, oTarget);
}
void RemoveTSFromObject(object oTarget)
{
effect eTest = GetFirstEffect(oTarget);
while(GetIsEffectValid(eTest))
{
int nSpellId = GetEffectSpellId(eTest);
if(nSpellId == SPELL_TIME_STOP
|| nSpellId == 4032 //epic TS
|| nSpellId == 14205 // POWER_TEMPORALACCELERATION
|| nSpellId == 17366 // MOVE_DM_MOMENT_ALACRITY
|| nSpellId == 17511 // MOVE_WR_WHITE_RAVEN_TACTICS
)
RemoveEffect(oTarget, eTest);
eTest = GetNextEffect(oTarget);
}
if(GetIsPC(oTarget))
StopFade(oTarget);
SetCommandable(TRUE, oTarget);
}

View File

@@ -0,0 +1,100 @@
//::///////////////////////////////////////////////
//:: Unique identifier generation include
//:: inc_uniqueid
//::///////////////////////////////////////////////
/** @file inc_uniqueid
Contains functions for generating unique IDs
within the scope of one module instance.
An ID is a string of format:
PRC_UID_X
where X is the concatenation of the values of
one or more running integer counters.
The uniqueness is quaranteed by using a
set of local integers stored on the module
object as counters.
At first, the set contains a single integer,
initialised to 0. Each UID generation
increments it's value by 1. Once the value
reaches the maximum an NWN integer type may
have (0xFFFFFFFF), a new integer is added
to the set, again initialised to 0.
NOTE: The generated strings are only unique
withing a single module instance. Reloading
a module (new game / server reset) will
reset the counter due to the counter array
being lost.
As such, UIDs should not be stored persistently.
@author Ornedan
@date Created - 2006.06.30
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Constants */
//////////////////////////////////////////////////
const string PRC_UID_PREFIX = "PRC_UID_";
const string PRC_UID_ARRAY = "PRC_UID_Counters";
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Generates an UID, as described in the header comments.
*
* @return A string unique within a single module instance.
*/
string GetUniqueID();
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
//#include "inc_utility"
#include "prc_inc_array"
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
string GetUniqueID()
{
object oModule = GetModule();
string sReturn = PRC_UID_PREFIX;
// Init if this is the first call
if(!array_exists(oModule, PRC_UID_ARRAY))
{
array_create(oModule, PRC_UID_ARRAY);
array_set_int(oModule, PRC_UID_ARRAY, 0, 0);
}
// Loop over all the integers and concatenate them onto the UID being generated
int i, nMax = array_get_size(oModule, PRC_UID_ARRAY);
for(i=0; i < nMax; i++)
sReturn += IntToString(array_get_int(oModule, PRC_UID_ARRAY, i));
// Increment the counters
if((i = array_get_int(oModule, PRC_UID_ARRAY, nMax - 1)) < 0xFFFFFFFF)
// We're below maximum integer size, just increment the stored value
array_set_int(oModule, PRC_UID_ARRAY, nMax - 1, i + 1);
else
// We need to add a new integer to the set
array_set_int(oModule, PRC_UID_ARRAY, nMax, 0);
// Return the generated value
return sReturn;
}
// Test main
//void main(){}

1741
src/include/inc_utility.nss Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,675 @@
//::///////////////////////////////////////////////
//:: Visual Effect constant include
//:: inc_vfx_const
//::///////////////////////////////////////////////
/*
Constants for vfx present in visualeffects.2da that
do not have a constant defined by bioware.
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Unenumerated BW VFX */
//////////////////////////////////////////////////
const int VFX_COM_BLOOD_REG_WIMPY = 296;
const int VFX_COM_BLOOD_LRG_WIMPY = 297;
const int VFX_COM_BLOOD_CRT_WIMPY = 298;
const int VFX_COM_BLOOD_REG_WIMPG = 299;
const int VFX_COM_BLOOD_LRG_WIMPG = 300;
const int VFX_COM_BLOOD_CRT_WIMPG = 301;
const int VFX_COM_BLOOD_CRT_RED_HEAD = 491;
const int VFX_COM_BLOOD_CRT_GREEN_HEAD = 492;
const int VFX_COM_BLOOD_CRT_YELLOW_HEAD = 493;
const int VFX_IMP_LEAF = 132;
const int VFX_IMP_CLOUD = 133;
const int VFX_IMP_WIND = 134;
const int VFX_IMP_ROCKEXPLODE = 135;
const int VFX_IMP_ROCKEXPLODE2 = 136;
const int VFX_IMP_ROCKSUP = 137;
const int VFX_IMP_DESTRUCTION_LOW = 302;
const int VFX_IMP_PULSE_BOMB = 469;
const int VFX_IMP_SILENCE_NO_SOUND = 470;
const int VFX_BEAM_FLAME = 444;
const int VFX_DUR_GHOSTLY_PULSE_QUICK = 295;
const int VFX_DUR_PROT_ACIDSHIELD = 448;
const int VFX_DUR_BARD_SONG_SILENT = 468;
const int VFX_DUR_CONECOLD_HEAD = 490;
const int VFX_DUR_BARD_SONG_EVIL = 507;
const int VFX_FNF_SPELL_FAIL_HEA = 292;
const int VFX_FNF_SPELL_FAIL_HAND = 293;
const int VFX_FNF_HIGHLIGHT_FLASH_WHITE = 294;
const int VFX_FNF_SCREEN_SHAKE2 = 356;
const int VFX_FNF_HELLBALL = 464;
const int VFX_FNF_TELEPORT_IN = 471;
const int VFX_FNF_TELEPORT_OUT = 472;
const int VFX_FNF_DRAGBREATHGROUND = 494;
const int VFX_CONJ_MIND = 466;
const int VFX_CONJ_FIRE = 467;
const int SCENE_WEIRD = 323;
const int SCENE_EVARD = 346;
const int SCENE_TOWER = 347;
const int SCENE_TEMPLE = 348;
const int SCENE_LAVA = 349;
const int SCENE_LAVA2 = 350;
const int SCENE_WATER = 401;
const int SCENE_GRASS = 402;
const int SCENE_FORMIAN1 = 404;
const int SCENE_FORMIAN2 = 405;
const int SCENE_PITTRAP = 406;
const int SCENE_ICE = 426;
const int SCENE_MFPillar = 427;
const int SCENE_MFWaterfall = 428;
const int SCENE_MFGroundCover = 429;
const int SCENE_MFGroundCover2 = 430;
const int SCENE_MF6 = 431;
const int SCENE_MF7 = 432;
const int SCENE_MF8 = 433;
const int SCENE_MF9 = 434;
const int SCENE_MF10 = 435;
const int SCENE_MF11 = 436;
const int SCENE_MF12 = 437;
const int SCENE_MF13 = 438;
const int SCENE_MF14 = 439;
const int SCENE_MF15 = 440;
const int SCENE_MF16 = 441;
const int SCENE_ICE_CLEAR = 442;
const int SCENE_EVIL_CASTLE_WALL = 443;
const int SCENE_BUILDING = 449;
const int SCENE_BURNED_RUBBLE = 450;
const int SCENE_BURNING_HALF_HOUSE = 451;
const int SCENE_RUINED_ARCH = 452;
const int SCENE_SOLID_ARCH = 453;
const int SCENE_BURNED_RUBBLE_2 = 454;
const int SCENE_MARKET_1 = 455;
const int SCENE_MARKET_2 = 456;
const int SCENE_GAZEBO = 457;
const int SCENE_WAGON = 458;
const int SCENE_SEWER_WATER = 461;
const int SCENE_BLACK_TILE = 506;
const int SCENE_PRISON_FLOOR = 511;
const int WELL = 358;
const int NORMAL_ARROW = 357;
const int NORMAL_DART = 359;
//////////////////////////////////////////////////
/* shadguy's spell VFX (visual effects) library */
//////////////////////////////////////////////////
// retextured magic missle effects
//
// Note: in game, these are a bit flakey; the engine tries to apply these as
// an impact VFX right away, even before the MIRV itself lands on target.
//
// I also tried Mirv's with chunk models - using the black skull from the mind
// fear effect. It looked even dumber manifesting at the target before impact.
const int VFX_IMP_MIRV_SILENT = 1000;
const int VFX_IMP_MIRV_DN_YELLOW = 1001;
const int VFX_IMP_MIRV_DN_RED = 1002;
const int VFX_IMP_MIRV_DN_GREEN = 1003;
const int VFX_IMP_MIRV_DN_VIOLET = 1004;
const int VFX_IMP_MIRV_DN_CYAN = 1005;
const int VFX_IMP_MIRV_DN_PURPLE = 1006;
const int VFX_IMP_MIRV_DN_MAGENTA = 1007;
const int VFX_IMP_MIRV_DN_LAWNGREEN = 1008;
const int VFX_IMP_MIRV_DN_ORANGE = 1009;
const int VFX_IMP_MIRV_DN_SPRINGGREEN = 1010;
const int VFX_IMP_MIRV_DN_STEELBLUE = 1011;
const int VFX_IMP_MIRV_DN_ECTO = 1012;
const int VFX_IMP_MIRV_DN_SOUNDFX = 1013;
// recolored AID VFX:
const int VFX_IMP_HOLY_AID_DN_SILENT = 1017;
const int VFX_IMP_HOLY_AID_DN_GREEN = 1018;
const int VFX_IMP_HOLY_AID_DN_CYAN = 1019;
const int VFX_IMP_HOLY_AID_DN_ORANGE = 1020;
const int VFX_IMP_HOLY_AID_DN_RED = 1021;
const int VFX_IMP_HOLY_AID_DN_BLUE = 1022;
const int VFX_IMP_HOLY_AID_DN_PURPLE = 1023;
const int VFX_IMP_HOLY_AID_DN_SOUNDFX = 1024;
//recolored Word of Faith VFX, slightly bastardized; nwmax wouldn't import the higres version, so these are all based on teh low res version
const int VFX_FNF_WORD_DN_SILENT = 1028;
const int VFX_FNF_WORD_DN_GREEN = 1029;
const int VFX_FNF_WORD_DN_CYAN = 1030;
const int VFX_FNF_WORD_DN_BLUE = 1031;
const int VFX_FNF_WORD_DN_PURPLE = 1032;
const int VFX_FNF_WORD_DN_RED = 1033;
const int VFX_FNF_WORD_DN_ORANGE = 1034;
const int VFX_FNF_WORD_DN_SOUNDFX = 1035;
//attempted recolor of Power Word Stun that turned out screwy but useable;
//I'll recommend using them in combo with silent version of stuff like timestop below
const int VFX_FNF_PW_DN_YG = 1039;
const int VFX_FNF_PW_DN_GB = 1040;
const int VFX_FNF_PW_DN_BP = 1041;
const int VFX_FNF_PW_DN_PR = 1042;
const int VFX_FNF_PW_DN_RY = 1043;
const int VFX_FNF_PW_DN_STUN_SOUNDFX = 1044;
const int VFX_FNF_PW_DN_KILL_SOUNDFX = 1045;
// recolored time stop VFX
const int VFX_IMP_TIME_STOP_DN_SOUNDFX = 1049;
const int VFX_IMP_TIME_STOP_DN_RED = 1050;
const int VFX_IMP_TIME_STOP_DN_ORANGE = 1051;
const int VFX_IMP_TIME_STOP_DN_YELLOW = 1052;
const int VFX_IMP_TIME_STOP_DN_GREEN = 1053;
const int VFX_IMP_TIME_STOP_DN_BLUE = 1054;
const int VFX_IMP_TIME_STOP_DN_PURPLE = 1055;
const int VFX_IMP_TIME_STOP_DN_SILENT = 1056;
// recolored blindness and deafness
const int VFX_IMP_BLINDDEAD_DN_RED = 1060;
const int VFX_IMP_BLINDDEAD_DN_YELLOW = 1061;
const int VFX_IMP_BLINDDEAD_DN_GREEN = 1062;
const int VFX_IMP_BLINDDEAD_DN_CYAN = 1063;
const int VFX_IMP_BLINDDEAD_DN_BLUE = 1064;
const int VFX_IMP_BLINDDEAD_DN_PURPLE = 1065;
const int VFX_IMP_BLINDDEAD_DN_SOUNDFX = 1066;
// recolored magic eye VFX
const int VFX_MAGICAL_VISION_DN_GREEN = 1070;
const int VFX_MAGICAL_VISION_DN_RED = 1071;
const int VFX_MAGICAL_VISION_DN_SOUNDFX = 1075;
// recolored healing_s
const int VFX_IMP_HEALING_S_VIO = 1079;
const int VFX_IMP_HEALING_S_MAG = 1080;
const int VFX_IMP_HEALING_S_ORA = 1081;
const int VFX_IMP_HEALING_S_LAW = 1082;
const int VFX_IMP_HEALING_S_SPR = 1083;
const int VFX_IMP_HEALING_S_SILENT = 1094;
const int VFX_IMP_HEALING_S_RED = 1085;
const int VFX_IMP_HEALING_S_SOUNDFX = 1086;
const int VFX_IMP_HEALING_HARM_SOUNDFX = 1087;
// recolored healing_m
const int VFX_IMP_HEALING_M_PUR = 1091;
const int VFX_IMP_HEALING_M_MAG = 1092;
const int VFX_IMP_HEALING_M_YEL = 1093;
const int VFX_IMP_HEALING_M_CYA = 1094;
const int VFX_IMP_HEALING_M_SILENT = 1095;
const int VFX_IMP_HEALING_M_RED = 1096;
const int VFX_IMP_HEALING_M_SOUNDFX = 1097;
// recolored healing_l
const int VFX_IMP_HEALING_L_MAG = 1101;
const int VFX_IMP_HEALING_L_ORA = 1102;
const int VFX_IMP_HEALING_L_LAW = 1103;
const int VFX_IMP_HEALING_L_SPR = 1104;
const int VFX_IMP_HEALING_L_VIO = 1105;
const int VFX_IMP_HEALING_L_RED = 1106;
const int VFX_IMP_HEALING_L_SILENT = 1107;
const int VFX_IMP_HEALING_L_SOUNDFX = 1108;
// recolored healing_G
const int VFX_IMP_HEALING_G_MAG = 1112;
const int VFX_IMP_HEALING_G_LAW = 1113;
const int VFX_IMP_HEALING_G_SPR = 1114;
const int VFX_IMP_HEALING_G_VIO = 1115;
const int VFX_IMP_HEALING_G_RED = 1116;
const int VFX_IMP_HEALING_G_SILENT = 1117;
const int VFX_IMP_HEALING_G_SOUNDFX = 1118;
// recolored healing_X
const int VFX_IMP_HEALING_X_MAG = 1122;
const int VFX_IMP_HEALING_X_ORA = 1123;
const int VFX_IMP_HEALING_X_LAW = 1124;
const int VFX_IMP_HEALING_X_SPR = 1125;
const int VFX_IMP_HEALING_X_VIO = 1126;
const int VFX_IMP_HEALING_X_SILENT = 1127;
const int VFX_IMP_HEALING_X_SOUNDFX = 1128;
// recolored magic impact VFX - these are for use with the recolorded MIRV (magic missile) FX
const int VFX_IMP_MAGCYA = 1132;
const int VFX_IMP_MAGBLU = 1133;
const int VFX_IMP_MAGVIO = 1134;
const int VFX_IMP_MAGPUR = 1135;
const int VFX_IMP_MAGRED = 1136;
const int VFX_IMP_MAGMAG = 1137;
const int VFX_IMP_MAGORA = 1138;
const int VFX_IMP_MAGYEL = 1139;
const int VFX_IMP_MAGLAW = 1140;
const int VFX_IMP_MAGGRN = 1141;
const int VFX_IMP_MAG_SOUNDFX = 1142;
// tornadoheal VFX recolored
const int VFX_IMP_TORNADO_L_SILENT = 990;
const int VFX_IMP_TORNADO_L_MAG = 991;
const int VFX_IMP_TORNADO_L_ORA = 992;
const int VFX_IMP_TORNADO_L_LAW = 993;
const int VFX_IMP_TORNADO_L_SPR = 994;
const int VFX_IMP_TORNADO_L_VIO = 995;
const int VFX_IMP_TORNADO_L_RED = 996;
const int VFX_IMP_TORNADO_L_SOUNDFX = 997;
// recolored flame_M effects
const int VFX_IMP_FLAME_M_SILENT = 1157;
const int VFX_IMP_FLAME_M_CYAN = 1158;
const int VFX_IMP_FLAME_M_GREEN = 1159;
const int VFX_IMP_FLAME_M_MAGENTA = 1160;
const int VFX_IMP_FLAME_M_PURPLE = 1161;
const int VFX_IMP_FLAME_M_SOUNDFX = 1162;
// recolored spell mantle ground VFX. I tried the impact VFX to and didn't get them working yet.
const int VFX_DUR_SPELLTURNING_SILENT = 1166;
const int VFX_DUR_SPELLTURNING_P = 1167;
const int VFX_DUR_SPELLTURNING_R = 1168;
const int VFX_DUR_SPELLTURNING_Y = 1169;
const int VFX_DUR_SPELLTURNING_G = 1170;
const int VFX_DUR_SPELLTURNING_C = 1171;
const int VFX_DUR_SPELLTURNING_O = 1172;
const int VFX_DUR_SPELLTURNING_V = 1173;
const int VFX_DUR_SPELLTURNING_S = 1174;
const int VFX_DUR_SPELLTURNING_M = 1175;
const int VFX_DUR_SPELLTURNING_SOUNDFX = 1176;
// recolored Magic resistence VFX rings
const int VFX_DUR_MAGIC_RESISTANCE_SILENT = 1180;
const int VFX_DUR_MAGIC_RESISTANCE_G = 1181;
const int VFX_DUR_MAGIC_RESISTANCE_B = 1182;
const int VFX_DUR_MAGIC_RESISTANCE_P = 1183;
const int VFX_DUR_MAGIC_RESISTANCE_O = 1184;
const int VFX_DUR_MAGIC_RESISTANCE_Y = 1185;
const int VFX_DUR_MAGIC_RESISTANCE_SOUNDFX = 1186;
// recolored IMP Magic VFX (the impact for "Spell Resistence")
const int VFX_IMP_MAGIC_PROTECTION_SILENT = 1190;
const int VFX_IMP_MAGIC_PROTECTION_G = 1191;
const int VFX_IMP_MAGIC_PROTECTION_B = 1192;
const int VFX_IMP_MAGIC_PROTECTION_P = 1193;
const int VFX_IMP_MAGIC_PROTECTION_O = 1194;
const int VFX_IMP_MAGIC_PROTECTION_Y = 1195;
const int VFX_IMP_MAGIC_PROTECTION_SOUND = 1196;
// recolored holy strike VFX
const int VFX_FNF_STRIKE_HOLY_SILENT = 1200;
const int VFX_FNF_STRIKE_HOLY_G = 1201;
const int VFX_FNF_STRIKE_HOLY_C = 1202;
const int VFX_FNF_STRIKE_HOLY_B = 1203;
const int VFX_FNF_STRIKE_HOLY_P = 1204;
const int VFX_FNF_STRIKE_HOLY_R = 1205;
const int VFX_FNF_STRIKE_HOLY_O = 1206;
const int VFX_FNF_STRIKE_HOLY_SOUNDFX = 1207;
// recolored ability score buff VFX
const int VFX_IMP_IMPROVE_ABILITY_SCORE_SILENT = 1211;
const int VFX_IMP_IMPROVE_ABILITY_SCORE_A = 1212;
const int VFX_IMP_IMPROVE_ABILITY_SCORE_B = 1213;
const int VFX_IMP_IMPROVE_ABILITY_SCORE_C = 1214;
const int VFX_IMP_IMPROVE_ABILITY_SCORE_D = 1215;
const int VFX_IMP_IMPROVE_ABILITY_SCORE_E = 1216;
const int VFX_IMP_IMPROVE_ABILITY_SCORE_SOUNDFX = 1217;
// recolroed "reduce ability score" vfx, with the darkness FX removed
const int VFX_IMP_REDUCE_ABILITY_SCORE_RED = 1221;
const int VFX_IMP_REDUCE_ABILITY_SCORE_YEL = 1222;
const int VFX_IMP_REDUCE_ABILITY_SCORE_ORA = 1223;
const int VFX_IMP_REDUCE_ABILITY_SCORE_GRN = 1224;
const int VFX_IMP_REDUCE_ABILITY_SCORE_CYA = 1225;
const int VFX_IMP_REDUCE_ABILITY_SCORE_BLU = 1226;
const int VFX_IMP_REDUCE_ABILITY_SCORE_PUR = 1227;
const int VFX_IMP_REDUCE_ABILITY_SCORE_SOUNDFX = 1228;
// Nother Set of Shadguy/DN VFX
const int TOF_VFX_ALARM_AUDIBLE = 1229;
const int TOF_VFX_ALARM_MENTAL = 1230;
const int VFX_COM_HIT_NEGATIVE2 = 1231;
const int VFX_COM_HIT_POSITIVE = 1232;
const int VFX_IMP_UNSUMMON_RED = 1233;
const int VFX_IMP_UNSUMMON_YEL = 1234;
const int VFX_FNF_LOS_GREEN_10 = 1235;
const int VFX_FNF_LOS_GREEN_20 = 1236;
const int VFX_FNF_LOS_GREEN_30 = 1237;
const int VFX_FNF_LOS_BLUE_10 = 1238;
const int VFX_FNF_LOS_BLUE_20 = 1239;
const int VFX_FNF_LOS_BLUE_30 = 1240;
const int TOF_VFX_FNF_ALARM_DINGDONG = 1241;
const int VFX_IMP_LONGSTRIDER = 1242;
const int VFX_FNF_RUSTING_GRASP = 1243;
const int VFX_IMP_EXPRETREAT = 1244;
const int VFX_DUR_ROOTED_TO_SPOT = 1245;
const int VFX_IMP_DAWN = 1246;
const int VFX_DUR_MARK_OF_THE_HUNTER = 1247;
const int VFX_DUR_HEARD = 1248;
const int VFX_DUR_SEEN = 1249;
const int VFX_IMP_SOUND_SYMBOL_NEC = 1250;
const int VFX_IMP_SOUND_SYMBOL_EVO = 1251;
const int VFX_IMP_SOUND_SYMBOL_ENC = 1252;
const int VFX_IMP_SOUND_SYMBOL_DEATH = 1253;
const int VFX_IMP_SOUND_SYMBOL_INSANITY = 1254;
const int VFX_IMP_SOUND_SYMBOL_WEAKNESS = 1255;
const int VFX_IMP_SOUND_SYMBOL_STUNNING = 1256;
const int VFX_IMP_SOUND_SYMBOL_FEAR = 1257;
const int VFX_IMP_SOUND_SYMBOL_SLEEP = 1258;
const int VFX_IMP_SOUND_SYMBOL_PAIN = 1259;
const int VFX_FNF_MASS_CURE = 1260;
const int VFX_FNF_MASS_INFLICT = 1261;
const int VFX_IMP_HEALING_X_UNDEAD = 1262;
const int VFX_IMP_BONUS_STRENGTH = 1263;
const int VFX_IMP_BONUS_DEXTERITY = 1264;
const int VFX_IMP_BONUS_CONSTITUTION = 1265;
const int VFX_IMP_BONUS_INTELLIGENCE = 1266;
const int VFX_IMP_BONUS_WISDOM = 1267;
const int VFX_IMP_BONUS_CHARISMA = 1268;
const int VFX_DUR_BRIGHT_LIGHT_WHITE = 1269;
const int VFX_DUR_BRIGHT_LIGHT_RED = 1270;
const int VFX_DUR_BRIGHT_LIGHT_ORANGE = 1271;
const int VFX_DUR_BRIGHT_LIGHT_YELLOW = 1272;
const int VFX_DUR_BRIGHT_LIGHT_GREEN = 1273;
const int VFX_DUR_BRIGHT_LIGHT_BLUE = 1274;
const int VFX_DUR_BRIGHT_LIGHT_MAGENTA = 1275;
const int VFX_DUR_BRIGHT_LIGHT_RED_TO_ORANGE = 1276;
const int VFX_DUR_BRIGHT_LIGHT_ORANGE_TO_YELLOW = 1277;
const int VFX_DUR_BRIGHT_LIGHT_YELLOW_TO_GREEN = 1278;
const int VFX_DUR_BRIGHT_LIGHT_GREEN_TO_BLUE = 1279;
const int VFX_DUR_BRIGHT_LIGHT_BLUE_TO_MAGENTA = 1280;
const int VFX_DUR_BRIGHT_LIGHT_MAGENTA_TO_RED = 1281;
const int VFX_DUR_BRIGHT_LIGHT_CYAN = 1282;
const int VFX_DUR_BRIGHT_LIGHT_WHITE_PULSE_SLOW = 1283;
const int VFX_DUR_BRIGHT_LIGHT_RED_PULSE_SLOW = 1284;
const int VFX_DUR_BRIGHT_LIGHT_ORANGE_PULSE_SLOW = 1285;
const int VFX_DUR_BRIGHT_LIGHT_YELLOW_PULSE_SLOW = 1286;
const int VFX_DUR_BRIGHT_LIGHT_GREEN_PULSE_SLOW = 1287;
const int VFX_DUR_BRIGHT_LIGHT_BLUE_PULSE_SLOW = 1288;
const int VFX_DUR_BRIGHT_LIGHT_INDIGO_PULSE_SLOW = 1289;
const int VFX_DUR_BRIGHT_LIGHT_CYAN_PULSE_SLOW = 1290;
const int VFX_DUR_BRIGHT_LIGHT_WHITE_PULSE_FAST = 1291;
const int VFX_DUR_BRIGHT_LIGHT_RED_PULSE_FAST = 1292;
const int VFX_DUR_BRIGHT_LIGHT_ORANGE_PULSE_FAST = 1293;
const int VFX_DUR_BRIGHT_LIGHT_YELLOW_PULSE_FAST = 1294;
const int VFX_DUR_BRIGHT_LIGHT_GREEN_PULSE_FAST = 1295;
const int VFX_DUR_BRIGHT_LIGHT_BLUE_PULSE_FAST = 1296;
const int VFX_DUR_BRIGHT_LIGHT_INDIGO_PULSE_FAST = 1297;
const int VFX_DUR_BRIGHT_LIGHT_CYAN_PULSE_FAST = 1298;
const int VFX_DUR_BRIGHT_LIGHT_RED_ORANGE_DISCO = 1299;
const int VFX_DUR_BRIGHT_LIGHT_ORANGE_YELLOW_DISCO = 1300;
const int VFX_DUR_BRIGHT_LIGHT_YELLOW_GREEN_DISCO = 1301;
const int VFX_DUR_BRIGHT_LIGHT_GREEN_BLUE_DISCO = 1302;
const int VFX_DUR_BRIGHT_LIGHT_BLUE_MAGENTA_DISCO = 1303;
const int VFX_DUR_BRIGHT_LIGHT_MAGENTA_RED_DISCO = 1304;
const int VFX_DUR_BRIGHT_LIGHT_DISCO_DISCO_DISCO = 1305;
const int VFX_DUR_BRIGHT_LIGHT_WHITE_PULSE_STROBE = 1306;
const int VFX_DUR_BRIGHT_LIGHT_RED_PULSE_STROBE = 1307;
const int VFX_DUR_BRIGHT_LIGHT_ORANGE_PULSE_STROBE = 1308;
const int VFX_DUR_BRIGHT_LIGHT_YELLOW_PULSE_STROBE = 1309;
const int VFX_DUR_BRIGHT_LIGHT_GREEN_PULSE_STROBE = 1310;
const int VFX_DUR_BRIGHT_LIGHT_BLUE_PULSE_STROBE = 1311;
const int VFX_DUR_BRIGHT_LIGHT_INDIGO_PULSE_STROBE = 1312;
const int VFX_DUR_BRIGHT_LIGHT_CYAN_PULSE_STROBE = 1313;
const int VFX_DUR_BRIGHT_LIGHT_BRASS = 1314;
const int VFX_DUR_BRIGHT_LIGHT_GOLD = 1315;
const int VFX_DUR_BRIGHT_LIGHT_LIME = 1316;
const int VFX_DUR_BRIGHT_LIGHT_TURQUOISE = 1317;
const int VFX_DUR_BRIGHT_LIGHT_INDIGO = 1318;
const int VFX_DUR_BRIGHT_LIGHT_VIOLET = 1319;
const int VFX_FNF_LOS_WHITE_10 = 1320;
const int VFX_FNF_LOS_WHITE_20 = 1321;
const int VFX_FNF_LOS_WHITE_30 = 1322;
const int VFX_FNF_LOS_PURPLE_10 = 1323;
const int VFX_FNF_LOS_PURPLE_20 = 1324;
const int VFX_FNF_LOS_PURPLE_30 = 1325;
const int VFX_DUR_BRIGHT_LIGHT_DISCO_SINGLE = 1326;
const int VFX_FNF_LOS_PURPLE_30_SILENT = 1327;
//Baelnorn eyes by Tenjac
const int VFX_DUR_BAELN_EYES = 808;
//Supamans Custom VFX for psionics & epic spells
const int VFX_IMP_EPIC_GEM_EMERALD = 809;
const int VFX_IMP_EPIC_GEM_SAPPHIRE = 810;
const int VFX_IMP_EPIC_GEM_DIAMOND = 811;
const int VFX_PRC_FNF_EARTHQUAKE = 812;
const int PSI_IMP_ULTRABLAST = 813;
const int PSI_DUR_TIMELESS_BODY = 814;
const int PSI_DUR_TEMPORAL_ACCELERATION = 815;
const int PSI_DUR_SHADOW_BODY = 816;
const int PSI_FNF_PSYCHIC_CRUSH = 817;
const int EPIC_DUR_FLEETNESS_OF_FOOT = 818;
const int PSI_DUR_ENERGY_ADAPTATION_ALL = 819;
const int PSI_DUR_BURST = 823;
const int PSI_FNF_CRISIS_OF_LIFE = 824;
const int PSI_FNF_RECALL_AGONY = 825;
const int PSI_DUR_SYNESTHETE = 826;
const int PSI_IMP_CONCUSSION_BLAST = 827;
const int PSI_FNF_PSYCHIC_CHIRURGY = 829;
const int PSI_FNF_ASTRAL_SEED = 830;
const int PSI_DUR_INTELLECT_FORTRESS = 831;
const int PSI_DUR_DISPELLING_BUFFER = 832;
//Spellfire
const int VFX_FNF_SPELLF_EXP = 797;
const int VFX_IMP_SPELLF_FLAME = 798;
const int VFX_IMP_SPELLF_HEAL = 799;
const int VFX_BEAM_SPELLFIRE = 800;
const int VFX_DUR_STONE3 = 834;
const int VFX_DUR_STONE4 = 835;
const int VFX_DUR_STONE5 = 836;
const int VFX_DUR_AIR1 = 837;
const int VFX_DUR_AIR2 = 838;
//split-effects
const int VFX_DUR_PROT_PRC_STONESKIN = 839;
const int VFX_DUR_PROT_PRC_CIRCLEROCK = 840;
const int VFX_DUR_PROT_PRC_SHADOW_ARMOR = 841;
const int VFX_DUR_PROT_PRC_CIRCLESHAD = 842;
//////////////////////////////////////////////////
/* Soopaman's VFX from SMP (Granted to us now) */
//////////////////////////////////////////////////
const int VFX_FNF_TORNADO = 851;
const int VFX_IMP_PWBLIND = 852;
const int VFX_IMP_RED_MISSLE = 853;
const int VFX_IMP_MAGRED_SMP = 854;
const int VFX_IMP_ICEWHIP = 855;
const int VFX_IMP_GRN_MISSLE = 856;
const int VFX_IMP_NEGBLAST_ENERGY = 857;
const int VFX_DUR_PRISMATIC_SPHERE = 858;
const int VFX_FNF_NEWWORD = 859;
const int VFX_DUR_BIGBYS_BIGBLUE_HAND2 = 860;
const int VFX_FNF_AWAKEN = 861;
const int VFX_FNF_CHAOSHAMMER = 862;
const int VFX_FNF_OTIL_COLDSPHERE = 863;
const int VFX_DUR_MAZE = 864;
const int VFX_DUR_CHILL_SHIELD = 865;
const int VFX_FNF_DRAGON_STRIKE = 866;
const int VFX_DUR_SHADOWS_ANTILIGHT = 867;
const int VFX_DUR_PROTECTION_ARROWS = 868;
const int VFX_FNF_HELLFIRE = 869;
const int VFX_FNF_HELLFIRESTORM = 870;
const int VFX_DUR_BLUESHIELDPROTECT = 871;
const int VFX_IMP_REGENERATE_IMPACT = 872;
const int VFX_FNF_BATSGIB = 873;
const int VFX_DUR_STORM_OF_VENGEANCE = 874;
const int VFX_IMP_FREEDOM = 875;
const int VIM_IMP_DIMENSIONDOOR_IN = 876;
const int VIM_IMP_DIMENSIONDOOR_OUT = 877;
const int VFX_DUR_ANTILIFE_SHELL = 878;
const int VFX_DUR_LIGHTNING_SHELL = 879;
const int VFX_IMP_DISENTIGRATION = 880;
const int VFX_IMP_DIMENSIONANCHOR = 881;
const int VFX_IMP_DIMENSIONLOCK = 882;
const int VFX_FNF_GLITTERDUST = 883;
const int VFX_FNF_INSANITY = 884;
const int VFX_IMP_IMPRISONMENT = 885;
const int VFX_DUR_PROTECTION_ENERGY_ACID = 886;
const int VFX_DUR_PROTECTION_ENERGY_COLD = 887;
const int VFX_DUR_PROTECTION_ENERGY_FIRE = 888;
const int VFX_DUR_PROTECTION_ENERGY_ELECT = 889;
const int VFX_DUR_PROTECTION_ENERGY_SONIC = 890;
const int VFX_DUR_PRISMATIC_WALL = 891;
const int VFX_FNF_FEEBLEMIND = 892;
const int VFX_FNF_SUMMON_NATURES_ALLY_1 = 893;
const int VFX_FNF_MAGIC_WEAPON = 894;
const int VFX_FNF_DEATH_WATCH = 895;
const int VFX_IMP_FAERIE_FIRE = 896;
const int VFX_DUR_RESISTANCE = 897;
const int VFX_IMP_EPIC_GEM_EMERALD_SMP = 898;
const int VFX_IMP_EPIC_GEM_SAPPHIRE_SMP = 899;
const int VFX_IMP_EPIC_GEM_DIAMOND_SMP = 900;
const int VFX_PERM_ELEMENTAL_SAVANT_WATER = 901;
const int VFX_PERM_ELEMENTAL_SAVANT_FIRE = 902;
const int VFX_FNF_SOUL_TRAP = 903;
const int VFX_DUR_AURA_LAW = 904;
const int VFX_DUR_SHIELD_OF_FAITH = 905;
const int VFX_FNF_CALM_ANIMALS = 906;
const int VFX_DUR_ENTROPIC_SHIELD = 907;
const int VFX_DUR_FLOATING_DISK = 908;
const int VFX_DUR_OBSCURING_MIST = 909;
const int VFX_IMP_MAGIC_ROCK = 910;
const int VFX_IMP_SHILLELAGH = 911;
const int VFX_FNF_METEORSWARM_IMPACT = 912;
const int VFX_FNF_SMP_GATE = 913;
const int VFX_FNF_ARMAGEDDON = 914;
const int VFX_DUR_SPHERE_OF_ANHILIATION = 915;
const int VFX_DUR_CHAOS_CLOAK = 916;
const int VFX_AOE_DESECRATE_20 = 917;
const int VFX_AOE_DESECRATE_100 = 918;
const int VFX_FNF_INVISIBILITY_SPHERE = 919;
const int VFX_DUR_DAYLIGHT = 920;
const int VFX_DUR_FLAMING_SPHERE = 921;
const int VFX_FNF_VAMPIRIC_DRAIN_PRC = 922;
const int VFX_FNF_BLASPHEMY = 923;
const int VFX_DUR_SHIELD_OF_LAW = 924;
const int VFX_DUR_UNHOLY_AURA_SMP = 925;
const int VFX_DUR_HOLY_AURA_SMP = 926;
const int VFX_DUR_PROT_IRON_SKIN = 927;
const int VFX_FNF_EARTHQUAKE_FISSURE = 928;
const int VFX_FNF_ORDERS_WRATH = 929;
const int VFX_DUR_RAINBOW_PATTERN = 930;
const int VFX_FNF_HOLY_SMITE_BATMAN = 931;
const int VFX_FNF_P2P_TESTER_OF_D3WM = 932;
const int VFX_FNF_PYRO_FIREWORKS_REDORANGE = 933;
const int VFX_DUR_BLOOD_FOUNTAIN = 934;
const int VFX_IMP_DISENTIGRATION_SMP = 935;
const int VFX_IMP_SPARKS = 936;
const int VFX_AOE_FORBIDDANCE = 937;
const int VFX_DUR_CROWN_OF_GLORY = 938;
const int VFX_DUR_ARMOR_OF_DARKNESS = 939;
const int VFX_FNF_MAGIC_VESTAMENT = 940;
const int VFX_DUR_FREEDOM_MOVEMENT = 941;
const int VFX_PRC_FNF_EARTHQUAKE_SMP = 942;
const int VFX_DUR_TEMPORAL_STASIS = 943;
const int VFX_DUR_RESILIENT_SPHERE = 944;
const int VFX_DUR_DEATHWARD = 945;
const int VFX_DUR_PHASE_DOOR = 946;
const int VFX_FNF_SCINTILLATING_PATTERN = 947;
const int VFX_IMP_DRAGONBLAST = 948;
const int VFX_FNF_DEEP_SLUMBER = 949;
const int VFX_AOE_ZONE_OF_TRUTH = 950;
const int VFX_IMP_FAERIE_FIRE_BLUE = 951;
const int VFX_IMP_FAERIE_FIRE_GREEN = 952;
const int VFX_IMP_FAERIE_FIRE_VIOLET = 953;
//Tenser's Floating discs
const int VFX_DUR_FLOATING_DISK_BLUE = 954;
const int VFX_DUR_FLOATING_DISK_GREEN = 955;
const int VFX_DUR_FLOATING_DISK_YELLOW = 956;
const int VFX_DUR_FLOATING_DISK_ORANGE = 957;
const int VFX_DUR_FLOATING_DISK_RED = 958;
const int VFX_DUR_FLOATING_DISK_PURPLE = 959;
const int VFX_DUR_FLOATING_DISK_GREY = 960;
//Recolored Dragon Disciple breath weapon
const int VFX_FNF_DRAGBREATHACID = 961;
const int VFX_FNF_DRAGBREATHCOLD = 962;
const int VFX_FNF_DRAGBREATHELEC = 963;
const int VFX_FNF_DRAGBREATHSONIC = 964;
const int VFX_FNF_DRAGBREATHHOLY = 965;
const int VFX_FNF_DRAGBREATHGAS = 966;
const int VFX_FNF_DRAGBREATHMIND = 967;
const int VFX_FNF_DRAGBREATHODD = 968;
//Consecrate/Desecrate Effects
const int VFX_TN_DES_20 = 801;
const int VFX_TN_DES_100 = 802;
const int VFX_CON_20 = 803;
const int VFX_DES_20 = 804;
//ioun stones
const int VFX_IOUN_STONE_GREY = 969;
const int VFX_IOUN_STONE_ROSE = 970;
const int VFX_IOUN_STONE_CLEAR = 971;
const int VFX_IOUN_STONE_PALEBLUE = 972;
const int VFX_IOUN_STONE_SCARLETBLUE = 973;
const int VFX_IOUN_STONE_INCANBLUE = 974;
const int VFX_IOUN_STONE_RED = 975;
const int VFX_IOUN_STONE_PINK = 976;
const int VFX_IOUN_STONE_PINKGREEN = 977;
const int VFX_IOUN_STONE_BLUE = 978;
const int VFX_IOUN_STONE_PURPLE = 979;
const int VFX_IOUN_STONE_IRIDESCENT = 980;
const int VFX_IOUN_STONE_PALEGREEN = 981;
const int VFX_IOUN_STONE_WHITE = 982;
const int VFX_IOUN_STONE_LAVENDER = 983;
const int VFX_IOUN_STONE_LAVENDERGREEN = 984;
const int VFX_FNF_ACIDSTORM = 1014;
const int VFX_FNF_EXPLOSION_ACID = 821;
const int VFX_FNF_EXPLOSION_COLD = 822;
const int VFX_DUR_SYMB_DEATH = 783;
const int VFX_DUR_SYMB_FEAR = 784;
const int VFX_DUR_SYMB_INSAN = 785;
const int VFX_DUR_SYMB_PAIN = 786;
const int VFX_DUR_SYMB_PERS = 787;
const int VFX_DUR_SYMB_SLEEP = 788;
const int VFX_DUR_SYMB_STUN = 789;
const int VFX_DUR_SYMB_WEAK = 790;
const int VFX_DUR_GLYPH_OF_WARDING_BLUE = 791;
const int VFX_DUR_GLYPH_OF_WARDING_COLD = 792;
const int VFX_DUR_GLYPH_OF_WARDING_RED = 793;
const int VFX_DUR_GLYPH_OF_WARDING_VIOLET = 794;
const int VFX_DUR_GLYPH_OF_WARDING_WHITE = 795;
const int VFX_DUR_GLYPH_OF_WARDING_YELLOW = 796;
const int VFX_DUR_AURA_CHAOS = 752;//violet
const int VFX_DUR_AURA_EVIL = 753;//red
const int VFX_DUR_AURA_GOOD = 754;//yellow
const int VFX_DUR_AURA_LAW2 = 755;//blue
const int VFX_DUR_AURA_UNDEAD = 756;//?
const int VFX_DUR_GR_AURA_CHAOS = 757;
const int VFX_DUR_GR_AURA_EVIL = 758;
const int VFX_DUR_GR_AURA_GOOD = 759;
const int VFX_DUR_GR_AURA_LAW = 760;
const int VFX_DUR_GR_AURA_UNDEAD = 761;
const int VFX_DUR_DETECT = 762;
const int VFX_IMP_DIVINE_STRIKE_ACID = 764;
const int VFX_IMP_DIVINE_STRIKE_COLD = 765;
const int VFX_IMP_DIVINE_STRIKE_SONIC = 766;

View File

@@ -0,0 +1,162 @@
#include "prc_inc_clsfunc"
int GetBlastDamageDices(object oInvoker, int nInvokerLevel)
{
int nDmgDice;
if(nInvokerLevel < 13)
nDmgDice = (nInvokerLevel + 1) / 2;
else if(nInvokerLevel < 20)
nDmgDice = (nInvokerLevel + 7) / 3;
else
nDmgDice = 9 + (nInvokerLevel - 20) / 2;
//check for the epic feats
if(GetHasFeat(FEAT_EPIC_ELDRITCH_BLAST_I, oInvoker))
{
int nFeatAmt = 0;
int bDone = FALSE;
while(!bDone)
{ if(nFeatAmt >= 9)
bDone = TRUE;
else if(GetHasFeat(FEAT_EPIC_ELDRITCH_BLAST_II + nFeatAmt, oInvoker))
nFeatAmt++;
else
bDone = TRUE;
}
nDmgDice += nFeatAmt;
}
return nDmgDice;
}
// Spellblast should use only AoE spells but Dispel Magic can be cast as AoE or single target
// we make sure here that we use AoE version
int CheckSpecialTarget(int nSpellID)
{
return nSpellID == SPELL_DISPEL_MAGIC
|| nSpellID == SPELL_GREATER_DISPELLING
|| nSpellID == SPELL_LESSER_DISPEL
|| nSpellID == SPELL_MORDENKAINENS_DISJUNCTION
|| nSpellID == SPELL_POWER_WORD_KILL;
}
void DoSpellBlast(object oPC, int bHit)
{
int nSpellbookID = GetLocalInt(oPC, "ET_SPELL_CURRENT");
//DoDebug("nSpellbookID = "+IntToString(nSpellbookID));
if(nSpellbookID)
{
object oTarget = GetSpellTargetObject();
if(GetIsObjectValid(oTarget))
{
nSpellbookID--;
DeleteLocalInt(oPC, "ET_SPELL_CURRENT");
int nSpellID = GetLocalInt(oPC, "ET_REAL_SPELL_CURRENT");
//DoDebug("nSpellID = "+IntToString(nSpellID));
string sArray = GetLocalString(oPC, "ET_SPELL_CURRENT");
//DoDebug("sArray = "+sArray);
int nUses = sArray == "" ? GetHasSpell(nSpellbookID, oPC) :
persistant_array_get_int(oPC, sArray, nSpellbookID);
if(nUses)
{
// expend spell use
if(sArray == "")
{
DecrementRemainingSpellUses(oPC, nSpellID);
}
else
{
nUses--;
persistant_array_set_int(oPC, sArray, nSpellbookID, nUses);
}
// use AoE Dispel Magic
int bTargetOverride = CheckSpecialTarget(nSpellID);
if(bHit)
{
int nCastingClass = GetETArcaneClass(oPC);
int nDC = 10 + PRCGetSpellLevelForClass(nSpellID, nCastingClass) + GetDCAbilityModForClass(nCastingClass, oPC);
//clear action queue to apply spell effect right after blast effect
ClearAllActions();
//override PRCDoMeleeTouchAttack() - we already know that blast hit
ActionDoCommand(SetLocalInt(oPC, "AttackHasHit", bHit));
SetLocalInt(oPC, "EldritchSpellBlast", TRUE);
if(DEBUG) DoDebug("inv_inc_blast >> EldritchSpellBlast Set");
ActionCastSpell(nSpellID, 0, nDC, 0, METAMAGIC_NONE, nCastingClass, FALSE, bTargetOverride);
ActionDoCommand(DeleteLocalInt(oPC, "AttackHasHit"));
DelayCommand(0.5, DeleteLocalInt(oPC, "EldritchSpellBlast"));
}
}
}
}
}
void ApplyBlastDamage(object oCaster, object oTarget, int iAttackRoll, int iSR, int iDamage, int iDamageType, int iDamageType2, int nHellFire, int bSneak = TRUE, int nMsg = FALSE)
{
if (DEBUG) DoDebug("ApplyBlastDamage oCaster "+GetName(oCaster)+" oTarget "+GetName(oTarget)+" iAttackRoll "+IntToString(iAttackRoll)+" iSR "+IntToString(iSR)+" iDamage "+IntToString(iDamage)+" iDamageType "+IntToString(iDamageType)+" iDamageType2 "+IntToString(iDamageType2)+" nHellFire "+IntToString(nHellFire)+" bSneak "+IntToString(bSneak)+" nMsg "+IntToString(nMsg));
// Is it a critical hit?
iDamage *= iAttackRoll;
if(iAttackRoll)
{
// Heal the Undead
if (iDamageType == DAMAGE_TYPE_NEGATIVE && (MyPRCGetRacialType(oTarget) == RACIAL_TYPE_UNDEAD || GetLocalInt(oTarget, "AcererakHealing") || (GetHasFeat(FEAT_TOMB_TAINTED_SOUL, oTarget) && GetAlignmentGoodEvil(oTarget) != ALIGNMENT_GOOD)))
{
//Set the heal effect
effect eHeal = EffectHeal(iDamage);
ApplyEffectToObject(DURATION_TYPE_INSTANT, eHeal, oTarget);
}
else // Other targets
{
if(!GetPRCSwitch(PRC_SPELL_SNEAK_DISABLE) && bSneak)
iDamage += SpellSneakAttackDamage(oCaster, oTarget);
effect eDamage;
if(!iSR)
{
if(iDamageType == iDamageType2)
eDamage = EffectDamage(iDamage, iDamageType);
else
{
eDamage = EffectDamage(iDamage / 2, iDamageType);
eDamage = EffectLinkEffects(eDamage, EffectDamage(iDamage / 2, iDamageType2));
}
if(nHellFire)
eDamage = EffectLinkEffects(eDamage, EffectDamage(d6(nHellFire), DAMAGE_TYPE_DIVINE));
}
else if(iDamageType == DAMAGE_TYPE_ACID || iDamageType2 == DAMAGE_TYPE_ACID)
{
if(iDamageType == iDamageType2)
eDamage = EffectDamage(iDamage, iDamageType);
else
eDamage = EffectDamage(iDamage / 2, iDamageType);
}
ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget);
}
}
}
int HellFireConDamage(object oPC)
{
if(GetIsImmune(oPC, IMMUNITY_TYPE_ABILITY_DECREASE))
{
if(DEBUG) DoDebug("HellFireConDamage: Immune to ability damage!");
return FALSE;
}
ApplyAbilityDamage(oPC, ABILITY_CONSTITUTION, 1, DURATION_TYPE_TEMPORARY, TRUE, -1.0);
return TRUE;
}
int GetIsHellFireBlast(object oPC)
{
if(GetLocalInt(oPC, "INV_HELLFIRE"))
{
DeleteLocalInt(oPC, "INV_HELLFIRE");
return TRUE;
}
return FALSE;
}

View File

@@ -0,0 +1,887 @@
//::///////////////////////////////////////////////
//:: Invocation include: Miscellaneous
//:: inv_inc_invfunc
//::///////////////////////////////////////////////
/** @file
Defines various functions and other stuff that
do something related to Invocation implementation.
Also acts as inclusion nexus for the general
invocation includes. In other words, don't include
them directly in your scripts, instead include this.
@author Fox
@date Created - 2008.1.25
Updated for .35 by Jaysyn 2023/03/10
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Constants */
//////////////////////////////////////////////////
const int INVOCATION_DRACONIC = 1;
const int INVOCATION_WARLOCK = 2;
const int INVOCATION_LEAST = 2;
const int INVOCATION_LESSER = 4;
const int INVOCATION_GREATER = 6;
const int INVOCATION_DARK = 8;
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
//:: Updates the Invocation DC for Ability Focus feats.
int InvokerAbilityFocus(object oPC, int nEssence, int nEssence2 = -1);
/**
* Determines from what class's invocation list the currently casted
* invocation is cast from.
*
* @param oInvoker A creature invoking at this moment
* @return CLASS_TYPE_* constant of the class
*/
int GetInvokingClass(object oInvoker = OBJECT_SELF);
/**
* Determines the given creature's Invoker level. If a class is specified,
* then returns the Invoker level for that class. Otherwise, returns
* the Invoker level for the currently active invocation.
*
* @param oInvoker The creature whose Invoker level to determine
* @param nSpecificClass The class to determine the creature's Invoker
* level in.
* @param bPracticedInvoker If this is set, it will add the bunus from
* Practiced Invoker feat.
* @return The Invoker level
*/
int GetInvokerLevel(object oInvoker = OBJECT_SELF, int nSpecificClass = CLASS_TYPE_INVALID, int bPracticedInvoker = TRUE);
/**
* Determines whether a given creature uses Invocations.
* Requires either levels in an invocation-related class or
* natural Invocation ability based on race.
*
* @param oCreature Creature to test
* @return TRUE if the creature can use Invocations, FALSE otherwise.
*/
int GetIsInvocationUser(object oCreature);
/**
* Determines the given creature's highest undmodified Invoker level among it's
* invoking classes.
*
* @param oCreature Creature whose highest Invoker level to determine
* @return The highest unmodified Invoker level the creature can have
*/
int GetHighestInvokerLevel(object oCreature);
/**
* Determines whether a given class is an invocation-related class or not.
*
* @param nClass CLASS_TYPE_* of the class to test
* @return TRUE if the class is an invocation-related class, FALSE otherwise
*/
int GetIsInvocationClass(int nClass);
/**
* Gets the level of the invocation being currently cast.
* WARNING: Return value is not defined when an invocation is not being cast.
*
* @param oInvoker The creature currently casting an invocation
* @return The level of the invocation being cast
*/
int GetInvocationLevel(object oInvoker);
/**
* Returns the name of the invocation
*
* @param nSpellId SpellId of the invocation
*/
string GetInvocationName(int nSpellId);
/**
* Calculates how many invoker levels are gained by a given creature from
* it's levels in prestige classes.
*
* @param oCreature Creature to calculate added invoker levels for
* @return The number of invoker levels gained
*/
int GetInvocationPRCLevels(object oCaster);
/**
* Determines which of the character's classes is their highest or first invocation
* casting class, if any. This is the one which gains invoker level raise benefits
* from prestige classes.
*
* @param oCreature Creature whose classes to test
* @return CLASS_TYPE_* of the first invocation casting class,
* CLASS_TYPE_INVALID if the creature does not possess any.
*/
int GetPrimaryInvocationClass(object oCreature = OBJECT_SELF);
/**
* Determines the position of a creature's first invocation casting class, if any.
*
* @param oCreature Creature whose classes to test
* @return The position of the first invocation class {1, 2, 3} or 0 if
* the creature possesses no levels in invocation classes.
*/
int GetFirstInvocationClassPosition(object oCreature = OBJECT_SELF);
/**
* Ruterns the number of damage dices that oInvokers eldritch blast has
*
* @param oInvoker Creature whose blast to test
* @param nInvokerLevel Invoker level
* @return The number of damage dices
*/
int GetBlastDamageDices(object oInvoker, int nInvokerLevel);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
//#include "prc_alterations"
#include "prc_feat_const"
#include "inv_inc_invknown"
#include "inv_inc_invoke"
#include "inv_inc_blast"
#include "prc_add_spell_dc"
//////////////////////////////////////////////////
/* Internal functions */
//////////////////////////////////////////////////
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
//:: Updates the Invocation DC for Ability Focus feats.
int InvokerAbilityFocus(object oPC, int nEssence, int nEssence2 = -1)
{
int nBonus = 0;
// Check for the shape
switch(nEssence)
{
case INVOKE_ELDRITCH_BLAST:
if (GetHasFeat(FEAT_ABFOC_ELDRITCH_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_ELDRITCH_CHAIN:
if (GetHasFeat(FEAT_ABFOC_ELDRITCH_CHAIN, oPC)) nBonus += 2;
break;
case INVOKE_ELDRITCH_CONE:
if (GetHasFeat(FEAT_ABFOC_ELDRITCH_CONE, oPC)) nBonus += 2;
break;
case INVOKE_ELDRITCH_DOOM:
if (GetHasFeat(FEAT_ABFOC_ELDRITCH_DOOM, oPC)) nBonus += 2;
break;
case INVOKE_ELDRITCH_GLAIVE:
if (GetHasFeat(FEAT_ABFOC_ELDRITCH_GLAIVE, oPC)) nBonus += 2;
break;
case INVOKE_ELDRITCH_LINE:
if (GetHasFeat(FEAT_ABFOC_ELDRITCH_LINE, oPC)) nBonus += 2;
break;
case INVOKE_ELDRITCH_SPEAR:
if (GetHasFeat(FEAT_ABFOC_ELDRITCH_SPEAR, oPC)) nBonus += 2;
break;
case INVOKE_BRIMSTONE_BLAST:
if (GetHasFeat(FEAT_ABFOC_BRIMSTONE_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_NOXIOUS_BLAST:
if (GetHasFeat(FEAT_ABFOC_NOXIOUS_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_FRIGHTFUL_BLAST:
if (GetHasFeat(FEAT_ABFOC_FRIGHTFUL_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_SICKENING_BLAST:
if (GetHasFeat(FEAT_ABFOC_SICKENING_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_HELLRIME_BLAST:
if (GetHasFeat(FEAT_ABFOC_HELLRIME_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_BEWITCHING_BLAST:
if (GetHasFeat(FEAT_ABFOC_BEWITCHING_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_BINDING_BLAST:
if (GetHasFeat(FEAT_ABFOC_BINDING_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_HINDERING_BLAST:
if (GetHasFeat(FEAT_ABFOC_HINDERING_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_PENETRATING_BLAST:
if (GetHasFeat(FEAT_ABFOC_PENETRATING_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_UTTERDARK_BLAST:
if (GetHasFeat(FEAT_ABFOC_UTTERDARK_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_INCARNUM_BLAST:
if (GetHasFeat(FEAT_ABFOC_INCARNUM_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_HAMMER_BLAST:
if (GetHasFeat(FEAT_ABFOC_HAMMER_BLAST, oPC)) nBonus += 2;
break;
// case INVOKE_VITRIOLIC_BLAST:
// if (GetHasFeat(FEAT_ABFOC_VITRIOLIC_BLAST, oPC)) nBonus += 2;
// break;
case INVOKE_BANEFUL_BLAST_ABERRATION:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_ABERRATION, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_BEAST:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_BEAST, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_CONSTRUCT:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_CONSTRUCT, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_DRAGON:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_DRAGON, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_DWARF:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_DWARF, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_ELEMENTAL:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_ELEMENTAL, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_ELF:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_ELF, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_FEY:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_FEY, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_GIANT:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_GIANT, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_GOBLINOID:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_GOBLINOID, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_GNOME:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_GNOME, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_HALFLING:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_HALFLING, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_HUMAN:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_HUMAN, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_MONSTROUS:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_MONSTROUS, oPC)) nBonus += 2;
break;
// case INVOKE_BANEFUL_BLAST_OOZE:
// if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_OOZE, oPC)) nBonus += 2;
// break;
case INVOKE_BANEFUL_BLAST_ORC:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_ORC, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_OUTSIDER:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_OUTSIDER, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_PLANT:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_PLANT, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_REPTILIAN:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_REPTILIAN, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_SHAPECHANGER:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_SHAPECHANGER, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_UNDEAD:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_UNDEAD, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_VERMIN:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_VERMIN, oPC)) nBonus += 2;
break;
}
// Check for the secondary shape or essence component
switch(nEssence2)
{
case INVOKE_ELDRITCH_BLAST:
if (GetHasFeat(FEAT_ABFOC_ELDRITCH_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_ELDRITCH_CHAIN:
if (GetHasFeat(FEAT_ABFOC_ELDRITCH_CHAIN, oPC)) nBonus += 2;
break;
case INVOKE_ELDRITCH_CONE:
if (GetHasFeat(FEAT_ABFOC_ELDRITCH_CONE, oPC)) nBonus += 2;
break;
case INVOKE_ELDRITCH_DOOM:
if (GetHasFeat(FEAT_ABFOC_ELDRITCH_DOOM, oPC)) nBonus += 2;
break;
case INVOKE_ELDRITCH_GLAIVE:
if (GetHasFeat(FEAT_ABFOC_ELDRITCH_GLAIVE, oPC)) nBonus += 2;
break;
case INVOKE_ELDRITCH_LINE:
if (GetHasFeat(FEAT_ABFOC_ELDRITCH_LINE, oPC)) nBonus += 2;
break;
case INVOKE_ELDRITCH_SPEAR:
if (GetHasFeat(FEAT_ABFOC_ELDRITCH_SPEAR, oPC)) nBonus += 2;
break;
case INVOKE_BRIMSTONE_BLAST:
if (GetHasFeat(FEAT_ABFOC_BRIMSTONE_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_NOXIOUS_BLAST:
if (GetHasFeat(FEAT_ABFOC_NOXIOUS_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_FRIGHTFUL_BLAST:
if (GetHasFeat(FEAT_ABFOC_FRIGHTFUL_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_SICKENING_BLAST:
if (GetHasFeat(FEAT_ABFOC_SICKENING_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_HELLRIME_BLAST:
if (GetHasFeat(FEAT_ABFOC_HELLRIME_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_BEWITCHING_BLAST:
if (GetHasFeat(FEAT_ABFOC_BEWITCHING_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_BINDING_BLAST:
if (GetHasFeat(FEAT_ABFOC_BINDING_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_HINDERING_BLAST:
if (GetHasFeat(FEAT_ABFOC_HINDERING_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_PENETRATING_BLAST:
if (GetHasFeat(FEAT_ABFOC_PENETRATING_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_UTTERDARK_BLAST:
if (GetHasFeat(FEAT_ABFOC_UTTERDARK_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_INCARNUM_BLAST:
if (GetHasFeat(FEAT_ABFOC_INCARNUM_BLAST, oPC)) nBonus += 2;
break;
case INVOKE_HAMMER_BLAST:
if (GetHasFeat(FEAT_ABFOC_HAMMER_BLAST, oPC)) nBonus += 2;
break;
// case INVOKE_VITRIOLIC_BLAST:
// if (GetHasFeat(FEAT_ABFOC_VITRIOLIC_BLAST, oPC)) nBonus += 2;
// break;
case INVOKE_BANEFUL_BLAST_ABERRATION:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_ABERRATION, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_BEAST:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_BEAST, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_CONSTRUCT:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_CONSTRUCT, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_DRAGON:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_DRAGON, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_DWARF:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_DWARF, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_ELEMENTAL:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_ELEMENTAL, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_ELF:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_ELF, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_FEY:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_FEY, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_GIANT:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_GIANT, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_GOBLINOID:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_GOBLINOID, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_GNOME:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_GNOME, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_HALFLING:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_HALFLING, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_HUMAN:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_HUMAN, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_MONSTROUS:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_MONSTROUS, oPC)) nBonus += 2;
break;
// case INVOKE_BANEFUL_BLAST_OOZE:
// if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_OOZE, oPC)) nBonus += 2;
// break;
case INVOKE_BANEFUL_BLAST_ORC:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_ORC, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_OUTSIDER:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_OUTSIDER, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_PLANT:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_PLANT, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_REPTILIAN:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_REPTILIAN, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_SHAPECHANGER:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_SHAPECHANGER, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_UNDEAD:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_UNDEAD, oPC)) nBonus += 2;
break;
case INVOKE_BANEFUL_BLAST_VERMIN:
if (GetHasFeat(FEAT_ABFOC_BANEFUL_BLAST_VERMIN, oPC)) nBonus += 2;
break;
}
return nBonus;
}
int GetInvokingClass(object oInvoker = OBJECT_SELF)
{
return GetLocalInt(oInvoker, PRC_INVOKING_CLASS) - 1;
}
/*int PracticedInvoker(object oInvoker, int iInvokingClass, int iInvokingLevels)
{
int nFeat;
int iAdjustment = GetHitDice(oInvoker) - iInvokingLevels;
if(iAdjustment > 4) iAdjustment = 4;
if(iAdjustment < 0) iAdjustment = 0;
switch(iInvokingClass)
{
case CLASS_TYPE_DRAGONFIRE_ADEPT: nFeat = FEAT_PRACTICED_INVOKER_DRAGONFIRE_ADEPT; break;
case CLASS_TYPE_WARLOCK: nFeat = FEAT_PRACTICED_INVOKER_WARLOCK; break;
default: return 0;
}
if(GetHasFeat(nFeat, oInvoker))
return iAdjustment;
return 0;
}*/
int GetInvokerLevel(object oInvoker = OBJECT_SELF, int nSpecificClass = CLASS_TYPE_INVALID, int bPracticedInvoker = TRUE)
{
int nAdjust = GetLocalInt(oInvoker, PRC_CASTERLEVEL_ADJUSTMENT);
int nLevel = GetLocalInt(oInvoker, PRC_CASTERLEVEL_OVERRIDE);
// For when you want to assign the caster level.
if(nLevel)
{
if(DEBUG) SendMessageToPC(oInvoker, "Forced-level Invoking at level " + IntToString(GetCasterLevel(oInvoker)));
//DelayCommand(1.0, DeleteLocalInt(oInvoker, PRC_CASTERLEVEL_OVERRIDE));
return nLevel + nAdjust;
}
if(nSpecificClass == CLASS_TYPE_INVALID)
nSpecificClass = GetInvokingClass(oInvoker);
if(nSpecificClass != -1)
{
if(!GetIsInvocationClass(nSpecificClass))
return 0;
if(nSpecificClass == CLASS_TYPE_DRAGON_SHAMAN)
nLevel = PRCMax(GetLevelByClass(nSpecificClass, oInvoker) - 4, 1); // Can't go below 1
else
nLevel = GetLevelByClass(nSpecificClass, oInvoker);
if(DEBUG) DoDebug("Invoker Class Level is: " + IntToString(nLevel));
if(GetPrimaryInvocationClass(oInvoker) == nSpecificClass)
{
//Invoker level is class level + any arcane spellcasting or invoking levels in any PRCs
nLevel += GetInvocationPRCLevels(oInvoker);
}
/*if(bPracticedInvoker)
nLevel += PracticedInvoker(oInvoker, nSpecificClass, nLevel);*/
}
else
nLevel = GetLevelByClass(GetPrimaryInvocationClass(oInvoker), oInvoker);
nLevel += nAdjust;
SetLocalInt(oInvoker, "InvokerLevel", nLevel);
return nLevel;
}
int GetIsInvocationUser(object oCreature)
{
return !!(GetLevelByClass(CLASS_TYPE_DRAGONFIRE_ADEPT, oCreature) ||
GetLevelByClass(CLASS_TYPE_WARLOCK, oCreature) ||
GetLevelByClass(CLASS_TYPE_DRAGON_SHAMAN, oCreature)
);
}
int GetHighestInvokerLevel(object oCreature)
{
int n = 0;
int nHighest;
int nTemp;
while(n <= 8)
{
if(GetClassByPosition(n, oCreature) != CLASS_TYPE_INVALID)
{
nTemp = GetInvokerLevel(oCreature, GetClassByPosition(n, oCreature));
if(nTemp > nHighest)
nHighest = nTemp;
}
n++;
}
return nHighest;
}
/* int GetHighestInvokerLevel(object oCreature)
{
return PRCMax(PRCMax(GetClassByPosition(1, oCreature) != CLASS_TYPE_INVALID ? GetInvokerLevel(oCreature, GetClassByPosition(1, oCreature)) : 0,
GetClassByPosition(2, oCreature) != CLASS_TYPE_INVALID ? GetInvokerLevel(oCreature, GetClassByPosition(2, oCreature)) : 0
),
GetClassByPosition(3, oCreature) != CLASS_TYPE_INVALID ? GetInvokerLevel(oCreature, GetClassByPosition(3, oCreature)) : 0
);
} */
int GetIsInvocationClass(int nClass)
{
int bTest = nClass == CLASS_TYPE_DRAGONFIRE_ADEPT
|| nClass == CLASS_TYPE_WARLOCK
|| nClass == CLASS_TYPE_DRAGON_SHAMAN;
return bTest;
}
int GetInvocationLevel(object oInvoker)
{
return GetLocalInt(oInvoker, PRC_INVOCATION_LEVEL);
}
string GetInvocationName(int nSpellId)
{
return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellId)));
}
int GetInvocationPRCLevels(object oCaster)
{
int nLevel = GetLevelByClass(CLASS_TYPE_HELLFIRE_WARLOCK, oCaster)
+ GetLevelByClass(CLASS_TYPE_ELDRITCH_DISCIPLE, oCaster)
+ GetLevelByClass(CLASS_TYPE_ELDRITCH_THEURGE, oCaster);
//:: Some Arcane PrCs boost invocations
/* if(GetLocalInt(oCaster, "INV_Caster") == 2)
nLevel += (GetLevelByClass(CLASS_TYPE_ACOLYTE, oCaster) + 1) / 2
+ (GetLevelByClass(CLASS_TYPE_DISCIPLE_OF_ASMODEUS, oCaster) + 1) / 2
+ GetLevelByClass(CLASS_TYPE_ENLIGHTENEDFIST, oCaster)
+ GetLevelByClass(CLASS_TYPE_MAESTER, oCaster)
+ (GetLevelByClass(CLASS_TYPE_TALON_OF_TIAMAT, oCaster) + 1) / 2; */
if(GetLocalInt(oCaster, "INV_Caster") == 2)
{
//:: Abjurant Champion Invoking
if(GetHasFeat(FEAT_ABCHAMP_INVOKING_WARLOCK, oCaster))
nLevel += GetLevelByClass(CLASS_TYPE_ABJURANT_CHAMPION, oCaster);
if(GetHasFeat(FEAT_ABCHAMP_INVOKING_DFA, oCaster))
nLevel += GetLevelByClass(CLASS_TYPE_ABJURANT_CHAMPION, oCaster);
if(GetHasFeat(FEAT_ABCHAMP_INVOKING_DRAGON_SHAMAN, oCaster))
nLevel += GetLevelByClass(CLASS_TYPE_ABJURANT_CHAMPION, oCaster);
//:: Acolyte of the Skin Invoking
if(GetHasFeat(FEAT_AOTS_INVOKING_WARLOCK, oCaster))
nLevel += (GetLevelByClass(CLASS_TYPE_ACOLYTE, oCaster) + 1) / 2;
if(GetHasFeat(FEAT_AOTS_INVOKING_DFA, oCaster))
nLevel += (GetLevelByClass(CLASS_TYPE_ACOLYTE, oCaster) + 1) / 2;
//:: Anima Mage Invoking
if(GetHasFeat(FEAT_ANIMA_INVOKING_WARLOCK, oCaster))
nLevel += GetLevelByClass(CLASS_TYPE_ANIMA_MAGE, oCaster);
if(GetHasFeat(FEAT_ANIMA_INVOKING_DFA, oCaster))
nLevel += GetLevelByClass(CLASS_TYPE_ANIMA_MAGE, oCaster);
//:: Arcane Trickster Invoking
if(GetHasFeat(FEAT_ARCTRICK_INVOKING_WARLOCK, oCaster))
nLevel += GetLevelByClass(CLASS_TYPE_ARCTRICK, oCaster);
if(GetHasFeat(FEAT_ARCTRICK_INVOKING_DFA, oCaster))
nLevel += GetLevelByClass(CLASS_TYPE_ARCTRICK, oCaster);
//:: Disciple of Asmodeus Invoking
if(GetHasFeat(FEAT_ASMODEUS_INVOKING_WARLOCK, oCaster))
nLevel += (GetLevelByClass(CLASS_TYPE_DISCIPLE_OF_ASMODEUS, oCaster) + 1) / 2;
if(GetHasFeat(FEAT_ASMODEUS_INVOKING_DFA, oCaster))
nLevel += (GetLevelByClass(CLASS_TYPE_DISCIPLE_OF_ASMODEUS, oCaster) + 1) / 2;
if(GetHasFeat(FEAT_ASMODEUS_INVOKING_DRAGON_SHAMAN, oCaster))
nLevel += (GetLevelByClass(CLASS_TYPE_DISCIPLE_OF_ASMODEUS, oCaster) + 1) / 2;
//:: Blood Magus Invoking
if(GetHasFeat(FEAT_BLDMAGUS_INVOKING_WARLOCK, oCaster))
nLevel += (GetLevelByClass(CLASS_TYPE_BLOOD_MAGUS, oCaster) + 1) / 2;
if(GetHasFeat(FEAT_BLDMAGUS_INVOKING_DFA, oCaster))
nLevel += (GetLevelByClass(CLASS_TYPE_BLOOD_MAGUS, oCaster) + 1) / 2;
//:: Enlightened Fist Invoking
if(GetHasFeat(FEAT_ENLIGHTENEDFIST_INVOKING_WARLOCK, oCaster))
nLevel += GetLevelByClass(CLASS_TYPE_ENLIGHTENEDFIST, oCaster);
if(GetHasFeat(FEAT_ENLIGHTENEDFIST_INVOKING_DFA, oCaster))
nLevel += GetLevelByClass(CLASS_TYPE_ENLIGHTENEDFIST, oCaster);
if(GetHasFeat(FEAT_ENLIGHTENEDFIST_INVOKING_DRAGON_SHAMAN, oCaster))
nLevel += GetLevelByClass(CLASS_TYPE_ENLIGHTENEDFIST, oCaster);
//:: Maester Invoking
if(GetHasFeat(FEAT_MAESTER_INVOKING_WARLOCK, oCaster))
nLevel += GetLevelByClass(CLASS_TYPE_MAESTER, oCaster);
if(GetHasFeat(FEAT_MAESTER_INVOKING_DFA, oCaster))
nLevel += GetLevelByClass(CLASS_TYPE_MAESTER, oCaster);
//:: Talon of Tiamat Invoking
if(GetHasFeat(FEAT_TIAMAT_INVOKING_WARLOCK, oCaster))
nLevel += (GetLevelByClass(CLASS_TYPE_TALON_OF_TIAMAT, oCaster) + 1) / 2;
if(GetHasFeat(FEAT_TIAMAT_INVOKING_DFA, oCaster))
nLevel += (GetLevelByClass(CLASS_TYPE_TALON_OF_TIAMAT, oCaster) + 1) / 2;
if(GetHasFeat(FEAT_TIAMAT_INVOKING_DRAGON_SHAMAN, oCaster))
nLevel += (GetLevelByClass(CLASS_TYPE_TALON_OF_TIAMAT, oCaster) + 1) / 2;
//:: Unseen Seer Invoking
if(GetHasFeat(FEAT_UNSEEN_INVOKING_WARLOCK, oCaster))
nLevel += GetLevelByClass(CLASS_TYPE_UNSEEN_SEER, oCaster);
if(GetHasFeat(FEAT_UNSEEN_INVOKING_DFA, oCaster))
nLevel += GetLevelByClass(CLASS_TYPE_UNSEEN_SEER, oCaster);
if(GetHasFeat(FEAT_UNSEEN_INVOKING_DRAGON_SHAMAN, oCaster))
nLevel += GetLevelByClass(CLASS_TYPE_UNSEEN_SEER, oCaster);
//:: Virtuoso Invoking
if(GetHasFeat(FEAT_VIRTUOSO_INVOKING_WARLOCK, oCaster))
nLevel += GetLevelByClass(CLASS_TYPE_VIRTUOSO, oCaster);
if(GetHasFeat(FEAT_VIRTUOSO_INVOKING_DFA, oCaster))
nLevel += GetLevelByClass(CLASS_TYPE_VIRTUOSO, oCaster);
if(GetHasFeat(FEAT_VIRTUOSO_INVOKING_DRAGON_SHAMAN, oCaster))
nLevel += GetLevelByClass(CLASS_TYPE_VIRTUOSO, oCaster);
//:: Wild Mage Invoking
if(GetHasFeat(FEAT_WILDMAGE_INVOKING_WARLOCK, oCaster))
{
int nClass = GetLevelByClass(CLASS_TYPE_WILD_MAGE, oCaster);
if (nClass)
nLevel += nClass - 3 + d6();
}
if(GetHasFeat(FEAT_WILDMAGE_INVOKING_DFA, oCaster))
{
int nClass = GetLevelByClass(CLASS_TYPE_WILD_MAGE, oCaster);
if (nClass)
nLevel += nClass - 3 + d6();
}
if(GetHasFeat(FEAT_WILDMAGE_INVOKING_DRAGON_SHAMAN, oCaster))
{
int nClass = GetLevelByClass(CLASS_TYPE_WILD_MAGE, oCaster);
if (nClass)
nLevel += nClass - 3 + d6();
}
}
return nLevel;
}
int GetPrimaryInvocationClass(object oCreature = OBJECT_SELF)
{
int nClass;
if(GetPRCSwitch(PRC_CASTERLEVEL_FIRST_CLASS_RULE))
{
int nInvocationPos = GetFirstInvocationClassPosition(oCreature);
if (!nInvocationPos) return CLASS_TYPE_INVALID; // no invoking class
nClass = GetClassByPosition(nInvocationPos, oCreature);
}
else
{
int nClassLvl;
int nClass1, nClass2, nClass3, nClass4, nClass5, nClass6, nClass7, nClass8;
int nClass1Lvl, nClass2Lvl, nClass3Lvl, nClass4Lvl, nClass5Lvl, nClass6Lvl, nClass7Lvl, nClass8Lvl;
nClass1 = GetClassByPosition(1, oCreature);
nClass2 = GetClassByPosition(2, oCreature);
nClass3 = GetClassByPosition(3, oCreature);
nClass4 = GetClassByPosition(4, oCreature);
nClass5 = GetClassByPosition(5, oCreature);
nClass6 = GetClassByPosition(6, oCreature);
nClass7 = GetClassByPosition(7, oCreature);
nClass8 = GetClassByPosition(8, oCreature);
if(GetIsInvocationClass(nClass1)) nClass1Lvl = GetLevelByClass(nClass1, oCreature);
if(GetIsInvocationClass(nClass2)) nClass2Lvl = GetLevelByClass(nClass2, oCreature);
if(GetIsInvocationClass(nClass3)) nClass3Lvl = GetLevelByClass(nClass3, oCreature);
if(GetIsInvocationClass(nClass4)) nClass4Lvl = GetLevelByClass(nClass4, oCreature);
if(GetIsInvocationClass(nClass5)) nClass5Lvl = GetLevelByClass(nClass5, oCreature);
if(GetIsInvocationClass(nClass6)) nClass6Lvl = GetLevelByClass(nClass6, oCreature);
if(GetIsInvocationClass(nClass7)) nClass7Lvl = GetLevelByClass(nClass7, oCreature);
if(GetIsInvocationClass(nClass8)) nClass8Lvl = GetLevelByClass(nClass8, oCreature);
nClass = nClass1;
nClassLvl = nClass1Lvl;
if(nClass2Lvl > nClassLvl)
{
nClass = nClass2;
nClassLvl = nClass2Lvl;
}
if(nClass3Lvl > nClassLvl)
{
nClass = nClass3;
nClassLvl = nClass3Lvl;
}
if(nClass4Lvl > nClassLvl)
{
nClass = nClass4;
nClassLvl = nClass4Lvl;
}
if(nClass5Lvl > nClassLvl)
{
nClass = nClass5;
nClassLvl = nClass5Lvl;
}
if(nClass6Lvl > nClassLvl)
{
nClass = nClass6;
nClassLvl = nClass6Lvl;
}
if(nClass7Lvl > nClassLvl)
{
nClass = nClass7;
nClassLvl = nClass7Lvl;
}
if(nClass8Lvl > nClassLvl)
{
nClass = nClass8;
nClassLvl = nClass8Lvl;
}
if(nClassLvl == 0)
nClass = CLASS_TYPE_INVALID;
}
return nClass;
}
int GetFirstInvocationClassPosition(object oCreature = OBJECT_SELF)
{
if (GetIsInvocationClass(GetClassByPosition(1, oCreature)))
return 1;
if (GetIsInvocationClass(GetClassByPosition(2, oCreature)))
return 2;
if (GetIsInvocationClass(GetClassByPosition(3, oCreature)))
return 3;
if (GetIsInvocationClass(GetClassByPosition(4, oCreature)))
return 4;
if (GetIsInvocationClass(GetClassByPosition(5, oCreature)))
return 5;
if (GetIsInvocationClass(GetClassByPosition(6, oCreature)))
return 6;
if (GetIsInvocationClass(GetClassByPosition(7, oCreature)))
return 7;
if (GetIsInvocationClass(GetClassByPosition(8, oCreature)))
return 8;
return 0;
}
int GetInvocationSaveDC(object oTarget, object oCaster, int nSpellID = -1)
{
int nDC;
// For when you want to assign the caster DC
//this does not take feat/race/class into account, it is an absolute override
if (GetLocalInt(oCaster, PRC_DC_TOTAL_OVERRIDE) != 0)
{
nDC = GetLocalInt(oCaster, PRC_DC_TOTAL_OVERRIDE);
DoDebug("Forced-DC PRC_DC_TOTAL_OVERRIDE casting at DC " + IntToString(nDC));
return nDC;
}
// For when you want to assign the caster DC
//this does take feat/race/class into account, it only overrides the baseDC
if(GetLocalInt(oCaster, PRC_DC_BASE_OVERRIDE) > 0)
{
nDC = GetLocalInt(oCaster, PRC_DC_BASE_OVERRIDE);
if(DEBUG) DoDebug("Forced Base-DC casting at DC " + IntToString(nDC));
}
else
{
if(nSpellID == -1) nSpellID = PRCGetSpellId();
//10+spelllevel+stat(cha default)
nDC = 10;
nDC += StringToInt(Get2DACache("Spells", "Innate", nSpellID));
nDC += GetAbilityModifier(ABILITY_CHARISMA, oCaster);
}
nDC += GetChangesToSaveDC(oTarget, oCaster, nSpellID, 0);
return nDC;
}
void ClearInvocationLocalVars(object oPC)
{
//Invocations
if (DEBUG) DoDebug("Clearing invocation flags");
DeleteLocalObject(oPC, "ChillingFog");
//Endure Exposure wearing off
array_delete(oPC, "BreathProtected");
DeleteLocalInt(oPC, "DragonWard");
//cleaning targets of Endure exposure cast by resting caster
if (array_exists(oPC, "BreathProtectTargets"))
{
if(DEBUG) DoDebug("Checking for casts of Endure Exposure");
int nBPTIndex = 0;
int bCasterDone = FALSE;
int bTargetDone = FALSE;
object oBreathTarget;
while(!bCasterDone)
{
oBreathTarget = array_get_object(oPC, "BreathProtectTargets", nBPTIndex);
if(DEBUG) DoDebug("Possible target: " + GetName(oBreathTarget) + " - " + ObjectToString(oBreathTarget));
if(oBreathTarget != OBJECT_INVALID)
{
//replace caster with target... always immune to own breath, so good way to erase caster from array without deleting whole array
int nBPIndex = 0;
while(!bTargetDone)
{
if(DEBUG) DoDebug("Checking " + GetName(oBreathTarget));
//if it matches, remove and end
if(array_get_object(oBreathTarget, "BreathProtected", nBPIndex) == oPC)
{
array_set_object(oBreathTarget, "BreathProtected", nBPIndex, oBreathTarget);
bTargetDone = TRUE;
if(DEBUG) DoDebug("Found caster, clearing.");
}
//if it is not end of array, keep going
else if(array_get_object(oBreathTarget, "BreathProtected", nBPTIndex) != OBJECT_INVALID)
{
nBPIndex++;
}
else
bTargetDone = TRUE;
}
nBPTIndex++;
bTargetDone = FALSE;
}
else
{
array_delete(oPC, "BreathProtectTargets");
bCasterDone = TRUE;
}
}
}
}
// Test main
// void main(){}

View File

@@ -0,0 +1,529 @@
//::///////////////////////////////////////////////
//:: Invocation include: Invocations Known
//:: inv_inc_invknown
//::///////////////////////////////////////////////
/** @file
Defines functions for adding & removing
Invocations known.
Data stored:
- For each Class list
-- Total number of Invocations known
-- A modifier value to maximum Invocations known on this list to account for feats and classes that add Invocations
-- An array related to Invocations the knowledge of which is not dependent on character level
--- Each array entry specifies the spells.2da row of the known Invocations's class-specific entry
-- For each character level on which Invocations have been gained from this list
--- An array of Invocations gained on this level
---- Each array entry specifies the spells.2da row of the known Invocations's class-specific entry
@author Fox
@date Created - 2008.01.25
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
// Included here to provide the values for the constants below
#include "prc_class_const"
//////////////////////////////////////////////////
/* Constants */
//////////////////////////////////////////////////
const int INVOCATION_LIST_DRAGONFIRE_ADEPT = CLASS_TYPE_DRAGONFIRE_ADEPT;
const int INVOCATION_LIST_WARLOCK = CLASS_TYPE_WARLOCK;
const int INVOCATION_LIST_DRAGON_SHAMAN = CLASS_TYPE_DRAGON_SHAMAN;
/// Special Maneuver list. Maneuvers gained via Extra Invocation or other sources.
const int INVOCATION_LIST_EXTRA = CLASS_TYPE_INVALID;//-1;
const int INVOCATION_LIST_EXTRA_EPIC = /*CLASS_TYPE_INVALID - 1;*/-2; //needs a constant in there to compile properly
const string _INVOCATION_LIST_NAME_BASE = "PRC_InvocationList_";
const string _INVOCATION_LIST_TOTAL_KNOWN = "_TotalKnown";
const string _INVOCATION_LIST_MODIFIER = "_KnownModifier";
const string _INVOCATION_LIST_EXTRA_ARRAY = "_InvocationsKnownExtraArray";
const string _INVOCATION_LIST_EXTRA_EPIC_ARRAY = "_InvocationsKnownExtraEpicArray";
const string _INVOCATION_LIST_LEVEL_ARRAY = "_InvocationsKnownLevelArray_";
const string _INVOCATION_LIST_GENERAL_ARRAY = "_InvocationsKnownGeneralArray";
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Gives the creature the control feats for the given Invocation and marks the Invocation
* in a Invocations known array.
* If the Invocation's data is already stored in one of the Invocations known arrays for
* the list or adding the Invocation's data to the array fails, the function aborts.
*
* @param oCreature The creature to gain the Invocation
* @param nList The list the Invocation comes from. One of INVOCATION_LIST_*
* @param n2daRow The 2da row in the lists's 2da file that specifies the Invocation.
* @param bLevelDependent If this is TRUE, the Invocation is tied to a certain level and can
* be lost via level loss. If FALSE, the Invocation is not dependent
* of a level and cannot be lost via level loss.
* @param nLevelToTieTo If bLevelDependent is TRUE, this specifies the level the Invocation
* is gained on. Otherwise, it's ignored.
* The default value (-1) means that the current level of oCreature
* will be used.
*
* @return TRUE if the Invocation was successfully stored and control feats added.
* FALSE otherwise.
*/
int AddInvocationKnown(object oCreature, int nList, int n2daRow, int bLevelDependent = FALSE, int nLevelToTieTo = -1);
/**
* Removes all Invocations gained from each list on the given level.
*
* @param oCreature The creature whose Invocations to remove
* @param nLevel The level to clear
*/
void RemoveInvocationsKnownOnLevel(object oCreature, int nLevel);
/**
* Gets the value of the Invocations known modifier, which is a value that is added
* to the 2da-specified maximum Invocations known to determine the actual maximum.
*
* @param oCreature The creature whose modifier to get
* @param nList The list the maximum Invocations known from which the modifier
* modifies. One of INVOCATION_LIST_*
*/
int GetKnownInvocationsModifier(object oCreature, int nList);
/**
* Sets the value of the Invocations known modifier, which is a value that is added
* to the 2da-specified maximum Invocations known to determine the actual maximum.
*
* @param oCreature The creature whose modifier to set
* @param nList The list the maximum Invocations known from which the modifier
* modifies. One of INVOCATION_LIST_*
*/
void SetKnownInvocationsModifier(object oCreature, int nList, int nNewValue);
/**
* Gets the number of Invocations a character character possesses from a
* specific list and lexicon
*
* @param oCreature The creature whose Invocations to check
* @param nList The list to check. One of INVOCATION_LIST_*
* @return The number of Invocations known oCreature has from nList
*/
int GetInvocationCount(object oCreature, int nList);
/**
* Gets the maximum number of Invocations a character may posses from a given list
* at this time. Calculated based on class levels, feats and a misceallenous
* modifier. There are three Types of Invocations, so it checks each seperately.
*
* @param oCreature Character to determine maximum Invocations for
* @param nList INVOCATION_LIST_* of the list to determine maximum Invocations for
* @return Maximum number of Invocations that oCreature may know from the given list.
*/
int GetMaxInvocationCount(object oCreature, int nList);
/**
* Determines whether a character has a given Invocation, gained via some Invocation list.
*
* @param nInvocation INVOKE_* of the Invocation to test
* @param oCreature Character to test for the possession of the Invocation
* @return TRUE if the character has the Invocation, FALSE otherwise
*/
int GetHasInvocation(int nInvocation, object oCreature = OBJECT_SELF);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
#include "inc_item_props"
#include "prc_x2_itemprop"
#include "inc_lookups"
#include "prc_inc_nwscript"
//////////////////////////////////////////////////
/* Internal functions */
//////////////////////////////////////////////////
void _InvocationRecurseRemoveArray(object oCreature, string sArrayName, string sInvocFile, int nArraySize, int nCurIndex)
{
if(DEBUG) DoDebug("_InvocationRecurseRemoveArray():\n"
+ "oCreature = " + DebugObject2Str(oCreature) + "\n"
+ "sArrayName = '" + sArrayName + "'\n"
+ "sInvocFile = '" + sInvocFile + "'\n"
+ "nArraySize = " + IntToString(nArraySize) + "\n"
+ "nCurIndex = " + IntToString(nCurIndex) + "\n"
);
// Determine whether we've already parsed the whole array or not
if(nCurIndex >= nArraySize)
{
if(DEBUG) DoDebug("_InvocationRecurseRemoveArray(): Running itemproperty removal loop.");
// Loop over itemproperties on the skin and remove each match
object oSkin = GetPCSkin(oCreature);
itemproperty ipTest = GetFirstItemProperty(oSkin);
while(GetIsItemPropertyValid(ipTest))
{
// Check if the itemproperty is a bonus feat that has been marked for removal
if(GetItemPropertyType(ipTest) == ITEM_PROPERTY_BONUS_FEAT &&
GetLocalInt(oCreature, "PRC_InvocFeatRemovalMarker_" + IntToString(GetItemPropertySubType(ipTest)))
)
{
if(DEBUG) DoDebug("_InvocationRecurseRemoveArray(): Removing bonus feat itemproperty:\n" + DebugIProp2Str(ipTest));
// If so, remove it
RemoveItemProperty(oSkin, ipTest);
}
ipTest = GetNextItemProperty(oSkin);
}
}
// Still parsing the array
else
{
// Set the marker
string sName = "PRC_InvocFeatRemovalMarker_" + Get2DACache(sInvocFile, "IPFeatID",
GetPowerfileIndexFromSpellID(persistant_array_get_int(oCreature, sArrayName, nCurIndex))
);
if(DEBUG) DoDebug("_InvocationRecurseRemoveArray(): Recursing through array, marker set:\n" + sName);
SetLocalInt(oCreature, sName, TRUE);
// Recurse to next array index
_InvocationRecurseRemoveArray(oCreature, sArrayName, sInvocFile, nArraySize, nCurIndex + 1);
// After returning, delete the local
DeleteLocalInt(oCreature, sName);
}
}
void _RemoveInvocationArray(object oCreature, int nList, int nLevel)
{
if(DEBUG) DoDebug("_RemoveInvocationArray():\n"
+ "oCreature = " + DebugObject2Str(oCreature) + "\n"
+ "nList = " + IntToString(nList) + "\n"
);
string sBase = _INVOCATION_LIST_NAME_BASE + IntToString(nList);
string sArray = sBase + _INVOCATION_LIST_LEVEL_ARRAY + IntToString(nLevel);
int nSize = persistant_array_get_size(oCreature, sArray);
// Reduce the total by the array size
SetPersistantLocalInt(oCreature, sBase + _INVOCATION_LIST_TOTAL_KNOWN,
GetPersistantLocalInt(oCreature, sBase + _INVOCATION_LIST_TOTAL_KNOWN) - nSize
);
// Remove each Invocation in the array
_InvocationRecurseRemoveArray(oCreature, sArray, GetAMSDefinitionFileName(nList), nSize, 0);
// Remove the array itself
persistant_array_delete(oCreature, sArray);
}
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
int AddInvocationKnown(object oCreature, int nList, int n2daRow, int bLevelDependent = FALSE, int nLevelToTieTo = -1)
{
string sBase = _INVOCATION_LIST_NAME_BASE + IntToString(nList);
string sArray = sBase;
string sPowerFile = GetAMSDefinitionFileName(/*PowerListToClassType(*/nList/*)*/);
if(nList == -2 || nList == CLASS_TYPE_INVALID)
{
sPowerFile = GetAMSDefinitionFileName(GetPrimaryInvocationClass(oCreature));
}
string sTestArray;
int i, j, nSize, bReturn;
// Get the spells.2da row corresponding to the cls_psipw_*.2da row
int nSpells2daRow = StringToInt(Get2DACache(sPowerFile, "SpellID", n2daRow));
// Determine the array name.
if(bLevelDependent)
{
// If no level is specified, default to the creature's current level
if(nLevelToTieTo == -1)
nLevelToTieTo = GetHitDice(oCreature);
sArray += _INVOCATION_LIST_LEVEL_ARRAY + IntToString(nLevelToTieTo);
}
else
{
sArray += _INVOCATION_LIST_GENERAL_ARRAY;
}
// Make sure the power isn't already in an array. If it is, abort and return FALSE
// Loop over each level array and check that it isn't there.
if(DEBUG) DoDebug("inv_inc_invknown: Checking first array set for duplicates.");
for(i = 1; i <= GetHitDice(oCreature); i++)
{
sTestArray = sBase + _INVOCATION_LIST_LEVEL_ARRAY + IntToString(i);
if(persistant_array_exists(oCreature, sTestArray))
{
nSize = persistant_array_get_size(oCreature, sTestArray);
for(j = 0; j < nSize; j++)
if(persistant_array_get_int(oCreature, sArray, j) == nSpells2daRow)
return FALSE;
}
}
// Check the non-level-dependent array
if(DEBUG) DoDebug("inv_inc_invknown: Checking second array set for duplicates.");
sTestArray = sBase + _INVOCATION_LIST_GENERAL_ARRAY;
if(persistant_array_exists(oCreature, sTestArray))
{
nSize = persistant_array_get_size(oCreature, sTestArray);
for(j = 0; j < nSize; j++)
if(persistant_array_get_int(oCreature, sArray, j) == nSpells2daRow)
return FALSE;
}
// All checks are made, now start adding the new power
// Create the array if it doesn't exist yet
if(!persistant_array_exists(oCreature, sArray))
persistant_array_create(oCreature, sArray);
// Store the power in the array
if(DEBUG) DoDebug("inv_inc_invknown: Adding to invocation array.");
if(persistant_array_set_int(oCreature, sArray, persistant_array_get_size(oCreature, sArray), nSpells2daRow) != SDL_SUCCESS)
{
if(DEBUG) DoDebug("inv_inc_invknown: AddPowerKnown(): ERROR: Unable to add power to known array\n"
+ "oCreature = " + DebugObject2Str(oCreature) + "\n"
+ "nList = " + IntToString(nList) + "\n"
+ "n2daRow = " + IntToString(n2daRow) + "\n"
+ "bLevelDependent = " + DebugBool2String(bLevelDependent) + "\n"
+ "nLevelToTieTo = " + IntToString(nLevelToTieTo) + "\n"
+ "nSpells2daRow = " + IntToString(nSpells2daRow) + "\n"
);
return FALSE;
}
// Increment Invocations known total
SetPersistantLocalInt(oCreature, sBase + _INVOCATION_LIST_TOTAL_KNOWN,
GetPersistantLocalInt(oCreature, sBase + _INVOCATION_LIST_TOTAL_KNOWN) + 1
);
// Give the power's control feats
object oSkin = GetPCSkin(oCreature);
string sPowerFeatIP = Get2DACache(sPowerFile, "IPFeatID", n2daRow);
itemproperty ipFeat = PRCItemPropertyBonusFeat(StringToInt(sPowerFeatIP));
IPSafeAddItemProperty(oSkin, ipFeat, 0.0f, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
// Second power feat, if any
sPowerFeatIP = Get2DACache(sPowerFile, "IPFeatID2", n2daRow);
if(sPowerFeatIP != "")
{
ipFeat = PRCItemPropertyBonusFeat(StringToInt(sPowerFeatIP));
IPSafeAddItemProperty(oSkin, ipFeat, 0.0f, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
}
return TRUE;
}
void RemoveInvocationsKnownOnLevel(object oCreature, int nLevel)
{
if(DEBUG) DoDebug("inv_inc_invknown: RemoveInvocationKnownOnLevel():\n"
+ "oCreature = " + DebugObject2Str(oCreature) + "\n"
+ "nLevel = " + IntToString(nLevel) + "\n"
);
string sPostFix = _INVOCATION_LIST_LEVEL_ARRAY + IntToString(nLevel);
// For each Invocation list, determine if an array exists for this level.
if(persistant_array_exists(oCreature, _INVOCATION_LIST_NAME_BASE + IntToString(INVOCATION_LIST_DRAGONFIRE_ADEPT) + sPostFix))
// If one does exist, clear it
_RemoveInvocationArray(oCreature, INVOCATION_LIST_DRAGONFIRE_ADEPT, nLevel);
if(persistant_array_exists(oCreature, _INVOCATION_LIST_NAME_BASE + IntToString(INVOCATION_LIST_WARLOCK) + sPostFix))
_RemoveInvocationArray(oCreature, INVOCATION_LIST_WARLOCK, nLevel);
if(persistant_array_exists(oCreature, _INVOCATION_LIST_NAME_BASE + IntToString(INVOCATION_LIST_DRAGON_SHAMAN) + sPostFix))
_RemoveInvocationArray(oCreature, INVOCATION_LIST_DRAGON_SHAMAN, nLevel);
if(persistant_array_exists(oCreature, _INVOCATION_LIST_NAME_BASE + IntToString(INVOCATION_LIST_EXTRA) + sPostFix))
_RemoveInvocationArray(oCreature, INVOCATION_LIST_EXTRA, nLevel);
if(persistant_array_exists(oCreature, _INVOCATION_LIST_NAME_BASE + IntToString(INVOCATION_LIST_EXTRA_EPIC) + sPostFix))
_RemoveInvocationArray(oCreature, INVOCATION_LIST_EXTRA_EPIC, nLevel);
}
int GetKnownInvocationsModifier(object oCreature, int nList)
{
return GetPersistantLocalInt(oCreature, _INVOCATION_LIST_NAME_BASE + IntToString(nList) + _INVOCATION_LIST_MODIFIER);
}
void SetKnownInvocationsModifier(object oCreature, int nList, int nNewValue)
{
SetPersistantLocalInt(oCreature, _INVOCATION_LIST_NAME_BASE + IntToString(nList) + _INVOCATION_LIST_MODIFIER, nNewValue);
}
int GetInvocationCount(object oCreature, int nList)
{
return GetPersistantLocalInt(oCreature, _INVOCATION_LIST_NAME_BASE + IntToString(nList) + _INVOCATION_LIST_TOTAL_KNOWN);
}
int GetMaxInvocationCount(object oCreature, int nList)
{
int nMaxInvocations = 0;
switch(nList)
{
case INVOCATION_LIST_DRAGONFIRE_ADEPT:{
// Determine base Invocations known
int nLevel = GetLevelByClass(CLASS_TYPE_DRAGONFIRE_ADEPT, oCreature);
nLevel += GetPrimaryInvocationClass(oCreature) == CLASS_TYPE_DRAGONFIRE_ADEPT ? GetInvocationPRCLevels(oCreature) : 0;
if(nLevel == 0)
break;
nMaxInvocations = StringToInt(Get2DACache(GetAMSKnownFileName(CLASS_TYPE_DRAGONFIRE_ADEPT), "InvocationKnown", nLevel - 1));
// Calculate feats
// Add in the custom modifier
nMaxInvocations += GetKnownInvocationsModifier(oCreature, nList);
break;
}
case INVOCATION_LIST_WARLOCK:{
// Determine base Invocations known
int nLevel = GetLevelByClass(CLASS_TYPE_WARLOCK, oCreature);
nLevel += GetPrimaryInvocationClass(oCreature) == CLASS_TYPE_WARLOCK ? GetInvocationPRCLevels(oCreature) : 0;
if(nLevel == 0)
break;
nMaxInvocations = StringToInt(Get2DACache(GetAMSKnownFileName(CLASS_TYPE_WARLOCK), "InvocationKnown", nLevel - 1));
// Calculate feats
// Add in the custom modifier
nMaxInvocations += GetKnownInvocationsModifier(oCreature, nList);
break;
}
case INVOCATION_LIST_DRAGON_SHAMAN:{
// Determine base Invocations known
int nLevel = GetLevelByClass(CLASS_TYPE_DRAGON_SHAMAN, oCreature);
nLevel += GetPrimaryInvocationClass(oCreature) == CLASS_TYPE_DRAGON_SHAMAN ? GetInvocationPRCLevels(oCreature) : 0;
if(nLevel == 0)
break;
nMaxInvocations = StringToInt(Get2DACache(GetAMSKnownFileName(CLASS_TYPE_DRAGON_SHAMAN), "InvocationKnown", nLevel - 1));
// Calculate feats
// Add in the custom modifier
nMaxInvocations += GetKnownInvocationsModifier(oCreature, nList);
break;
}
case INVOCATION_LIST_EXTRA:
nMaxInvocations = GetHasFeat(FEAT_EXTRA_INVOCATION_I, oCreature) +
GetHasFeat(FEAT_EXTRA_INVOCATION_II, oCreature) +
GetHasFeat(FEAT_EXTRA_INVOCATION_III, oCreature) +
GetHasFeat(FEAT_EXTRA_INVOCATION_IV, oCreature) +
GetHasFeat(FEAT_EXTRA_INVOCATION_V, oCreature) +
GetHasFeat(FEAT_EXTRA_INVOCATION_VI, oCreature) +
GetHasFeat(FEAT_EXTRA_INVOCATION_VII, oCreature) +
GetHasFeat(FEAT_EXTRA_INVOCATION_VIII, oCreature) +
GetHasFeat(FEAT_EXTRA_INVOCATION_IX, oCreature) +
GetHasFeat(FEAT_EXTRA_INVOCATION_X, oCreature);
break;
case INVOCATION_LIST_EXTRA_EPIC:
nMaxInvocations = GetHasFeat(FEAT_EPIC_EXTRA_INVOCATION_I, oCreature) +
GetHasFeat(FEAT_EPIC_EXTRA_INVOCATION_II, oCreature) +
GetHasFeat(FEAT_EPIC_EXTRA_INVOCATION_III, oCreature) +
GetHasFeat(FEAT_EPIC_EXTRA_INVOCATION_IV, oCreature) +
GetHasFeat(FEAT_EPIC_EXTRA_INVOCATION_V, oCreature) +
GetHasFeat(FEAT_EPIC_EXTRA_INVOCATION_VI, oCreature) +
GetHasFeat(FEAT_EPIC_EXTRA_INVOCATION_VII, oCreature) +
GetHasFeat(FEAT_EPIC_EXTRA_INVOCATION_VIII, oCreature) +
GetHasFeat(FEAT_EPIC_EXTRA_INVOCATION_IX, oCreature) +
GetHasFeat(FEAT_EPIC_EXTRA_INVOCATION_X, oCreature);
break;
default:{
string sErr = "GetMaxInvocationCount(): ERROR: Unknown power list value: " + IntToString(nList);
if(DEBUG) DoDebug(sErr);
else WriteTimestampedLogEntry(sErr);
}
}
return nMaxInvocations;
}
int GetHasInvocation(int nInvocation, object oCreature = OBJECT_SELF)
{
if((GetLevelByClass(CLASS_TYPE_DRAGONFIRE_ADEPT, oCreature)
&& GetHasFeat(GetClassFeatFromPower(nInvocation, CLASS_TYPE_DRAGONFIRE_ADEPT), oCreature)
) ||
(GetLevelByClass(CLASS_TYPE_WARLOCK, oCreature)
&& GetHasFeat(GetClassFeatFromPower(nInvocation, CLASS_TYPE_WARLOCK), oCreature)
) ||
(GetLevelByClass(CLASS_TYPE_DRAGON_SHAMAN, oCreature)
&& GetHasFeat(GetClassFeatFromPower(nInvocation, CLASS_TYPE_DRAGON_SHAMAN), oCreature)
)
// add new Invocation classes here
)
return TRUE;
return FALSE;
}
string DebugListKnownInvocations(object oCreature)
{
string sReturn = "Invocations known by " + DebugObject2Str(oCreature) + ":\n";
int i, j, k, numPowerLists = 6;
int nPowerList, nSize;
string sTemp, sArray, sArrayBase, sPowerFile;
// Loop over all power lists
for(i = 1; i <= numPowerLists; i++)
{
// Some padding
sReturn += " ";
// Get the power list for this loop
switch(i)
{
case 1: nPowerList = INVOCATION_LIST_DRAGONFIRE_ADEPT; sReturn += "Dragonfire Adept"; break;
case 2: nPowerList = INVOCATION_LIST_WARLOCK; sReturn += "Warlock"; break;
case 3: nPowerList = INVOCATION_LIST_DRAGON_SHAMAN; sReturn += "Dragon Shaman"; break;
// This should always be last
case 5: nPowerList = INVOCATION_LIST_EXTRA; sReturn += "Extra"; break;
case 6: nPowerList = INVOCATION_LIST_EXTRA_EPIC; sReturn += "Epic Extra"; break;
}
sReturn += " Invocations known:\n";
// Determine if the character has any Invocations from this list
sPowerFile = GetAMSDefinitionFileName(nPowerList);
sArrayBase = _INVOCATION_LIST_NAME_BASE + IntToString(nPowerList);
// Loop over levels
for(j = 1; j <= GetHitDice(oCreature); j++)
{
sArray = sArrayBase + _INVOCATION_LIST_LEVEL_ARRAY + IntToString(j);
if(persistant_array_exists(oCreature, sArray))
{
sReturn += " Gained on level " + IntToString(j) + ":\n";
nSize = persistant_array_get_size(oCreature, sArray);
for(k = 0; k < nSize; k++)
sReturn += " " + GetStringByStrRef(StringToInt(Get2DACache(sPowerFile, "Name",
GetPowerfileIndexFromSpellID(persistant_array_get_int(oCreature, sArray, k))
)
)
)
+ "\n";
}
}
// Non-leveldependent Invocations
sArray = sArrayBase + _INVOCATION_LIST_GENERAL_ARRAY;
if(persistant_array_exists(oCreature, sArray))
{
sReturn += " Non-leveldependent:\n";
nSize = persistant_array_get_size(oCreature, sArray);
for(k = 0; k < nSize; k++)
sReturn += " " + GetStringByStrRef(StringToInt(Get2DACache(sPowerFile, "Name",
GetPowerfileIndexFromSpellID(persistant_array_get_int(oCreature, sArray, k))
)
)
)
+ "\n";
}
}
return sReturn;
}
// Test main
//void main(){}

View File

@@ -0,0 +1,577 @@
//::///////////////////////////////////////////////
//:: Invocation include: Casting
//:: inv_inc_invoke
//::///////////////////////////////////////////////
/** @file
Defines structures and functions for handling
initiating a invocation
@author Fox
@date Created - 2008.1.26
@thanks to Ornedan for his work on Psionics upon which this is based.
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Constants */
//////////////////////////////////////////////////
const string PRC_INVOKING_CLASS = "PRC_CurrentInvocation_InitiatingClass";
const string PRC_INVOCATION_LEVEL = "PRC_CurrentInvocation_Level";
const string INV_DEBUG_IGNORE_CONSTRAINTS = "INV_DEBUG_IGNORE_CONSTRAINTS";
/**
* The variable in which the invocation token is stored. If no token exists,
* the variable is set to point at the invoker itself. That way OBJECT_INVALID
* means the variable is unitialised.
*/
//const string PRC_INVOCATION_TOKEN_VAR = "PRC_InvocationToken";
//const string PRC_INVOCATION_TOKEN_NAME = "PRC_INVOKETOKEN";
//const float PRC_INVOCATION_HB_DELAY = 0.5f;
//////////////////////////////////////////////////
/* Structures */
//////////////////////////////////////////////////
/**
* A structure that contains common data used during invocation.
*/
struct invocation{
/* Generic stuff */
/// The creature Truespeaking the Invocation
object oInvoker;
/// Whether the invocation is successful or not
int bCanInvoke;
/// The creature's invoker level in regards to this invocation
int nInvokerLevel;
/// The invocation's spell ID
int nInvocationId;
};
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Determines if the invocation that is currently being attempted to be TrueSpoken
* can in fact be truespoken. Determines metainvocations used.
*
* @param oInvoker A creature attempting to truespeak a invocation at this moment.
* @param oTarget The target of the invocation, if any. For pure Area of Effect.
* invocations, this should be OBJECT_INVALID. Otherwise the main
* target of the invocation as returned by PRCGetSpellTargetObject().
*
* @return A invocation structure that contains the data about whether
* the invocation was successfully initiated and some other
* commonly used data, like the PC's invoker level for this invocation.
*/
struct invocation EvaluateInvocation(object oInvoker, object oTarget);
/**
* Causes OBJECT_SELF to use the given invocation.
*
* @param nInvocation The index of the invocation to use in spells.2da or an UTTER_*
* @param nClass The index of the class to use the invocation as in classes.2da or a CLASS_TYPE_*
* @param nLevelOverride An optional override to normal invoker level.
* @param bInstant If true invocation will be used without casting animations (eldritch sculptor)
* Default: 0, which means the parameter is ignored.
*/
void UseInvocation(int nInvocation, int nClass, int nLevelOverride = 0, int bInstant = FALSE);
/**
* A debugging function. Takes a invocation structure and
* makes a string describing the contents.
*
* @param move A set of invocation data
* @return A string describing the contents of move
*/
string DebugInvocation2Str(struct invocation invoked);
/**
* Stores a invocation structure as a set of local variables. If
* a structure was already stored with the same name on the same object,
* it is overwritten.
*
* @param oObject The object on which to store the structure
* @param sName The name under which to store the structure
* @param move The invocation structure to store
*/
void SetLocalInvocation(object oObject, string sName, struct invocation invoked);
/**
* Retrieves a previously stored invocation structure. If no structure is stored
* by the given name, the structure returned is empty.
*
* @param oObject The object from which to retrieve the structure
* @param sName The name under which the structure is stored
* @return The structure built from local variables stored on oObject under sName
*/
struct invocation GetLocalInvocation(object oObject, string sName);
/**
* Deletes a stored invocation structure.
*
* @param oObject The object on which the structure is stored
* @param sName The name under which the structure is stored
*/
void DeleteLocalInvocation(object oObject, string sName);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
//#include "inv_inc_invfunc" //Access in parent
#include "prc_spellf_inc"
//////////////////////////////////////////////////
/* Internal functions */
//////////////////////////////////////////////////
/** Internal function.
* Handles Spellfire absorption when a utterance is used on a friendly spellfire
* user.
*/
struct invocation _DoInvocationSpellfireFriendlyAbsorption(struct invocation invoked, object oTarget)
{
if(GetLocalInt(oTarget, "SpellfireAbsorbFriendly") &&
GetIsFriend(oTarget, invoked.oInvoker)
)
{
if(CheckSpellfire(invoked.oInvoker, oTarget, TRUE))
{
PRCShowSpellResist(invoked.oInvoker, oTarget, SPELL_RESIST_MANTLE);
invoked.bCanInvoke = FALSE;
}
}
return invoked;
}
/** Internal function.
* Sets invocation-related local variables.
*
* @param oInvoker The creature currently casting invocation
* @param nClass Invocation casting class constant
* @param nLevel Invocation level
*/
void _SetInvocationVariables(object oInvoker, int nClass, int nLevel)
{
if (DEBUG) FloatingTextStringOnCreature(GetName(oInvoker)+" is a "+IntToString(nClass)+" at "+IntToString(nLevel)+" invocation level", oInvoker);
SetLocalInt(oInvoker, PRC_INVOKING_CLASS, nClass + 1);
SetLocalInt(oInvoker, PRC_INVOCATION_LEVEL, nLevel);
}
/** Internal function.
* Deletes invocation-related local variables.
*
* @param oInvoker The creature currently initiating a invocation
*/
void _CleanInvocationVariables(object oInvoker)
{
DeleteLocalInt(oInvoker, PRC_INVOKING_CLASS);
DeleteLocalInt(oInvoker, PRC_INVOCATION_LEVEL);
}
/** Internal function.
* Determines whether a invocation token exists. If one does, returns it.
*
* @param oInvoker A creature whose invocation token to get
* @return The invocation token if it exists, OBJECT_INVALID otherwise.
*/
/*object _GetInvocationToken(object oInvoker)
{
object oInvokeToken = GetLocalObject(oInvoker, PRC_INVOCATION_TOKEN_VAR);
// If the token object is no longer valid, set the variable to point at invoker
if(!GetIsObjectValid(oInvokeToken))
{
oInvokeToken = oInvoker;
SetLocalObject(oInvoker, PRC_INVOCATION_TOKEN_VAR, oInvokeToken);
}
// Check if there is no token
if(oInvokeToken == oInvoker)
oInvokeToken = OBJECT_INVALID;
return oInvokeToken;
}*/
/** Internal function.
* Destroys the given invocation token and sets the creature's invocation token variable
* to point at itself.
*
* @param oInvoker The invoker whose token to destroy
* @param oInvokeToken The token to destroy
*/
/*void _DestroyInvocationToken(object oInvoker, object oInvokeToken)
{
DestroyObject(oInvokeToken);
SetLocalObject(oInvoker, PRC_INVOCATION_TOKEN_VAR, oInvoker);
}*/
/** Internal function.
* Destroys the previous invocation token, if any, and creates a new one.
*
* @param oInvoker A creature for whom to create a invocation token
* @return The newly created token
*/
/*object _CreateInvocationToken(object oInvoker)
{
object oInvokeToken = _GetInvocationToken(oInvoker);
object oStore = GetObjectByTag("PRC_MANIFTOKEN_STORE"); //GetPCSkin(oInvoker);
// Delete any previous tokens
if(GetIsObjectValid(oInvokeToken))
_DestroyInvocationToken(oInvoker, oInvokeToken);
// Create new token and store a reference to it
oInvokeToken = CreateItemOnObject(PRC_INVOCATION_TOKEN_NAME, oStore);
SetLocalObject(oInvoker, PRC_INVOCATION_TOKEN_VAR, oInvokeToken);
Assert(GetIsObjectValid(oInvokeToken), "GetIsObjectValid(oInvokeToken)", "ERROR: Unable to create invocation token! Store object: " + DebugObject2Str(oStore), "inv_inc_invoke", "_CreateInvocationToken()");
return oInvokeToken;
}*/
/** Internal function.
* Determines whether the given invoker is doing something that would
* interrupt initiating a invocation or affected by an effect that would do
* the same.
*
* @param oInvoker A creature on which _InvocationHB() is running
* @return TRUE if the creature can continue initiating,
* FALSE otherwise
*/
/*int _InvocationStateCheck(object oInvoker)
{
int nAction = GetCurrentAction(oInvoker);
// If the current action is not among those that could either be used to truespeak the invocation or movement, the invocation fails
if(!(nAction || ACTION_CASTSPELL || nAction == ACTION_INVALID ||
nAction || ACTION_ITEMCASTSPELL || nAction == ACTION_MOVETOPOINT ||
nAction || ACTION_USEOBJECT || nAction == ACTION_WAIT
) )
return FALSE;
// Affected by something that prevents one from initiating
effect eTest = GetFirstEffect(oInvoker);
int nEType;
while(GetIsEffectValid(eTest))
{
nEType = GetEffectType(eTest);
if(nEType == EFFECT_TYPE_CUTSCENE_PARALYZE ||
nEType == EFFECT_TYPE_DAZED ||
nEType == EFFECT_TYPE_PARALYZE ||
nEType == EFFECT_TYPE_PETRIFY ||
nEType == EFFECT_TYPE_SLEEP ||
nEType == EFFECT_TYPE_STUNNED
)
return FALSE;
// Get next effect
eTest = GetNextEffect(oInvoker);
}
return TRUE;
}*/
/** Internal function.
* Runs while the given creature is initiating. If they move, take other actions
* that would cause them to interrupt initiating the invocation or are affected by an
* effect that would cause such interruption, deletes the invocation token.
* Stops if such condition occurs or something else destroys the token.
*
* @param oInvoker A creature initiating a invocation
* @param lInvoker The location where the invoker was when starting the invocation
* @param oInvokeToken The invocation token that controls the ongoing invocation
*/
/*void _InvocationHB(object oInvoker, location lInvoker, object oInvokeToken)
{
if(DEBUG) DoDebug("_InvocationHB() running:\n"
+ "oInvoker = " + DebugObject2Str(oInvoker) + "\n"
+ "lInvoker = " + DebugLocation2Str(lInvoker) + "\n"
+ "oInvokeToken = " + DebugObject2Str(oInvokeToken) + "\n"
+ "Distance between invocation start location and current location: " + FloatToString(GetDistanceBetweenLocations(lInvoker, GetLocation(oInvoker))) + "\n"
);
if(GetIsObjectValid(oInvokeToken))
{
// Continuance check
if(GetDistanceBetweenLocations(lInvoker, GetLocation(oInvoker)) > 2.0f || // Allow some variance in the location to account for dodging and random fidgeting
!_InvocationStateCheck(oInvoker) // Action and effect check
)
{
if(DEBUG) DoDebug("_InvocationHB(): invoker moved or lost concentration, destroying token");
_DestroyInvocationToken(oInvoker, oInvokeToken);
// Inform invoker
FloatingTextStrRefOnCreature(16832980, oInvoker, FALSE); // "You have lost concentration on the invocation you were attempting to cast!"
}
// Schedule next HB
else
DelayCommand(PRC_INVOCATION_HB_DELAY, _InvocationHB(oInvoker, lInvoker, oInvokeToken));
}
}*/
/** Internal function.
* Checks if the invoker is in range to use the invocation they are trying to use.
* If not, queues commands to make the invoker to run into range.
*
* @param oInvoker A creature initiating a invocation
* @param nInvocation SpellID of the invocation being initiated
* @param lTarget The target location or the location of the target object
*/
/*void _InvocationRangeCheck(object oInvoker, int nInvocation, location lTarget)
{
float fDistance = GetDistanceBetweenLocations(GetLocation(oInvoker), lTarget);
float fRangeLimit;
string sRange = Get2DACache("spells", "Range", nInvocation);
// Personal range invocations are always in range
if(sRange == "P")
return;
// Ranges according to the CCG spells.2da page
else if(sRange == "T")
fRangeLimit = 2.25f;
else if(sRange == "S")
fRangeLimit = 8.0f;
else if(sRange == "M")
fRangeLimit = 20.0f;
else if(sRange == "L")
fRangeLimit = 40.0f;
// See if we are out of range
if(fDistance > fRangeLimit)
{
// Create waypoint for the movement
object oWP = CreateObject(OBJECT_TYPE_WAYPOINT, "nw_waypoint001", lTarget);
// Move into range, with a bit of fudge-factor
//ActionMoveToObject(oWP, TRUE, fRangeLimit - 0.15f);
// CleanUp
ActionDoCommand(DestroyObject(oWP));
// CleanUp, paranoia
AssignCommand(oWP, ActionDoCommand(DestroyObject(oWP, 60.0f)));
}
}*/
/** Internal function.
* Assigns the fakecast command that is used to display the conjuration VFX when using an invocation.
* Separated from UseInvocation() due to a bug with ActionFakeCastSpellAtObject(), which requires
* use of ClearAllActions() to work around.
* The problem is that if the target is an item on the ground, if the actor is out of spell
* range when doing the fakecast, they will run on top of the item instead of to the edge of
* the spell range. This only happens if there was a "real action" in the actor's action queue
* immediately prior to the fakecast.
*/
/*void _AssignUseInvocationFakeCastCommands(object oInvoker, object oTarget, location lTarget, int nSpellID)
{
// Nuke actions to prevent the fakecast action from bugging
ClearAllActions();
if(GetIsObjectValid(oTarget))
ActionCastFakeSpellAtObject(nSpellID, oTarget, PROJECTILE_PATH_TYPE_DEFAULT);
else
ActionCastFakeSpellAtLocation(nSpellID, lTarget, PROJECTILE_PATH_TYPE_DEFAULT);
}*/
/** Internal function.
* Places the cheatcasting of the real invocation into the invoker's action queue.
*/
/*void _UseInvocationAux(object oInvoker, object oInvokeToken, int nSpellId,
object oTarget, location lTarget,
int nInvocation, int nClass, int nLevelOverride)
{
if(DEBUG) DoDebug("_UseInvocationAux() running:\n"
+ "oInvoker = " + DebugObject2Str(oInvoker) + "\n"
+ "oInvokeToken = " + DebugObject2Str(oInvokeToken) + "\n"
+ "nSpellId = " + IntToString(nSpellId) + "\n"
+ "oTarget = " + DebugObject2Str(oTarget) + "\n"
+ "lTarget = " + DebugLocation2Str(lTarget) + "\n"
+ "nInvocation = " + IntToString(nInvocation) + "\n"
+ "nClass = " + IntToString(nClass) + "\n"
+ "nLevelOverride = " + IntToString(nLevelOverride) + "\n"
);
// Make sure nothing has interrupted this invocation
if(GetIsObjectValid(oInvokeToken))
{
if(DEBUG) DoDebug("_UseInvocationAux(): Token was valid, queueing actual invocation");
// Set the class to cast as
SetLocalInt(oInvoker, PRC_INVOKING_CLASS, nClass + 1);
// Set the invocation's level
SetLocalInt(oInvoker, PRC_INVOCATION_LEVEL, StringToInt(lookup_spell_innate(nSpellId)));
if(nLevelOverride != 0)
AssignCommand(oInvoker, ActionDoCommand(SetLocalInt(oInvoker, PRC_CASTERLEVEL_OVERRIDE, nLevelOverride)));
if(GetIsObjectValid(oTarget))
AssignCommand(oInvoker, ActionCastSpellAtObject(nInvocation, oTarget, METAMAGIC_NONE, TRUE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE));
else
AssignCommand(oInvoker, ActionCastSpellAtLocation(nInvocation, lTarget, METAMAGIC_NONE, TRUE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE));
if(nLevelOverride != 0)
AssignCommand(oInvoker, ActionDoCommand(DeleteLocalInt(oInvoker, PRC_CASTERLEVEL_OVERRIDE)));
// Destroy the invocation token for this invocation
_DestroyInvocationToken(oInvoker, oInvokeToken);
}
}*/
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
struct invocation EvaluateInvocation(object oInvoker, object oTarget)
{
/* Get some data */
int bIgnoreConstraints = (DEBUG) ? GetLocalInt(oInvoker, INV_DEBUG_IGNORE_CONSTRAINTS) : FALSE;
// invoker-related stuff
int nInvokerLevel = GetInvokerLevel(oInvoker);
int nInvocationLevel = GetInvocationLevel(oInvoker);
int nClass = GetInvokingClass(oInvoker);
/* Initialise the invocation structure */
struct invocation invoked;
invoked.oInvoker = oInvoker;
invoked.bCanInvoke = TRUE; // Assume successfull invocation by default
invoked.nInvokerLevel = nInvokerLevel;
invoked.nInvocationId = PRCGetSpellId();
if (DEBUG) FloatingTextStringOnCreature(GetName(oInvoker)+" is a "+IntToString(nClass)+" casting invocation "+IntToString(invoked.nInvocationId)+", a "+IntToString(nInvocationLevel)+" level invocation, at "+IntToString(nInvokerLevel)+" invoker level", oInvoker);
// Skip doing anything if something has prevented a successful invocation already by this point
//if(invoked.bCanInvoke)
//{
invoked = _DoInvocationSpellfireFriendlyAbsorption(invoked, oTarget);
//}//end if
if(DEBUG) DoDebug("EvaluateInvocation(): Final result:\n" + DebugInvocation2Str(invoked));
// Initiate invocation-related variable CleanUp
//DelayCommand(0.5f, _CleanInvocationVariables(oInvoker));
return invoked;
}
void UseInvocation(int nInvocation, int nClass, int nLevelOverride = 0, int bInstant = FALSE)
{
if(nClass < 0)
nClass = CLASS_TYPE_WARLOCK;
object oInvoker = OBJECT_SELF;
// object oSkin = GetPCSkin(oInvoker);
// object oTarget = PRCGetSpellTargetObject();
// object oInvokeToken;
// location lTarget = PRCGetSpellTargetLocation();
// int nSpellID = PRCGetSpellId();
//int nInvocationDur = StringToInt(Get2DACache("spells", "ConjTime", nInvocation)) + StringToInt(Get2DACache("spells", "CastTime", nInvocation));
// This is a test case to speed up the impact of the melee attacks, as PerformAttackRound takes the full 6 second.
// int nInvocationDur = 0;
// Setup invocation-related variables
ActionDoCommand(_SetInvocationVariables(oInvoker, nClass, StringToInt(lookup_spell_innate(nInvocation))));
// Cast the actual invocation
ActionCastSpell(nInvocation, nLevelOverride, 0, 0, METAMAGIC_NONE, CLASS_TYPE_INVALID, 0, 0, OBJECT_INVALID, bInstant);
// Initiate invocation-related variable CleanUp
ActionDoCommand(_CleanInvocationVariables(oInvoker));
// Normally swift action invocations check
/*if(Get2DACache("feat", "Constant", GetClassFeatFromPower(nInvocation, nClass)) == "SWIFT_ACTION" && // The invocation is swift action to use
TakeSwiftAction(oInvoker) // And the invoker can take a swift action now
)
{
nInvocationDur = 0;
}*/
/*if(DEBUG) DoDebug("UseInvocation(): invoker is " + DebugObject2Str(oInvoker) + "\n"
+ "nInvocation = " + IntToString(nInvocation) + "\n"
+ "nClass = " + IntToString(nClass) + "\n"
+ "nLevelOverride = " + IntToString(nLevelOverride) + "\n"
+ "invocation duration = " + IntToString(nInvocationDur) + "ms \n"
//+ "Token exists = " + DebugBool2String(GetIsObjectValid(oInvokeToken))
);*/
// Create the invocation token. Deletes any old tokens and cancels corresponding invocations as a side effect
//oInvokeToken = _CreateInvocationToken(oInvoker);
/// @todo Hook to the invoker's OnDamaged event for the concentration checks to avoid losing the invocation
// Nuke action queue to prevent cheating with creative invocation stacking.
// Probably not necessary anymore - Ornedan
//if(DEBUG) SendMessageToPC(oInvoker, "Clearing all actions in preparation for second stage of the invocation.");
//ClearAllActions();
// If out of range, move to range
//_InvocationRangeCheck(oInvoker, nInvocation, GetIsObjectValid(oTarget) ? GetLocation(oTarget) : lTarget);
// Start the invocation monitor HB
//DelayCommand(IntToFloat(nInvocationDur), ActionDoCommand(_InvocationHB(oInvoker, GetLocation(oInvoker), oInvokeToken)));
// Assuming the spell isn't used as a swift action, fakecast for visuals
/*if(nInvocationDur > 0)
{
// Hack. Workaround of a bug with the fakecast actions. See function comment for details
ActionDoCommand(_AssignUseInvocationFakeCastCommands(oInvoker, oTarget, lTarget, nSpellID));
}*/
// Action queue the function that will cheatcast the actual invocation
//DelayCommand(IntToFloat(nInvocationDur), AssignCommand(oInvoker, ActionDoCommand(_UseInvocationAux(oInvoker, oInvokeToken, nSpellID, oTarget, lTarget, nInvocation, nClass, nLevelOverride))));
}
string DebugInvocation2Str(struct invocation invoked)
{
string sRet;
sRet += "oInvoker = " + DebugObject2Str(invoked.oInvoker) + "\n";
sRet += "bCanInvoke = " + DebugBool2String(invoked.bCanInvoke) + "\n";
sRet += "nInvokerLevel = " + IntToString(invoked.nInvokerLevel);
return sRet;
}
void SetLocalInvocation(object oObject, string sName, struct invocation invoked)
{
//SetLocal (oObject, sName + "_", );
SetLocalObject(oObject, sName + "_oInvoker", invoked.oInvoker);
SetLocalInt(oObject, sName + "_bCanInvoke", invoked.bCanInvoke);
SetLocalInt(oObject, sName + "_nInvokerLevel", invoked.nInvokerLevel);
SetLocalInt(oObject, sName + "_nSpellID", invoked.nInvocationId);
}
struct invocation GetLocalInvocation(object oObject, string sName)
{
struct invocation invoked;
invoked.oInvoker = GetLocalObject(oObject, sName + "_oInvoker");
invoked.bCanInvoke = GetLocalInt(oObject, sName + "_bCanInvoke");
invoked.nInvokerLevel = GetLocalInt(oObject, sName + "_nInvokerLevel");
invoked.nInvocationId = GetLocalInt(oObject, sName + "_nSpellID");
return invoked;
}
void DeleteLocalInvocation(object oObject, string sName)
{
DeleteLocalObject(oObject, sName + "_oInvoker");
DeleteLocalInt(oObject, sName + "_bCanInvoke");
DeleteLocalInt(oObject, sName + "_nInvokerLevel");
DeleteLocalInt(oObject, sName + "_nSpellID");
}
void InvocationDebugIgnoreConstraints(object oInvoker)
{
SetLocalInt(oInvoker, INV_DEBUG_IGNORE_CONSTRAINTS, TRUE);
DelayCommand(0.0f, DeleteLocalInt(oInvoker, INV_DEBUG_IGNORE_CONSTRAINTS));
}
// Test main
//void main(){}

View File

@@ -0,0 +1,258 @@
// Real Invocation SpellId Constants
/*
*/
// Least Draconic Invocations
const int INVOKE_BEGUILING_INFLUENCE = 18001;
const int INVOKE_BREATH_OF_THE_NIGHT = 18002;
const int INVOKE_DARKNESS = 18003;
const int INVOKE_DEAFENING_ROAR = 18004;
const int INVOKE_DRACONIC_KNOWLEDGE = 18005;
const int INVOKE_ENDURE_EXPOSURE = 18006;
const int INVOKE_MAGIC_INSIGHT = 18007;
const int INVOKE_SCALDING_GUST = 18008;
const int INVOKE_SEE_THE_UNSEEN = 18009;
// Lesser Draconic Invocations
const int INVOKE_CHARM = 18010;
const int INVOKE_ENERGY_RESISTANCE = 18011;
const int INVOKE_ENERGY_RESISTANCE_ACID = 18012;
const int INVOKE_ENERGY_RESISTANCE_COLD = 18013;
const int INVOKE_ENERGY_RESISTANCE_ELEC = 18014;
const int INVOKE_ENERGY_RESISTANCE_FIRE = 18015;
const int INVOKE_ENERGY_RESISTANCE_SONIC = 18016;
const int INVOKE_FRIGHTFUL_PRESENCE = 18017;
const int INVOKE_HUMANOID_SHAPE = 18018;
const int INVOKE_HUMANOID_SHAPE_LEARN = 18019;
const int INVOKE_HUMANOID_SHAPE_OPTION = 18020;
const int INVOKE_HUMANOID_SHAPE_TRUE = 18021;
const int INVOKE_HUMANOID_SHAPE_QS1 = 18022;
const int INVOKE_HUMANOID_SHAPE_QS2 = 18023;
const int INVOKE_VOIDSENSE = 18024;
const int INVOKE_VORACIOUS_DISPELLING = 18025;
const int INVOKE_WALK_UNSEEN = 18026;
// Greater Draconic Invocations
const int INVOKE_AURA_OF_FLAME = 18027;
const int INVOKE_CHILLING_FOG = 18028;
const int INVOKE_DEVOUR_MAGIC = 18029;
const int INVOKE_DRACONIC_TOUGHNESS = 18030;
const int INVOKE_TERRIFYING_ROAR = 18031;
// Dark Draconic Invocations
const int INVOKE_ENERGY_IMMUNITY = 18032;
const int INVOKE_ENERGY_IMMUNITY_ACID = 18033;
const int INVOKE_ENERGY_IMMUNITY_COLD = 18034;
const int INVOKE_ENERGY_IMMUNITY_ELEC = 18035;
const int INVOKE_ENERGY_IMMUNITY_FIRE = 18036;
const int INVOKE_ENERGY_IMMUNITY_SONIC = 18037;
const int INVOKE_INSTILL_VULNERABILITY = 18038;
const int INVOKE_INSTILL_VULNERABIL_ACID = 18039;
const int INVOKE_INSTILL_VULNERABIL_COLD = 18040;
const int INVOKE_INSTILL_VULNERABIL_ELEC = 18041;
const int INVOKE_INSTILL_VULNERABIL_FIRE = 18042;
const int INVOKE_INSTILL_VULNERABIL_SON = 18043;
//Least Warlock Invocations
const int INVOKE_ALL_SEEING_EYES = 18045;
const int INVOKE_BALEFUL_UTTERANCE = 18046;
const int INVOKE_CALL_OF_THE_BEAST = 18047;
const int INVOKE_COCOON_OF_REFUSE = 18048;
const int INVOKE_DARK_ONES_OWN_LUCK = 18049;
const int INVOKE_DARK_ONES_OWN_LUCK_FORT = 18050;
const int INVOKE_DARK_ONES_OWN_LUCK_REFLEX = 18051;
const int INVOKE_DARK_ONES_OWN_LUCK_WILL = 18052;
const int INVOKE_DEVILS_SIGHT = 18053;
const int INVOKE_DRAIN_INCARNUM = -1;
const int INVOKE_EARTHEN_GRASP = 18055;
const int INVOKE_ELDRITCH_GLAIVE = 18056;
const int INVOKE_ELDRITCH_SPEAR = 18058;
const int INVOKE_ENTROPIC_WARDING = 18059;
const int INVOKE_FRIGHTFUL_BLAST = 18060;
const int INVOKE_HAMMER_BLAST = 18061;
const int INVOKE_HIDEOUS_BLOW = 18062;
const int INVOKE_LEAPS_AND_BOUNDS = 18063;
const int INVOKE_MIASMIC_CLOUD = 18064;
const int INVOKE_OTHERWORLDLY_WHISPERS = 18065;
const int INVOKE_SERPENTS_TONGUE = 18066;
const int INVOKE_SICKENING_BLAST = 18067;
const int INVOKE_SOULREAVING_AURA = 18068;
const int INVOKE_SUMMON_SWARM = 18069;
const int INVOKE_SUMMON_SWARM_RAT = 18070;
const int INVOKE_SUMMON_SWARM_BAT = 18071;
const int INVOKE_SWIMMING_THE_STYX = 18072;
//Lesser Warlock Invocations
const int INVOKE_BANEFUL_BLAST_ABERRATION = 18073;
const int INVOKE_BANEFUL_BLAST_BEAST = 18074;
const int INVOKE_BANEFUL_BLAST_CONSTRUCT = 18075;
const int INVOKE_BANEFUL_BLAST_DRAGON = 18076;
const int INVOKE_BANEFUL_BLAST_DWARF = 18077;
const int INVOKE_BANEFUL_BLAST_ELEMENTAL = 18078;
const int INVOKE_BANEFUL_BLAST_ELF = 18079;
const int INVOKE_BANEFUL_BLAST_FEY = 18080;
const int INVOKE_BANEFUL_BLAST_GIANT = 18081;
const int INVOKE_BANEFUL_BLAST_GOBLINOID = 18082;
const int INVOKE_BANEFUL_BLAST_GNOME = 18083;
const int INVOKE_BANEFUL_BLAST_HALFLING = 18084;
const int INVOKE_BANEFUL_BLAST_HUMAN = 18085;
const int INVOKE_BANEFUL_BLAST_MONSTROUS = 18086;
const int INVOKE_BANEFUL_BLAST_ORC = 18087;
const int INVOKE_BANEFUL_BLAST_OUTSIDER = 18088;
const int INVOKE_BANEFUL_BLAST_PLANT = 18089;
const int INVOKE_BANEFUL_BLAST_REPTILIAN = 18090;
const int INVOKE_BANEFUL_BLAST_SHAPECHANGER = 18091;
const int INVOKE_BANEFUL_BLAST_UNDEAD = 18092;
const int INVOKE_BANEFUL_BLAST_VERMIN = 18093;
const int INVOKE_BESHADOWED_BLAST = 18094;
const int INVOKE_BRIMSTONE_BLAST = 18095;
const int INVOKE_COLD_COMFORT = 18096;
const int INVOKE_CURSE_OF_DESPAIR = 18097;
const int INVOKE_DREAD_SEIZURE = 18098;
const int INVOKE_ELDRITCH_CHAIN = 18099;
const int INVOKE_FLEE_THE_SCENE = 18100;
const int INVOKE_FLEE_THE_SCENE_SELECT = 18101;
const int INVOKE_FLEE_THE_SCENE_DIRDIST = 18102;
const int INVOKE_HELLRIME_BLAST = 18103;
const int INVOKE_HUNGRY_DARKNESS = 18104;
const int INVOKE_IGNORE_THE_PYRE = 18105;
const int INVOKE_IGNORE_THE_PYRE_ACID = 18106;
const int INVOKE_IGNORE_THE_PYRE_COLD = 18107;
const int INVOKE_IGNORE_THE_PYRE_ELEC = 18108;
const int INVOKE_IGNORE_THE_PYRE_FIRE = 18109;
const int INVOKE_IGNORE_THE_PYRE_SONIC = 18110;
const int INVOKE_MASK_OF_FLESH = 18111;
const int INVOKE_MASK_OF_FLESH_FRIENDLY = 18112;
const int INVOKE_MASK_OF_FLESH_HOSTILE = 18113;
const int INVOKE_RELENTLESS_DISPELLING = 18114;
const int INVOKE_SPIDER_SHAPE = 18115;
const int INVOKE_STEAL_INCARNUM = -1;
const int INVOKE_STONY_GRASP = 18117;
const int INVOKE_THE_DEAD_WALK = 18118;
const int INVOKE_WALL_OF_GLOOM = 18119;
const int INVOKE_WITCHWOOD_STEP = 18120;
//Greater Warlock Invocations
const int INVOKE_BEWITCHING_BLAST = 18121;
const int INVOKE_CAUSTIC_MIRE = 18122;
const int INVOKE_CHILLING_TENTACLES = 18123;
const int INVOKE_DRAGON_WARD = 18124;
const int INVOKE_ELDRITCH_CONE = 18125;
const int INVOKE_ELDRITCH_LINE = 18126;
const int INVOKE_ENERVATING_SHADOW = 18127;
const int INVOKE_HELLSPAWNED_GRACE = 18128;
const int INVOKE_HINDERING_BLAST = 18129;
const int INVOKE_INCARNUM_BLAST = -1;
const int INVOKE_NIGHTMARES_MADE_REAL = 18131;
const int INVOKE_NOXIOUS_BLAST = 18132;
const int INVOKE_PAINFUL_SLUMBER_OF_AGES = 18133;
const int INVOKE_PENETRATING_BLAST = 18134;
const int INVOKE_TENACIOUS_PLAGUE = 18135;
const int INVOKE_VITRIOLIC_BLAST = 18136;
const int INVOKE_WALL_OF_PERILOUS_FLAME = 18137;
//Dark Warlock Invocations
const int INVOKE_BINDING_BLAST = 18138;
const int INVOKE_CASTERS_LAMENT = 18139;
const int INVOKE_DARK_DISCORPORATION = 18140;
const int INVOKE_DARK_FORESIGHT = 18141;
const int INVOKE_ELDRITCH_DOOM = 18142;
const int INVOKE_INCARNUM_SHROUD = -1;
const int INVOKE_PATH_OF_SHADOW = 18144;
const int INVOKE_PATH_OF_SHADOW_SELF = 18145;
const int INVOKE_PATH_OF_SHADOW_PARTY = 18146;
const int INVOKE_RETRIBUTIVE_INVISIBILITY = 18147;
const int INVOKE_STEAL_SUMMONING = 18148;
const int INVOKE_UTTERDARK_BLAST = 18149;
const int INVOKE_WORD_OF_CHANGING = 18150;
//AOEs
const int INVOKE_AOE_CHILLFOG = 224;
const int INVOKE_AOE_BREATH_OF_NIGHT = 142;
const int INVOKE_AOE_COLD_COMFORT = 226;
const int INVOKE_VFX_CHILLING_TENTACLES = 227;
const int INVOKE_VFX_PER_WALLPERILFIRE = 228;
const int INVOKE_AOE_MIASMIC_CLOUD = 229;
const int INVOKE_AOE_CAUSTIC_MIRE = 230;
const int INVOKE_AOE_ENERVATING_SHADOW = 231;
const int INVOKE_VFX_NIGHTMARE_TERRAIN_1 = 232;
const int INVOKE_VFX_NIGHTMARE_TERRAIN_4 = 233;
const int INVOKE_VFX_NIGHTMARE_TERRAIN_7 = 234;
const int INVOKE_VFX_NIGHTMARE_TERRAIN_11 = 235;
const int INVOKE_VFX_NIGHTMARE_TERRAIN_15 = 236;
const int INVOKE_VFX_NIGHTMARE_TERRAIN_21 = 237;
const int INVOKE_VFX_NIGHTMARE_TERRAIN_25 = 238;
const int INVOKE_VFX_NIGHTMARE_TERRAIN_31 = 239;
const int INVOKE_VFX_NIGHTMARE_TERRAIN_37 = 240;
const int INVOKE_AOE_SWARMDMG = 241;
const int INVOKE_VFX_HUNGRY_DARKNESS = 242;
const int INVOKE_AOE_SWARMDMG_2 = 243;
const int INVOKE_AOE_SWARMDMG_3 = 244;
const int INVOKE_AOE_SWARMDMG_4 = 245;
const int INVOKE_AOE_SWARMDMG_5 = 246;
const int INVOKE_AOE_SWARMDMG_6 = 247;
const int INVOKE_VFX_DARK_DISCORPORATION = 248;
const int INVOKE_VFX_PER_WALL_OF_GLOOM = 249;
const int INVOKE_AOE_EARTHEN_GRASP_GRAPPLE = 250;
//class abilities
const int INVOKE_ELDRITCH_BLAST = 2083;
const int INVOKE_IMBUE_ITEM = 2082;
const int INVOKE_FIENDISH_RESILIENCE = 2084;
//epic warlock feats
const int INVOKE_LORD_OF_ALL_ESSENCES = 3758;
const int INVOKE_MASTER_OF_ELEMENTS_AIR = 3753;
const int INVOKE_MASTER_OF_ELEMENTS_EARTH = 3754;
const int INVOKE_MASTER_OF_ELEMENTS_FIRE = 3755;
const int INVOKE_MASTER_OF_ELEMENTS_WATER = 3756;
const int INVOKE_MASTER_OF_ELEMENTS_DOMINATE = 3757;
const int INVOKE_MORPHEME_SAVANT_WORD_KILL = 3750;
const int INVOKE_MORPHEME_SAVANT_WORD_STUN = 3751;
const int INVOKE_SHADOWMASTER_CONCEALMENT = 3743;
const int INVOKE_SHADOWMASTER_SUMMON_SHADOW = 3745;
const int INVOKE_SHADOWMASTER_CONE_OF_COLD = 3746;
const int INVOKE_SHADOWMASTER_FIREBALL = 3747;
const int INVOKE_SHADOWMASTER_STONESKIN = 3748;
const int INVOKE_SHADOWMASTER_WALL_OF_FIRE = 3749;
//other invocation-related abilities
const int INVOKE_ELDRITCH_GLAIVE_ONHIT = 205;
//Hellfire Warlock
const int INVOKE_HELLFIRE_BLAST = 17282;
const int INVOKE_HELLFIRE_SPEAR = 17283;
const int INVOKE_HELLFIRE_GLAIVE = 17284;
const int INVOKE_HELLFIRE_BLOW = 17285;
const int INVOKE_HELLFIRE_CHAIN = 17286;
const int INVOKE_HELLFIRE_CONE = 17287;
const int INVOKE_HELLFIRE_LINE = 17288;
const int INVOKE_HELLFIRE_DOOM = 17289;
const int INVOKE_HF_INFUSION_EXTEND = 17291;
const int INVOKE_HF_INFUSION_EMPOWER = 17292;
const int INVOKE_HF_INFUSION_WIDEN = 17293;
const int INVOKE_HF_INFUSION_MAXIMIZE = 17294;
const int INVOKE_HELLFIRE_SHIELD = 17295;
//Eldritch Disciple
const int INVOKE_CORRUPTING_BLAST = 17270;
const int INVOKE_DAMAGE_REDUCTION = 17271;
const int INVOKE_FEARFUL_GLARE = 17272;
const int INVOKE_FIENDISH_RESISTANCE = 17273;
const int INVOKE_HEALING_BLAST = 17274;
const int INVOKE_PROTECTIVE_AURA = 17275;
const int INVOKE_STRENGTH_OF_WILL = 17276;
const int INVOKE_WILD_FRENZY = 17277;
//Eldritch Theurge
const int INVOKE_GR_SPELL_SELECT_CONVO = 17259;
const int INVOKE_GR_SPELL_SELECT_QUICK1 = 17260;
const int INVOKE_GR_SPELL_SELECT_QUICK2 = 17261;
const int INVOKE_GR_SPELL_SELECT_QUICK3 = 17262;
const int INVOKE_GR_SPELL_SELECT_QUICK4 = 17263;
const int INVOKE_SB_SPELL_SELECT_CONVO = 17265;
const int INVOKE_SB_SPELL_SELECT_QUICK1 = 17266;
const int INVOKE_SB_SPELL_SELECT_QUICK2 = 17267;
const int INVOKE_SB_SPELL_SELECT_QUICK3 = 17268;
const int INVOKE_SB_SPELL_SELECT_QUICK4 = 17269;

View File

@@ -0,0 +1,170 @@
//::///////////////////////////////////////////////
//:: Invocation Hook File.
//:: inv_invokehook.nss
//:://////////////////////////////////////////////
/*
This file acts as a hub for all code that
is hooked into the invocation scripts
*/
//:://////////////////////////////////////////////
//:: Created By: Fox
//:: Created On: 25-1-2008
//:://////////////////////////////////////////////
#include "prc_inc_spells"
#include "inv_inc_invfunc"
#include "x2_inc_spellhook"
// This function holds all functions that are supposed to run before the actual
// spellscript gets run. If this functions returns FALSE, the spell is aborted
// and the spellscript will not run
int PreInvocationCastCode();
// All invocations have somatic component so we will roll ASF check here
int InvocationASFCheck(object oInvoker, int nClass)
{
int nASF = GetArcaneSpellFailure(oInvoker);
// Warlocks ignore ASF chance while casting in light armor
if(nClass == CLASS_TYPE_WARLOCK)
{
object oArmor = GetItemInSlot(INVENTORY_SLOT_CHEST, oInvoker);
int nAC = GetBaseAC(oArmor);
//armors
switch(nAC)
{
case 1: nASF -= 5; break;//light
case 2: nASF -= 10; break;//light
case 3: nASF -= 20; break;//light
case 4: nASF -= GetHasFeat(FEAT_BATTLE_CASTER, oInvoker) ? 20 : 0; break;//medium;
case 5: nASF -= GetHasFeat(FEAT_BATTLE_CASTER, oInvoker) ? 30 : 0; break;//medium
default: break;
}
}
else if(nClass == CLASS_TYPE_DRAGON_SHAMAN)
{
//no ASF chance
return TRUE;
}
if(Random(100) < nASF)
{
//52946 = Spell failed due to arcane spell failure!
FloatingTextStrRefOnCreature(52946, oInvoker, FALSE);
return FALSE;
}
return TRUE;
}
//------------------------------------------------------------------------------
// if FALSE is returned by this function, the spell will not be cast
// the order in which the functions are called here DOES MATTER, changing it
// WILL break the crafting subsystems
//------------------------------------------------------------------------------
int PreInvocationCastCode()
{
object oInvoker = OBJECT_SELF;
object oTarget = PRCGetSpellTargetObject();
object oCastItem = GetSpellCastItem();
int nInvokeId = PRCGetSpellId();
int nInvokingClass = GetInvokingClass(oInvoker);
int nInvokeLevel = GetInvocationLevel(oInvoker);
int bInvokeIsHostile = Get2DACache("spells", "HostileSetting", nInvokeId) == "1";
int nContinue = !ExecuteScriptAndReturnInt("prespellcode", oInvoker);
//---------------------------------------------------------------------------
// Break any spell require maintaining concentration
//---------------------------------------------------------------------------
X2BreakConcentrationSpells();
//---------------------------------------------------------------------------
// No invoking while using expertise
//---------------------------------------------------------------------------
if(nContinue)
if (GetActionMode(oInvoker, ACTION_MODE_EXPERTISE) || GetActionMode(oInvoker, ACTION_MODE_IMPROVED_EXPERTISE))
nContinue = FALSE;
//---------------------------------------------------------------------------
// Check for PRC spell effects
//---------------------------------------------------------------------------
if(nContinue)
nContinue = PRCSpellEffects(oInvoker, oTarget, nInvokeId, nInvokeLevel, nInvokingClass, bInvokeIsHostile, -1);
//---------------------------------------------------------------------------
// Run Grappling Concentration Check
//---------------------------------------------------------------------------
if(nContinue)
nContinue = GrappleConc(oInvoker, nInvokeLevel);
//---------------------------------------------------------------------------
// Run ASF Check
//---------------------------------------------------------------------------
if(nContinue)
nContinue = InvocationASFCheck(oInvoker, nInvokingClass);
//---------------------------------------------------------------------------
// This stuff is only interesting for player characters we assume that use
// magic device always works and NPCs don't use the crafting feats or
// sequencers anyway. Thus, any NON PC spellcaster always exits this script
// with TRUE (unless they are DM possessed or in the Wild Magic Area in
// Chapter 2 of Hordes of the Underdark.
//---------------------------------------------------------------------------
if(!GetIsPC(oInvoker)
&& !GetPRCSwitch(PRC_NPC_HAS_PC_SPELLCASTING))
{
if(!GetIsDMPossessed(oInvoker) && !GetLocalInt(GetArea(oInvoker), "X2_L_WILD_MAGIC"))
{
return TRUE;
}
}
//---------------------------------------------------------------------------
// Run use magic device skill check
//---------------------------------------------------------------------------
if(nContinue)
{
nContinue = X2UseMagicDeviceCheck(oInvoker);
}
//-----------------------------------------------------------------------
// run any user defined spellscript here
//-----------------------------------------------------------------------
if (nContinue)
{
nContinue = X2RunUserDefinedSpellScript();
}
//---------------------------------------------------------------------------
// Check for the new restricted itemproperties
//---------------------------------------------------------------------------
if(nContinue
&& GetIsObjectValid(oCastItem)
&& !CheckPRCLimitations(oCastItem, oInvoker))
{
SendMessageToPC(oInvoker, "You cannot use "+GetName(oCastItem));
nContinue = FALSE;
}
//Cleaning spell variables used for holding the charge
if(!GetLocalInt(oInvoker, "PRC_SPELL_EVENT"))
{
DeleteLocalInt(oInvoker, "PRC_SPELL_CHARGE_COUNT");
DeleteLocalInt(oInvoker, "PRC_SPELL_CHARGE_SPELLID");
DeleteLocalObject(oInvoker, "PRC_SPELL_CONC_TARGET");
DeleteLocalInt(oInvoker, "PRC_SPELL_METAMAGIC");
DeleteLocalManifestation(oInvoker, "PRC_POWER_HOLD_MANIFESTATION");
DeleteLocalMystery(oInvoker, "MYST_HOLD_MYST");
}
else if(GetLocalInt(oInvoker, "PRC_SPELL_CHARGE_SPELLID") != nInvokeId)
{ //Sanity check, in case something goes wrong with the action queue
DeleteLocalInt(oInvoker, "PRC_SPELL_EVENT");
}
return nContinue;
}

View File

@@ -0,0 +1,123 @@
/*
** Spell lookup&caching code by DarkGod
** Because the engine sucks so badly ...
*/
#include "inc_2dacache"
//const string PRC_CACHE_SUB_STRING = "NULL";
string
lookup_and_cache_spell_field(int spell_id, string tag_base, string column, object oModule = OBJECT_INVALID)
{
//modifed by Primogenitor to a more general 2da caching system
/*
// Verify the module
if (!GetIsObjectValid(oModule))
oModule = GetModule();
// Create the tag string
string tag = tag_base + IntToString(spell_id);
// lookup the tag in cache
string val = GetLocalString(oModule, tag);
// lookup and fill the cache if required
if (val == "") {
val = Get2DACache("spells", column, spell_id);
// Get2DAString() will return "" for invalid fields
// In order to make our per field cache work, we need to
// perform a substitution so that non-existant and invalid
// values are different. Verify that this constant is indeed
// unique within the 2da file if this code is reused
if (val == "")
val = PRC_CACHE_SUB_STRING;
SetLocalString(oModule, tag, val);
}
// Undo the substitution, see above comments for details
if (val == PRC_CACHE_SUB_STRING)
val = "";
return val;
*/
return Get2DACache("spells", column, spell_id);
}
string
lookup_spell_name(int spell_id, object oModule = OBJECT_INVALID)
{
return lookup_and_cache_spell_field(spell_id,
"PRC_PACK_SPELL_NAME_", "Name", oModule);
}
string
lookup_spell_level(int spell_id, object oModule = OBJECT_INVALID)
{
return lookup_and_cache_spell_field(spell_id,
"PRC_PACK_SPELL_LEVEL_", "Wiz_Sorc", oModule);
}
string
lookup_spell_innate(int spell_id, object oModule = OBJECT_INVALID)
{
string sTemp = lookup_and_cache_spell_field(spell_id, "PRC_PACK_SPELL_INNATE_LEVEL_", "Innate", oModule);
if(sTemp == "")
{
string sMaster = Get2DACache("spells", "Master", spell_id);
if(sMaster != "")
{
sTemp = Get2DACache("spells", "Innate", StringToInt(sMaster));
}
}
return sTemp;
}
string
lookup_spell_druid_level(int spell_id, object oModule = OBJECT_INVALID)
{
return lookup_and_cache_spell_field(spell_id,
"PRC_PACK_SPELL_DRUID_LEVEL_", "Druid", oModule);
}
string
lookup_spell_cleric_level(int spell_id, object oModule = OBJECT_INVALID)
{
return lookup_and_cache_spell_field(spell_id,
"PRC_PACK_SPELL_CLERIC_LEVEL_", "Cleric", oModule);
}
string
lookup_spell_type(int spell_id, object oModule = OBJECT_INVALID)
{
return lookup_and_cache_spell_field(spell_id,
"PRC_PACK_SPELL_TYPE_", "ImmunityType", oModule);
}
string
lookup_spell_vs(int spell_id, object oModule = OBJECT_INVALID)
{
return lookup_and_cache_spell_field(spell_id,
"PRC_PACK_SPELL_VS_", "VS", oModule);
}
string
lookup_spell_school(int spell_id, object oModule = OBJECT_INVALID)
{
return lookup_and_cache_spell_field(spell_id,
"PRC_PACK_SPELL_SCHOOL_", "School", oModule);
}
void
lookup_spell(int spell_id)
{
object module = GetModule();
lookup_spell_level(spell_id, module);
lookup_spell_cleric_level(spell_id, module);
lookup_spell_innate(spell_id, module);
lookup_spell_cleric_level(spell_id, module);
lookup_spell_type(spell_id, module);
lookup_spell_vs(spell_id, module);
lookup_spell_school(spell_id, module);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,338 @@
// Chakra Constants
const int CHAKRA_CROWN = 1;
const int CHAKRA_FEET = 2;
const int CHAKRA_HANDS = 3;
const int CHAKRA_ARMS = 4;
const int CHAKRA_BROW = 5;
const int CHAKRA_SHOULDERS = 6;
const int CHAKRA_THROAT = 7;
const int CHAKRA_WAIST = 8;
const int CHAKRA_HEART = 9;
const int CHAKRA_SOUL = 10;
const int CHAKRA_TOTEM = 11;
const int CHAKRA_DOUBLE_CROWN = 12;
const int CHAKRA_DOUBLE_FEET = 13;
const int CHAKRA_DOUBLE_HANDS = 14;
const int CHAKRA_DOUBLE_ARMS = 15;
const int CHAKRA_DOUBLE_BROW = 16;
const int CHAKRA_DOUBLE_SHOULDERS = 17;
const int CHAKRA_DOUBLE_THROAT = 18;
const int CHAKRA_DOUBLE_WAIST = 19;
const int CHAKRA_DOUBLE_HEART = 20;
const int CHAKRA_DOUBLE_SOUL = 21;
const int CHAKRA_DOUBLE_TOTEM = 22;
// Meld SpellId Constants
const int MELD_ACROBAT_BOOTS = 18701;
const int MELD_ADAMANT_PAULDRONS = 18702;
const int MELD_CRYSTAL_HELM = 18703;
const int MELD_ANKHEG_BREASTPLATE = 18704;
const int MELD_APPARITION_RIBBON = 18705;
const int MELD_ARCANE_FOCUS = 18706;
const int MELD_ARMGUARDS_OF_DISRUPTION = 18707;
const int MELD_BASILISK_MASK = 18708;
const int MELD_BEAST_TAMER_CIRCLET = 18709;
const int MELD_BEHIR_GORGET = 18710;
const int MELD_BLINK_SHIRT = 18711;
const int MELD_BLOODTALONS = 18712;
const int MELD_BLOODWAR_GAUNTLETS = 18713;
const int MELD_BLUESTEEL_BRACERS = 18714;
const int MELD_BRASS_MANE = 18715;
const int MELD_CERULEAN_SANDALS = 18716;
const int MELD_DIADEM_OF_PURELIGHT = 18717;
const int MELD_DISENCHANTER_MASK = 18718;
const int MELD_DISPLACER_MANTLE = 18719;
const int MELD_DISSOLVING_SPITTLE = 18720;
const int MELD_DREAD_CARAPACE = 18721;
const int MELD_ENIGMA_HELM = 18722;
const int MELD_FEARSOME_MASK = 18723;
const int MELD_FELLMIST_ROBE = 18724;
const int MELD_FLAME_CINCTURE = 18725;
const int MELD_FROST_HELM = 18726;
const int MELD_GIRALLON_ARMS = 18727;
const int MELD_GLOVES_OF_THE_POISONED_SOUL = 18728;
const int MELD_GORGON_MASK = 18729;
const int MELD_GREAT_RAPTOR_MASK = 18730;
const int MELD_HEART_OF_FIRE = 18731;
const int MELD_HUNTERS_CIRCLET = 18732;
const int MELD_ILLUSION_VEIL = 18733;
const int MELD_IMPULSE_BOOTS = 18734;
const int MELD_INCARNATE_AVATAR = 18735;
const int MELD_INCARNATE_WEAPON = 18736;
const int MELD_KEENEYE_LENSES = 18737;
const int MELD_KRAKEN_MANTLE = 18738;
const int MELD_KRENSHAR_MASK = 18739;
const int MELD_KRUTHIK_CLAWS = 18740;
const int MELD_LAMIA_BELT = 18741;
const int MELD_LAMMASU_MANTLE = 18742;
const int MELD_LANDSHARK_BOOTS = 18743;
const int MELD_LIFEBOND_VESTMENTS = 18744;
const int MELD_LIGHTNING_GAUNTLETS = 18745;
const int MELD_LUCKY_DICE = 18746;
const int MELD_MAGES_SPECTACLES = 18747;
const int MELD_MANTICORE_BELT = 18748;
const int MELD_MANTLE_OF_FLAME = 18749;
const int MELD_MAULING_GAUNTLETS = 18750;
const int MELD_NECROCARNUM_CIRCLET = 18751;
const int MELD_NECROCARNUM_MANTLE = 18752;
const int MELD_NECROCARNUM_SHROUD = 18753;
const int MELD_NECROCARNUM_TOUCH = 18754;
const int MELD_NECROCARNUM_VESTMENTS = 18755;
const int MELD_NECROCARNUM_WEAPON = 18756;
const int MELD_PAULDRONS_OF_HEALTH = 18757;
const int MELD_PEGASUS_CLOAK = 18758;
const int MELD_PHASE_CLOAK = 18759;
const int MELD_PHOENIX_BELT = 18760;
const int MELD_PLANAR_CHASUBLE = 18761;
const int MELD_PLANAR_WARD = 18762;
const int MELD_RAGECLAWS = 18763;
const int MELD_RIDING_BRACERS = 18764;
const int MELD_SAILORS_BRACERS = 18765;
const int MELD_SHADOW_MANTLE = 18766;
const int MELD_SHEDU_CROWN = 18767;
const int MELD_SIGHTING_GLOVES = 18768;
const int MELD_SILVERTONGUE_MASK = 18769;
const int MELD_SOULSPARK_FAMILIAR = 18770;
const int MELD_SOULSPEAKER_CIRCLET = 18771;
const int MELD_SPELLWARD_SHIRT = 18772;
const int MELD_SPHINX_CLAWS = 18773;
const int MELD_STRONGHEART_VEST = 18774;
const int MELD_THEFT_GLOVES = 18775;
const int MELD_THERAPEUTIC_MANTLE = 18776;
const int MELD_THREEFOLD_MASK_OF_THE_CHIMERA = 18777;
const int MELD_THUNDERSTEP_BOOTS = 18778;
const int MELD_TOTEM_AVATAR = 18779;
const int MELD_TRUTHSEEKER_GOGGLES = 18780;
const int MELD_UNICORN_HORN = 18781;
const int MELD_URSKAN_GREAVES = 18782;
const int MELD_VITALITY_BELT = 18783;
const int MELD_WIND_CLOAK = 18784;
const int MELD_WINTER_MASK = 18785;
const int MELD_WORG_PELT = 18786;
const int MELD_WORMTAIL_BELT = 18787;
const int MELD_YRTHAK_MASK = 18788;
const int MELD_ASTRAL_VAMBRACES = 18789;
const int MELD_CHARMING_VEIL = 18790;
const int MELD_PSIONS_EYES = 18791;
const int MELD_PSIONKILLER_MASK = 18792;
const int MELD_PSYCHIC_FOCUS = 18793;
const int MELD_CLAW_OF_THE_WYRM = 18794;
const int MELD_DRAGON_MANTLE = 18795;
const int MELD_DRAGON_TAIL = 18796;
const int MELD_DRAGONFIRE_MASK = 18797;
const int MELD_ELDER_SPIRIT = 18798;
// Meld IPFeat Constants
const int IP_CONST_MELD_ACROBAT_BOOTS = 13550;
const int IP_CONST_MELD_ADAMANT_PAULDRONS = 13551;
const int IP_CONST_MELD_CRYSTAL_HELM = 13552;
const int IP_CONST_MELD_ANKHEG_BREASTPLATE = 13553;
const int IP_CONST_MELD_APPARITION_RIBBON = 13554;
const int IP_CONST_MELD_ARCANE_FOCUS = 13555;
const int IP_CONST_MELD_ARMGUARDS_OF_DISRUPTION = 13556;
const int IP_CONST_MELD_BASILISK_MASK = 13557;
const int IP_CONST_MELD_BEAST_TAMER_CIRCLET = 13558;
const int IP_CONST_MELD_BEHIR_GORGET = 13559;
const int IP_CONST_MELD_BLINK_SHIRT = 13560;
const int IP_CONST_MELD_BLOODTALONS = 13561;
const int IP_CONST_MELD_BLOODWAR_GAUNTLETS = 13562;
const int IP_CONST_MELD_BLUESTEEL_BRACERS = 13563;
const int IP_CONST_MELD_BRASS_MANE = 13564;
const int IP_CONST_MELD_CERULEAN_SANDALS = 13565;
const int IP_CONST_MELD_DIADEM_OF_PURELIGHT = 13566;
const int IP_CONST_MELD_DISENCHANTER_MASK = 13567;
const int IP_CONST_MELD_DISPLACER_MANTLE = 13568;
const int IP_CONST_MELD_DISSOLVING_SPITTLE = 13569;
const int IP_CONST_MELD_DREAD_CARAPACE = 13570;
const int IP_CONST_MELD_ENIGMA_HELM = 13571;
const int IP_CONST_MELD_FEARSOME_MASK = 13572;
const int IP_CONST_MELD_FELLMIST_ROBE = 13573;
const int IP_CONST_MELD_FLAME_CINCTURE = 13574;
const int IP_CONST_MELD_FROST_HELM = 13575;
const int IP_CONST_MELD_GIRALLON_ARMS = 13576;
const int IP_CONST_MELD_GLOVES_OF_THE_POISONED_SOUL = 13577;
const int IP_CONST_MELD_GORGON_MASK = 13578;
const int IP_CONST_MELD_GREAT_RAPTOR_MASK = 13579;
const int IP_CONST_MELD_HEART_OF_FIRE = 13580;
const int IP_CONST_MELD_HUNTERS_CIRCLET = 13581;
const int IP_CONST_MELD_ILLUSION_VEIL = 13582;
const int IP_CONST_MELD_IMPULSE_BOOTS = 13583;
const int IP_CONST_MELD_INCARNATE_AVATAR = 13584;
const int IP_CONST_MELD_INCARNATE_WEAPON = 13585;
const int IP_CONST_MELD_KEENEYE_LENSES = 13586;
const int IP_CONST_MELD_KRAKEN_MANTLE = 13587;
const int IP_CONST_MELD_KRENSHAR_MASK = 13588;
const int IP_CONST_MELD_KRUTHIK_CLAWS = 13589;
const int IP_CONST_MELD_LAMIA_BELT = 13590;
const int IP_CONST_MELD_LAMMASU_MANTLE = 13591;
const int IP_CONST_MELD_LANDSHARK_BOOTS = 13592;
const int IP_CONST_MELD_LIFEBOND_VESTMENTS = 13593;
const int IP_CONST_MELD_LIGHTNING_GAUNTLETS = 13594;
const int IP_CONST_MELD_LUCKY_DICE = 13595;
const int IP_CONST_MELD_MAGES_SPECTACLES = 13596;
const int IP_CONST_MELD_MANTICORE_BELT = 13597;
const int IP_CONST_MELD_MANTLE_OF_FLAME = 13598;
const int IP_CONST_MELD_MAULING_GAUNTLETS = 13599;
const int IP_CONST_MELD_NECROCARNUM_CIRCLET = 13600;
const int IP_CONST_MELD_NECROCARNUM_MANTLE = 13601;
const int IP_CONST_MELD_NECROCARNUM_SHROUD = 13602;
const int IP_CONST_MELD_NECROCARNUM_TOUCH = 13603;
const int IP_CONST_MELD_NECROCARNUM_VESTMENTS = 13604;
const int IP_CONST_MELD_NECROCARNUM_WEAPON = 13605;
const int IP_CONST_MELD_PAULDRONS_OF_HEALTH = 13606;
const int IP_CONST_MELD_PEGASUS_CLOAK = 13607;
const int IP_CONST_MELD_PHASE_CLOAK = 13608;
const int IP_CONST_MELD_PHOENIX_BELT = 13609;
const int IP_CONST_MELD_PLANAR_CHASUBLE = 13610;
const int IP_CONST_MELD_PLANAR_WARD = 13611;
const int IP_CONST_MELD_RAGECLAWS = 13612;
const int IP_CONST_MELD_RIDING_BRACERS = 13613;
const int IP_CONST_MELD_SAILORS_BRACERS = 13614;
const int IP_CONST_MELD_SHADOW_MANTLE = 13615;
const int IP_CONST_MELD_SHEDU_CROWN = 13616;
const int IP_CONST_MELD_SIGHTING_GLOVES = 13617;
const int IP_CONST_MELD_SILVERTONGUE_MASK = 13618;
const int IP_CONST_MELD_SOULSPARK_FAMILIAR = 13619;
const int IP_CONST_MELD_SOULSPEAKER_CIRCLET = 13620;
const int IP_CONST_MELD_SPELLWARD_SHIRT = 13621;
const int IP_CONST_MELD_SPHINX_CLAWS = 13622;
const int IP_CONST_MELD_STRONGHEART_VEST = 13623;
const int IP_CONST_MELD_THEFT_GLOVES = 13624;
const int IP_CONST_MELD_THERAPEUTIC_MANTLE = 13625;
const int IP_CONST_MELD_THREEFOLD_MASK_OF_THE_CHIMERA = 13626;
const int IP_CONST_MELD_THUNDERSTEP_BOOTS = 13627;
const int IP_CONST_MELD_TOTEM_AVATAR = 13628;
const int IP_CONST_MELD_TRUTHSEEKER_GOGGLES = 13629;
const int IP_CONST_MELD_UNICORN_HORN = 13630;
const int IP_CONST_MELD_URSKAN_GREAVES = 13631;
const int IP_CONST_MELD_VITALITY_BELT = 13632;
const int IP_CONST_MELD_WIND_CLOAK = 13633;
const int IP_CONST_MELD_WINTER_MASK = 13634;
const int IP_CONST_MELD_WORG_PELT = 13635;
const int IP_CONST_MELD_WORMTAIL_BELT = 13636;
const int IP_CONST_MELD_YRTHAK_MASK = 13637;
const int IP_CONST_MELD_ASTRAL_VAMBRACES = 13638;
const int IP_CONST_MELD_CHARMING_VEIL = 13639;
const int IP_CONST_MELD_PSIONS_EYES = 13640;
const int IP_CONST_MELD_PSIONKILLER_MASK = 13641;
const int IP_CONST_MELD_PSYCHIC_FOCUS = 13642;
const int IP_CONST_MELD_CLAW_OF_THE_WYRM = 13643;
const int IP_CONST_MELD_DRAGON_MANTLE = 13644;
const int IP_CONST_MELD_DRAGON_TAIL = 13645;
const int IP_CONST_MELD_DRAGONFIRE_MASK = 13646;
const int IP_CONST_MELD_ELDER_SPIRIT = 13647;
// Bind IPFeat Constants
const int IP_CONST_MELD_ANKHEG_BREASTPLATE_THROAT = 13650;
const int IP_CONST_MELD_APPARITION_RIBBON_THROAT = 13651;
const int IP_CONST_MELD_ARMGUARDS_OF_DISRUPTION_ARMS = 13652;
const int IP_CONST_MELD_BASILISK_MASK_TOTEM = 13653;
const int IP_CONST_MELD_BEAST_TAMER_CIRCLET_CROWN = 13654;
const int IP_CONST_MELD_BEAST_TAMER_CIRCLET_TOTEM = 13655;
const int IP_CONST_MELD_BEHIR_GORGET_THROAT = 13656;
const int IP_CONST_MELD_BLINK_SHIRT_DOOR_ST = 13657;
const int IP_CONST_MELD_BLINK_SHIRT_HEART = 13658;
const int IP_CONST_MELD_BLINK_SHIRT_DOOR_MV = 13659;
const int IP_CONST_MELD_BLOODWAR_GAUNTLETS_ARMS = 13660;
const int IP_CONST_MELD_BRASS_MANE_THROAT = 13661;
const int IP_CONST_MELD_CERULEAN_SANDALS_FEET = 13662;
const int IP_CONST_MELD_DISENCHANTER_MASK_DETECT = 13663;
const int IP_CONST_MELD_DISENCHANTER_MASK_TOTEM = 13664;
const int IP_CONST_MELD_DISPLACER_MANTLE_TOTEM = 13665;
const int IP_CONST_MELD_DISSOLVING_SPITTLE_SPIT = 13666;
const int IP_CONST_MELD_DREAD_CARAPACE_FEET = 13667;
const int IP_CONST_MELD_FLAME_CINCTURE_WAIST = 13668;
const int IP_CONST_MELD_FROST_HELM_CROWN = 13669;
const int IP_CONST_MELD_FROST_HELM_TOTEM = 13670;
const int IP_CONST_MELD_GLOVES_OF_THE_POISONED_SOUL_HANDS = 13671;
const int IP_CONST_MELD_GORGON_MASK_THROAT = 13672;
const int IP_CONST_MELD_GORGON_MASK_TOTEM = 13673;
const int IP_CONST_MELD_INCARNATE_WEAPON_ARMS = 13674;
const int IP_CONST_MELD_KRENSHAR_MASK_TOTEM = 13675;
const int IP_CONST_MELD_LAMMASU_MANTLE_TOTEM = 13676;
const int IP_CONST_MELD_LANDSHARK_BOOTS_FEET = 13677;
const int IP_CONST_MELD_LANDSHARK_BOOTS_TOTEM = 13678;
const int IP_CONST_MELD_LIFEBOND_VESTMENTS_HEAL = 13679;
const int IP_CONST_MELD_LIFEBOND_VESTMENTS_ARMS = 13680;
const int IP_CONST_MELD_LIGHTNING_GAUNTLETS_ZAP = 13681;
const int IP_CONST_MELD_LIGHTNING_GAUNTLETS_HANDS = 13682;
const int IP_CONST_MELD_LUCKY_DICE_LUCK = 13683;
const int IP_CONST_MELD_MAGES_SPECTACLES_BROW = 13684;
const int IP_CONST_MELD_MANTICORE_TOTEM = 13685;
const int IP_CONST_MELD_MANTLE_OF_FLAME_SHOULDERS = 13686;
const int IP_CONST_MELD_PHOENIX_BELT_TOTEM = 13687;
const int IP_CONST_MELD_PLANAR_CHASUBLE_SOUL = 13688;
const int IP_CONST_MELD_SHADOW_MANTLE_SHOULDERS = 13689;
const int IP_CONST_MELD_SHEDU_CROWN_HEART = 13690;
const int IP_CONST_MELD_SILVERTONGUE_MASK_THROAT = 13691;
const int IP_CONST_MELD_UNICORN_HORN_BROW = 13692;
const int IP_CONST_MELD_WINTER_MASK_TOUCH = 13693;
const int IP_CONST_MELD_WINTER_MASK_THROAT = 13694;
const int IP_CONST_MELD_WORMTAIL_BELT_TOTEM = 13695;
const int IP_CONST_MELD_YRTHAK_MASK_BROW = 13696;
const int IP_CONST_MELD_YRTHAK_MASK_TOTEM = 13697;
const int IP_CONST_MELD_NECRO_CIRCLET_BROW = 13698;
const int IP_CONST_MELD_NECROCARNUM_SHROUD_SOUL = 13699;
const int IP_CONST_MELD_NECROCARNUM_TOUCH_ESS = 13700;
const int IP_CONST_MELD_NECROCARNUM_TOUCH_ARMS = 13701;
const int IP_CONST_MELD_SOULSPARK_FAMILIAR_ESS = 13702;
const int IP_CONST_MELD_BLADEMELD_SHOUT = 13703;
const int IP_CONST_MELD_PSIONS_EYES_BROW = 13704;
const int IP_CONST_MELD_PSIONKILLER_MASK_DETECT = 13705;
const int IP_CONST_MELD_PSIONKILLER_MASK_TOTEM = 13706;
const int IP_CONST_MELD_DRAGON_TAIL_SLAM = 13707;
const int IP_CONST_MELD_DRAGON_TAIL_SWEEP = 13708;
const int IP_CONST_MELD_DRAGONFIRE_MASK_THROAT = 13709;
const int IP_CONST_MELD_DRAGONFIRE_MASK_TOTEM = 13710;
// Radial SubSpell Constants
const int MELD_LUCKY_DICE_ATTACK = 18935;
const int MELD_LUCKY_DICE_SAVING_THROWS = 18936;
const int MELD_LUCKY_DICE_SKILLS = 18937;
const int MELD_SHADOW_MANTLE_SHOULDERS = 18943;
// Class Spell Constants
const int MELD_INCARNUM_RADIANCE = 18698;
const int MELD_SPINE_ENHANCEMENT = 18691;
const int MELD_IRONSOUL_SHIELD = 18687;
const int MELD_IRONSOUL_ARMOR = 18685;
const int MELD_IRONSOUL_WEAPON = 18683;
const int MELD_UMBRAL_STEP = 18681;
const int MELD_UMBRAL_SHADOW = 18679;
const int MELD_UMBRAL_SIGHT = 18677;
const int MELD_UMBRAL_SOUL = 18675;
const int MELD_UMBRAL_KISS = 18673;
const int MELD_INCANDESCENT_STRIKE = 18670;
const int MELD_INCANDESCENT_HEAL = 18668;
const int MELD_INCANDESCENT_COUNTENANCE = 18666;
const int MELD_INCANDESCENT_RAY = 18663;
const int MELD_INCANDESCENT_AURA = 18659;
const int MELD_BLADEMELD_CROWN = 18647;
const int MELD_BLADEMELD_FEET = 18648;
const int MELD_BLADEMELD_HANDS = 18649;
const int MELD_BLADEMELD_ARMS = 18650;
const int MELD_BLADEMELD_BROW = 18651;
const int MELD_BLADEMELD_SHOULDERS = 18652;
const int MELD_BLADEMELD_THROAT = 18653;
const int MELD_BLADEMELD_WAIST = 18654;
const int MELD_BLADEMELD_HEART = 18655;
const int MELD_BLADEMELD_SOUL = 18656;
const int MELD_WITCH_MELDSHIELD = 18634;
const int MELD_WITCH_DISPEL = 18636;
const int MELD_WITCH_SHACKLES = 18638;
const int MELD_WITCH_ABROGATION = 18640;
const int MELD_WITCH_SPIRITFLAY = 18642;
const int MELD_WITCH_INTEGUMENT = 18644;
// Race Spell Constants
const int MELD_DUSKLING_SPEED = 18973;
// Feat Spell Constants
const int MELD_OPEN_SOUL_CHAKRA = 18632;
// Bind spell Constants
const int MELD_DRAGON_TAIL_SWEEP = 18962;
// Essentia Conv
const int IP_CONST_FEAT_INVEST_ESSENTIA_CONV = 13549;

1193
src/include/nw_inc_nui.nss Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,475 @@
//::///////////////////////////////////////////////
//:: Name Lich
//:: FileName pnp_lich_inc
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/* Functions needed to handle the amulet, soul gem, and hide
*/
//:://////////////////////////////////////////////
//:: Created By: Shane Hennessy
//:: Created On:
//:://////////////////////////////////////////////
// Returns the lich amulet level
int GetAmuletLevel(object oAmulet);
// Sets the passed in amulet to nLevel
void LevelUpAmulet(object oAmulet,int nLevel);
// Returns the lich power level
int GetPowerLevel(object oHide);
// Sets the passed in hide on the PC to nLevel
void LevelUpHide(object oPC, object oHide, int nLevel);
// Creates some VFX on the object when crafting
void CraftVFX(object oObject);
#include "inc_utility"
#include "pnp_shft_main"
void LichSkills(object oHide, int iLevel)
{
SetCompositeBonus(oHide, "LichSkillHide", iLevel, ITEM_PROPERTY_SKILL_BONUS, SKILL_HIDE);
SetCompositeBonus(oHide, "LichSkillListen", iLevel, ITEM_PROPERTY_SKILL_BONUS, SKILL_LISTEN);
SetCompositeBonus(oHide, "LichSkillPersuade", iLevel, ITEM_PROPERTY_SKILL_BONUS, SKILL_PERSUADE);
SetCompositeBonus(oHide, "LichSkillSilent", iLevel, ITEM_PROPERTY_SKILL_BONUS, SKILL_MOVE_SILENTLY);
SetCompositeBonus(oHide, "LichSkillSearch", iLevel, ITEM_PROPERTY_SKILL_BONUS, SKILL_SEARCH);
SetCompositeBonus(oHide, "LichSkillSpot", iLevel, ITEM_PROPERTY_SKILL_BONUS, SKILL_SPOT);
}
int GetAmuletLevel(object oAmulet)
{
object oPC = GetFirstPC();
//SendMessageToPC(oPC,"Amulet level func");
itemproperty iProp = GetFirstItemProperty(oAmulet);
int nLevel = 0;
while (GetIsItemPropertyValid(iProp))
{
if (GetItemPropertyType(iProp) == ITEM_PROPERTY_AC_BONUS)
{
//SendMessageToPC(oPC," AC found");
int nAC = GetItemPropertyCostTableValue(iProp);
//SendMessageToPC(oPC, "AC = " + IntToString(nAC));
switch (nAC)
{
case 2:
return 1;
case 3:
return 2;
case 4:
return 3;
case 5:
// cant return because anything above has this AC 5 bonus
nLevel = 4;
break;
default:
return 0;
}
}
// for levels above 4 use a junk item like weight reduction
if (GetItemPropertyType(iProp) == ITEM_PROPERTY_BASE_ITEM_WEIGHT_REDUCTION)
{
int nWt = GetItemPropertyCostTableValue(iProp);
//SendMessageToPC(oPC, "wt = " + IntToString(nWt));
switch(nWt)
{
case IP_CONST_REDUCEDWEIGHT_10_PERCENT:
return 5;
case IP_CONST_REDUCEDWEIGHT_20_PERCENT:
return 6;
case IP_CONST_REDUCEDWEIGHT_40_PERCENT:
return 7;
case IP_CONST_REDUCEDWEIGHT_60_PERCENT:
return 8;
case IP_CONST_REDUCEDWEIGHT_80_PERCENT:
return 9;
default:
return 0;
}
}
// level 10 gets something special (we ran out of weight reduction)
if (GetItemPropertyType(iProp) == ITEM_PROPERTY_CAST_SPELL)
{
int nSpell = GetItemPropertySubType(iProp);
if (nSpell == IP_CONST_CASTSPELL_CREATE_GREATER_UNDEAD_18)
return 10;
}
iProp = GetNextItemProperty(oAmulet);
}
return nLevel;
}
int GetPowerLevel(object oPC)
{
return GetLocalInt(oPC, "PNP_LichPowerLevel");
}
void LevelUpHide(object oPC, object oHide, int nLevel)
{
itemproperty iprop;
// Clean the hide of all things that dont stack
// remember to put everything for every level back on!
// - Now the event scripts give us a new hide.
//RemoveAllNonComposite(oHide);
// Common things for being undead and a lich
if (nLevel >= 4)
{
// Ability bonus
//SetCompositeBonus(oHide, "LichCon", 12, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_CON);
IPSafeAddItemProperty(oHide, PRCItemPropertyBonusFeat(IP_CONST_FEAT_UNDEAD_HD), 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
// Undead abilities
iprop = ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_CRITICAL_HITS);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
iprop = ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_BACKSTAB);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
iprop = ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_DEATH_MAGIC);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
iprop = ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_DISEASE);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
iprop = ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_LEVEL_ABIL_DRAIN);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
iprop = ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_MINDSPELLS);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
iprop = ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_PARALYSIS);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
iprop = ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_POISON);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
// 100 % immune to cold
iprop = ItemPropertyDamageImmunity(IP_CONST_DAMAGETYPE_COLD,IP_CONST_DAMAGEIMMUNITY_100_PERCENT);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
// 100 % immune to electric
iprop = ItemPropertyDamageImmunity(IP_CONST_DAMAGETYPE_ELECTRICAL,IP_CONST_DAMAGEIMMUNITY_100_PERCENT);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
// Bugfix
iprop = ItemPropertyDamageImmunity(IP_CONST_DAMAGETYPE_NEGATIVE, IP_CONST_DAMAGEIMMUNITY_100_PERCENT);
IPSafeAddItemProperty(oHide, iprop, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
}
// Level 1 hide
if (nLevel == 1)
{
// Ability bonus
//SetCompositeBonus(oHide, "LichInt", 2, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_INT);
// Turn resistance
SetCompositeBonus(oHide, "LichTurn", 1, ITEM_PROPERTY_TURN_RESISTANCE);
//Lich skills +2
LichSkills(oHide, 2);
//Damage reduction 5/- cold
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_COLD,IP_CONST_DAMAGERESIST_5);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
//Damage reduction 5/- electric
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_ELECTRICAL,IP_CONST_DAMAGERESIST_5);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
}
// Level 2
else if (nLevel == 2)
{
// Ability bonus
//SetCompositeBonus(oHide, "LichInt", 2, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_INT);
// Turn resistance
SetCompositeBonus(oHide, "LichTurn", 2, ITEM_PROPERTY_TURN_RESISTANCE);
//Lich skills +4
LichSkills(oHide, 4);
//Damage reduction 5/+1
iprop = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_1,IP_CONST_DAMAGESOAK_5_HP);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
//Damage reduction 10/- cold
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_COLD,IP_CONST_DAMAGERESIST_10);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
//Damage reduction 10/- electric
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_ELECTRICAL,IP_CONST_DAMAGERESIST_10);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
}
else if (nLevel == 3)
{
// Ability bonus
//SetCompositeBonus(oHide, "LichInt", 2, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_INT);
//SetCompositeBonus(oHide, "LichWis", 2, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_WIS);
// Turn resistance
SetCompositeBonus(oHide, "LichTurn", 3, ITEM_PROPERTY_TURN_RESISTANCE);
//Lich skills +6
LichSkills(oHide, 6);
//Damage reduction 10/1
iprop = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_1,IP_CONST_DAMAGESOAK_10_HP);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
//Damage reduction 20/- cold
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_COLD,IP_CONST_DAMAGERESIST_20);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
//Damage reduction 20/- electric
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_ELECTRICAL,IP_CONST_DAMAGERESIST_20);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
}
else if (nLevel == 4)
{
// Ability bonus
//SetCompositeBonus(oHide, "LichInt", 2, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_INT);
//SetCompositeBonus(oHide, "LichWis", 2, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_WIS);
//SetCompositeBonus(oHide, "LichCha", 2, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_CHA);
// Turn resistance
SetCompositeBonus(oHide, "LichTurn", 4, ITEM_PROPERTY_TURN_RESISTANCE);
//Lich skills +8
LichSkills(oHide, 8);
//Damage reduction 15/1
iprop = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_1,IP_CONST_DAMAGESOAK_15_HP);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
}
else if (nLevel == 5)
{
// Ability bonus
//SetCompositeBonus(oHide, "LichInt", 3, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_INT);
//SetCompositeBonus(oHide, "LichWis", 3, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_WIS);
//SetCompositeBonus(oHide, "LichCha", 3, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_CHA);
// Turn resistance
SetCompositeBonus(oHide, "LichTurn", 5, ITEM_PROPERTY_TURN_RESISTANCE);
//Lich skills +10
LichSkills(oHide, 10);
//Damage reduction 5/+5
iprop = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_5,IP_CONST_DAMAGESOAK_5_HP);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
//Damage reduction 5/- ACID
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_ACID,IP_CONST_DAMAGERESIST_5);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
//Damage reduction 5/- fire
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_FIRE,IP_CONST_DAMAGERESIST_5);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
//Damage reduction 5/- sonic
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_SONIC,IP_CONST_DAMAGERESIST_5);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
// Spell level immune to 1 and lower
iprop = ItemPropertyImmunityToSpellLevel(1);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
}
else if (nLevel == 6)
{
// Ability bonus
//SetCompositeBonus(oHide, "LichInt", 4, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_INT);
//SetCompositeBonus(oHide, "LichWis", 4, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_WIS);
//SetCompositeBonus(oHide, "LichCha", 4, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_CHA);
// Turn resistance
SetCompositeBonus(oHide, "LichTurn", 8, ITEM_PROPERTY_TURN_RESISTANCE);
//Lich skills +12
LichSkills(oHide, 12);
//Damage reduction 10/+8
iprop = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_8,IP_CONST_DAMAGESOAK_10_HP);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
//Damage reduction 10/- ACID
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_ACID,IP_CONST_DAMAGERESIST_10);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
//Damage reduction 10/- fire
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_FIRE,IP_CONST_DAMAGERESIST_10);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
//Damage reduction 10/- sonic
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_SONIC,IP_CONST_DAMAGERESIST_10);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
// Spell level immune to 3 and lower
iprop = ItemPropertyImmunityToSpellLevel(3);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
}
else if (nLevel == 7)
{
// Ability bonus
//SetCompositeBonus(oHide, "LichInt", 6, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_INT);
//SetCompositeBonus(oHide, "LichWis", 6, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_WIS);
//SetCompositeBonus(oHide, "LichCha", 6, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_CHA);
// Turn resistance
SetCompositeBonus(oHide, "LichTurn", 11, ITEM_PROPERTY_TURN_RESISTANCE);
//Lich skills +14
LichSkills(oHide, 14);
//Damage reduction 15/+11
iprop = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_11,IP_CONST_DAMAGESOAK_15_HP);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
//Damage reduction 10/- ACID
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_ACID,IP_CONST_DAMAGERESIST_10);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
//Damage reduction 10/- fire
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_FIRE,IP_CONST_DAMAGERESIST_10);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
//Damage reduction 10/- sonic
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_SONIC,IP_CONST_DAMAGERESIST_10);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
// Spell level immune to 5 and lower
iprop = ItemPropertyImmunityToSpellLevel(5);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
}
else if (nLevel == 8)
{
// Ability bonus
//SetCompositeBonus(oHide, "LichInt", 7, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_INT);
//SetCompositeBonus(oHide, "LichWis", 7, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_WIS);
//SetCompositeBonus(oHide, "LichCha", 7, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_CHA);
// Turn resistance
SetCompositeBonus(oHide, "LichTurn", 14, ITEM_PROPERTY_TURN_RESISTANCE);
//Lich skills +16
LichSkills(oHide, 16);
//Damage reduction 20/+14
iprop = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_14,IP_CONST_DAMAGESOAK_20_HP);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
//Damage reduction 15/- ACID
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_ACID,IP_CONST_DAMAGERESIST_15);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
//Damage reduction 15/- fire
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_FIRE,IP_CONST_DAMAGERESIST_15);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
//Damage reduction 15/- sonic
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_SONIC,IP_CONST_DAMAGERESIST_15);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
// Spell level immune to 7 and lower
iprop = ItemPropertyImmunityToSpellLevel(7);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
}
else if (nLevel == 9)
{
// Ability bonus
//SetCompositeBonus(oHide, "LichInt", 8, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_INT);
//SetCompositeBonus(oHide, "LichWis", 8, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_WIS);
//SetCompositeBonus(oHide, "LichCha", 8, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_CHA);
// Turn resistance
SetCompositeBonus(oHide, "LichTurn", 17, ITEM_PROPERTY_TURN_RESISTANCE);
//Lich skills +18
LichSkills(oHide, 18);
//Damage reduction 25/+17
iprop = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_17,IP_CONST_DAMAGESOAK_25_HP);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
//Damage reduction 15/- ACID
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_ACID,IP_CONST_DAMAGERESIST_15);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
//Damage reduction 15/- fire
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_FIRE,IP_CONST_DAMAGERESIST_15);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
//Damage reduction 15/- sonic
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_SONIC,IP_CONST_DAMAGERESIST_15);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
// Spell level immune to 8 and lower
iprop = ItemPropertyImmunityToSpellLevel(8);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
}
else if (nLevel == 10)
{
// Ability bonus
//SetCompositeBonus(oHide, "LichInt", 10, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_INT);
//SetCompositeBonus(oHide, "LichWis", 10, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_WIS);
//SetCompositeBonus(oHide, "LichCha", 10, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_CHA);
// Turn resistance
SetCompositeBonus(oHide, "LichTurn", 20, ITEM_PROPERTY_TURN_RESISTANCE);
//Lich skills +20
LichSkills(oHide, 20);
//Damage reduction 30/+20
iprop = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_20,IP_CONST_DAMAGESOAK_30_HP);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
//Damage reduction 20/- ACID
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_ACID,IP_CONST_DAMAGERESIST_20);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
//Damage reduction 20/- fire
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_FIRE,IP_CONST_DAMAGERESIST_20);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
//Damage reduction 20/- sonic
iprop = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_SONIC,IP_CONST_DAMAGERESIST_20);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
// Spell level immune to 9 and lower
iprop = ItemPropertyImmunityToSpellLevel(9);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oHide);
}
SetLocalInt(oPC, "PNP_LichPowerLevel", nLevel);
}
void LevelUpAmulet(object oAmulet,int nLevel)
{
RemoveAllItemProperties(oAmulet);
itemproperty iprop;
// Common level 4 and above things
if (nLevel >= 4)
{
// Ac bonus
iprop = ItemPropertyACBonus(5);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oAmulet);
// Extra so the amulet is useful til 20th level
iprop = ItemPropertyRegeneration(1);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oAmulet);
iprop = ItemPropertyCastSpell(IP_CONST_CASTSPELL_ANIMATE_DEAD_15,IP_CONST_CASTSPELL_NUMUSES_UNLIMITED_USE);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oAmulet);
iprop = PRCItemPropertyBonusFeat(IP_CONST_FEAT_SPELLFOCUSNEC);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oAmulet);
}
// Level 2
if (nLevel == 2)
{
// Ac bonus
iprop = ItemPropertyACBonus(3);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oAmulet);
}
else if (nLevel == 3)
{
// Ac bonus
iprop = ItemPropertyACBonus(4);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oAmulet);
}
else if (nLevel == 4)
{
// nothing
}
else if (nLevel == 5)
{
// reduction is used to permenantly track how much the PC has paid for level ups
// because reduction of 1/2 lb is nothing usefull
iprop = ItemPropertyWeightReduction(IP_CONST_REDUCEDWEIGHT_10_PERCENT);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oAmulet);
}
else if (nLevel == 6)
{
iprop = ItemPropertyWeightReduction(IP_CONST_REDUCEDWEIGHT_20_PERCENT);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oAmulet);
}
else if (nLevel == 7)
{
iprop = ItemPropertyWeightReduction(IP_CONST_REDUCEDWEIGHT_40_PERCENT);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oAmulet);
}
else if (nLevel == 8)
{
iprop = ItemPropertyWeightReduction(IP_CONST_REDUCEDWEIGHT_60_PERCENT);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oAmulet);
}
else if (nLevel == 9)
{
iprop = ItemPropertyWeightReduction(IP_CONST_REDUCEDWEIGHT_80_PERCENT);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oAmulet);
}
else if (nLevel == 10)
{
iprop = ItemPropertyCastSpell(IP_CONST_CASTSPELL_CREATE_GREATER_UNDEAD_18,IP_CONST_CASTSPELL_NUMUSES_UNLIMITED_USE);
AddItemProperty(DURATION_TYPE_PERMANENT,iprop,oAmulet);
}
}
void CraftVFX(object oObject)
{
effect eFx = EffectVisualEffect(VFX_FNF_GAS_EXPLOSION_EVIL);
ApplyEffectToObject(DURATION_TYPE_INSTANT,eFx,oObject,3.0);
eFx = EffectVisualEffect(VFX_FNF_LOS_EVIL_30);
ApplyEffectToObject(DURATION_TYPE_INSTANT,eFx,oObject, 4.0);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,249 @@
// Used to polymorph characters to lycanthrope shapes
// Merges Weapons, Armors, Items if told to by 2da.
// - object oPC: Player to Polymorph
// - int nPoly: POLYMORPH_TYPE_* Constant
void LycanthropePoly(object oPC, int nPoly);
void DoDisguise(int nRace, object oTarget = OBJECT_SELF);
void ShifterCheck(object oPC);
#include "pnp_shft_main"
#include "prc_inc_shifting"
const string PRC_PNP_SHIFTING = "PRC_Shift";
////////////////Begin Werewolf//////////////////
void LycanthropePoly(object oPC, int nPoly)
{
effect eVis = EffectVisualEffect(VFX_IMP_POLYMORPH);
effect ePoly;
ePoly = EffectPolymorph(nPoly);
ePoly = SupernaturalEffect(ePoly);
int bWeapon = StringToInt(Get2DACache("polymorph","MergeW",nPoly)) == 1;
int bArmor = StringToInt(Get2DACache("polymorph","MergeA",nPoly)) == 1;
int bItems = StringToInt(Get2DACache("polymorph","MergeI",nPoly)) == 1;
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 oShield = GetItemInSlot(INVENTORY_SLOT_LEFTHAND,oPC);
if (GetIsObjectValid(oShield))
{
if (GetBaseItemType(oShield) !=BASE_ITEM_LARGESHIELD &&
GetBaseItemType(oShield) !=BASE_ITEM_SMALLSHIELD &&
GetBaseItemType(oShield) !=BASE_ITEM_TOWERSHIELD)
{
oShield = OBJECT_INVALID;
}
}
//check if a shifter and if shifted then unshift
ShifterCheck(oPC);
ClearAllActions(); // prevents an exploit
//Apply the VFX impact and effects
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oPC);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, ePoly, oPC);
object oWeaponNewRight = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R,oPC);
object oWeaponNewLeft = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L,oPC);
object oWeaponNewBite = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B,oPC);
object oArmorNew = GetItemInSlot(INVENTORY_SLOT_CARMOUR,oPC);
if (bWeapon)
{
IPWildShapeCopyItemProperties(oWeaponOld,oWeaponNewLeft, TRUE);
IPWildShapeCopyItemProperties(oWeaponOld,oWeaponNewRight, TRUE);
IPWildShapeCopyItemProperties(oWeaponOld,oWeaponNewBite, TRUE);
}
if (bArmor)
{
IPWildShapeCopyItemProperties(oShield,oArmorNew);
IPWildShapeCopyItemProperties(oHelmetOld,oArmorNew);
IPWildShapeCopyItemProperties(oArmorOld,oArmorNew);
}
if (bItems)
{
IPWildShapeCopyItemProperties(oRing1Old,oArmorNew);
IPWildShapeCopyItemProperties(oRing2Old,oArmorNew);
IPWildShapeCopyItemProperties(oAmuletOld,oArmorNew);
IPWildShapeCopyItemProperties(oCloakOld,oArmorNew);
IPWildShapeCopyItemProperties(oBootsOld,oArmorNew);
IPWildShapeCopyItemProperties(oBeltOld,oArmorNew);
}
}
////////////////End Werewolf//////////////////
void ShifterCheck(object oPC)
{
if (!GetIsPC(oPC))
return;
//int iShifterLevels = GetLevelByClass(CLASS_TYPE_PNP_SHIFTER,oPC);
//if (iShifterLevels>0)
//{
int iTemp = GetPersistantLocalInt(oPC,"nPCShifted");
if (iTemp)
{
DoDebug("ShifterCheck(): calling UnShift()");
//SetShiftTrueForm(oPC);
UnShift(oPC, TRUE);
}
//}
}
//changes portrait, head, and appearance
//based on the target race with a degree of randomization.
void DoDisguise(int nRace, object oTarget = OBJECT_SELF)
{
//store current appearance to be safe
StoreAppearance(oTarget);
int nAppearance; //appearance to change into
int nHeadMax; //max head ID, changed to random 1-max
int nGender = GetGender(oTarget);
int nPortraitMin;//minimum row in portraits.2da
int nPortraitMax;//maximum row in portraits.2da
switch(nRace)
{
case RACIAL_TYPE_DWARF:
nAppearance = APPEARANCE_TYPE_DWARF;
if(nGender == GENDER_MALE)
{ nHeadMax = 10; nPortraitMin = 9; nPortraitMax = 17; }
else
{ nHeadMax = 12; nPortraitMin = 1; nPortraitMax = 8; }
break;
case RACIAL_TYPE_ELF:
nAppearance = APPEARANCE_TYPE_ELF;
if(nGender == GENDER_MALE)
{ nHeadMax = 10; nPortraitMin = 31; nPortraitMax = 40; }
else
{ nHeadMax = 16; nPortraitMin = 18; nPortraitMax = 30; }
break;
case RACIAL_TYPE_HALFELF:
nAppearance = APPEARANCE_TYPE_HALF_ELF;
if(nGender == GENDER_MALE)
{ nHeadMax = 18; nPortraitMin = 93; nPortraitMax = 112; }
else
{ nHeadMax = 15; nPortraitMin = 67; nPortraitMax = 92; }
break;
case RACIAL_TYPE_HALFORC:
nAppearance = APPEARANCE_TYPE_HALF_ORC;
if(nGender == GENDER_MALE)
{ nHeadMax = 11; nPortraitMin = 134; nPortraitMax = 139; }
else
{ nHeadMax = 1; nPortraitMin = 130; nPortraitMax = 133; }
break;
case RACIAL_TYPE_HUMAN:
nAppearance = APPEARANCE_TYPE_HUMAN;
if(nGender == GENDER_MALE)
{ nHeadMax = 18; nPortraitMin = 93; nPortraitMax = 112; }
else
{ nHeadMax = 15; nPortraitMin = 67; nPortraitMax = 92; }
break;
case RACIAL_TYPE_HALFLING:
nAppearance = APPEARANCE_TYPE_HALFLING;
if(nGender == GENDER_MALE)
{ nHeadMax = 8; nPortraitMin = 61; nPortraitMax = 66; }
else
{ nHeadMax = 11; nPortraitMin = 54; nPortraitMax = 59; }
break;
case RACIAL_TYPE_GNOME:
nAppearance = APPEARANCE_TYPE_GNOME;
if(nGender == GENDER_MALE)
{ nHeadMax = 11; nPortraitMin = 47; nPortraitMax = 53; }
else
{ nHeadMax = 9; nPortraitMin = 41; nPortraitMax = 46; }
break;
default: //not a normal race, abort
return;
}
//change the appearance
SetCreatureAppearanceType(oTarget, nAppearance);
//need to be delayed a bit otherwise you get "supergnome" and "exploded elf" effects
DelayCommand(1.1, SetCreatureBodyPart(CREATURE_PART_RIGHT_SHIN, d2(), oTarget));
DelayCommand(1.2, SetCreatureBodyPart(CREATURE_PART_LEFT_SHIN, d2(), oTarget));
DelayCommand(1.3, SetCreatureBodyPart(CREATURE_PART_RIGHT_THIGH, d2(), oTarget));
DelayCommand(1.4, SetCreatureBodyPart(CREATURE_PART_LEFT_THIGH, d2(), oTarget));
DelayCommand(1.5, SetCreatureBodyPart(CREATURE_PART_TORSO, d2(), oTarget));
DelayCommand(1.6, SetCreatureBodyPart(CREATURE_PART_RIGHT_FOREARM, d2(), oTarget));
DelayCommand(1.7, SetCreatureBodyPart(CREATURE_PART_LEFT_FOREARM, d2(), oTarget));
DelayCommand(1.8, SetCreatureBodyPart(CREATURE_PART_RIGHT_BICEP, d2(), oTarget));
DelayCommand(1.9, SetCreatureBodyPart(CREATURE_PART_LEFT_BICEP, d2(), oTarget));
//dont do these body parts, they dont have tattoos and weird things could happen
//SetCreatureBodyPart(CREATURE_PART_BELT, d2(), oTarget);
//SetCreatureBodyPart(CREATURE_PART_NECK, d2(), oTarget);
//SetCreatureBodyPart(CREATURE_PART_RIGHT_SHOULDER, d2(), oTarget);
//SetCreatureBodyPart(CREATURE_PART_LEFT_SHOULDER, d2(), oTarget);
//SetCreatureBodyPart(CREATURE_PART_RIGHT_HAND, d2(), oTarget);
//SetCreatureBodyPart(CREATURE_PART_LEFT_HAND, d2(), oTarget);
//SetCreatureBodyPart(CREATURE_PART_PELVIS, d2(), oTarget);
//SetCreatureBodyPart(CREATURE_PART_RIGHT_FOOT, d2(), oTarget);
//SetCreatureBodyPart(CREATURE_PART_LEFT_FOOT, d2(), oTarget);
//randomise the head
DelayCommand(2.0, SetCreatureBodyPart(CREATURE_PART_HEAD, Random(nHeadMax)+1, oTarget));
//remove any wings/tails
SetCreatureWingType(CREATURE_WING_TYPE_NONE, oTarget);
SetCreatureTailType(CREATURE_TAIL_TYPE_NONE, oTarget);
int nPortraitID = Random(nPortraitMax-nPortraitMin+1)+nPortraitMin;
string sPortraitResRef = Get2DACache("portraits", "BaseResRef", nPortraitID);
sPortraitResRef = GetStringLeft(sPortraitResRef, GetStringLength(sPortraitResRef)-1); //trim the trailing _
SetPortraitResRef(oTarget, sPortraitResRef);
SetPortraitId(oTarget, nPortraitID);
}
//utility functions to make sure characters that gain wings/tails permanently
//interact with the polymorph system by overwriting the default form
void DoWings(object oPC, int nWingType)
{
//wing invalid, abort
if(nWingType <= 0)
return;
//already has wings, keep them
if(GetCreatureWingType(oPC) != CREATURE_WING_TYPE_NONE)
return;
//already has a default wings, keep them
if(GetPersistantLocalInt(oPC, "AppearanceStoredWing"))
return;
//if polymorphed or shifted, dont do the real change
if(!GetIsPolyMorphedOrShifted(oPC))
SetCreatureWingType(nWingType, oPC);
//override any stored default appearance
SetPersistantLocalInt(oPC, "AppearanceStoredWing", nWingType);
}
void DoTail(object oPC, int nTailType)
{
//tail invalid, use current
if(nTailType == -1)
return;
//already has tail, keep it
if(GetCreatureTailType(oPC))
return;
//already has a default tail, keep it
if(GetPersistantLocalInt(oPC, "AppearanceStoredTail"))
return;
//if polymorphed or shifted, dont do the real change
if(!GetIsPolyMorphedOrShifted(oPC))
SetCreatureTailType(nTailType, oPC);
//override any stored default appearance
SetPersistantLocalInt(oPC, "AppearanceStoredTail", nTailType);
}

View File

@@ -0,0 +1,788 @@
// Get the DC to save against for a spell (10 + spell level + relevant ability
// bonus). This can be called by a creature or by an Area of Effect object.
// Takes into account PRC classes
int PRCGetSpellSaveDC(int nSpellID = -1, int nSchool = -1, object oCaster = OBJECT_SELF);
// Use this function to get the adjustments to a spell or SLAs saving throw
// from the various class effects
// Update this function if any new classes change saving throws
int PRCGetSaveDC(object oTarget, object oCaster, int nSpellID = -1);
//called just from above and from inc_epicspells
int GetChangesToSaveDC(object oTarget, object oCaster, int nSpellID, int nSchool);
#include "prc_add_spl_pen"
// #include "prc_inc_spells"
// #include "prc_class_const"
// #include "prc_feat_const"
// #include "lookup_2da_spell"
// #include "prcsp_archmaginc"
// #include "prc_alterations"
// #include "prc_inc_racial"
#include "inc_newspellbook"
int GetCorruptSpellFocus(int nSpellID, object oCaster)
{
int nCorrupt = FALSE;
if(nSpellID == SPELL_ABSORB_STRENGTH
|| nSpellID == SPELL_APOCALYPSE_FROM_THE_SKY
|| nSpellID == SPELL_CLAWS_OF_THE_BEBILITH
|| nSpellID == SPELL_DEATH_BY_THORNS
|| nSpellID == SPELL_EVIL_WEATHER
|| nSpellID == SPELL_FANGS_OF_THE_VAMPIRE_KING
|| nSpellID == SPELL_LAHMS_FINGER_DARTS
|| nSpellID == SPELL_POWER_LEECH
|| nSpellID == SPELL_RAPTURE_OF_RUPTURE
|| nSpellID == SPELL_RED_FESTER
|| nSpellID == SPELL_ROTTING_CURSE_OF_URFESTRA
|| nSpellID == SPELL_SEETHING_EYEBANE
|| nSpellID == SPELL_TOUCH_OF_JUIBLEX)
nCorrupt = TRUE;
if (GetHasFeat(FEAT_GREATER_CORRUPT_SPELL_FOCUS, oCaster) && nCorrupt) return 2;
else if (GetHasFeat(FEAT_CORRUPT_SPELL_FOCUS, oCaster) && nCorrupt) return 1;
return 0;
}
int GetHeartWarderDC(int spell_id, int nSchool, object oCaster)
{
// Check the curent school
if(nSchool != SPELL_SCHOOL_ENCHANTMENT)
return 0;
if(!GetHasFeat(FEAT_VOICE_SIREN, oCaster))
return 0;
// Bonus Requires Verbal Spells
string VS = GetStringLowerCase(Get2DACache("spells", "VS",spell_id));
if(FindSubString(VS, "v") == -1)
return 0;
// These feats provide greater bonuses or remove the Verbal requirement
if(PRCGetMetaMagicFeat(oCaster, FALSE) & METAMAGIC_SILENT
|| GetHasFeat(FEAT_GREATER_SPELL_FOCUS_ENCHANTMENT, oCaster)
|| GetHasFeat(FEAT_EPIC_SPELL_FOCUS_ENCHANTMENT, oCaster))
return 0;
return 2;
}
//Elemental Savant DC boost based on elemental spell type.
int ElementalSavantDC(int spell_id, int nElement, object oCaster)
{
int nDC = 0;
// All Elemental Savants will have this feat
// when they first gain a DC bonus.
if(GetHasFeat(FEAT_ES_FOCUS_1, oCaster))
{
// Any value that does not match one of the enumerated feats
int feat, nES;
nES = GetLevelByClass(CLASS_TYPE_ELEMENTAL_SAVANT, oCaster);
// Specify the elemental type rather than lookup by class?
if(nElement & DESCRIPTOR_FIRE)
{
feat = FEAT_ES_FIRE;
}
else if(nElement & DESCRIPTOR_COLD)
{
feat = FEAT_ES_COLD;
}
else if(nElement & DESCRIPTOR_ELECTRICITY)
{
feat = FEAT_ES_ELEC;
}
else if(nElement & DESCRIPTOR_ACID)
{
feat = FEAT_ES_ACID;
}
// Now determine the bonus
if(feat && GetHasFeat(feat, oCaster))
nDC = (nES + 1) / 3;
}
// SendMessageToPC(GetFirstPC(), "Your Elemental Focus modifier is " + IntToString(nDC));
return nDC;
}
// This does other spell focus feats, starting with Spell Focus: Cold
int SpellFocus(int nSpellId, int nElement, object oCaster)
{
int nDC = 0;
// Specify the elemental type
if(nElement & DESCRIPTOR_COLD)
{
if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_COLD, oCaster))
nDC += 2;
else if(GetHasFeat(FEAT_SPELL_FOCUS_COLD, oCaster))
nDC += 1;
}
if (GetHasDescriptor(nSpellId, DESCRIPTOR_CHAOTIC) && GetHasFeat(FEAT_SPELL_FOCUS_CHAOS, oCaster)) nDC += 1;
if (GetHasDescriptor(nSpellId, DESCRIPTOR_EVIL) && GetHasFeat(FEAT_SPELL_FOCUS_EVIL, oCaster)) nDC += 1;
if (GetHasDescriptor(nSpellId, DESCRIPTOR_GOOD) && GetHasFeat(FEAT_SPELL_FOCUS_GOOD, oCaster)) nDC += 1;
if (GetHasDescriptor(nSpellId, DESCRIPTOR_LAWFUL) && GetHasFeat(FEAT_SPELL_FOCUS_LAWFUL, oCaster)) nDC += 1;
return nDC;
}
//Red Wizard DC boost based on spell school specialization
int RedWizardDC(int spell_id, int nSchool, object oCaster)
{
int iRedWizard = GetLevelByClass(CLASS_TYPE_RED_WIZARD, oCaster);
int nDC;
if(iRedWizard)
{
int iRWSpec;
switch(nSchool)
{
case SPELL_SCHOOL_ABJURATION: iRWSpec = FEAT_RW_TF_ABJ; break;
case SPELL_SCHOOL_CONJURATION: iRWSpec = FEAT_RW_TF_CON; break;
case SPELL_SCHOOL_DIVINATION: iRWSpec = FEAT_RW_TF_DIV; break;
case SPELL_SCHOOL_ENCHANTMENT: iRWSpec = FEAT_RW_TF_ENC; break;
case SPELL_SCHOOL_EVOCATION: iRWSpec = FEAT_RW_TF_EVO; break;
case SPELL_SCHOOL_ILLUSION: iRWSpec = FEAT_RW_TF_ILL; break;
case SPELL_SCHOOL_NECROMANCY: iRWSpec = FEAT_RW_TF_NEC; break;
case SPELL_SCHOOL_TRANSMUTATION: iRWSpec = FEAT_RW_TF_TRS; break;
}
if(iRWSpec && GetHasFeat(iRWSpec, oCaster))
nDC = iRedWizard / 2;
}
// SendMessageToPC(GetFirstPC(), "Your Spell Power modifier is " + IntToString(nDC));
return nDC;
}
//Red Wizards recieve a bonus against their specialist schools
// this is done by lowering the DC of spells cast against them
int RedWizardDCPenalty(int spell_id, int nSchool, object oTarget)
{
int nDC;
int iRW = GetLevelByClass(CLASS_TYPE_RED_WIZARD, oTarget);
if(iRW)
{
int iRWSpec;
switch(nSchool)
{
case SPELL_SCHOOL_ABJURATION: iRWSpec = FEAT_RW_TF_ABJ; break;
case SPELL_SCHOOL_CONJURATION: iRWSpec = FEAT_RW_TF_CON; break;
case SPELL_SCHOOL_DIVINATION: iRWSpec = FEAT_RW_TF_DIV; break;
case SPELL_SCHOOL_ENCHANTMENT: iRWSpec = FEAT_RW_TF_ENC; break;
case SPELL_SCHOOL_EVOCATION: iRWSpec = FEAT_RW_TF_EVO; break;
case SPELL_SCHOOL_ILLUSION: iRWSpec = FEAT_RW_TF_ILL; break;
case SPELL_SCHOOL_NECROMANCY: iRWSpec = FEAT_RW_TF_NEC; break;
case SPELL_SCHOOL_TRANSMUTATION: iRWSpec = FEAT_RW_TF_TRS; break;
}
if(iRWSpec && GetHasFeat(iRWSpec, oTarget))
nDC -= iRW > 4 ? (iRW - 1) / 2 : (iRW + 1) / 2;
}
return nDC;
}
int ShadowAdeptDCPenalty(int spell_id, int nSchool, object oTarget)
{
int nDC;
int iShadow = GetLevelByClass(CLASS_TYPE_SHADOW_ADEPT, oTarget);
if(iShadow)
{
if(nSchool == SPELL_SCHOOL_ENCHANTMENT
|| nSchool == SPELL_SCHOOL_NECROMANCY
|| nSchool == SPELL_SCHOOL_ILLUSION)
{
nDC -= (iShadow + 1) / 3;
}
//SendMessageToPC(GetFirstPC(), "Your Spell Save modifier is " + IntToString(nDC));
}
return nDC;
}
//Tattoo Focus DC boost based on spell school specialization
int TattooFocus(int spell_id, int nSchool, object oCaster)
{
int nDC;
int iRWSpec;
switch(nSchool)
{
case SPELL_SCHOOL_ABJURATION: iRWSpec = FEAT_RW_TF_ABJ; break;
case SPELL_SCHOOL_CONJURATION: iRWSpec = FEAT_RW_TF_CON; break;
case SPELL_SCHOOL_DIVINATION: iRWSpec = FEAT_RW_TF_DIV; break;
case SPELL_SCHOOL_ENCHANTMENT: iRWSpec = FEAT_RW_TF_ENC; break;
case SPELL_SCHOOL_EVOCATION: iRWSpec = FEAT_RW_TF_EVO; break;
case SPELL_SCHOOL_ILLUSION: iRWSpec = FEAT_RW_TF_ILL; break;
case SPELL_SCHOOL_NECROMANCY: iRWSpec = FEAT_RW_TF_NEC; break;
case SPELL_SCHOOL_TRANSMUTATION: iRWSpec = FEAT_RW_TF_TRS; break;
}
if(iRWSpec && GetHasFeat(iRWSpec, oCaster))
nDC = 1;
return nDC;
}
//:: Jaebrins get a +1 to Enchantment spells.
int JaebrinEnchant(int nSchool, object oCaster)
{
int nDC;
if(nSchool == SPELL_SCHOOL_ENCHANTMENT && GetRacialType(oCaster) == RACIAL_TYPE_JAEBRIN)
nDC = 1;
return nDC;
}
int ShadowWeaveDC(int spell_id, int nSchool, object oCaster)
{
// Account for the Shadow Weave feat
int nDC = ShadowWeave(oCaster, spell_id, nSchool) == 1;
// Account for Shadow Adept levels
int iShadow = GetLevelByClass(CLASS_TYPE_SHADOW_ADEPT, oCaster);
if(iShadow && nDC)
// Shadow Spell Power
nDC += iShadow / 3;
return nDC;
}
int KOTCSpellFocusVsDemons(object oTarget, object oCaster)
{
if(GetLevelByClass(CLASS_TYPE_KNIGHT_CHALICE, oCaster) >= 1)
{
if(MyPRCGetRacialType(oTarget) == RACIAL_TYPE_OUTSIDER)
{
if(GetAlignmentGoodEvil(oTarget) == ALIGNMENT_EVIL)
{
return 2;
}
}
}
return 0;
}
int BloodMagusBloodComponent(object oCaster)
{
int nDC = 0;
if (GetLevelByClass(CLASS_TYPE_BLOOD_MAGUS, oCaster) > 0 && GetLocalInt(oCaster, "BloodComponent") == TRUE)
{
nDC = 1;
effect eSelfDamage = EffectDamage(1, DAMAGE_TYPE_MAGICAL);
// To make sure it doesn't cause a conc check
DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eSelfDamage, oCaster));
}
return nDC;
}
int RunecasterRunePowerDC(object oCaster)
{
int nDC;
if(GetHasSpellEffect(SPELL_RUNE_CHANT))
{
int nClass = GetLevelByClass(CLASS_TYPE_RUNECASTER, oCaster);
if (nClass >= 30) nDC = 10;
else if (nClass >= 27) nDC = 9;
else if (nClass >= 24) nDC = 8;
else if (nClass >= 21) nDC = 7;
else if (nClass >= 18) nDC = 6;
else if (nClass >= 15) nDC = 5;
else if (nClass >= 12) nDC = 4;
else if (nClass >= 9) nDC = 3;
else if (nClass >= 5) nDC = 2;
else if (nClass >= 2) nDC = 1;
}
return nDC;
}
//Unheavened spell
int UnheavenedAdjustment(object oTarget, object oCaster)
{
if(GetHasSpellEffect(SPELL_UNHEAVENED, oTarget))
{
if((MyPRCGetRacialType(oCaster) == RACIAL_TYPE_OUTSIDER) && (GetAlignmentGoodEvil(oCaster) == ALIGNMENT_GOOD))
{
return -4;
}
}
return 0;
}
// Soul Eater's 10th level Soul Power ability. If they've drained in the last 24h, they get +2 to DCs
int SoulEaterSoulPower(object oCaster)
{
return (GetLocalInt(oCaster, "PRC_SoulEater_HasDrained") && GetLevelByClass(CLASS_TYPE_SOUL_EATER, oCaster) >= 10) ? 2 : 0;
}
//:: Saint Template gets a +2 DC on all spells, powers & abilites.
int SaintHolySpellPower(object oCaster)
{
if(GetHasFeat(FEAT_TEMPLATE_SAINT_HOLY_POWER, oCaster))
{
if (GetAlignmentGoodEvil(oCaster) == ALIGNMENT_GOOD)
{
return 2;
}
else
{
return 0;
}
}
//:: If it gets here, the caster does not have the feat
return 0;
}
//Draconic Power's elemental boost to spell DCs
int DraconicPowerDC(int spell_id, int nElement, object oCaster)
{
if(GetHasFeat(FEAT_DRACONIC_POWER, oCaster))
{
// Compare heritage type and elemental type
if(nElement & DESCRIPTOR_FIRE)
{
if(GetHasFeat(FEAT_DRACONIC_HERITAGE_BS, oCaster)
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_GD, oCaster)
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_RD, oCaster))
return 1;
}
else if(nElement & DESCRIPTOR_COLD)
{
if(GetHasFeat(FEAT_DRACONIC_HERITAGE_CR, oCaster)
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_SR, oCaster)
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_TP, oCaster)
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_WH, oCaster))
return 1;
}
else if(nElement & DESCRIPTOR_ELECTRICITY)
{
if(GetHasFeat(FEAT_DRACONIC_HERITAGE_BL, oCaster)
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_BZ, oCaster)
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_SA, oCaster))
return 1;
}
else if(nElement & DESCRIPTOR_ACID)
{
if(GetHasFeat(FEAT_DRACONIC_HERITAGE_BK, oCaster)
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_CP, oCaster)
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_GR, oCaster))
return 1;
}
else if(nElement & DESCRIPTOR_SONIC)
{
if(GetHasFeat(FEAT_DRACONIC_HERITAGE_EM, oCaster))
return 1;
}
}
//if it gets here, the caster does not have the feat, or is a heritage type without a NWN element (e.g. Amethyst)
return 0;
}
//Energy Draconc Aura's elemental boost to spell DCs
int EnergyAuraDC(int spell_id, int nElement, object oCaster)
{
// Compare aura type and elemental type
if(nElement & DESCRIPTOR_FIRE)
return GetLocalInt(oCaster, "FireEnergyAura");
else if(nElement & DESCRIPTOR_COLD)
return GetLocalInt(oCaster, "ColdEnergyAura");
else if(nElement & DESCRIPTOR_ELECTRICITY)
return GetLocalInt(oCaster, "ElecEnergyAura");
else if(nElement & DESCRIPTOR_ACID)
return GetLocalInt(oCaster, "AcidEnergyAura");
//if it gets here, the caster is not in this type of Draconic Aura
return 0;
}
//Spirit Folk get a better save vs elemental stuff
int SpiritFolkAdjustment(int spell_id, int nElement, object oTarget)
{
if(nElement & DESCRIPTOR_FIRE && GetHasFeat(FEAT_BONUS_SEA, oTarget))
{
return -2;
}
else if(nElement & DESCRIPTOR_COLD && GetHasFeat(FEAT_BONUS_RIVER, oTarget))
{
return -2;
}
else if(nElement & DESCRIPTOR_ACID && GetHasFeat(FEAT_BONUS_BAMBOO, oTarget))
{
return -2;
}
//if it gets here, the target is not a Spirit Folk
return 0;
}
//Angry Spell for Rage Mage class
int AngrySpell(int spell_id, int nSchool, object oCaster)
{
int nDC;
if(GetHasSpellEffect(SPELL_SPELL_RAGE, oCaster))
{
if(nSchool == SPELL_SCHOOL_ABJURATION
|| nSchool == SPELL_SCHOOL_CONJURATION
|| nSchool == SPELL_SCHOOL_EVOCATION
|| nSchool == SPELL_SCHOOL_NECROMANCY
|| nSchool == SPELL_SCHOOL_TRANSMUTATION)
{
if(GetLevelByClass(CLASS_TYPE_RAGE_MAGE, oCaster) >= 10)
nDC = 4;
else if(GetLevelByClass(CLASS_TYPE_RAGE_MAGE, oCaster) >= 5)
nDC = 2;
}
}
return nDC;
}
int CloakedCastingDC(int spell_id, object oTarget, object oCaster)
{
int nDC;
int iBeguiler = GetLevelByClass(CLASS_TYPE_BEGUILER, oCaster);
if(iBeguiler)
{
if(GetIsDeniedDexBonusToAC(oTarget, oCaster, TRUE))
{
if(iBeguiler >= 14)
nDC = 2;
else if(iBeguiler >= 2)
nDC = 1;
}
}
return nDC;
}
// Wyrmbane Helm
int WyrmbaneHelmDC(object oTarget, object oCaster)
{
// You get nothing if you aren't wielding the legacy item
object oWOL = GetItemPossessedBy(oCaster, "WOL_Wyrmbane");
if(oWOL != GetItemInSlot(INVENTORY_SLOT_HEAD, oCaster)) return 0;
if((MyPRCGetRacialType(oTarget) == RACIAL_TYPE_DRAGON))
{
return 2;
}
return 0;
}
// Arkamoi Strength From Magic
int StrengthFromMagic(object oCaster)
{
if (GetRacialType(oCaster) != RACIAL_TYPE_ARKAMOI)
return 0;
if (GetIsArcaneClass(PRCGetLastSpellCastClass(oCaster)))
return GetLocalInt(oCaster, "StrengthFromMagic");
return 0;
}
// Hobgoblin Warsoul Soul Tyrant
int SoulTyrant(object oCaster)
{
if (GetRacialType(oCaster) != RACIAL_TYPE_HOBGOBLIN_WARSOUL)
return 0;
if (GetIsArcaneClass(PRCGetLastSpellCastClass(oCaster)))
return GetLocalInt(oCaster, "WarsoulTyrant");
return 0;
}
int PRCGetSpellSaveDC(int nSpellID = -1, int nSchool = -1, object oCaster = OBJECT_SELF)
{
if(nSpellID == -1)
nSpellID = PRCGetSpellId();
if(nSchool == -1)
nSchool = GetSpellSchool(nSpellID);
int nClass = PRCGetLastSpellCastClass(oCaster);
int nDC = 10;
if(nClass == CLASS_TYPE_BARD)
nDC += StringToInt(Get2DACache("Spells", "Bard", 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)
nDC += StringToInt(Get2DACache("Spells", "Druid", nSpellID));
else if(nClass == CLASS_TYPE_RANGER)
nDC += StringToInt(Get2DACache("Spells", "Ranger", nSpellID));
else if(nClass == CLASS_TYPE_PALADIN)
nDC += StringToInt(Get2DACache("Spells", "Paladin", nSpellID));
else if (nClass == CLASS_TYPE_CULTIST_SHATTERED_PEAK)
nDC += StringToInt(Get2DACache("spells", "Cultist", nSpellID));
else if (nClass == CLASS_TYPE_NENTYAR_HUNTER)
nDC += StringToInt(Get2DACache("spells", "Nentyar", nSpellID));
else if (nClass == CLASS_TYPE_SHADOWLORD)
nDC += StringToInt(Get2DACache("spells", "Telflammar", nSpellID));
else if (nClass == CLASS_TYPE_SLAYER_OF_DOMIEL)
nDC += StringToInt(Get2DACache("spells", "Domiel", nSpellID));
else if (nClass == CLASS_TYPE_SOHEI)
nDC += StringToInt(Get2DACache("spells", "Sohei", nSpellID));
else if (nClass == CLASS_TYPE_VASSAL)
nDC += StringToInt(Get2DACache("spells", "Bahamut", nSpellID));
else if (nClass == CLASS_TYPE_BLACKGUARD)
nDC += StringToInt(Get2DACache("spells", "Blackguard", nSpellID));
else if (nClass == CLASS_TYPE_KNIGHT_CHALICE)
nDC += StringToInt(Get2DACache("spells", "Chalice", nSpellID));
else if (nClass == CLASS_TYPE_KNIGHT_MIDDLECIRCLE)
nDC += StringToInt(Get2DACache("spells", "MiddleCircle", nSpellID));
else if (nClass == CLASS_TYPE_SOLDIER_OF_LIGHT)
nDC += StringToInt(Get2DACache("spells", "SoLight", nSpellID));
else if (nClass == CLASS_TYPE_BLIGHTER)
nDC += StringToInt(Get2DACache("spells", "Blighter", nSpellID));
else if (nClass == CLASS_TYPE_HEALER)
nDC += StringToInt(Get2DACache("spells", "Healer", nSpellID));
else if (nClass == CLASS_TYPE_SHAMAN)
nDC += StringToInt(Get2DACache("spells", "Shaman", nSpellID));
else if(nClass == CLASS_TYPE_WIZARD
|| nClass == CLASS_TYPE_SORCERER)
nDC += StringToInt(Get2DACache("Spells", "Wiz_Sorc", nSpellID));
else if(nClass != CLASS_TYPE_INVALID)
{
int nSpellbookID = RealSpellToSpellbookID(nClass, nSpellID);
string sFile = GetFileForClass(nClass);
nDC += StringToInt(Get2DACache(sFile, "Level", nSpellbookID));
}
else
nDC += StringToInt(Get2DACache("Spells", "Innate", nSpellID));
// This is here because a Cleric casting a domain spell like Chain Lightning has a 0 in the cleric column, resulting in a DC of 10
if (nDC == 10 && nClass == CLASS_TYPE_CLERIC)
nDC += StringToInt(Get2DACache("Spells", "Innate", nSpellID));
nDC += GetDCAbilityModForClass(nClass, oCaster);
object oItem = GetSpellCastItem();
int nEpic = 6;
int nGreat = 4;
int nSF = 2;
if (GetPRCSwitch(PRC_35_SPELL_FOCUS))
{
nEpic = 3;
nGreat = 2;
nSF = 1;
}
if(DEBUG && !GetIsObjectValid(oItem)) DoDebug("PRCGetSpellSaveDC oItem is OBJECT_INVALID");
if(DEBUG) DoDebug("PRCGetSpellSaveDC oCaster "+GetName(oCaster)+", nSpell "+IntToString(nSpellID)+", nSchool "+IntToString(nSchool)+", nClass "+IntToString(nClass)+", oItem "+GetName(oItem));
if(!GetIsObjectValid(oItem) || (GetBaseItemType(oItem) == BASE_ITEM_MAGICSTAFF && GetPRCSwitch(PRC_STAFF_CASTER_LEVEL)))
{
if(nSchool == SPELL_SCHOOL_EVOCATION)
{
if(GetHasFeat(FEAT_EPIC_SPELL_FOCUS_EVOCATION, oCaster))
nDC+=nEpic;
else if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_EVOCATION, oCaster))
nDC+=nGreat;
else if(GetHasFeat(FEAT_SPELL_FOCUS_EVOCATION, oCaster))
nDC+=nSF;
}
else if(nSchool == SPELL_SCHOOL_TRANSMUTATION)
{
if(GetHasFeat(FEAT_EPIC_SPELL_FOCUS_TRANSMUTATION, oCaster))
nDC+=nEpic;
else if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_TRANSMUTATION, oCaster))
nDC+=nGreat;
else if(GetHasFeat(FEAT_SPELL_FOCUS_TRANSMUTATION, oCaster))
nDC+=nSF;
}
else if(nSchool == SPELL_SCHOOL_NECROMANCY)
{
if(GetHasFeat(FEAT_EPIC_SPELL_FOCUS_NECROMANCY, oCaster))
nDC+=nEpic;
else if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_NECROMANCY, oCaster))
nDC+=nGreat;
else if(GetHasFeat(FEAT_SPELL_FOCUS_NECROMANCY, oCaster))
nDC+=nSF;
}
else if(nSchool == SPELL_SCHOOL_ILLUSION)
{
if(GetHasFeat(FEAT_EPIC_SPELL_FOCUS_ILLUSION, oCaster))
nDC+=nEpic;
else if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_ILLUSION, oCaster))
nDC+=nGreat;
else if(GetHasFeat(FEAT_SPELL_FOCUS_ILLUSION, oCaster))
nDC+=nSF;
}
else if(nSchool == SPELL_SCHOOL_ABJURATION)
{
if(GetHasFeat(FEAT_EPIC_SPELL_FOCUS_ABJURATION, oCaster))
nDC+=nEpic;
else if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_ABJURATION, oCaster))
nDC+=nGreat;
else if(GetHasFeat(FEAT_SPELL_FOCUS_ABJURATION, oCaster))
nDC+=nSF;
}
else if(nSchool == SPELL_SCHOOL_CONJURATION)
{
if(GetHasFeat(FEAT_EPIC_SPELL_FOCUS_CONJURATION, oCaster))
nDC+=nEpic;
else if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_CONJURATION, oCaster))
nDC+=nGreat;
else if(GetHasFeat(FEAT_SPELL_FOCUS_CONJURATION, oCaster))
nDC+=nSF;
}
else if(nSchool == SPELL_SCHOOL_DIVINATION)
{
if(GetHasFeat(FEAT_EPIC_SPELL_FOCUS_DIVINATION, oCaster))
nDC+=nEpic;
else if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_DIVINATION, oCaster))
nDC+=nGreat;
else if(GetHasFeat(FEAT_SPELL_FOCUS_DIVINATION, oCaster))
nDC+=nSF;
}
else if(nSchool == SPELL_SCHOOL_ENCHANTMENT)
{
if(GetHasFeat(FEAT_EPIC_SPELL_FOCUS_ENCHANTMENT, oCaster))
nDC+=nEpic;
else if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_ENCHANTMENT, oCaster))
nDC+=nGreat;
else if(GetHasFeat(FEAT_SPELL_FOCUS_ENCHANTMENT, oCaster))
nDC+=nSF;
}
}
return nDC;
}
int PRCGetSaveDC(object oTarget, object oCaster, int nSpellID = -1)
{
object oItem = GetSpellCastItem();
if(nSpellID == -1)
nSpellID = PRCGetSpellId();
int nSchool = GetSpellSchool(nSpellID);
int nDC;
// at this point, if it's still -1 then this is running on an AoE
if (nSpellID == -1)
{
// get the needed values off the AoE
nSpellID = GetLocalInt(OBJECT_SELF, "X2_AoE_SpellID");
nDC = GetLocalInt(OBJECT_SELF, "X2_AoE_BaseSaveDC");
nSchool = GetSpellSchool(nSpellID);
}
else // not persistent AoE script
{
//10+spelllevel+stat(cha default)
nDC = PRCGetSpellSaveDC(nSpellID, nSchool, oCaster);
}
// For when you want to assign the caster DC
//this does not take feat/race/class into account, it is an absolute override
if (GetLocalInt(oCaster, PRC_DC_TOTAL_OVERRIDE) != 0)
{
nDC = GetLocalInt(oCaster, PRC_DC_TOTAL_OVERRIDE);
if(DEBUG) DoDebug("Forced-DC PRC_DC_TOTAL_OVERRIDE casting at DC " + IntToString(nDC));
}
// For when you want to assign the caster DC
//this does take feat/race/class into account, it only overrides the baseDC
else if (GetLocalInt(oCaster, PRC_DC_BASE_OVERRIDE) != 0)
{
nDC = GetLocalInt(oCaster, PRC_DC_BASE_OVERRIDE);
if(nDC == -1)
nDC = PRCGetSpellSaveDC(nSpellID, nSchool, oCaster);
if(DEBUG) DoDebug("Forced Base-DC casting at DC " + IntToString(nDC));
nDC += GetChangesToSaveDC(oTarget, oCaster, nSpellID, nSchool);
}
else if(GetIsObjectValid(oItem) && !(GetBaseItemType(oItem) == BASE_ITEM_MAGICSTAFF && GetPRCSwitch(PRC_STAFF_CASTER_LEVEL)))
{
//code for getting new ip type
itemproperty ipTest = GetFirstItemProperty(oItem);
while(GetIsItemPropertyValid(ipTest))
{
if(GetItemPropertyType(ipTest) == ITEM_PROPERTY_CAST_SPELL_DC)
{
int nSubType = GetItemPropertySubType(ipTest);
nSubType = StringToInt(Get2DACache("iprp_spells", "SpellIndex", nSubType));
if(nSubType == nSpellID)
{
nDC = GetItemPropertyCostTableValue (ipTest);
break;//end while
}
}
ipTest = GetNextItemProperty(oItem);
}
int nType = GetBaseItemType(oItem);
if(nType == BASE_ITEM_MAGICWAND || nType == BASE_ITEM_ENCHANTED_WAND)
{
if (GetHasFeat(FEAT_WAND_MASTERY, oCaster))
nDC += 2;
}
}
else
nDC += GetChangesToSaveDC(oTarget, oCaster, nSpellID, nSchool);
// Karsus's Heavy Magic ability
if(GetIsObjectValid(oItem) && GetHasSpellEffect(VESTIGE_KARSUS, oCaster) && GetLocalInt(oCaster, "ExploitVestige") != VESTIGE_KARSUS_HEAVY_MAGIC && (GetLevelByClass(CLASS_TYPE_BINDER, oCaster) || GetHasFeat(FEAT_PRACTICED_BINDER, oCaster)))
nDC += 2;
//target-based adjustments go here
nDC += RedWizardDCPenalty(nSpellID, nSchool, oTarget);
nDC += ShadowAdeptDCPenalty(nSpellID, nSchool, oTarget);
if (GetPRCSwitch(PRC_ACTIVATE_MAX_SPELL_DC_CAP))
{
if (nDC > GetPRCSwitch(PRC_SET_MAX_SPELL_DC_CAP))
{
nDC = GetPRCSwitch(PRC_SET_MAX_SPELL_DC_CAP);
}
}
return nDC;
}
//called just from above and from inc_epicspells
int GetChangesToSaveDC(object oTarget, object oCaster, int nSpellID, int nSchool)
{
int nDC;
int nElement = GetIsElementalSpell(nSpellID);
if(nElement)
{
nDC += ElementalSavantDC(nSpellID, nElement, oCaster);
nDC += SpiritFolkAdjustment(nSpellID, nElement, oTarget);
nDC += SpellFocus(nSpellID, nElement, oCaster);
nDC += DraconicPowerDC(nSpellID, nElement, oCaster);
nDC += EnergyAuraDC(nSpellID, nElement, oCaster);
}
nDC += GetHeartWarderDC(nSpellID, nSchool, oCaster);
nDC += GetSpellPowerBonus(oCaster);
nDC += ShadowWeaveDC(nSpellID, nSchool, oCaster);
nDC += RedWizardDC(nSpellID, nSchool, oCaster);
nDC += TattooFocus(nSpellID, nSchool, oCaster);
nDC += KOTCSpellFocusVsDemons(oTarget, oCaster);
//nDC += BloodMagusBloodComponent(oCaster);
nDC += RunecasterRunePowerDC(oCaster);
nDC += UnheavenedAdjustment(oTarget, oCaster);
nDC += SoulEaterSoulPower(oCaster);
nDC += AngrySpell(nSpellID, nSchool, oCaster);
nDC += CloakedCastingDC(nSpellID, oTarget, oCaster);
nDC += GetCorruptSpellFocus(nSpellID, oCaster);
nDC += Soulcaster(oCaster, nSpellID);
nDC += WyrmbaneHelmDC(oTarget, oCaster);
nDC += StrengthFromMagic(oCaster);
nDC += SoulTyrant(oCaster);
nDC += SaintHolySpellPower(oCaster);
nDC += GetLocalInt(oCaster, PRC_DC_ADJUSTMENT);//this is for builder use
nDC += JaebrinEnchant(nSchool, oCaster);
return nDC;
}
// Test main
//:: void main(){}

View File

@@ -0,0 +1,425 @@
//::///////////////////////////////////////////////
//:: Spells include: Spell Penetration
//:: prc_add_spl_pen
//::///////////////////////////////////////////////
/** @file
Defines functions that may have something to do
with modifying a spell's caster level in regards
to Spell Resistance penetration.
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
int GetHeartWarderPene(int spell_id, object oCaster = OBJECT_SELF);
int ElementalSavantSP(int spell_id, object oCaster = OBJECT_SELF);
int RedWizardSP(int spell_id, int nSchool, object oCaster = OBJECT_SELF);
int GetSpellPenetreFocusSchool(int nSchool, object oCaster = OBJECT_SELF);
int GetSpellPowerBonus(object oCaster = OBJECT_SELF);
int ShadowWeavePen(int spell_id, int nSchool, object oCaster = OBJECT_SELF);
int KOTCSpellPenVsDemons(object oCaster, object oTarget);
int RunecasterRunePowerSP(object oCaster);
int MarshalDeterminedCaster(object oCaster);
int DuskbladeSpellPower(object oCaster, object oTarget);
int DraconicMagicPower(object oCaster);
int TrueCastingSpell(object oCaster);
string ChangedElementalType(int spell_id, object oCaster = OBJECT_SELF);
// Use this function to get the adjustments to a spell or SLAs spell penetration
// from the various class effects
// Update this function if any new classes change spell pentration
int add_spl_pen(object oCaster = OBJECT_SELF);
int SPGetPenetr(object oCaster = OBJECT_SELF);
int SPGetPenetrAOE(object oCaster = OBJECT_SELF, int nCasterLvl = 0);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
//#include "prc_inc_spells"
//#include "prc_alterations"
//#include "prcsp_archmaginc"
//#include "prc_inc_racial"
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
//
// Determine if a spell type is elemental
//
int IsSpellTypeElemental(string type)
{
return type == "Acid"
|| type == "Cold"
|| type == "Electricity"
|| type == "Fire"
|| type == "Sonic";
}
int GetHeartWarderPene(int spell_id, object oCaster = OBJECT_SELF)
{
// Guard Expensive Calculations
if(!GetHasFeat(FEAT_VOICE_SIREN, oCaster))
return 0;
// Bonus Requires Verbal Spells
string VS = GetStringLowerCase(Get2DACache("spells", "VS", spell_id));
if(FindSubString(VS, "v") == -1)
return 0;
// These feats provide greater bonuses or remove the Verbal requirement
if(PRCGetMetaMagicFeat(oCaster, FALSE) & METAMAGIC_SILENT
|| GetHasFeat(FEAT_SPELL_PENETRATION, oCaster)
|| GetHasFeat(FEAT_GREATER_SPELL_PENETRATION, oCaster)
|| GetHasFeat(FEAT_EPIC_SPELL_PENETRATION, oCaster))
return 0;
return 2;
}
//
// Calculate Elemental Savant Contributions
//
int ElementalSavantSP(int spell_id, object oCaster = OBJECT_SELF)
{
// get spell elemental type
int element = GetIsElementalSpell(spell_id);
//not an elemental spell
if(!element)
return 0;
int nSP = 0;
// All Elemental Savants will have this feat
// when they first gain a penetration bonus.
// Otherwise this would require checking ~4 items (class or specific feats)
if(GetHasFeat(FEAT_ES_PEN_1, oCaster))
{
int feat, nES;
nES = GetLevelByClass(CLASS_TYPE_ELEMENTAL_SAVANT, oCaster);
// Specify the elemental type rather than lookup by class?
if(element & DESCRIPTOR_FIRE)
{
feat = FEAT_ES_FIRE;
}
else if(element & DESCRIPTOR_COLD)
{
feat = FEAT_ES_COLD;
}
else if(element & DESCRIPTOR_ELECTRICITY)
{
feat = FEAT_ES_ELEC;
}
else if(element & DESCRIPTOR_ACID)
{
feat = FEAT_ES_ACID;
}
// Now determine the bonus
if(feat && GetHasFeat(feat, oCaster))
nSP = nES / 3;
}
// SendMessageToPC(GetFirstPC(), "Your Elemental Penetration modifier is " + IntToString(nSP));
return nSP;
}
//Red Wizard SP boost based on spell school specialization
int RedWizardSP(int spell_id, int nSchool, object oCaster = OBJECT_SELF)
{
int iRedWizard = GetLevelByClass(CLASS_TYPE_RED_WIZARD, oCaster);
int nSP;
if(iRedWizard)
{
int iRWSpec;
switch(nSchool)
{
case SPELL_SCHOOL_ABJURATION: iRWSpec = FEAT_RW_TF_ABJ; break;
case SPELL_SCHOOL_CONJURATION: iRWSpec = FEAT_RW_TF_CON; break;
case SPELL_SCHOOL_DIVINATION: iRWSpec = FEAT_RW_TF_DIV; break;
case SPELL_SCHOOL_ENCHANTMENT: iRWSpec = FEAT_RW_TF_ENC; break;
case SPELL_SCHOOL_EVOCATION: iRWSpec = FEAT_RW_TF_EVO; break;
case SPELL_SCHOOL_ILLUSION: iRWSpec = FEAT_RW_TF_ILL; break;
case SPELL_SCHOOL_NECROMANCY: iRWSpec = FEAT_RW_TF_NEC; break;
case SPELL_SCHOOL_TRANSMUTATION: iRWSpec = FEAT_RW_TF_TRS; break;
}
if(iRWSpec && GetHasFeat(iRWSpec, oCaster))
nSP = (iRedWizard / 2) + 1;
}
// SendMessageToPC(GetFirstPC(), "Your Spell Power modifier is " + IntToString(nSP));
return nSP;
}
int GetSpellPenetreFocusSchool(int nSchool, object oCaster = OBJECT_SELF)
{
if(nSchool)
{
if(GetHasFeat(FEAT_FOCUSED_SPELL_PENETRATION_ABJURATION+nSchool-1, oCaster))
return 4;
}
return 0;
}
int GetSpellPowerBonus(object oCaster = OBJECT_SELF)
{
if(GetHasFeat(FEAT_SPELLPOWER_10, oCaster))
return 10;
else if(GetHasFeat(FEAT_SPELLPOWER_8, oCaster))
return 8;
else if(GetHasFeat(FEAT_SPELLPOWER_6, oCaster))
return 6;
else if(GetHasFeat(FEAT_SPELLPOWER_4, oCaster))
return 4;
else if(GetHasFeat(FEAT_SPELLPOWER_2, oCaster))
return 2;
return 0;
}
// Shadow Weave Feat
// +1 caster level vs SR (school Ench,Illu,Necro)
int ShadowWeavePen(int spell_id, int nSchool, object oCaster = OBJECT_SELF)
{
int iShadow = GetLevelByClass(CLASS_TYPE_SHADOW_ADEPT, oCaster);
int nSP;
// Apply changes if the caster has level in Shadow Adept class
// and this spell is eligible for the spell penetration check increase
if (iShadow > 0 && ShadowWeave(oCaster, spell_id, nSchool) == 1)
// Shadow Spell Power
nSP = iShadow / 3;
return nSP;
}
int KOTCSpellPenVsDemons(object oCaster, object oTarget)
{
if(GetLevelByClass(CLASS_TYPE_KNIGHT_CHALICE, oCaster) >= 1)
{
if(MyPRCGetRacialType(oTarget) == RACIAL_TYPE_OUTSIDER)
{
if(GetAlignmentGoodEvil(oTarget) == ALIGNMENT_EVIL)
{
return 2;
}
}
}
return 0;
}
int RunecasterRunePowerSP(object oCaster)
{
int nSP = 0;
// casting from a rune
if(GetResRef(GetSpellCastItem()) == "prc_rune_1")
{
nSP = StringToInt(GetTag(GetSpellCastItem()));
}
// caster is runechanting
else if(GetHasSpellEffect(SPELL_RUNE_CHANT))
{
int nClass = GetLevelByClass(CLASS_TYPE_RUNECASTER, oCaster);
if (nClass >= 30) nSP = 10;
else if (nClass >= 27) nSP = 9;
else if (nClass >= 24) nSP = 8;
else if (nClass >= 21) nSP = 7;
else if (nClass >= 18) nSP = 6;
else if (nClass >= 15) nSP = 5;
else if (nClass >= 12) nSP = 4;
else if (nClass >= 9) nSP = 3;
else if (nClass >= 5) nSP = 2;
else if (nClass >= 2) nSP = 1;
}
return nSP;
}
int MarshalDeterminedCaster(object oCaster)
{
return GetLocalInt(oCaster,"Marshal_DetCast");
}
int DuskbladeSpellPower(object oCaster, object oTarget)
{
int nSP = 0;
if(GetLocalInt(oTarget, "DuskbladeSpellPower"))
{
int nClass = GetLevelByClass(CLASS_TYPE_DUSKBLADE, oCaster);
if(nClass >= 38) nSP = 10;
else if(nClass >= 36) nSP = 9;
else if(nClass >= 31) nSP = 8;
else if(nClass >= 26) nSP = 7;
else if(nClass >= 21) nSP = 6;
else if(nClass >= 18) nSP = 5;
else if(nClass >= 16) nSP = 4;
else if(nClass >= 11) nSP = 3;
else if(nClass >= 6) nSP = 2;
}
return nSP;
}
int DraconicMagicPower(object oCaster)
{
return GetLocalInt(oCaster,"MagicPowerAura");
}
int TrueCastingSpell(object oCaster)
{
if(GetHasSpellEffect(SPELL_TRUE_CASTING, oCaster))
return 10;
return 0;
}
// Beguilers of level 8+ gain +2 bonus to SR agianst enemis that are denided DEX bonus to AC
int CloakedCastingSR(object oCaster, object oTarget)
{
if(GetLevelByClass(CLASS_TYPE_BEGUILER, oCaster) >= 8)
{
if(GetIsDeniedDexBonusToAC(oTarget, oCaster, TRUE))
return 2;
}
return 0;
}
int PenetratingBlast(object oCaster, object oTarget)
{
if(oTarget == GetLocalObject(oCaster, "SPELLWEAVE_TARGET"))
{
if(GetLocalInt(oCaster, "BlastEssence") == INVOKE_PENETRATING_BLAST)
return 4;
}
return 0;
}
int add_spl_pen(object oCaster = OBJECT_SELF)
{
object oTarget = PRCGetSpellTargetObject();
int spell_id = PRCGetSpellId();
int nSchool = GetSpellSchool(spell_id);
int nSP = ElementalSavantSP(spell_id, oCaster);
nSP += GetHeartWarderPene(spell_id, oCaster);
nSP += RedWizardSP(spell_id, nSchool, oCaster);
nSP += GetSpellPowerBonus(oCaster);
nSP += GetSpellPenetreFocusSchool(nSchool, oCaster);
nSP += ShadowWeavePen(spell_id, nSchool, oCaster);
nSP += RunecasterRunePowerSP(oCaster);
nSP += MarshalDeterminedCaster(oCaster);
nSP += DraconicMagicPower(oCaster);
nSP += TrueCastingSpell(oCaster);
nSP += GetEssentiaInvestedFeat(oCaster, FEAT_SOULTOUCHED_SPELLCASTING);
if(GetIsObjectValid(oTarget))
{
nSP += CloakedCastingSR(oCaster, oTarget);
nSP += PenetratingBlast(oCaster, oTarget);
nSP += KOTCSpellPenVsDemons(oCaster, oTarget);
nSP += DuskbladeSpellPower(oCaster, oTarget);
}
return nSP;
}
//
// This function converts elemental types as needed
//
string ChangedElementalType(int spell_id, object oCaster = OBJECT_SELF)
{
// Lookup the spell type
string spellType = Get2DACache("spells", "ImmunityType", spell_id);//lookup_spell_type(spell_id);
// Check if an override is set
string sType = GetLocalString(oCaster, "archmage_mastery_elements_name");
// If so, check if the spell qualifies for a change
if (sType == "" || !IsSpellTypeElemental(spellType))
sType = spellType;
return sType;
}
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
//
// Get the Spell Penetration Bonuses
//
int SPGetPenetr(object oCaster = OBJECT_SELF)
{
int nPenetr = 0;
// This is a deliberate optimization attempt.
// The first feat determines if the others even need
// to be referenced.
if(GetHasFeat(FEAT_SPELL_PENETRATION, oCaster))
{
nPenetr += 2;
if(GetHasFeat(FEAT_EPIC_SPELL_PENETRATION, oCaster))
nPenetr += 4;
else if (GetHasFeat(FEAT_GREATER_SPELL_PENETRATION, oCaster))
nPenetr += 2;
}
// Check for additional improvements
nPenetr += add_spl_pen(oCaster);
return nPenetr;
}
//
// Interface for specific AOE requirements
// TODO: Determine who or what removes the cached local var (bug?)
// TODO: Try and remove this function completely? It does 2 things the
// above function doesnt: Effective Caster Level and Cache
//
int SPGetPenetrAOE(object oCaster = OBJECT_SELF, int nCasterLvl = 0)
{
// Check the cache
int nPenetr = GetLocalInt(OBJECT_SELF, "nPenetre");
// Compute the result
if (!nPenetr) {
nPenetr = (nCasterLvl) ? nCasterLvl : PRCGetCasterLevel(oCaster);
// Factor in Penetration Bonuses
nPenetr += SPGetPenetr(oCaster);
// Who removed this?
SetLocalInt(OBJECT_SELF,"nPenetre",nPenetr);
}
return nPenetr;
}
// Test main
//void main(){}

View File

@@ -0,0 +1,296 @@
// Base Classes
// BW
const string ALLOW_CLASS_BARBARIAN = "PRC_AllowBarbarian";
const string ALLOW_CLASS_BARD = "PRC_AllowBard";
const string ALLOW_CLASS_CLERIC = "PRC_AllowCleric";
const string ALLOW_CLASS_DRUID = "PRC_AllowDruid";
const string ALLOW_CLASS_FIGHTER = "PRC_AllowFighter";
const string ALLOW_CLASS_MONK = "PRC_AllowMonk";
const string ALLOW_CLASS_PALADIN = "PRC_AllowPaladin";
const string ALLOW_CLASS_RANGER = "PRC_AllowRanger";
const string ALLOW_CLASS_ROGUE = "PRC_AllowRogue";
const string ALLOW_CLASS_SORCERER = "PRC_AllowSorcerer";
const string ALLOW_CLASS_WIZARD = "PRC_AllowWizard";
//: Racial Classes
const string ALLOW_CLASS_ABERRATION = "PRC_AllowAberration";
const string ALLOW_CLASS_ANIMAL = "PRC_AllowAnimal";
const string ALLOW_CLASS_BEAST = "PRC_AllowBeast";
const string ALLOW_CLASS_CONSTRUCT = "PRC_AllowConstruct";
const string ALLOW_CLASS_DRAGON = "PRC_AllowDragon";
const string ALLOW_CLASS_ELEMENTAL = "PRC_AllowEle";
const string ALLOW_CLASS_FEY = "PRC_AllowFey";
const string ALLOW_CLASS_GIANT = "PRC_AllowGiant";
const string ALLOW_CLASS_HUMANOID = "PRC_AllowHumanoid";
const string ALLOW_CLASS_MAGICAL_BEAST = "PRC_AllowMagicalBeast";
const string ALLOW_CLASS_MON_HUMANOID = "PRC_AllowMonstrous";
const string ALLOW_CLASS_OOZE = "PRC_AllowOoze";
const string ALLOW_CLASS_OUTSIDER = "PRC_AllowOutsider";
const string ALLOW_CLASS_PLANT = "PRC_AllowPlant";
const string ALLOW_CLASS_SHAPECHANGER = "PRC_AllowShapechanger";
const string ALLOW_CLASS_UNDEAD = "PRC_AllowUndead";
const string ALLOW_CLASS_VERMIN = "PRC_AllowVermin";
// PRC
const string ALLOW_CLASS_ANTIPALADIN = "PRC_AllowAntiPal";
const string ALLOW_CLASS_ARTIFICER = "PRC_AllowArtificer";
const string ALLOW_CLASS_BINDER = "PRC_AllowBinder";
const string ALLOW_CLASS_CRUSADER = "PRC_AllowCrusader";
const string ALLOW_CLASS_DRAGONFIRE_ADEPT = "PRC_AllowDFAdept";
const string ALLOW_CLASS_DRAGON_SHAMAN = "PRC_AllowDragSham";
const string ALLOW_CLASS_DREAD_NECROMANCER = "PRC_AllowDNecro";
const string ALLOW_CLASS_DUSKBLADE = "PRC_AllowDuskblade";
const string ALLOW_CLASS_FACTOTUM = "PRC_AllowFactotum";
const string ALLOW_CLASS_FAVOURED_SOUL = "PRC_AllowFavouredSoul";
const string ALLOW_CLASS_HEALER = "PRC_AllowHealer";
const string ALLOW_CLASS_HEXBLADE = "PRC_AllowHexblade";
const string ALLOW_CLASS_INCARNATE = "PRC_AllowIncarnate";
const string ALLOW_CLASS_KNIGHT = "PRC_AllowKnight";
const string ALLOW_CLASS_MARSHAL = "PRC_AllowMarshal";
const string ALLOW_CLASS_NINJA = "PRC_AllowNinjaCA";
const string ALLOW_CLASS_PSION = "PRC_AllowPsion";
const string ALLOW_CLASS_PSYCHIC_ROGUE = "PRC_AllowPsyRog";
const string ALLOW_CLASS_PSYCHIC_WARRIOR = "PRC_AllowPsyWar";
const string ALLOW_CLASS_SAMURAI = "PRC_AllowSamurai";
const string ALLOW_CLASS_SAMURAI_CW = "PRC_AllowCWSam";
const string ALLOW_CLASS_SCOUT = "PRC_AllowScout";
const string ALLOW_CLASS_SHADOWCASTER = "PRC_AllowShadowcaster";
const string ALLOW_CLASS_SHAMAN = "PRC_AllowShaman";
const string ALLOW_CLASS_SOHEI = "PRC_AllowSohei";
const string ALLOW_CLASS_SOULBORN = "PRC_AllowSoulborn";
const string ALLOW_CLASS_SOULKNIFE = "PRC_AllowSoulKnife";
const string ALLOW_CLASS_SWASHBUCKLER = "PRC_AllowSwash";
const string ALLOW_CLASS_SWORDSAGE = "PRC_AllowSwordsage";
const string ALLOW_CLASS_TOTEMIST = "PRC_AllowTotemist";
const string ALLOW_CLASS_TRUENAMER = "PRC_AllowTruenamer";
const string ALLOW_CLASS_WARBLADE = "PRC_AllowWarblade";
const string ALLOW_CLASS_WARLOCK = "PRC_AllowWarlock";
const string ALLOW_CLASS_WARMAGE = "PRC_AllowWarmage";
const string ALLOW_CLASS_WILDER = "PRC_AllowWilder";
// Prestige Classes
// BW
const string ALLOW_SHADOWDANCER = "X1_AllowShadow";
const string ALLOW_HARPER = "X1_AllowHarper";
const string ALLOW_CLASS_ARCANE_ARCHER = "X1_AllowArcher";
const string ALLOW_ASSASSIN = "X1_AllowAsasin";
const string ALLOW_BLACKGUARD = "X1_AllowBlkGrd";
const string ALLOW_DIVINE_CHAMPION = "X2_AllowDivcha";
const string ALLOW_WEAPON_MASTER = "X2_AllowWM";
const string ALLOW_PALE_MASTER = "X2_AllowPalema";
const string ALLOW_SHIFTER = "X2_AllowShiftr";
const string ALLOW_DWARVEN_DEFENDER = "X1_AllowDwDef";
const string ALLOW_DRAGON_DISCIPLE = "X1_AllowDrDis";
// PRC
const string ALLOW_CLASS_ABJURANT_CHAMPION = "PRC_AllowAbjCha";
const string ALLOW_CLASS_ACOLYTE = "PRC_AllowAcolyte";
const string ALLOW_CLASS_ACOLYTE_EGO = "PRC_AllowEgo";
const string ALLOW_CLASS_ALAGHAR = "PRC_AllowAlag";
const string ALLOW_CLASS_ALIENIST = "PRC_AllowAlien";
const string ALLOW_CLASS_ARCANE_DUELIST = "PRC_AllowArcDuel";
const string ALLOW_CLASS_ARCHMAGE = "PRC_AllowArchmage";
const string ALLOW_CLASS_ARCTRICK = "PRC_AllowArcTrick";
const string ALLOW_CLASS_BAELNORN = "PRC_AllowBaeln";
const string ALLOW_CLASS_BATTLERAGER = "PRC_AllowBRage";
const string ALLOW_CLASS_BATTLESMITH = "PRC_AllowBattlesmith";
const string ALLOW_CLASS_BEREFT = "PRC_AllowBereft";
const string ALLOW_CLASS_BFZ = "PRC_AllowBFZ";
const string ALLOW_CLASS_BLACK_BLOOD_CULTIST = "PRC_AllowBBC";
const string ALLOW_CLASS_BLADESINGER = "PRC_AllowBlades";
const string ALLOW_CLASS_BLIGHTLORD = "PRC_AllowBlightlord";
const string ALLOW_CLASS_BLIGHTER = "PRC_AllowBlighter";
const string ALLOW_CLASS_BLOOD_MAGUS = "PRC_AllowBLMagus";
const string ALLOW_CLASS_BLOODCLAW_MASTER = "PRC_AllowBloodclaw";
const string ALLOW_CLASS_BONDED_SUMMONNER = "PRC_AllowBonded";
const string ALLOW_CLASS_BRIMSTONE_SPEAKER = "PRC_AllowBrimstone";
const string ALLOW_CLASS_CELEBRANT_SHARESS = "PRC_AllowCelebrant";
const string ALLOW_CLASS_CEREBREMANCER = "PRC_AllowCereb";
const string ALLOW_CLASS_CHAMPION_BANE = "PRC_AllowChaBane";
const string ALLOW_CLASS_CHAMPION_CORELLON = "PRC_AllowCoC";
const string ALLOW_CLASS_CHILD_OF_NIGHT = "PRC_AllowChildNight";
const string ALLOW_CLASS_COMBAT_MEDIC = "PRC_AllowCbtMed";
const string ALLOW_CLASS_CONTEMPLATIVE = "PRC_AllowContemp";
const string ALLOW_CLASS_CRINTI = "PRC_AllowCrinti";
const string ALLOW_CLASS_CULTIST_SHATTERED_PEAK = "PRC_AllowCultist";
const string ALLOW_CLASS_DEEPSTONE_SENTINEL = "PRC_AllowDeepSt";
const string ALLOW_CLASS_DIABOLIST = "PRC_AllowDiablo";
const string ALLOW_CLASS_DIAMOND_DRAGON = "PRC_AllowDiaDra";
const string ALLOW_CLASS_DIRGESINGER = "PRC_AllowDirge";
const string ALLOW_CLASS_DISCIPLE_OF_MEPH = "PRC_AllowDiscmep";
const string ALLOW_CLASS_DISC_ASMODEUS = "PRC_AllowAsmodeus";
const string ALLOW_CLASS_DISC_BAALZEBUL = "PRC_AllowBaal";
const string ALLOW_CLASS_DISPATER = "PRC_AllowDisp";
const string ALLOW_CLASS_DRAGON_DEVOTEE = "PRC_AllowDragonDevotee";
const string ALLOW_CLASS_DRAGONHEART_MAGE = "PRC_AllowDragonheart";
const string ALLOW_CLASS_DRAGONSONG_LYRIST = "PRC_AllowDraSong";
const string ALLOW_CLASS_DROW_JUDICATOR = "PRC_AllowDrowJud";
const string ALLOW_CLASS_DRUNKEN_MASTER = "PRC_AllowDrnkn";
const string ALLOW_CLASS_DUELIST = "PRC_AllowDuel";
const string ALLOW_CLASS_ELDRITCH_DISCIPLE = "PRC_AllowEDisc";
const string ALLOW_CLASS_ELDRITCH_KNIGHT = "PRC_AllowEldknight";
const string ALLOW_CLASS_ELDRITCH_THEURGE = "PRC_AllowETheurg";
const string ALLOW_CLASS_ENLIGHTENED_FIST = "PRC_AllowEnlFist";
const string ALLOW_CLASS_ELEMENTAL_SAVANT = "PRC_AllowElSav";
const string ALLOW_CLASS_ETERNAL_BLADE = "PRC_AllowETBL";
const string ALLOW_CLASS_EYE_OF_GRUUMSH = "PRC_AllowEoG";
const string ALLOW_CLASS_FISTRAZIEL = "PRC_AllowFistRaz";
const string ALLOW_CLASS_FIST_OF_DAL_QUOR = "PRC_AllowDalQuor";
const string ALLOW_CLASS_FIST_OF_ZUOKEN = "PRC_AllowFoZ";
const string ALLOW_CLASS_FMM = "PRC_AllowFMM";
const string ALLOW_CLASS_FOCHULAN_LYRIST = "PRC_AllowFocLyr";
const string ALLOW_CLASS_FOE_HUNTER = "PRC_AllowFH";
const string ALLOW_CLASS_FORESTMASTER = "PRC_AllowForMast";
const string ALLOW_CLASS_FORSAKER = "PRC_AllowForsaker";
const string ALLOW_CLASS_FRE_BERSERKER = "PRC_AllowFrebzk";
const string ALLOW_CLASS_FROST_MAGE = "PRC_AllowFrostMage";
const string ALLOW_CLASS_FROST_RAGER = "PRC_AllowFrostRager";
const string ALLOW_CLASS_GHOST_FACED_KILLER = "PRC_AllowGhostFacedKiller";
const string ALLOW_CLASS_HAND_WINGED_MASTERS = "PRC_AllowHotWM";
const string ALLOW_CLASS_HARPERMAGE = "PRC_AllowHarperM";
const string ALLOW_CLASS_HATHRAN = "PRC_AllowHath";
const string ALLOW_CLASS_HAVOC_MAGE = "PRC_AllowHavocM";
const string ALLOW_CLASS_HEARTWARDER = "PRC_AllowHeartW";
const string ALLOW_CLASS_HELLFIRE_WARLOCK = "PRC_AllowHFWar";
const string ALLOW_CLASS_HENSHIN_MYSTIC = "PRC_AllowHnshn";
const string ALLOW_CLASS_HEXTOR = "PRC_AllowHextor";
const string ALLOW_CLASS_HIEROPHANT = "PRC_AllowHiero";
const string ALLOW_CLASS_HOSPITALER = "PRC_AllowHosp";
const string ALLOW_CLASS_IAIJUTSU_MASTER = "PRC_AllowIaij";
const string ALLOW_CLASS_INCANDESCENT_CHAMPION = "PRC_AllowIncandescent";
const string ALLOW_CLASS_INCARNUM_BLADE = "PRC_AllowIBlade";
const string ALLOW_CLASS_INITIATE_DRACONIC = "PRC_AllowIniDra";
const string ALLOW_CLASS_IRON_MIND = "PRC_AllowIronMind";
const string ALLOW_CLASS_IRONSOUL_FORGEMASTER = "PRC_AllowIronsoul";
const string ALLOW_CLASS_JADE_PHOENIX_MAGE = "PRC_AllowJPM";
const string ALLOW_CLASS_JUSTICE_WEALD_AND_WOE = "PRC_AllowJustWW";
const string ALLOW_CLASS_KNIGHT_CHALICE = "PRC_AllowKnghtCh";
const string ALLOW_CLASS_KNIGHT_MIDDLECIRCLE = "PRC_AllowKotMC";
const string ALLOW_CLASS_KNIGHT_WEAVE = "PRC_AllowKnightWeave";
const string ALLOW_CLASS_LASHER = "PRC_AllowLash";
const string ALLOW_CLASS_LEGENDARY_DREADNOUGHT = "PRC_AllowLgDr";
const string ALLOW_CLASS_LICH = "PRC_AllowLich";
const string ALLOW_CLASS_MAESTER = "PRC_AllowMaester";
const string ALLOW_CLASS_MAGEKILLER = "PRC_AllowMageK";
const string ALLOW_CLASS_MANATARMS = "PRC_AllowManAt";
const string ALLOW_CLASS_MASTER_ALCHEMIST = "PRC_AllowMstAlc";
const string ALLOW_CLASS_MASTER_HARPER = "PRC_AllowMaster";
const string ALLOW_CLASS_MASTER_OF_NINE = "PRC_AllowMoNine";
const string ALLOW_CLASS_MASTER_OF_SHADOW = "PRC_AllowMasterShadow";
const string ALLOW_CLASS_MASTER_OF_SHROUDS = "PRC_AllowShrouds";
const string ALLOW_CLASS_MIGHTY_CONTENDER_KORD = "PRC_AllowKord";
const string ALLOW_CLASS_MINSTREL = "PRC_AllowMinstrel";
const string ALLOW_CLASS_MORNINGLORD_LATHANDER = "PRC_AllowMorninglord";
const string ALLOW_CLASS_MYSTIC_THEURGE = "PRC_AllowMysticTheurge";
const string ALLOW_CLASS_NECROCARNUM_ACOLYTE = "PRC_AllowNecrocarnum";
const string ALLOW_CLASS_NENTYAR_HUNTER = "PRC_AllowNentyar";
const string ALLOW_CLASS_NIGHTSHADE = "PRC_AllowNights";
const string ALLOW_CLASS_NINJA_SPY = "PRC_AllowNinja";
const string ALLOW_CLASS_NOCTUMANCER = "PRC_AllowNoctumancer";
const string ALLOW_CLASS_OCULAR = "PRC_AllowOccAd";
const string ALLOW_CLASS_OLLAM = "PRC_AllowOllam";
const string ALLOW_CLASS_OOZEMASTER = "PRC_AllowUzi";
const string ALLOW_CLASS_ORCUS = "PRC_AllowOrcus";
const string ALLOW_CLASS_ORC_WARLORD = "PRC_AllowOrcWar";
const string ALLOW_CLASS_ORDER_BOW_INNATE = "PRC_AllowOOTBI";
const string ALLOW_CLASS_PEERLESS = "PRC_AllowPArcher";
const string ALLOW_CLASS_PNP_SHIFTER = "PRC_AllowPNPSfr";
const string ALLOW_CLASS_PSYCHIC_THEURGE = "PRC_AllowPsychic";
const string ALLOW_CLASS_PURPLE_DRAGON_KNIGHT = "PRC_AllowPDK";
const string ALLOW_CLASS_PYROKINETICIST = "PRC_AllowPyro";
const string ALLOW_CLASS_RAGE_MAGE = "PRC_AllowRageMage";
const string ALLOW_CLASS_RAVAGER = "PRC_Allow_Rava";
const string ALLOW_CLASS_REAPING_MAULER = "PRC_AllowReapMauler";
const string ALLOW_CLASS_RED_AVENGER = "PRC_AllowRedavng";
const string ALLOW_CLASS_RED_WIZARD = "PRC_AllowRedWiz";
const string ALLOW_CLASS_RUBY_KNIGHT_VINDICATOR = "PRC_AllowRubyKnight";
const string ALLOW_CLASS_RUNECASTER = "PRC_AllowRunecaster";
const string ALLOW_CLASS_RUNESCARRED = "PRC_Allow_Rune";
const string ALLOW_CLASS_SACREDFIST = "PRC_AllowSacFist";
const string ALLOW_CLASS_SACREDPURIFIER = "PRC_AllowPurifier";
const string ALLOW_CLASS_SANCTIFIED_MIND = "PRC_AllowSancMind";
const string ALLOW_CLASS_SAPPHIE_HIERARCH = "PRC_AllowSapphire";
const string ALLOW_CLASS_SCION_DANTALION = "PRC_AllowScion";
const string ALLOW_CLASS_SERENE_GUARDIAN = "PRC_AllowSerGuard";
const string ALLOW_CLASS_SHADOWBLADE = "PRC_AllowShdBld";
const string ALLOW_CLASS_SHADOWMIND = "PRC_AllowShadowmind";
const string ALLOW_CLASS_SHADOWLORD = "PRC_AllowShaLow";
const string ALLOW_CLASS_SHADOW_ADEPT = "PRC_AllowShadAde";
const string ALLOW_CLASS_SHADOW_SUN_NINJA = "PRC_AllowSSN";
const string ALLOW_CLASS_SHADOWBANE_INQUISITOR = "PRC_AllowShadowInq";
const string ALLOW_CLASS_SHADOWBANE_STALKER = "PRC_AllowShadowStalk";
const string ALLOW_CLASS_SHADOWSMITH = "PRC_AllowShadowsmith";
const string ALLOW_CLASS_SHADOW_THIEF = "PRC_AllowShadowThief";
const string ALLOW_CLASS_SHINING_BLADE = "PRC_AllowSBHeir";
const string ALLOW_CLASS_SHOU = "PRC_AllowShou";
const string ALLOW_CLASS_SKULLCLAN_HUNTER = "PRC_AllowSkullClan";
const string ALLOW_CLASS_SLAYER_OF_DOMIEL = "PRC_AllowDomiel";
const string ALLOW_CLASS_SOLDIER_OF_LIGHT = "PRC_AllowSoLight";
const string ALLOW_CLASS_SOULCASTER = "PRC_AllowSoulcaster";
const string ALLOW_CLASS_SOUL_EATER = "PRC_AllowSoulEater";
const string ALLOW_CLASS_SPELLDANCER = "PRC_AllowSpelldancer";
const string ALLOW_CLASS_SPELLFIRE_CHANNELER = "PRC_Allow_Spellf";
const string ALLOW_CLASS_SPELLSWORD = "PRC_AllowSpellS";
const string ALLOW_CLASS_SPINEMELD_WARRIOR = "PRC_AllowSpinemeld";
const string ALLOW_CLASS_STORMLORD = "PRC_AllowStormL";
const string ALLOW_CLASS_SUEL_ARCHANAMACH = "PRC_AllowSuel";
const string ALLOW_CLASS_SWIFT_WING = "PRC_AllowSwiftW";
const string ALLOW_CLASS_TALON_OF_TIAMAT = "PRC_TalonOfTiamat";
const string ALLOW_CLASS_TEMPEST = "PRC_AllowTempest";
const string ALLOW_CLASS_TEMPUS = "PRC_AllowTempus";
const string ALLOW_CLASS_TENEBROUS_APOSTATE = "PRC_AllowTenebrous";
const string ALLOW_CLASS_THAYAN_KNIGHT = "PRC_AllowThayKt";
const string ALLOW_CLASS_THRALL_OF_GRAZZT = "PRC_AllowTOG";
const string ALLOW_CLASS_THRALLHERD = "PRC_AllowThrallherd";
const string ALLOW_CLASS_TOTEMRAGER = "PRC_AllowTotemRager";
const string ALLOW_CLASS_TRUENECRO = "PRC_AllowTNecro";
const string ALLOW_CLASS_UMBRAL_DISCIPLE = "PRC_AllowUmbral";
const string ALLOW_CLASS_UNSEEN_SEER = "PRC_AllowUnseenSeer";
const string ALLOW_CLASS_UR_PRIEST = "PRC_AllowUrPriest";
const string ALLOW_CLASS_VASSAL = "PRC_AllowVassal";
const string ALLOW_CLASS_VIGILANT = "PRC_AllowVigil";
const string ALLOW_CLASS_VIRTUOSO = "PRC_AllowVirtuoso";
const string ALLOW_CLASS_WARCHIEF = "PRC_AllowWarchief";
const string ALLOW_CLASS_WARFORGED_JUGGERNAUT = "PRC_AllowJuggernaut";
const string ALLOW_CLASS_WARMIND = "PRC_AllowWarmind";
const string ALLOW_CLASS_WARPRIEST = "PRC_AllowWarPrst";
const string ALLOW_CLASS_WARSLING_SNIPER = "PRC_AllowWarsling";
const string ALLOW_CLASS_WAYFARER_GUIDE = "PRC_AllowWayfarer";
const string ALLOW_CLASS_WAR_WIZARD_OF_CORMYR = "PRC_AllowWWoC";
const string ALLOW_CLASS_WEREWOLF = "PRC_AllowWWolf";
const string ALLOW_CLASS_WITCHBORN_BINDER = "PRC_AllowWitchborn";
const string ALLOW_CLASS_WILD_MAGE = "PRC_AllowWildMage";
/*AL_SAVAGE = 205;
const string ALLOW_CLASS_WARLORD = 206;
const string ALLOW_CLASS_SCOUT = 207;
const string ALLOW_CLASS_DRAGON_SLAYER = 208;
const string ALLOW_CLASS_HOLY_CRUSADER = 209;
const string ALLOW_CLASS_GREY_WANDERER = 210;
const string ALLOW_CLASS_PROTECTOR = 211;
const string ALLOW_CLASS_SUMMONER = 212;
const string ALLOW_CLASS_ASTRAL_ADEPT = 213;
const string ALLOW_CLASS_DEMON_MASTER = 214;
const string ALLOW_CLASS_AURAMANCER = 215;
const string ALLOW_CLASS_ABJURER = 217;
const string ALLOW_CLASS_PUPPET_MASTER = 218 ;
const string ALLOW_CLASS_XENOWIZARD = 219;
const string ALLOW_CLASS_NATURALIST = 220;
const string ALLOW_CLASS_GEOMANCER = 221;
const string ALLOW_CLASS_PROPHET = 223 ;
const string ALLOW_CLASS_SHAMAN = 224;
const string ALLOW_CLASS_WITCH_DOCTOR = 225;
const string ALLOW_CLASS_BATTLEMAGE = 226;
const string ALLOW_CLASS_MYSTICAL_KNIGHT = 227;
const string ALLOW_CLASS_ARCANE_THEOLOGIST = 22;
const string ALLOW_CLASS_CRYSTAL_MASTER = 229;
const string ALLOW_CLASS_ARCANE_ASSASSIN = 230;
const string ALLOW_CLASS_ARCANE_SWORDSMAN = 231;
const string ALLOW_CLASS_VAMPIRE = 132;
*/

View File

@@ -0,0 +1,158 @@
//::///////////////////////////////////////////////
//:: Include nexus
//:: prc_alterations
//::///////////////////////////////////////////////
/*
This is the original include file for the PRC Spell Engine.
Various spells, components and designs within this system have
been contributed by many individuals within and without the PRC.
These days, it serves to gather links to almost all the PRC
includes to one file. Should probably get sorted out someday,
since this slows compilation. On the other hand, it may be
necessary, since the custom compiler can't seem to handle
the most twisted include loops.
Related TODO to any C++ experts: Add #DEFINE support to nwnnsscomp
Also, this file contains misceallenous functions that haven't
got a better home.
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//return a location that PCs will never be able to access
location PRC_GetLimbo();
//int GetSkill(object oObject, int nSkill, int bSynergy = FALSE, int bSize = FALSE, int bAbilityMod = TRUE, int bEffect = TRUE, int bArmor = TRUE, int bShield = TRUE, int bFeat = TRUE);
//////////////////////////////////////////////////
/* Constants */
//////////////////////////////////////////////////
// const int ERROR_CODE_5_FIX_YET_ANOTHER_TIME = 1;
//////////////////////////////////////////////////
/* Include section */
//////////////////////////////////////////////////
// Generic includes
#include "inc_abil_damage"
//////////////////////////////////////////////////
/* Function Definitions */
//////////////////////////////////////////////////
//return a location that PCs will never be able to access
location PRC_GetLimbo()
{
int i = 0;
location lLimbo;
while (1)
{
object oLimbo = GetObjectByTag("Limbo", i++);
if (oLimbo == OBJECT_INVALID) {
PrintString("PRC ERROR: no Limbo area! (did you import the latest PRC .ERF file?)");
return lLimbo;
}
if (GetName(oLimbo) == "Limbo" && GetArea(oLimbo) == OBJECT_INVALID)
{
vector vLimbo = Vector(0.0f, 0.0f, 0.0f);
lLimbo = Location(oLimbo, vLimbo, 0.0f);
}
}
return lLimbo; //never reached
}
//Also serves as a store of all item creation feats
int GetItemCreationFeatCount()
{
return(GetHasFeat(FEAT_CRAFT_WONDROUS)
+ GetHasFeat(FEAT_CRAFT_STAFF)
+ GetHasFeat(FEAT_CRAFT_ARMS_ARMOR)
+ GetHasFeat(FEAT_FORGE_RING)
+ GetHasFeat(FEAT_CRAFT_ROD)
+ GetHasFeat(FEAT_CRAFT_CONSTRUCT)
+ GetHasFeat(FEAT_SCRIBE_SCROLL)
+ GetHasFeat(FEAT_BREW_POTION)
+ GetHasFeat(FEAT_CRAFT_WAND)
+ GetHasFeat(FEAT_ATTUNE_GEM)
+ GetHasFeat(FEAT_CRAFT_SKULL_TALISMAN)
+ GetHasFeat(FEAT_INSCRIBE_RUNE)
//+ GetHasFeat(?)
);
}
// Returns the IP_CONST_DAMAGESOAK_*_HP constant that does the given
// amount of damage reduction
int GetDamageSoakConstant(int nDamRed)
{
switch(nDamRed)
{
case 1: return IP_CONST_DAMAGESOAK_1_HP;
case 2: return IP_CONST_DAMAGESOAK_2_HP;
case 3: return IP_CONST_DAMAGESOAK_3_HP;
case 4: return IP_CONST_DAMAGESOAK_4_HP;
case 5: return IP_CONST_DAMAGESOAK_5_HP;
case 6: return IP_CONST_DAMAGESOAK_6_HP;
case 7: return IP_CONST_DAMAGESOAK_7_HP;
case 8: return IP_CONST_DAMAGESOAK_8_HP;
case 9: return IP_CONST_DAMAGESOAK_9_HP;
case 10: return IP_CONST_DAMAGESOAK_10_HP;
case 11: return IP_CONST_DAMAGESOAK_11_HP;
case 12: return IP_CONST_DAMAGESOAK_12_HP;
case 13: return IP_CONST_DAMAGESOAK_13_HP;
case 14: return IP_CONST_DAMAGESOAK_14_HP;
case 15: return IP_CONST_DAMAGESOAK_15_HP;
case 16: return IP_CONST_DAMAGESOAK_16_HP;
case 17: return IP_CONST_DAMAGESOAK_17_HP;
case 18: return IP_CONST_DAMAGESOAK_18_HP;
case 19: return IP_CONST_DAMAGESOAK_19_HP;
case 20: return IP_CONST_DAMAGESOAK_20_HP;
case 21: return IP_CONST_DAMAGESOAK_21_HP;
case 22: return IP_CONST_DAMAGESOAK_22_HP;
case 23: return IP_CONST_DAMAGESOAK_23_HP;
case 24: return IP_CONST_DAMAGESOAK_24_HP;
case 25: return IP_CONST_DAMAGESOAK_25_HP;
case 26: return IP_CONST_DAMAGESOAK_26_HP;
case 27: return IP_CONST_DAMAGESOAK_27_HP;
case 28: return IP_CONST_DAMAGESOAK_28_HP;
case 29: return IP_CONST_DAMAGESOAK_29_HP;
case 30: return IP_CONST_DAMAGESOAK_30_HP;
case 31: return IP_CONST_DAMAGESOAK_31_HP;
case 32: return IP_CONST_DAMAGESOAK_32_HP;
case 33: return IP_CONST_DAMAGESOAK_33_HP;
case 34: return IP_CONST_DAMAGESOAK_34_HP;
case 35: return IP_CONST_DAMAGESOAK_35_HP;
case 36: return IP_CONST_DAMAGESOAK_36_HP;
case 37: return IP_CONST_DAMAGESOAK_37_HP;
case 38: return IP_CONST_DAMAGESOAK_38_HP;
case 39: return IP_CONST_DAMAGESOAK_39_HP;
case 40: return IP_CONST_DAMAGESOAK_40_HP;
case 41: return IP_CONST_DAMAGESOAK_41_HP;
case 42: return IP_CONST_DAMAGESOAK_42_HP;
case 43: return IP_CONST_DAMAGESOAK_43_HP;
case 44: return IP_CONST_DAMAGESOAK_44_HP;
case 45: return IP_CONST_DAMAGESOAK_45_HP;
case 46: return IP_CONST_DAMAGESOAK_46_HP;
case 47: return IP_CONST_DAMAGESOAK_47_HP;
case 48: return IP_CONST_DAMAGESOAK_48_HP;
case 49: return IP_CONST_DAMAGESOAK_49_HP;
case 50: return IP_CONST_DAMAGESOAK_50_HP;
default:
WriteTimestampedLogEntry("Erroneous value for nDamRed in GetDamageReductionConstant: " + IntToString(nDamRed));
}
return -1;
}
//:: void main(){}

View File

@@ -0,0 +1,85 @@
/**
* prc_ccc_const
*
* contains the constants
*/
/**
* Constants for determining whether a PC goes through the convoCC
*/
const int CONVOCC_ENTER_BOOT_PC = 0;
const int CONVOCC_ENTER_NEW_PC = 1;
const int CONVOCC_ENTER_RETURNING_PC = 2;
/**
* Constants for each stage in the convoCC
*/
const int STAGE_INTRODUCTION = 0;
const int STAGE_GENDER = 1;
const int STAGE_GENDER_CHECK = 2;
const int STAGE_RACE = 3;
const int STAGE_RACE_CHECK = 4;
const int STAGE_CLASS = 5;
const int STAGE_CLASS_CHECK = 6;
const int STAGE_ALIGNMENT = 7;
const int STAGE_ALIGNMENT_CHECK = 8;
const int STAGE_ABILITY = 9;
const int STAGE_ABILITY_CHECK = 10;
const int STAGE_SKILL = 11;
const int STAGE_SKILL_CHECK = 12;
const int STAGE_FEAT = 13;
const int STAGE_FEAT_CHECK = 14;
const int STAGE_BONUS_FEAT = 15;
const int STAGE_BONUS_FEAT_CHECK = 16;
const int STAGE_WIZ_SCHOOL = 17;
const int STAGE_WIZ_SCHOOL_CHECK = 18;
const int STAGE_SPELLS_0 = 19;
const int STAGE_SPELLS_1 = 20;
const int STAGE_SPELLS_CHECK = 21;
const int STAGE_FAMILIAR = 22;
const int STAGE_FAMILIAR_CHECK = 23;
const int STAGE_DOMAIN = 24;
const int STAGE_DOMAIN_CHECK1 = 25;
const int STAGE_DOMAIN_CHECK2 = 26;
const int STAGE_APPEARANCE = 27;
const int STAGE_APPEARANCE_CHECK = 28;
const int STAGE_PORTRAIT = 29;
const int STAGE_PORTRAIT_CHECK = 30;
const int STAGE_SOUNDSET = 31;
const int STAGE_SOUNDSET_CHECK = 32;
const int STAGE_HEAD = 33;
const int STAGE_HEAD_CHECK = 34;
const int STAGE_TATTOO = 35;
const int STAGE_TATTOO_CHECK = 36;
const int STAGE_WINGS = 37;
const int STAGE_WINGS_CHECK = 38;
const int STAGE_TAIL = 39;
const int STAGE_TAIL_CHECK = 40;
const int STAGE_SKIN_COLOUR = 41;
const int STAGE_SKIN_COLOUR_CHOICE = 42;
const int STAGE_SKIN_COLOUR_CHECK = 43;
const int STAGE_HAIR_COLOUR = 44;
const int STAGE_HAIR_COLOUR_CHOICE = 45;
const int STAGE_HAIR_COLOUR_CHECK = 46;
const int STAGE_TATTOO1_COLOUR = 47;
const int STAGE_TATTOO1_COLOUR_CHOICE = 48;
const int STAGE_TATTOO1_COLOUR_CHECK = 49;
const int STAGE_TATTOO2_COLOUR = 50;
const int STAGE_TATTOO2_COLOUR_CHOICE = 51;
const int STAGE_TATTOO2_COLOUR_CHECK = 52;
const int FINAL_STAGE = 99;
/**
* constants used in the convoCC that aren't convo stages
*/
// brownie model in the CEP
const int APPEARANCE_TYPE_CEP_BROWNIE = 1002;
// wemic model in the CEP
const int APPEARANCE_TYPE_CEP_WEMIC = 1000;

View File

@@ -0,0 +1,192 @@
/*
Conversation Character Creator v1.4
This is a conversation driven in-game 100% serverside character creator allowing
the use of custom content on a serverside game from level 1 (including new races
and new base classes ). It is also more secure than conventional character creation
methods
You Need:
PRC (current version is 2.2d, but this should work with any
http://nwnprc.netgamers.co.uk/
or
http://nwvault.ign.com/Files/hakpacks/data/1071643329920.shtml
or
http://nwvault.ign.com/Files/hakpacks/data/1082946089000.shtml
NWNX 2
http://nwvault.ign.com/Files/other/data/1046636009723.shtml
NWNX-Leto
http://prdownloads.sourceforge.net/leto/nwnxleto-build-03%2B18.rar?download
This is an in-game conversation driven character creator. This is designed for
servervault so that custom content is used at character creation. To work
properly however, several things need to be done.
NWNX2 must be instlled and used to run the module ( http://nwvault.ign.com/Files/
other/...636009723.shtml ) See the readme included with NWNX2 for instructions,
its very easy.
The NWNX_ODBC plugin included with NWNX2 should be installed and setup. See the
readme included with NWNX2 for instructions, this is quite straightforward but
trickier than installing NWNX2. In particular, make sure that the aps_onload
script is setup and that the database can be read to and from using the demo module
included in NWNX2. The ConvoCC should work with Access or MySQL databases.
To enable the database system for 2da caching, you must set a local int on the
module named "USE_2DA_DB_CACHE" to 1.
In addition to using NWNX2 for database storage, the cache can also be stored as
object in the bioware database. This cache is only updated when a character is
created, and is only restored when the module is loaded. This is to keep lag to
a minimum. To enable this, add RestoreCache(); to your OnModuleLoad script just
after void main() and add #include "prc_ccc_cache" above void main()
NWNX-Leto plugin build 18 must be installed ( http://sourceforge.net/projects/leto/ )
See the readme included with NWNX-Leto for instructions, its very easy.
THIS IS A VERY IMPORTANT NOTE Inside the module, in inc_letoscript, the constant
NWN_DIR must point to your servers hard disk location where NWN is installed.
After this, the scripts must be recompiled. THIS IS A VERY IMPORTANT NOTE
The player start should be placed in an area with no access to the rest of the
module. Then you should add code to jump the player to a starting waypoint in
the mod_cliententer script. There is an example commented out, if you delete
the comments ( // at the start of the line) then you can simply place a waypoint
tagged "WP_RealStart" where you want players to be jumped to.
You must connect the mod_cliententer script to the modules on client enter event.
You must connect the mod_clientexit script to the modules on client exit event.
Since much of the data is read directly from 2da's, this can be very slow,
especially for feats and spells where an enourmous amount of data is used. To
speed this process up, all 2da reads are cached via NWNX_ODBC to form a
persistant cache. This is a single tabled named "prccache". This means
that the first time a character is created it is much slower than subsequent
times will be. Also, whenever the PRC updates, or your 2da files change, you
should delete the table from the DB. In addition you must delete the bioware
database named "ConvoCC" when your 2das are updated.
If you wish to expand it to include more custom content (for example CEP portraits),
you need to change the constants in inc_fileends to define the last lines of the
relevant 2das. You will also need to recompile all the scripts.
You may be able to use FastFrenchs NWNX development, I havn't tested it
particularly, but there is no reason why not. I have also only tested it with an
MS Access database, though it should work with MySQL too.
In addition, there is now a few optional extras. These are toggled by local int
variables set on the module.
PRC_CONVOCC_AVARIEL_WINGS Avariel characters have bird wings
PRC_CONVOCC_FEYRI_WINGS Fey'ri characters have bat wings
PRC_CONVOCC_FEYRI_TAIL Fey'ri characters have a demonic tail
PRC_CONVOCC_DROW_ENFORCE_GENDER Force Drow characters to be of the correct gender for
their race
PRC_CONVOCC_GENSAI_ENFORCE_DOMAINS Force Gensai clerics to select the relevant elemental
domain as one of their feats
PRC_CONVOCC_ENFORCE_BLOOD_OF_THE_WARLORD Makes Blood of the Warlord only avliable to orcish characters
PRC_CONVOCC_ENFORCE_FEAT_NIMBUSLIGHT Enforces the "moral" feats
PRC_CONVOCC_ENFORCE_FEAT_HOLYRADIANCE
PRC_CONVOCC_ENFORCE_FEAT_SERVHEAVEN
PRC_CONVOCC_ENFORCE_FEAT_SAC_VOW
PRC_CONVOCC_ENFORCE_FEAT_VOW_OBED
PRC_CONVOCC_ENFORCE_FEAT_THRALL_TO_DEMON
PRC_CONVOCC_ENFORCE_FEAT_DISCIPLE_OF_DARKNESS
PRC_CONVOCC_ENFORCE_FEAT_LICHLOVED
PRC_CONVOCC_ENFORCE_FEAT_EVIL_BRANDS
PRC_CONVOCC_ENFORCE_FEAT_VILE_WILL_DEFORM
PRC_CONVOCC_ENFORCE_FEAT_VILE_DEFORM_OBESE
PRC_CONVOCC_ENFORCE_FEAT_VILE_DEFORM_GAUNT
PRC_CONVOCC_RAKSHASHA_FEMALE_APPEARANCE Female rakshasha use the female rakshasha model
PRC_CONVOCC_DRIDER_FEMALE_APPEARANCE Female drider use the female drider model
PRC_CONVOCC_DISALLOW_CUSTOMISE_WINGS Stops players changing their wings
PRC_CONVOCC_DISALLOW_CUSTOMISE_TAIL Stops players changing their tail
PRC_CONVOCC_DISALLOW_CUSTOMISE_MODEL Stops players changing their model at all
PRC_CONVOCC_USE_RACIAL_APPEARANCES Players can only change their model / portrait / soundset
PRC_CONVOCC_USE_RACIAL_PORTRAIT to alternatives of the same race. If you have extra
PRC_CONVOCC_USE_RACIAL_SOUNDSET content (e.g. from CEP) you must add them to
SetupRacialAppearances or SetupRacialPortraits or
SetupRacialSoundsets in prc_ccc_inc_e in order for
them to be shown on the list.
PRC_CONVOCC_ONLY_PLAYER_VOICESETS Players can only select from the player voicesets
NPC voicesets are not complete, so wont play sounds
for many things such as emotes.
PRC_CONVOCC_RESTRICT_VOICESETS_BY_SEX Only allows players to select voiceset of the same gender
PRC_CONVOCC_FORCE_KEEP_VOICESET Skips the select a voiceset step entirely, and players
have to keep their current voiceset
PRC_CONVOCC_ALLOW_TO_KEEP_PORTRAIT Allow players to keep their exisiting portrait
The ConvoCC cannot allow players to select custom
portriats, so the only way for players to have them
is to select them in the bioware character creator
and then select to keep them in the ConvoCC.
PRC_CONVOCC_FORCE_KEEP_PORTRAIT Skips the select a portrait step entirely, and players
have to keep their current portrait
PRC_CONVOCC_RESTRICT_PORTRAIT_BY_SEX Only allow players to select portraits of the same gender.
Most of the NPC portraits do not have a gender so are also
removed.
PRC_CONVOCC_ENABLE_RACIAL_HITDICE This option give players the ability to start with racial
hit dice for some of the more powerful races. These are
defined in ECL.2da For these races, players do not pick
a class in the ConvoCC but instead select 1 or more levels
in a racial class (such as monsterous humanoid, or outsider).
This is not a complete ECL system, it mearly gives players
the racial hit dice component. It does not make any measure
of the Level Adjustment component. For example, a pixie has
no racial hit dice, but has a +4 level adjustment.
PRC_CONVOCC_ALLOW_HIDDEN_SKIN_COLOURS These enable players to select the hidden skin, hair,
PRC_CONVOCC_ALLOW_HIDDEN_HAIR_COLOURS and tattoo colours (metalics, matt black, matt white).
PRC_CONVOCC_ALLOW_HIDDEN_TATTOO_COLOURS
PRC_CONVOCC_ALLOW_SKILL_POINT_ROLLOVER This option allows players to keep their skillpoints
from one level to the next, if they want to.
PRC_CONVOCC_USE_XP_FOR_NEW_CHAR This will identify new characters based on X which is
the same as v1.3 but less secure.
PRC_CONVOCC_ENCRYPTION_KEY This is the key used to encrypt characters names if
USE_XP_FOR_NEW_CHAR is false in order to identify
returning characters. It should be in the range 1-100.
If USE_XP_FOR_NEW_CHAR is true, then returning
characters will be encrypted too, so once everone has
logged on at least once, USE_XP_FOR_NEW_CHAR can be
set to false for greater security.
Change log
v1.4
Changed several systems to the more general systems the PRC will use in 2.3
Fixed alertness not being given as a racial/bonus feat
Fixed cross class skills not dissapering at 1 skill point remaining
Fixed clerical domain feats not being given correctly
Fixed bonus feats not being given correctly
Fixed quick to master feat selection not being reset correctly
Added model selection
Added wing selection
Added tail selection
Added skin colour selection
Added hair colour selection
Added preview for character customizations (model, soundset, colors, etc)
Added builder options for lots of things
Added skill point storage
v1.3
Fixed a nasty bug 1.2 introduced where all characters were given elven radial feats and appearance
v1.2
Fixed another bug with user and character names with unusual characters in
Fixed bugs with MySQL database
Added BiowareDB caching (at character creation and module load only)
Added confirmation stages
Added "keep existing" options to portrait and soundset
v1.1
Fixed bug with usernames with spaces in them
Fixed bug with cleric second domain scrolling
Fixed bug with missing scripts in erf
Added portrait selection
Added soundset selection
v1.0
First Release
*/

View File

@@ -0,0 +1,241 @@
//:: Class constants
const int CLASS_TYPE_PLANT = 164;
const int CLASS_TYPE_PRC_EYE_OF_GRUUMSH = 39;
const int CLASS_TYPE_SHOU = 40;
const int CLASS_TYPE_UR_PRIEST = 42;
const int CLASS_TYPE_BINDER = 43;
const int CLASS_TYPE_ANIMA_MAGE = 44;
const int CLASS_TYPE_KNIGHT_SACRED_SEAL = 45;
const int CLASS_TYPE_SCION_DANTALION = 46;
const int CLASS_TYPE_TENEBROUS_APOSTATE = 47;
const int CLASS_TYPE_REAPING_MAULER = 48;
const int CLASS_TYPE_SERENE_GUARDIAN = 49;
const int CLASS_TYPE_SACREDPURIFIER = 50;
const int CLASS_TYPE_OCULAR = 51;
const int CLASS_TYPE_BATTLERAGER = 52;
const int CLASS_TYPE_MYSTIC_THEURGE = 53;
const int CLASS_TYPE_NINJA_SPY = 54;
const int CLASS_TYPE_SAMURAI = 55;
const int CLASS_TYPE_WARPRIEST = 56;
const int CLASS_TYPE_SPELLFIRE = 57;
const int CLASS_TYPE_VIRTUOSO = 58;
const int CLASS_TYPE_MARSHAL = 59;
const int CLASS_TYPE_SWASHBUCKLER = 60;
const int CLASS_TYPE_HEXBLADE = 61;
const int CLASS_TYPE_DUSKBLADE = 62;
const int CLASS_TYPE_SCOUT = 63;
const int CLASS_TYPE_HEALER = 64;
const int CLASS_TYPE_MAGEKILLER = 65;
const int CLASS_TYPE_HARPERMAGE = 66;
const int CLASS_TYPE_SPELLSWORD = 67;
const int CLASS_TYPE_ACOLYTE = 68;
const int CLASS_TYPE_UNSEEN_SEER = 69;
const int CLASS_TYPE_ELDRITCH_KNIGHT = 70;
const int CLASS_TYPE_ELEMENTAL_SAVANT = 71;
const int CLASS_TYPE_FACTOTUM = 72;
const int CLASS_TYPE_CELEBRANT_SHARESS = 73;
const int CLASS_TYPE_CULTIST_SHATTERED_PEAK = 74;
const int CLASS_TYPE_FORSAKER = 75;
const int CLASS_TYPE_INCARNATE = 76;
const int CLASS_TYPE_SOULBORN = 77;
const int CLASS_TYPE_TOTEMIST = 78;
const int CLASS_TYPE_BEGUILER = 79;
const int CLASS_TYPE_DUELIST = 80;
const int CLASS_TYPE_HIEROPHANT = 81;
const int CLASS_TYPE_RED_AVENGER = 82;
const int CLASS_TYPE_KNIGHT_CHALICE = 83;
const int CLASS_TYPE_HATHRAN = 84;
const int CLASS_TYPE_IRONSOUL_FORGEMASTER = 85;
const int CLASS_TYPE_STORMLORD = 86;
const int CLASS_TYPE_HEARTWARDER = 87;
const int CLASS_TYPE_FISTRAZIEL = 88;
const int CLASS_TYPE_VASSAL = 89;
const int CLASS_TYPE_LICH = 90;
const int CLASS_TYPE_PNP_SHIFTER = 91;
const int CLASS_TYPE_COC = 92;
const int CLASS_TYPE_SUBLIME_CHORD = 93;
const int CLASS_TYPE_ARTIFICER = 94;
const int CLASS_TYPE_ARCANE_DUELIST = 95;
const int CLASS_TYPE_FMM = 96;
const int CLASS_TYPE_WILD_MAGE = 97;
const int CLASS_TYPE_SHADOWSMITH = 98;
const int CLASS_TYPE_ABJURANT_CHAMPION = 99;
const int CLASS_TYPE_ARCHMAGE = 100;
const int CLASS_TYPE_OOZEMASTER = 101;
const int CLASS_TYPE_PSYCHIC_ROGUE = 102;
const int CLASS_TYPE_SPELLDANCER = 103;
const int CLASS_TYPE_KNIGHT_WEAVE = 104;
const int CLASS_TYPE_JUDICATOR = 105;
const int CLASS_TYPE_SHADOWBANE_INQUISITOR = 106;
const int CLASS_TYPE_SHADOWBANE_STALKER = 107;
const int CLASS_TYPE_WAYFARER_GUIDE = 108;
const int CLASS_TYPE_UMBRAL_DISCIPLE = 109;
const int CLASS_TYPE_ALIENIST = 110;
const int CLASS_TYPE_BLACK_BLOOD_CULTIST = 111;
const int CLASS_TYPE_WARLOCK = 112;
const int CLASS_TYPE_FOCHLUCAN_LYRIST = 113;
const int CLASS_TYPE_DRAGONSONG_LYRIST = 114;
const int CLASS_TYPE_SPINEMELD_WARRIOR = 115;
const int CLASS_TYPE_NIGHTSHADE = 116;
const int CLASS_TYPE_SHADOW_ADEPT = 117;
const int CLASS_TYPE_SOLDIER_OF_LIGHT = 118;
const int CLASS_TYPE_SAPPHIRE_HIERARCH = 119;
const int CLASS_TYPE_SHADOWLORD = 120;
const int CLASS_TYPE_BONDED_SUMMONNER = 121;
const int CLASS_TYPE_INITIATE_DRACONIC = 122;
const int CLASS_TYPE_TEMPUS = 123;
const int CLASS_TYPE_BLADESINGER = 124;
const int CLASS_TYPE_SOULCASTER = 125;
const int CLASS_TYPE_SACREDFIST = 126;
const int CLASS_TYPE_LEGENDARY_DREADNOUGHT = 127;
const int CLASS_TYPE_DISC_BAALZEBUL = 128;
const int CLASS_TYPE_MIGHTY_CONTENDER_KORD = 129;
const int CLASS_TYPE_IAIJUTSU_MASTER = 130;
const int CLASS_TYPE_DISPATER = 131;
const int CLASS_TYPE_CW_SAMURAI = 132;
const int CLASS_TYPE_RAVAGER = 133;
const int CLASS_TYPE_RUNESCARRED = 134;
const int CLASS_TYPE_BLIGHTLORD = 135;
const int CLASS_TYPE_SHADOWCASTER = 136;
const int CLASS_TYPE_CHILD_OF_NIGHT = 137;
const int CLASS_TYPE_MASTER_OF_SHADOW = 138;
const int CLASS_TYPE_NOCTUMANCER = 139;
const int CLASS_TYPE_TOTEM_RAGER = 140;
const int CLASS_TYPE_NINJA = 141;
const int CLASS_TYPE_SHADOWBLADE = 142;
const int CLASS_TYPE_DRAGON_SHAMAN = 143;
const int CLASS_TYPE_DRAGONFIRE_ADEPT = 144;
const int CLASS_TYPE_PSION = 145;
const int CLASS_TYPE_PSYWAR = 146;
const int CLASS_TYPE_SOULKNIFE = 147;
const int CLASS_TYPE_WILDER = 148;
const int CLASS_TYPE_THAYAN_KNIGHT = 149;
const int CLASS_TYPE_RED_WIZARD = 150;
const int CLASS_TYPE_TRUENECRO = 151;
const int CLASS_TYPE_ARCTRICK = 152;
const int CLASS_TYPE_BLOOD_MAGUS = 153;
const int CLASS_TYPE_DIABOLIST = 154;
const int CLASS_TYPE_HEXTOR = 155;
const int CLASS_TYPE_INCANDESCENT_CHAMPION = 156;
const int CLASS_TYPE_JUSTICEWW = 157;
const int CLASS_TYPE_ACOLYTE_EGO = 158;
const int CLASS_TYPE_PEERLESS = 159;
const int CLASS_TYPE_LASHER = 160;
const int CLASS_TYPE_ORDER_BOW_INITIATE = 161;
const int CLASS_TYPE_HELLFIRE_WARLOCK = 162;
const int CLASS_TYPE_ORCUS = 163;
//:: Plant = 164
const int CLASS_TYPE_BFZ = 165;
const int CLASS_TYPE_SHINING_BLADE = 166;
const int CLASS_TYPE_KNIGHT_MIDDLECIRCLE = 167;
const int CLASS_TYPE_MAESTER = 168;
const int CLASS_TYPE_COMBAT_MEDIC = 169;
const int CLASS_TYPE_OLLAM = 170;
const int CLASS_TYPE_HALFLING_WARSLINGER = 171;
const int CLASS_TYPE_SPIRIT_SHAMAN = 172;
const int CLASS_TYPE_WEREWOLF = 173;
const int CLASS_TYPE_HOSPITALER = 174;
const int CLASS_TYPE_MASTER_OF_SHROUDS = 175;
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_ORC_WARLORD = 181;
const int CLASS_TYPE_THRALL_OF_GRAZZT_A = 182;
const int CLASS_TYPE_NECROCARNATE = 183;
const int CLASS_TYPE_ELDRITCH_DISCIPLE = 184;
const int CLASS_TYPE_ELDRITCH_THEURGE = 185;
const int CLASS_TYPE_GHOST_FACED_KILLER = 186;
const int CLASS_TYPE_DREAD_NECROMANCER = 187;
const int CLASS_TYPE_ULTIMATE_MAGUS = 188;
const int CLASS_TYPE_FORESTMASTER = 189;
const int CLASS_TYPE_ARCHIVIST = 190;
const int CLASS_TYPE_DEEPSTONE_SENTINEL = 191;
const int CLASS_TYPE_JADE_PHOENIX_MAGE = 192;
const int CLASS_TYPE_BLOODCLAW_MASTER = 193;
const int CLASS_TYPE_RUBY_VINDICATOR = 194;
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_DISCIPLE_OF_MEPH = 200;
const int CLASS_TYPE_SOUL_EATER = 201;
const int CLASS_TYPE_HENSHIN_MYSTIC = 202;
const int CLASS_TYPE_DRUNKEN_MASTER = 203;
const int CLASS_TYPE_ENLIGHTENEDFIST = 204;
const int CLASS_TYPE_MORNINGLORD = 205;
const int CLASS_TYPE_INCARNUM_BLADE = 206;
const int CLASS_TYPE_SHAMAN = 207;
const int CLASS_TYPE_PYROKINETICIST = 208;
const int CLASS_TYPE_SHADOWMIND = 209;
const int CLASS_TYPE_PSYCHIC_THEURGE = 210;
const int CLASS_TYPE_CEREBREMANCER = 211;
const int CLASS_TYPE_THRALLHERD = 212;
const int CLASS_TYPE_FIST_OF_ZUOKEN = 213;
const int CLASS_TYPE_HAVOC_MAGE = 214;
const int CLASS_TYPE_CONTEMPLATIVE = 215;
const int CLASS_TYPE_RUNECASTER = 216;
const int CLASS_TYPE_WARCHIEF = 217;
const int CLASS_TYPE_WARMIND = 218;
const int CLASS_TYPE_IRONMIND = 219;
const int CLASS_TYPE_SANCTIFIED_MIND = 220;
const int CLASS_TYPE_SLAYER_OF_DOMIEL = 221;
const int CLASS_TYPE_DISCIPLE_OF_ASMODEUS = 222;
const int CLASS_TYPE_DIRGESINGER = 223;
const int CLASS_TYPE_SUEL_ARCHANAMACH = 224;
const int CLASS_TYPE_FAVOURED_SOUL = 225;
const int CLASS_TYPE_WAR_WIZARD_OF_CORMYR = 226;
const int CLASS_TYPE_SKULLCLAN_HUNTER = 227;
const int CLASS_TYPE_TRUENAMER = 228;
const int CLASS_TYPE_MASTER_ALCHEMIST = 229;
const int CLASS_TYPE_BEREFT = 230;
const int CLASS_TYPE_BRIMSTONE_SPEAKER = 231;
const int CLASS_TYPE_SHUGENJA = 232;
const int CLASS_TYPE_SOHEI = 233;
const int CLASS_TYPE_CRUSADER = 234;
const int CLASS_TYPE_SWORDSAGE = 235;
const int CLASS_TYPE_WARBLADE = 236;
const int CLASS_TYPE_WARMAGE = 237;
const int CLASS_TYPE_KNIGHT = 238;
const int CLASS_TYPE_FIST_DAL_QUOR = 239;
const int CLASS_TYPE_HANDOTWM = 240;
const int CLASS_TYPE_TALON_OF_TIAMAT = 241;
const int CLASS_TYPE_DRAGON_DEVOTEE = 242;
const int CLASS_TYPE_FROST_MAGE = 243;
const int CLASS_TYPE_WARFORGED_JUGGERNAUT = 244;
const int CLASS_TYPE_BATTLESMITH = 245;
const int CLASS_TYPE_NENTYAR_HUNTER = 246;
const int CLASS_TYPE_BLIGHTER = 247;
const int CLASS_TYPE_RAGE_MAGE = 248;
const int CLASS_TYPE_DRAGONHEART_MAGE = 249;
const int CLASS_TYPE_SWIFT_WING = 250;
const int CLASS_TYPE_DIAMOND_DRAGON = 251;
const int CLASS_TYPE_FROSTRAGER = 252;
const int CLASS_TYPE_CRINTI_SHADOW_MARAUDER = 253;
const int CLASS_TYPE_SHADOW_THIEF_AMN = 254;
const int CLASS_TYPE_ANTI_PALADIN = -1;
const int CLASS_TYPE_NIGHTSTALKER = -1; //Just here to make things compile until it gets stripped out
const int CLASS_TYPE_MINSTREL_EDGE = -1;
const int CLASS_TYPE_BRAWLER = -1;
const int CLASS_TYPE_THRALL_OF_GRAZZT_D = -1;
const int CLASS_TYPE_MASTER_HARPER_DIV = -1;
const int CLASS_TYPE_ULTIMATE_RANGER = -1;
const int CLASS_TYPE_MANATARMS = -1;
const int CLASS_TYPE_BOWMAN = -1;
const int CLASS_TYPE_VIGILANT = -1;
const int CLASS_TYPE_ARCANE_HIEROPHANT = -1;
const int CLASS_TYPE_ALAGHAR = -1;
const int CLASS_TYPE_BLARCHER = -1;
const int CLASS_TYPE_WITCH = -1;
const int CLASS_TYPE_TEMPLAR = -1;
const int CLASS_TYPE_MYSTIC = -1;
const int CLASS_TYPE_NOBLE = -1;
//void main (){}

View File

@@ -0,0 +1,171 @@
const int PRC_COMP_APPEARANCE_TYPE_BEHOLDER_EYEBALL_150 = 482;
const int PRC_COMP_APPEARANCE_TYPE_BEHOLDER_125 = 483;
const int PRC_COMP_APPEARANCE_TYPE_BEHOLDER_MAGE_125 = 484;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_BLACK_75 = 485;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_BLACK_125 = 486;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_BRASS_75 = 487;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_BRASS_125 = 488;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_COPPER_75 = 489;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_COPPER_125 = 490;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_SILVER_75 = 491;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_SILVER_125 = 492;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_BRONZE_75 = 493;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_BRONZE_125 = 494;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_GOLD_75 = 495;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_GOLD_125 = 496;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_BLUE_75 = 497;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_BLUE_125 = 498;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_GREEN_75 = 499;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_GREEN_125 = 500;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_RED_75 = 501;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_RED_125 = 502;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_WHITE_75 = 503;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_WHITE_125 = 504;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_SHADOW_75 = 505;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_SHADOW_125 = 506;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_PRISM_75 = 507;
const int PRC_COMP_APPEARANCE_TYPE_DRAGON_PRISM_125 = 508;
const int PRC_COMP_APPEARANCE_TYPE_BEETLE_SLICER_125 = 509;
const int PRC_COMP_APPEARANCE_TYPE_BEETLE_STAG_125 = 510;
const int PRC_COMP_APPEARANCE_TYPE_ELEMENTAL_AIR_125 = 511;
const int PRC_COMP_APPEARANCE_TYPE_ELEMENTAL_AIR_150 = 512;
const int PRC_COMP_APPEARANCE_TYPE_ELEMENTAL_AIR_ELDER_125 = 513;
const int PRC_COMP_APPEARANCE_TYPE_ELEMENTAL_AIR_ELDER_150 = 514;
const int PRC_COMP_APPEARANCE_TYPE_ELEMENTAL_EARTH_125 = 515;
const int PRC_COMP_APPEARANCE_TYPE_ELEMENTAL_EARTH_150 = 516;
const int PRC_COMP_APPEARANCE_TYPE_ELEMENTAL_EARTH_ELDER_125=517;
const int PRC_COMP_APPEARANCE_TYPE_ELEMENTAL_EARTH_ELDER_150=518;
const int PRC_COMP_APPEARANCE_TYPE_ELEMENTAL_FIRE_125 = 519;
const int PRC_COMP_APPEARANCE_TYPE_ELEMENTAL_FIRE_150 = 520;
const int PRC_COMP_APPEARANCE_TYPE_ELEMENTAL_FIRE_ELDER_125= 521;
const int PRC_COMP_APPEARANCE_TYPE_ELEMENTAL_FIRE_ELDER_150= 522;
const int PRC_COMP_APPEARANCE_TYPE_ELEMENTAL_WATER_125 = 523;
const int PRC_COMP_APPEARANCE_TYPE_ELEMENTAL_WATER_150 = 524;
const int PRC_COMP_APPEARANCE_TYPE_ELEMENTAL_WATER_ELDER_125=525;
const int PRC_COMP_APPEARANCE_TYPE_ELEMENTAL_WATER_ELDER_150=526;
const int PRC_COMP_APPEARANCE_TYPE_MUMMY_COMMON_125 = 527;
const int PRC_COMP_APPEARANCE_TYPE_SKELETON_COMMON_125 = 528;
const int PRC_COMP_APPEARANCE_TYPE_SKELETON_COMMON_150 = 529;
const int PRC_COMP_APPEARANCE_TYPE_SHIELD_GUARDIAN_125 = 530;
const int PRC_COMP_APPEARANCE_TYPE_GOLEM_CLAY_125 = 531;
const int PRC_COMP_APPEARANCE_TYPE_MOHRG_125 = 532;
const int PRC_COMP_APPEARANCE_TYPE_ZOMBIE_125 = 533;
const int PRC_COMP_APPEARANCE_TYPE_ZOMBIE_150 = 534;
const int PRC_COMP_APPEARANCE_TYPE_GARGOYLE_125 = 535;
const int PRC_COMP_APPEARANCE_TYPE_SKELETAL_DEVOURER_125 = 536;
const int PRC_COMP_APPEARANCE_TYPE_PENGUIN_150 = 537;
const int PRC_COMP_APPEARANCE_TYPE_PENGUIN_200 = 538;
const int PRC_COMP_APPEARANCE_TYPE_PENGUIN_300 = 539;
const int PRC_COMP_APPEARANCE_TYPE_PENGUIN_400 = 540;
const int PRC_COMP_APPEARANCE_TYPE_PENGUIN_500 = 541;
const int PRC_COMP_APPEARANCE_TYPE_BEETLE_STAG_50 = 542;
const int PRC_COMP_APPEARANCE_TYPE_BEETLE_STAG_25 = 543;
const int PRC_COMP_APPEARANCE_TYPE_BEETLE_STINK_50 = 544;
const int PRC_COMP_APPEARANCE_TYPE_BEETLE_STINK_25 = 545;
const int PRC_COMP_APPEARANCE_TYPE_BAT_50 = 546;
const int PRC_COMP_APPEARANCE_TYPE_BAT_60 = 547;
const int PRC_COMP_APPEARANCE_TYPE_BAT_70 = 548;
const int PRC_COMP_APPEARANCE_TYPE_BAT_80 = 549;
const int PRC_COMP_APPEARANCE_TYPE_BAT_90 = 550;
const int PRC_COMP_APPEARANCE_TYPE_BAT_125 = 551;
const int PRC_COMP_APPEARANCE_TYPE_CAT_COUGAR_40 = 552;
const int PRC_COMP_APPEARANCE_TYPE_CAT_COUGAR_50 = 553;
const int PRC_COMP_APPEARANCE_TYPE_CAT_COUGAR_75 = 554;
const int PRC_COMP_APPEARANCE_TYPE_CAT_LION_40 = 555;
const int PRC_COMP_APPEARANCE_TYPE_CAT_LION_50 = 556;
const int PRC_COMP_APPEARANCE_TYPE_CAT_LION_75 = 557;
const int PRC_COMP_APPEARANCE_TYPE_CAT_PANTHER_40 = 558;
const int PRC_COMP_APPEARANCE_TYPE_CAT_PANTHER_50 = 559;
const int PRC_COMP_APPEARANCE_TYPE_CAT_PANTHER_75 = 560;
const int PRC_COMP_APPEARANCE_TYPE_RAT_50 = 561;
const int PRC_COMP_APPEARANCE_TYPE_RAT_75 = 562;
const int PRC_COMP_APPEARANCE_TYPE_SKELETON_COMMON_50 = 563;
const int PRC_COMP_APPEARANCE_TYPE_SKELETON_COMMON_75 = 564;
const int PRC_COMP_APPEARANCE_TYPE_ZOMBIE_50 = 565;
const int PRC_COMP_APPEARANCE_TYPE_ZOMBIE_75 = 566;
const int PRC_COMP_APPEARANCE_TYPE_GOLEM_IRON_125 = 567;
const int PRC_COMP_APPEARANCE_TYPE_GOLEM_STONE_125 = 568;
const int PRC_COMP_APPEARANCE_TYPE_BAT_150 = 569;
const int PRC_COMP_APPEARANCE_TYPE_BAT_200 = 570;
const int PRC_COMP_APPEARANCE_TYPE_OGRE_DLA = 1535;
const int PRC_COMP_APPEARANCE_TYPE_MONODRONE = 1529;
const int PRC_COMP_APPEARANCE_TYPE_OSYLUTH_C = 1503;
const int PRC_COMP_APPEARANCE_TYPE_OSYLUTH_B = 1502;
const int PRC_COMP_APPEARANCE_TYPE_OSYLUTH_A = 1501;
const int PRC_COMP_APPEARANCE_TYPE_MAUG_COMMANDER = 1500;
const int PRC_COMP_APPEARANCE_TYPE_MAUG_LIEUTENANT = 1499;
const int PRC_COMP_APPEARANCE_TYPE_MAUG = 1498;
const int PRC_COMP_APPEARANCE_TYPE_TREANT = 1492;
const int PRC_COMP_APPEARANCE_TYPE_GLABREZU = 1418;
const int PRC_COMP_APPEARANCE_TYPE_HARLAT = 990;
const int PRC_COMP_APPEARANCE_TYPE_MASTERIUS = 991;
const int PRC_COMP_APPEARANCE_TYPE_BEHOLDER_GZORB = 993;
const int PRC_COMP_APPEARANCE_TYPE_HAGTHA = 994;
const int PRC_COMP_APPEARANCE_TYPE_WEREBOAR = 996;
const int PRC_COMP_APPEARANCE_TYPE_ANTOINE = 997;
const int PRC_COMP_APPEARANCE_TYPE_MAGGRIS = 998;
const int PRC_COMP_APPEARANCE_TYPE_HALASTER = 999;
const int PRC_COMP_POLYMORPH_TYPE_PENGUIN_150 = 151;
const int PRC_COMP_POLYMORPH_TYPE_PENGUIN_200 = 152;
const int PRC_COMP_POLYMORPH_TYPE_PENGUIN_300 = 153;
const int PRC_COMP_POLYMORPH_TYPE_PENGUIN_400 = 154;
const int PRC_COMP_POLYMORPH_TYPE_PENGUIN_500 = 155;
const int PRC_COMP_WING_TYPE_ERINYES = 30;
const int PRC_COMP_WING_TYPE_BIRD_RED = 31;
const int PRC_COMP_WING_TYPE_BIRD_DARK = 32;
const int PRC_COMP_WING_TYPE_BIRD_BLUE = 33;
const int PRC_COMP_WING_TYPE_DRAGON_BLACK = 34;
const int PRC_COMP_WING_TYPE_DRAGON_BLUE = 35;
const int PRC_COMP_WING_TYPE_DRAGON_BRASS = 36;
const int PRC_COMP_WING_TYPE_DRAGON_BRONZE = 37;
const int PRC_COMP_WING_TYPE_DRAGON_COPPER = 38;
const int PRC_COMP_WING_TYPE_DRAGON_GOLD = 39;
const int PRC_COMP_WING_TYPE_DRAGON_GREEN = 40;
const int PRC_COMP_WING_TYPE_DRAGON_SILVER = 41;
const int PRC_COMP_WING_TYPE_DRAGON_WHITE = 42;
const int PRC_COMP_WING_TYPE_BIRD_KENKU = 43;
const int PRC_COMP_WING_TYPE_HALFDRAGON_GOLD = 44;
const int PRC_COMP_WING_TYPE_HALFDRAGON_SILVER = 45;
const int PRC_COMP_WING_TYPE_ANGEL_ARMORED = 46;
const int PRC_COMP_WING_TYPE_ANGEL_FALLEN = 47;
const int PRC_COMP_WING_TYPE_RAVEN = 48;
const int PRC_COMP_WING_TYPE_MEPHISTO = 49;
const int PRC_COMP_WING_TYPE_DRAGON_SHADOW = 50;
const int PRC_COMP_WING_TYPE_DRAGON_DRACOLICH = 51;
const int PRC_COMP_WING_TYPE_DRAGON_PRISMATIC = 52;
const int PRC_COMP_TAIL_TYPE_CAT = 130;
const int PRC_COMP_TAIL_TYPE_MAGE_TAIL = 131;
const int PRC_COMP_TAIL_TYPE_MAGE_TAIL_2 = 132;
const int PRC_COMP_TAIL_TYPE_WAR_TAIL = 133;
const int PRC_COMP_TAIL_TYPE_LIZARD_RED = 134;
const int PRC_COMP_TAIL_TYPE_LIZARD_BLACK = 135;
const int PRC_COMP_TAIL_TYPE_LIZARD_BLUE = 136;
const int PRC_COMP_TAIL_TYPE_LIZARD_WHITE = 137;
const int PRC_COMP_TAIL_TYPE_LIZARD_PRISMATIC = 138;
const int PRC_COMP_TAIL_TYPE_LIZARD_SHADOW = 139;
const int PRC_COMP_TAIL_TYPE_LIZARD_BRASS = 140;
const int PRC_COMP_TAIL_TYPE_LIZARD_BRONZE = 141;
const int PRC_COMP_TAIL_TYPE_LIZARD_COPPER = 142;
const int PRC_COMP_TAIL_TYPE_LIZARD_GOLD = 143;
const int PRC_COMP_TAIL_TYPE_LIZARD_SILVER = 144;
const int PRC_COMP_TAIL_TYPE_GARGOYLE = 145;
const int PRC_COMP_TAIL_TYPE_MINOTAUR = 146;
const int PRC_COMP_TAIL_TYPE_WERECAT = 147;
const int PRC_COMP_TAIL_TYPE_BULETTER = 148;
const int PRC_COMP_TAIL_TYPE_RAVEN = 149;
const int PRC_COMP_TAIL_TYPE_FALCON = 150;
const int PRC_COMP_TAIL_TYPE_MANTICORE = 151;
const int PRC_COMP_TAIL_TYPE_HALFLIZARD_SILVER = 152;
const int PRC_COMP_TAIL_TYPE_HALFLIZARD_GOLD = 153;
const int PRC_COMP_TAIL_TYPE_LEOPARD = 154;
const int PRC_COMP_TAIL_TYPE_LEOPARD_SNOW = 155;
const int PRC_COMP_TAIL_TYPE_TIGER = 156;
const int PRC_COMP_TAIL_TYPE_TIGER_WHITE = 157;
const int PRC_COMP_TAIL_TYPE_FOX = 158;
const int PRC_COMP_TAIL_TYPE_WOLF = 159;
const int PRC_COMP_TAIL_TYPE_WOLF_SHAGGY = 160;
const int PRC_COMP_TAIL_TYPE_LIZARD_DYNAMIC = 161;
const int PRC_COMP_TAIL_TYPE_DEVIL_DYNAMIC = 162;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,750 @@
/**
* @file
* This file contains SPApplyEffectToObject(). This was in inc_dispel, but that include should only be in
* dispel-type spells and not the core spell engine.
*/
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Gets a creature that can apply an effect
* Useful to apply/remove specific effects rather than using spellID
* Remember to assigncommand the effect creation
*/
object GetObjectToApplyNewEffect(string sTag, object oPC, int nStripEffects = TRUE);
/**
* A wrapper for ApplyEffectToObject() that takes PRC feats into account.
*
* @param nDurationType One of the DURATION_TYPE_* constants
* @param eEffect The effect to apply
* @param oTarget The target of the effect
* @param fDuration The duration for temporary effects
* @param bDispellable TRUE if the effect should be dispellable, else FALSE
* @param nSpellID The Spell ID of the spell applying the effect. If default is used,
* PRCGetSpellId() is used internally to get the spell ID.
* @param nCasterLevel The caster level that the spell is cast with. If default is used,
* PRCGetCasterLevel() is used internally to get the caster level.
* @param oCaster The spell caster.
*/
void SPApplyEffectToObject(int nDurationType, effect eEffect, object oTarget, float fDuration = 0.0f,
int bDispellable = TRUE, int nSpellID = -1, int nCasterLevel = -1, object oCaster = OBJECT_SELF);
/**
* Removes all effects from target that are due to the given spell.
*
* Removes all effects caused by the spell nID regardless of caster. By
* default only removes magical effects.
*
* @author Georg Zoeller (presumably copied from a bio script somewhere)
*
* @param nID The spell ID whose effects to remove.
* @param oTarget The object to remove the effects from.
* @param bMagicalEffectsOnly Whether to remove only magical effects (TRUE, the default)
* or all effects (FALSE)
*/
void GZPRCRemoveSpellEffects(int nID,object oTarget, int bMagicalEffectsOnly = TRUE);
/**
* Tests to make sure the data in the effect arrays still refers to an actual effect.
*
* Called from within ReorderEffects() and DispelMagicBestMod() (in inc_dispel). It's purpose
* is to verify that the effect referred to by an entry in the 3 arrays is still in effect, in
* case it has been dispelled or run out its duration since the data was put there.
*
* @param nSpellID SpellID of the effect to test
* @param oCaster Caster of the spell that caused the effectbeing tested
* @param oTarget The object whose effect arrays are being looked at.
*
* @return TRUE if the effect is still active, otherwise FALSE.
*/
int IsStillRealEffect(int nSpellID, object oCaster, object oTarget);
/**
* Checks if target is a Frenzied Bersker with Deathless Frenzy Active
* If so removes immortality flag so that the death effect from a
* Death Spell can kill them
*
* @param oTarget Creature to test for Deathless Frenzy
*/
void DeathlessFrenzyCheck(object oTarget);
// * Searchs through a persons effects and removes those from a particular spell by a particular caster.
// * PRC Version of a Bioware function to disable include loops
void PRCRemoveSpellEffects(int nSpell_ID, object oCaster, object oTarget);
/**
* Dazzles the target: -1 Attack, Search, Spot, and VFX
*
* @return the Dazzle effect
*/
effect EffectDazzle();
/**
* Shaken effect: -2 to attack, all skills and saving throws
*
* @return the Shaken effect
*/
effect EffectShaken();
/**
* Fatigue effect: -2 to Strength and Dexterity, 25% speed decrease. Can't be dispelled.
*
* @return the Fatigue effect
*/
effect EffectFatigue();
/**
* Exhausted effect: -6 to Strength and Dexterity, 50% speed decrease. Can't be dispelled.
*
* @return the Exhausted effect
*/
effect EffectExhausted();
/**
* Cowering effect: -2 to AC, takes no actions (dazed)
*
* @return the Cowering effect
*/
effect EffectCowering();
/**
* Sickened effect: -2 to attack, damage, all skills, ability checks and saving throws
*
* @return the Sickened effect
*/
effect EffectSickened();
/**
* Nausea effect: Nauseated creatures are unable to attack, cast spells, concentrate on spells, or do anything
* else requiring attention. The only action such a character can take is a single move action per turn.
* This function takes a duration and target because it sets the enemy's number of attacks in a round to 1
* Which means once it's called, the BAB effect is applied
*
* @return the Nausea effect
*/
effect EffectNausea(object oTarget, float fDur);
/**
* Fascinate effect: charmed, -4 to Listen and Spot
*
* @return the Fascinate effect
*/
effect EffectFascinate();
/**
* It's Confused, as per normal
*
* @return the Confused effect
*/
effect PRCEffectConfused();
/**
* It's EffectHeal, but allows us to manipulate the HP total healed
*
* @return the Heal effect
*/
effect PRCEffectHeal(int nHP, object oTarget);
/**
* Creates skill bonus for all skills based on particular ability.
* Should be updated if skills.2da file was edited.
*
* @param iAbility base ability
* @param iIncrease bonus applied to each skill
*
* @return Skill increase
*/
effect EffectAbilityBasedSkillIncrease(int iAbility, int iIncrease = 1);
/**
* Creates skill penalty for all skills based on particular ability
* Should be updated if skills.2da file was edited.
*
* @param iAbility base ability
* @param iDecrease penalty applied to each skill
*
* @return Skill decrease
*/
effect EffectAbilityBasedSkillDecrease(int iAbility, int iDecrease = 1);
//ebonfowl: adding this function to check if a target is already shaken
int GetIsShaken(object oTarget);
//////////////////////////////////////////////////
/* Include section */
//////////////////////////////////////////////////
#include "prc_inc_castlvl" // get prc_racial_const, prc_inc_nwscript, prc_inc_newip
//////////////////////////////////////////////////
/* Internal functions */
//////////////////////////////////////////////////
/**
* Cleans up the 3 arrays used to store effect information on the object.
*
* Goes through the whole 3 stored lists of caster levels, spell id's, and casters,
* deletes any that aren't real anymore (refer to an effect no longer present), then
* builds a new list out of the ones that are still real/current (refer to effects that
* are still present)
* Thus, the list gets cleaned up every time it is added to.
*
* @param nSpellID Spell ID of the spell being cast.
* @param oTarget Object to modify the effect arrays of.
* @param oCaster The caster of the spell.
*
* @return The number of effects in the 3 new arrays
*/
int _ReorderEffects(int nSpellID, object oTarget, object oCaster = OBJECT_SELF){
int nIndex = GetLocalInt(oTarget, "X2_Effects_Index_Number");
int nEffectCastLevel;
int nEffectSpellID;
object oEffectCaster;
int nWeave ;
int nRealIndex = 0;
int nPlace;
for(nPlace = 0; nPlace <= nIndex; nPlace++)
{
nEffectSpellID = GetLocalInt(oTarget, " X2_Effect_Spell_ID_" + IntToString(nPlace));
oEffectCaster = GetLocalObject(oTarget, " X2_Effect_Caster_" + IntToString(nPlace));
nEffectCastLevel = GetLocalInt(oTarget, " X2_Effect_Cast_Level_" + IntToString(nPlace));
nWeave = GetLocalInt(oTarget, " X2_Effect_Weave_ID_" + IntToString(nPlace));
DeleteLocalInt(oTarget, " X2_Effect_Spell_ID_" + IntToString(nPlace));
DeleteLocalInt(oTarget, " X2_Effect_Cast_Level_" + IntToString(nPlace));
DeleteLocalObject(oTarget, " X2_Effect_Caster_" + IntToString(nPlace));
DeleteLocalInt(oTarget, " X2_Effect_Weave_ID_" + IntToString(nPlace));
if(IsStillRealEffect(nEffectSpellID, oEffectCaster, oTarget))
{
if(nEffectSpellID != nSpellID || oEffectCaster != oCaster)
// Take it out of the list if it's the spell now being cast, and by the same caster
// This way spells that don't self dispel when they're recast don't flood the list.
{
SetLocalInt(oTarget, " X2_Effect_Spell_ID_" + IntToString(nRealIndex), nEffectSpellID);
SetLocalInt(oTarget, " X2_Effect_Cast_Level_" + IntToString(nRealIndex), nEffectCastLevel);
SetLocalObject(oTarget, " X2_Effect_Caster_" + IntToString(nRealIndex),oEffectCaster );
SetLocalInt(oTarget, " X2_Effect_Weave_ID_" + IntToString(nRealIndex),nWeave);
nRealIndex++;
}// end of if is the same as the current spell and caster
}// end of if is valid effect statement
}// end of for statement
return nRealIndex; // This is the number of values currently in all 3 arrays -1.
}// end of function
//////////////////////////////////////////////////
/* Function Definitions */
//////////////////////////////////////////////////
object GetObjectToApplyNewEffect(string sTag, object oPC, int nStripEffects = TRUE)
{
object oWP = GetObjectByTag(sTag);
object oLimbo = GetObjectByTag("HEARTOFCHAOS");
location lLimbo = GetLocation(oLimbo);
if(!GetIsObjectValid(oLimbo))
lLimbo = GetStartingLocation();
//not valid, create it
if(!GetIsObjectValid(oWP))
{
//has to be a creature so it can be jumped around
//re-used the 2da cache blueprint since it has no scripts
oWP = CreateObject(OBJECT_TYPE_CREATURE, "prc_2da_cache", lLimbo, FALSE, sTag);
if(!GetIsObjectValid(oWP) && DEBUG)
{
DoDebug(sTag+" is not valid");
}
//make sure the player can never interact with WP
SetPlotFlag(oWP, TRUE);
SetCreatureAppearanceType(oWP, APPEARANCE_TYPE_INVISIBLE_HUMAN_MALE);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY), oWP);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectCutsceneGhost(), oWP);
}
//remove previous effects
if(nStripEffects)
{
effect eTest = GetFirstEffect(oPC);
while(GetIsEffectValid(eTest))
{
if(GetEffectCreator(eTest) == oWP
&& GetEffectSubType(eTest) == SUBTYPE_SUPERNATURAL)
{
if(DEBUG) DoDebug("Stripping previous effect");
RemoveEffect(oPC, eTest);
}
eTest = GetNextEffect(oPC);
}
}
//jump to PC
//must be in same area to apply effect
if(GetArea(oWP) != GetArea(oPC))
AssignCommand(oWP,
ActionJumpToObject(oPC));
//jump back to limbo afterwards
DelayCommand(0.1,
AssignCommand(oWP,
ActionJumpToObject(oLimbo)));
return oWP;
}
void SPApplyEffectToObject(int nDurationType, effect eEffect, object oTarget, float fDuration = 0.0f,
int bDispellable = TRUE, int nSpellID = -1, int nCasterLevel = -1, object oCaster = OBJECT_SELF)
{
if (-1 == nSpellID) nSpellID = PRCGetSpellId();
//if it was cast from the new spellbook, remove previous effects
//if(GetLocalInt(OBJECT_SELF, "UsingActionCastSpell"))
// GZPRCRemoveSpellEffects(nSpellID, oTarget);
//Fearsome Necromancy check
if(GetHasFeat(FEAT_FEARSOME_NECROMANCY, oCaster))
{
if(GetSpellSchool(nSpellID) == SPELL_SCHOOL_NECROMANCY)
{
if(GetIsEnemy(oTarget, oCaster)
&& !GetIsImmune(oTarget, IMMUNITY_TYPE_MIND_SPELLS))
{
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectShaken(), oTarget, 6.0);
}
}
}
// Illusion Veil Meld
if(GetHasSpellEffect(MELD_ILLUSION_VEIL, oCaster) && GetSpellSchool(nSpellID) == SPELL_SCHOOL_ILLUSION)
fDuration += GetEssentiaInvested(oCaster, MELD_ILLUSION_VEIL) * 6.0;
//Eldritch Spellweave
if(GetIsObjectValid(GetLocalObject(oCaster, "SPELLWEAVE_TARGET")))
ExecuteScript("inv_splweave", oCaster);
// Instant duration effects can use BioWare code, the PRC code doesn't care about those
if(DURATION_TYPE_INSTANT == nDurationType)
ApplyEffectToObject(nDurationType, eEffect, oTarget, fDuration);
else
{
// Extraordinary/Supernatural effects are not supposed to be dispellable.
if (GetEffectSubType(eEffect) == SUBTYPE_EXTRAORDINARY
|| GetEffectSubType(eEffect) == SUBTYPE_SUPERNATURAL)
{
bDispellable = FALSE;
}
// We need the extra arguments for the PRC code, get them if defaults were passed in.
if (-1 == nCasterLevel) nCasterLevel = PRCGetCasterLevel(oCaster);
// Invoke the PRC apply function passing the extra data.
int nIndex = _ReorderEffects(nSpellID, oTarget, oCaster);
// Add this new effect to the slot after the last effect already on the character.
//check if Master's Gift applies
if(GetHasFeat(FEAT_MASTERS_GIFT, oTarget) && GetIsArcaneClass(PRCGetLastSpellCastClass(), oCaster))
{
if(!StringToInt(Get2DACache("spells", "HostileSetting", nSpellID)))
fDuration *= 2;
}
ApplyEffectToObject(nDurationType, eEffect, oTarget, fDuration);
// may have code traverse the lists right here and not add the new effect
// if an identical one already appears in the list somewhere
SetLocalInt(oTarget, " X2_Effect_Spell_ID_" + IntToString(nIndex), nSpellID);
SetLocalInt(oTarget, " X2_Effect_Cast_Level_" + IntToString(nIndex), nCasterLevel);
SetLocalObject(oTarget, " X2_Effect_Caster_" + IntToString(nIndex), oCaster );
if(GetHasFeat(FEAT_SHADOWWEAVE, oCaster))
SetLocalInt(oTarget, " X2_Effect_Weave_ID_" + IntToString(nIndex), GetHasFeat(FEAT_TENACIOUSMAGIC,oCaster));
else
SetLocalInt(oTarget, " X2_Effect_Weave_ID_" + IntToString(nIndex), 0);
//nIndex++;
/// Set new index number to the character.
SetLocalInt(oTarget, "X2_Effects_Index_Number", nIndex);
}
}
void GZPRCRemoveSpellEffects(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);
}
}
int IsStillRealEffect(int nSpellID, object oCaster, object oTarget){
if(!GetHasSpellEffect(nSpellID, oTarget) || nSpellID == 0)
{
return FALSE;
}
effect eTestSubject = GetFirstEffect(oTarget);
while(GetIsEffectValid(eTestSubject))
{
if(GetEffectSpellId(eTestSubject) == nSpellID)
{
if(GetEffectCreator(eTestSubject) == oCaster)
{
return TRUE;
}// end of if originates from oCaster.
}// end if originates from nSpellID.
eTestSubject = GetNextEffect(oTarget);
}
return FALSE;
}
void DeathlessFrenzyCheck(object oTarget)
{
//if its immune to death, e.g via items
//then dont do this
if(GetIsImmune( oTarget, IMMUNITY_TYPE_DEATH))
return;
if(GetHasFeat(FEAT_DEATHLESS_FRENZY, oTarget)
&& GetHasFeatEffect(FEAT_FRENZY, oTarget)
&& GetImmortal(oTarget))
SetImmortal(oTarget, FALSE);
//mark them as being magically killed for death system
if(GetPRCSwitch(PRC_PNP_DEATH_ENABLE))
{
SetLocalInt(oTarget, "PRC_PNP_EfectDeathApplied",
GetLocalInt(oTarget, "PRC_PNP_EfectDeathApplied")+1);
AssignCommand(oTarget,
DelayCommand(1.0,
SetLocalInt(oTarget, "PRC_PNP_EfectDeathApplied",
GetLocalInt(oTarget, "PRC_PNP_EfectDeathApplied")-1)));
}
}
void PRCRemoveSpellEffects(int nSpell_ID, object oCaster, object oTarget){
//Declare major variables
int bValid = FALSE;
effect eAOE;
if(GetHasSpellEffect(nSpell_ID, 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)
{
RemoveEffect(oTarget, eAOE);
bValid = TRUE;
}
}
//Get next effect on the target
eAOE = GetNextEffect(oTarget);
}
}
}
// The creature is unable to see well because of overstimulation of the eyes. A dazzled
// creature takes a -1 penalty on attack rolls, Search checks, and Spot checks.
effect EffectDazzle(){
effect eBlank;
if (GetRacialType(PRCGetSpellTargetObject()) == RACIAL_TYPE_BHUKA) return eBlank;
effect eReturn = EffectLinkEffects(EffectAttackDecrease(1), EffectSkillDecrease(SKILL_SEARCH, 1));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_SPOT, 1));
eReturn = TagEffect(eReturn, "PRCDazzle");
return eReturn;
}
// A shaken character takes a -2 penalty on attack rolls, saving throws, skill checks,
// and ability checks.
// Shaken is a less severe state of fear than frightened or panicked.
effect EffectShaken(){
effect eBlank;
if (GetRacialType(PRCGetSpellTargetObject()) == RACIAL_TYPE_KRINTH) return eBlank;
effect eReturn = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_FEAR);
eReturn = EffectLinkEffects(eReturn, EffectAttackDecrease(2));
eReturn = EffectLinkEffects(eReturn, EffectSavingThrowDecrease(SAVING_THROW_ALL,2));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_ALL_SKILLS, 2));
eReturn = TagEffect(eReturn, "PRCShaken");
return eReturn;
}
// A fatigued character can neither run nor charge and takes a -2 penalty to Strength
// and Dexterity. Doing anything that would normally cause fatigue causes the fatigued
// character to become exhausted. After 8 hours of complete rest, fatigued characters
// are no longer fatigued.
effect EffectFatigue(){
effect eBlank;
if (GetLevelByClass(CLASS_TYPE_BATTLESMITH, PRCGetSpellTargetObject()) >= 3) return eBlank;
effect eReturn = EffectAbilityDecrease(ABILITY_STRENGTH, 2);
eReturn = EffectLinkEffects(eReturn, EffectAbilityDecrease(ABILITY_DEXTERITY, 2));
eReturn = EffectLinkEffects(eReturn, EffectMovementSpeedDecrease(25));
eReturn = TagEffect(eReturn, "PRCFatigue");
return eReturn;
}
// An exhausted character moves at half speed and takes a -6 penalty to Strength and
// Dexterity. After 1 hour of complete rest, an exhausted character becomes fatigued.
// A fatigued character becomes exhausted by doing something else that would normally
// cause fatigue.
effect EffectExhausted(){
effect eBlank;
if (GetLevelByClass(CLASS_TYPE_BATTLESMITH, PRCGetSpellTargetObject()) >= 3) return eBlank;
if (GetLocalInt(PRCGetSpellTargetObject(), "IncarnumDefenseLE")) return EffectFatigue();
effect eReturn = EffectAbilityDecrease(ABILITY_STRENGTH, 6);
eReturn = EffectLinkEffects(eReturn, EffectAbilityDecrease(ABILITY_DEXTERITY, 6));
eReturn = EffectLinkEffects(eReturn, EffectMovementSpeedDecrease(50));
eReturn = TagEffect(eReturn, "PRCExhausted");
return eReturn;
}
// The character is frozen in fear and can take no actions. A cowering character takes
// a -2 penalty to Armor Class and loses her Dexterity bonus (if any).
effect EffectCowering(){
effect eReturn = EffectACDecrease(2);
eReturn = EffectLinkEffects(eReturn, EffectDazed());
eReturn = TagEffect(eReturn, "PRCCowering");
return eReturn;
}
// The character takes a -2 penalty on all attack rolls, weapon damage rolls, saving
// throws, skill checks, and ability checks.
effect EffectSickened(){
effect eBlank;
if (GetHasFeat(FEAT_STRONG_STOMACH, PRCGetSpellTargetObject())) return eBlank;
if(GetHasSpellEffect(MELD_PAULDRONS_OF_HEALTH, PRCGetSpellTargetObject())) return eBlank;
effect eReturn = EffectAttackDecrease(2);
eReturn = EffectLinkEffects(eReturn, EffectDamageDecrease(2, DAMAGE_TYPE_BLUDGEONING|DAMAGE_TYPE_PIERCING|DAMAGE_TYPE_SLASHING));
eReturn = EffectLinkEffects(eReturn, EffectSavingThrowDecrease(SAVING_THROW_ALL, 2));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_ALL_SKILLS, 2));
eReturn = TagEffect(eReturn, "PRCSickened");
return eReturn;
}
// Nauseated creatures are unable to attack, cast spells, concentrate on spells, or do anything
// else requiring attention. The only action such a character can take is a single move action per turn.
effect EffectNausea(object oTarget, float fDur){
effect eBlank;
if (GetHasFeat(FEAT_STRONG_STOMACH, PRCGetSpellTargetObject())) return EffectSickened();
if(GetHasSpellEffect(MELD_PAULDRONS_OF_HEALTH, PRCGetSpellTargetObject())) return eBlank;
effect eReturn = EffectLinkEffects(EffectSpellFailure(), EffectAttackDecrease(20));
eReturn = EffectLinkEffects(eReturn, EffectSlow());
eReturn = EffectLinkEffects(EffectVisualEffect(VFX_IMP_DISEASE_S), eReturn);
eReturn = TagEffect(eReturn, "PRCNausea");
SetBaseAttackBonus(1, oTarget);
DelayCommand(fDur, RestoreBaseAttackBonus(oTarget));
return eReturn;
}
// The creature is fascinated by a magical effect. A fascinate creature
// is charmed and takes a -4 penalty to listen and spot
effect EffectFascinate(){
effect eReturn = EffectLinkEffects(EffectCharmed(), EffectSkillDecrease(SKILL_LISTEN, 4));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_SPOT, 4));
eReturn = TagEffect(eReturn, "PRCFascinate");
return eReturn;
}
// It's just Confused
effect PRCEffectConfused()
{
effect eBlank;
if (GetLevelByClass(CLASS_TYPE_WILD_MAGE, PRCGetSpellTargetObject()) >= 6 ||
(GetHasSpellEffect(VESTIGE_DAHLVERNAR, PRCGetSpellTargetObject()) && GetLocalInt(PRCGetSpellTargetObject(), "ExploitVestige") != VESTIGE_DAHLVERNAR_MAD_SOUL)
) return eBlank;
effect eEffect = EffectConfused();
eEffect = TagEffect(eEffect, "PRCConfused");
return eEffect;
}
// It's just Healing
effect PRCEffectHeal(int nHP, object oTarget)
{
// MELD_THERAPEUTIC_MANTLE
if (GetHasSpellEffect(MELD_THERAPEUTIC_MANTLE, oTarget))
nHP += (StringToInt(Get2DACache("spells", "Innate", PRCGetSpellId())) + (GetEssentiaInvested(oTarget, MELD_THERAPEUTIC_MANTLE) * 2));
return EffectHeal(nHP);
}
effect EffectAbilityBasedSkillIncrease(int iAbility, int iIncrease = 1){
effect eReturn;
switch(iAbility)
{
case ABILITY_STRENGTH:
eReturn = EffectSkillIncrease(SKILL_DISCIPLINE, iIncrease);
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_JUMP, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_CLIMB, iIncrease));
break;
case ABILITY_DEXTERITY:
eReturn = EffectSkillIncrease(SKILL_HIDE, iIncrease);
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_MOVE_SILENTLY, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_OPEN_LOCK, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_SET_TRAP, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_TUMBLE, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_RIDE, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_BALANCE, iIncrease));
break;
case ABILITY_CONSTITUTION:
eReturn = EffectSkillIncrease(SKILL_CONCENTRATION, iIncrease);
break;
case ABILITY_INTELLIGENCE:
eReturn = EffectSkillIncrease(SKILL_DISABLE_TRAP, iIncrease);
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_LORE, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_SEARCH, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_SPELLCRAFT, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_APPRAISE, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_CRAFT_TRAP, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_CRAFT_ARMOR, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_CRAFT_WEAPON, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_TRUESPEAK, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_MARTIAL_LORE, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_CRAFT_ALCHEMY, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_CRAFT_POISON, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_PSICRAFT, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_CRAFT_GENERAL, iIncrease));
break;
case ABILITY_WISDOM:
eReturn = EffectSkillIncrease(SKILL_HEAL, iIncrease);
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_LISTEN, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_SPOT, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_SENSE_MOTIVE, iIncrease));
break;
case ABILITY_CHARISMA:
eReturn = EffectSkillIncrease(SKILL_ANIMAL_EMPATHY, iIncrease);
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_PERFORM, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_PERSUADE, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_USE_MAGIC_DEVICE, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_BLUFF, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_INTIMIDATE, iIncrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillIncrease(SKILL_IAIJUTSU_FOCUS, iIncrease));
break;
}
return eReturn;
}
effect EffectAbilityBasedSkillDecrease(int iAbility, int iDecrease = 1){
effect eReturn;
switch(iAbility)
{
case ABILITY_STRENGTH:
eReturn = EffectSkillDecrease(SKILL_DISCIPLINE, iDecrease);
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_JUMP, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_CLIMB, iDecrease));
break;
case ABILITY_DEXTERITY:
eReturn = EffectSkillIncrease(SKILL_HIDE, iDecrease);
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_MOVE_SILENTLY, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_OPEN_LOCK, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_SET_TRAP, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_TUMBLE, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_RIDE, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_BALANCE, iDecrease));
break;
case ABILITY_CONSTITUTION:
eReturn = EffectSkillDecrease(SKILL_CONCENTRATION, iDecrease);
break;
case ABILITY_INTELLIGENCE:
eReturn = EffectSkillDecrease(SKILL_DISABLE_TRAP, iDecrease);
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_LORE, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_SEARCH, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_SPELLCRAFT, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_APPRAISE, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_CRAFT_TRAP, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_CRAFT_ARMOR, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_CRAFT_WEAPON, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_TRUESPEAK, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_MARTIAL_LORE, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_CRAFT_ALCHEMY, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_CRAFT_POISON, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_PSICRAFT, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_CRAFT_GENERAL, iDecrease));
break;
case ABILITY_WISDOM:
eReturn = EffectSkillDecrease(SKILL_HEAL, iDecrease);
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_LISTEN, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_SPOT, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_SENSE_MOTIVE, iDecrease));
break;
case ABILITY_CHARISMA:
eReturn = EffectSkillDecrease(SKILL_ANIMAL_EMPATHY, iDecrease);
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_PERFORM, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_PERSUADE, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_USE_MAGIC_DEVICE, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_BLUFF, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_INTIMIDATE, iDecrease));
eReturn = EffectLinkEffects(eReturn, EffectSkillDecrease(SKILL_IAIJUTSU_FOCUS, iDecrease));
break;
}
return eReturn;
}
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));
eReturn = EffectLinkEffects(eReturn, EffectDamageImmunityIncrease(DAMAGE_TYPE_DIVINE, 100));
eReturn = EffectLinkEffects(eReturn, EffectDamageImmunityIncrease(DAMAGE_TYPE_ELECTRICAL, 100));
eReturn = EffectLinkEffects(eReturn, EffectDamageImmunityIncrease(DAMAGE_TYPE_FIRE, 100));
eReturn = EffectLinkEffects(eReturn, EffectDamageImmunityIncrease(DAMAGE_TYPE_MAGICAL, 100));
eReturn = EffectLinkEffects(eReturn, EffectDamageImmunityIncrease(DAMAGE_TYPE_NEGATIVE, 100));
eReturn = EffectLinkEffects(eReturn, EffectDamageImmunityIncrease(DAMAGE_TYPE_PIERCING, 100));
eReturn = EffectLinkEffects(eReturn, EffectDamageImmunityIncrease(DAMAGE_TYPE_POSITIVE, 100));
eReturn = EffectLinkEffects(eReturn, EffectDamageImmunityIncrease(DAMAGE_TYPE_SLASHING, 100));
eReturn = EffectLinkEffects(eReturn, EffectDamageImmunityIncrease(DAMAGE_TYPE_SONIC, 100));
eReturn = TagEffect(eReturn, "PRCDamageImmunityAll");
return eReturn;
}
effect EffectImmunityMiscAll(){
effect eReturn = EffectImmunity(IMMUNITY_TYPE_ABILITY_DECREASE);
eReturn = EffectLinkEffects(eReturn, EffectImmunity(IMMUNITY_TYPE_BLINDNESS));
eReturn = EffectLinkEffects(eReturn, EffectImmunity(IMMUNITY_TYPE_DEAFNESS));
eReturn = EffectLinkEffects(eReturn, EffectImmunity(IMMUNITY_TYPE_CRITICAL_HIT));
eReturn = EffectLinkEffects(eReturn, EffectImmunity(IMMUNITY_TYPE_DEATH));
eReturn = EffectLinkEffects(eReturn, EffectImmunity(IMMUNITY_TYPE_DISEASE));
eReturn = EffectLinkEffects(eReturn, EffectImmunity(IMMUNITY_TYPE_ENTANGLE));
eReturn = EffectLinkEffects(eReturn, EffectImmunity(IMMUNITY_TYPE_SLOW));
eReturn = EffectLinkEffects(eReturn, EffectImmunity(IMMUNITY_TYPE_KNOCKDOWN));
eReturn = EffectLinkEffects(eReturn, EffectImmunity(IMMUNITY_TYPE_NEGATIVE_LEVEL));
eReturn = EffectLinkEffects(eReturn, EffectImmunity(IMMUNITY_TYPE_PARALYSIS));
eReturn = EffectLinkEffects(eReturn, EffectImmunity(IMMUNITY_TYPE_SILENCE));
eReturn = EffectLinkEffects(eReturn, EffectImmunity(IMMUNITY_TYPE_SNEAK_ATTACK));
eReturn = EffectLinkEffects(eReturn, EffectImmunity(IMMUNITY_TYPE_TRAP));
eReturn = EffectLinkEffects(eReturn, EffectImmunity(IMMUNITY_TYPE_MIND_SPELLS));
eReturn = TagEffect(eReturn, "PRCImmunityMiscAll");
return eReturn;
}
int GetIsShaken(object oTarget)
{
effect eEffect = GetFirstEffect(oTarget);
string sTag;
while (GetIsEffectValid(eEffect))
{
sTag = GetEffectTag(eEffect);
if (sTag == "PRCShaken") return TRUE;
eEffect = GetNextEffect(oTarget);
}
return FALSE;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,404 @@
// Returns the best available-for-casting n-th Level spell from oTarget.
int GetBestL0Spell(object oTarget, int nSpell);
int GetBestL1Spell(object oTarget, int nSpell);
int GetBestL2Spell(object oTarget, int nSpell);
int GetBestL3Spell(object oTarget, int nSpell);
int GetBestL4Spell(object oTarget, int nSpell);
int GetBestL5Spell(object oTarget, int nSpell);
int GetBestL6Spell(object oTarget, int nSpell);
int GetBestL7Spell(object oTarget, int nSpell);
int GetBestL8Spell(object oTarget, int nSpell);
int GetBestL9Spell(object oTarget, int nSpell);
// Returns the best available-for-casting spell from oTarget's repertoire.
int GetBestAvailableSpell(object oTarget);
#include "prc_inc_core"
int GetBestL0Spell(object oTarget, int nFallbackSpell)
{
int nRow = 0;
string s2DA = "spells";
string sInnate, sStrRef;
int nSpellID;
while (TRUE)
{
sInnate = Get2DACache(s2DA, "Innate", nRow);
if (sInnate == "") break; // End of 2DA
if (StringToInt(sInnate) == 0)
{
nSpellID = nRow;
if (PRCGetHasSpell(nSpellID, oTarget))
{
return nSpellID;
}
}
nRow++;
}
return nFallbackSpell;
}
/* int GetBestL0Spell(object oTarget, int nSpell)
{
if(PRCGetHasSpell(SPELL_ACID_SPLASH, oTarget)) return SPELL_ACID_SPLASH;
if(PRCGetHasSpell(SPELL_RAY_OF_FROST, oTarget)) return SPELL_RAY_OF_FROST;
if(PRCGetHasSpell(SPELL_DAZE, oTarget)) return SPELL_DAZE;
if(PRCGetHasSpell(SPELL_ELECTRIC_JOLT, oTarget)) return SPELL_ELECTRIC_JOLT;
if(PRCGetHasSpell(SPELL_FLARE, oTarget)) return SPELL_FLARE;
if(PRCGetHasSpell(SPELL_RESISTANCE, oTarget)) return SPELL_RESISTANCE;
if(PRCGetHasSpell(SPELL_LIGHT, oTarget)) return SPELL_LIGHT;
if(PRCGetHasSpell(SPELL_VIRTUE, oTarget)) return SPELL_VIRTUE;
if(PRCGetHasSpell(SPELL_CURE_MINOR_WOUNDS, oTarget)) return SPELL_CURE_MINOR_WOUNDS;
if(PRCGetHasSpell(SPELL_INFLICT_MINOR_WOUNDS, oTarget)) return SPELL_INFLICT_MINOR_WOUNDS;
return nSpell;
} */
/*
bscureObject
*/
int GetBestL1Spell(object oTarget, int nSpell)
{
if(PRCGetHasSpell(SPELL_MAGIC_MISSILE, oTarget)) return SPELL_MAGIC_MISSILE;
if(PRCGetHasSpell(SPELL_SUMMON_CREATURE_I, oTarget)) return SPELL_SUMMON_CREATURE_I;
if(PRCGetHasSpell(SPELL_DOOM, oTarget)) return SPELL_DOOM;
if(PRCGetHasSpell(SPELL_BANE, oTarget)) return SPELL_BANE;
if(PRCGetHasSpell(SPELL_BLESS, oTarget)) return SPELL_BLESS;
if(PRCGetHasSpell(SPELL_MAGIC_FANG, oTarget)) return SPELL_MAGIC_FANG;
if(PRCGetHasSpell(SPELL_MAGE_ARMOR, oTarget)) return SPELL_MAGE_ARMOR;
if(PRCGetHasSpell(SPELL_ENDURE_ELEMENTS, oTarget)) return SPELL_ENDURE_ELEMENTS;
if(PRCGetHasSpell(SPELL_LESSER_DISPEL, oTarget)) return SPELL_LESSER_DISPEL;
if(PRCGetHasSpell(SPELL_SANCTUARY, oTarget)) return SPELL_SANCTUARY;
if(PRCGetHasSpell(SPELL_SHIELD, oTarget)) return SPELL_SHIELD;
if(PRCGetHasSpell(SPELL_CHARM_PERSON, oTarget)) return SPELL_CHARM_PERSON;
if(PRCGetHasSpell(SPELL_DEAFENING_CLANG, oTarget)) return SPELL_DEAFENING_CLANG;
if(PRCGetHasSpell(SPELL_BALAGARNSIRONHORN, oTarget)) return SPELL_BALAGARNSIRONHORN;
if(PRCGetHasSpell(SPELL_BLESS_WEAPON, oTarget)) return SPELL_BLESS_WEAPON;
if(PRCGetHasSpell(SPELL_SHELGARNS_PERSISTENT_BLADE, oTarget)) return SPELL_SHELGARNS_PERSISTENT_BLADE;
if(PRCGetHasSpell(SPELL_NEGATIVE_ENERGY_RAY, oTarget)) return SPELL_NEGATIVE_ENERGY_RAY;
if(PRCGetHasSpell(SPELL_BURNING_HANDS, oTarget)) return SPELL_BURNING_HANDS;
if(PRCGetHasSpell(SPELL_HORIZIKAULS_BOOM, oTarget)) return SPELL_HORIZIKAULS_BOOM;
if(PRCGetHasSpell(SPELL_SHIELD_OF_FAITH, oTarget)) return SPELL_SHIELD_OF_FAITH;
if(PRCGetHasSpell(SPELL_AMPLIFY, oTarget)) return SPELL_AMPLIFY;
if(PRCGetHasSpell(SPELL_TRUE_STRIKE, oTarget)) return SPELL_TRUE_STRIKE;
if(PRCGetHasSpell(SPELL_RAY_OF_ENFEEBLEMENT, oTarget)) return SPELL_RAY_OF_ENFEEBLEMENT;
if(PRCGetHasSpell(SPELL_EXPEDITIOUS_RETREAT, oTarget)) return SPELL_EXPEDITIOUS_RETREAT;
if(PRCGetHasSpell(SPELL_ICE_DAGGER, oTarget)) return SPELL_ICE_DAGGER;
if(PRCGetHasSpell(SPELL_ENTROPIC_SHIELD, oTarget)) return SPELL_ENTROPIC_SHIELD;
if(PRCGetHasSpell(SPELL_ENTANGLE, oTarget)) return SPELL_ENTANGLE;
if(PRCGetHasSpell(SPELL_DIVINE_FAVOR, oTarget)) return SPELL_DIVINE_FAVOR;
if(PRCGetHasSpell(SPELL_FEAR, oTarget)) return SPELL_FEAR;
if(PRCGetHasSpell(SPELL_SLEEP, oTarget)) return SPELL_SLEEP;
if(PRCGetHasSpell(SPELL_SORROW, oTarget)) return SPELL_SORROW;
if(PRCGetHasSpell(SPELL_MAGIC_WEAPON, oTarget)) return SPELL_MAGIC_WEAPON;
if(PRCGetHasSpell(SPELL_SCARE, oTarget)) return SPELL_SCARE;
if(PRCGetHasSpell(SPELL_GREASE, oTarget)) return SPELL_GREASE;
if(PRCGetHasSpell(SPELL_CAMOFLAGE, oTarget)) return SPELL_CAMOFLAGE;
if(PRCGetHasSpell(SPELL_COLOR_SPRAY, oTarget)) return SPELL_COLOR_SPRAY;
if(PRCGetHasSpell(SPELL_RAY_OF_HOPE, oTarget)) return SPELL_RAY_OF_HOPE;
if(PRCGetHasSpell(SPELL_RESIST_ELEMENTS, oTarget)) return SPELL_RESIST_ELEMENTS;
if(PRCGetHasSpell(SPELL_REMOVE_FEAR, oTarget)) return SPELL_REMOVE_FEAR;
if(PRCGetHasSpell(SPELL_IRONGUTS, oTarget)) return SPELL_IRONGUTS;
if(PRCGetHasSpell(SPELL_PROTECTION_FROM_LAW, oTarget)) return SPELL_PROTECTION_FROM_LAW;
if(PRCGetHasSpell(SPELL_PROTECTION_FROM_GOOD, oTarget)) return SPELL_PROTECTION_FROM_GOOD;
if(PRCGetHasSpell(SPELL_PROTECTION__FROM_CHAOS, oTarget)) return SPELL_PROTECTION__FROM_CHAOS;
if(PRCGetHasSpell(SPELL_PROTECTION_FROM_EVIL, oTarget)) return SPELL_PROTECTION_FROM_EVIL;
if(PRCGetHasSpell(SPELL_IDENTIFY, oTarget)) return SPELL_IDENTIFY;
if(PRCGetHasSpell(SPELL_CURE_LIGHT_WOUNDS, oTarget)) return SPELL_CURE_LIGHT_WOUNDS;
if(PRCGetHasSpell(SPELL_INFLICT_LIGHT_WOUNDS, oTarget)) return SPELL_INFLICT_LIGHT_WOUNDS;
if(PRCGetHasSpell(SPELL_EXTRACT_DRUG, oTarget)) return SPELL_EXTRACT_DRUG;
if(PRCGetHasSpell(SPELL_OBSCURE_OBJECT, oTarget)) return SPELL_OBSCURE_OBJECT;
if(PRCGetHasSpell(2839, oTarget)) return 2839; //:: Disguise Self
return nSpell;
}
int GetBestL2Spell(object oTarget, int nSpell)
{
if(PRCGetHasSpell(SPELL_MELFS_ACID_ARROW, oTarget)) return SPELL_MELFS_ACID_ARROW;
if(PRCGetHasSpell(SPELL_BULLS_STRENGTH, oTarget)) return SPELL_BULLS_STRENGTH;
if(PRCGetHasSpell(SPELL_CATS_GRACE, oTarget)) return SPELL_CATS_GRACE;
if(PRCGetHasSpell(SPELL_ENDURANCE, oTarget)) return SPELL_ENDURANCE;
if(PRCGetHasSpell(SPELL_FOXS_CUNNING, oTarget)) return SPELL_FOXS_CUNNING;
if(PRCGetHasSpell(SPELL_EAGLE_SPLEDOR, oTarget)) return SPELL_EAGLE_SPLEDOR;
if(PRCGetHasSpell(SPELL_OWLS_WISDOM, oTarget)) return SPELL_OWLS_WISDOM;
if(PRCGetHasSpell(SPELL_PROTECTION_FROM_ELEMENTS, oTarget)) return SPELL_PROTECTION_FROM_ELEMENTS;
if(PRCGetHasSpell(SPELL_SUMMON_CREATURE_II, oTarget)) return SPELL_SUMMON_CREATURE_II;
if(PRCGetHasSpell(SPELL_ONE_WITH_THE_LAND, oTarget)) return SPELL_ONE_WITH_THE_LAND;
if(PRCGetHasSpell(SPELL_INVISIBILITY, oTarget)) return SPELL_INVISIBILITY;
if(PRCGetHasSpell(SPELL_CLARITY, oTarget)) return SPELL_CLARITY;
if(PRCGetHasSpell(SPELL_FIND_TRAPS, oTarget)) return SPELL_FIND_TRAPS;
if(PRCGetHasSpell(SPELL_LESSER_RESTORATION, oTarget)) return SPELL_LESSER_RESTORATION;
if(PRCGetHasSpell(SPELL_FLAME_LASH, oTarget)) return SPELL_FLAME_LASH;
if(PRCGetHasSpell(SPELL_FLAME_WEAPON, oTarget)) return SPELL_FLAME_WEAPON;
if(PRCGetHasSpell(SPELL_WEB, oTarget)) return SPELL_WEB;
if(PRCGetHasSpell(SPELL_COMBUST, oTarget)) return SPELL_COMBUST;
if(PRCGetHasSpell(SPELL_GHOUL_TOUCH, oTarget)) return SPELL_GHOUL_TOUCH;
if(PRCGetHasSpell(SPELL_KNOCK, oTarget)) return SPELL_KNOCK;
if(PRCGetHasSpell(SPELL_GHOSTLY_VISAGE, oTarget)) return SPELL_GHOSTLY_VISAGE;
if(PRCGetHasSpell(SPELL_SOUND_BURST, oTarget)) return SPELL_SOUND_BURST;
if(PRCGetHasSpell(SPELL_SILENCE, oTarget)) return SPELL_SILENCE;
if(PRCGetHasSpell(SPELL_SEE_INVISIBILITY, oTarget)) return SPELL_SEE_INVISIBILITY;
if(PRCGetHasSpell(SPELL_HOLD_PERSON, oTarget)) return SPELL_HOLD_PERSON;
if(PRCGetHasSpell(SPELL_GEDLEES_ELECTRIC_LOOP, oTarget)) return SPELL_GEDLEES_ELECTRIC_LOOP;
if(PRCGetHasSpell(SPELL_REMOVE_PARALYSIS, oTarget)) return SPELL_REMOVE_PARALYSIS;
if(PRCGetHasSpell(SPELL_CLOUD_OF_BEWILDERMENT, oTarget)) return SPELL_CLOUD_OF_BEWILDERMENT;
if(PRCGetHasSpell(SPELL_TASHAS_HIDEOUS_LAUGHTER, oTarget)) return SPELL_TASHAS_HIDEOUS_LAUGHTER;
if(PRCGetHasSpell(SPELL_BLOOD_FRENZY, oTarget)) return SPELL_BLOOD_FRENZY;
if(PRCGetHasSpell(SPELL_BLINDNESS_AND_DEAFNESS, oTarget)) return SPELL_BLINDNESS_AND_DEAFNESS;
if(PRCGetHasSpell(SPELL_STONE_BONES, oTarget)) return SPELL_STONE_BONES;
if(PRCGetHasSpell(SPELL_BARKSKIN, oTarget)) return SPELL_BARKSKIN;
if(PRCGetHasSpell(SPELL_DARKVISION, oTarget)) return SPELL_DARKVISION;
if(PRCGetHasSpell(SPELL_DEATH_ARMOR, oTarget)) return SPELL_DEATH_ARMOR;
if(PRCGetHasSpell(SPELL_DARKNESS, oTarget)) return SPELL_DARKNESS;
if(PRCGetHasSpell(SPELL_CHARM_PERSON_OR_ANIMAL, oTarget)) return SPELL_CHARM_PERSON_OR_ANIMAL;
if(PRCGetHasSpell(SPELL_AURAOFGLORY, oTarget)) return SPELL_AURAOFGLORY;
if(PRCGetHasSpell(SPELL_HOLD_ANIMAL, oTarget)) return SPELL_HOLD_ANIMAL;
if(PRCGetHasSpell(SPELL_AID, oTarget)) return SPELL_AID;
if(PRCGetHasSpell(SPELL_CONTINUAL_FLAME, oTarget)) return SPELL_CONTINUAL_FLAME;
if(PRCGetHasSpell(SPELL_CURE_MODERATE_WOUNDS, oTarget)) return SPELL_CURE_MODERATE_WOUNDS;
if(PRCGetHasSpell(SPELL_INFLICT_MODERATE_WOUNDS, oTarget)) return SPELL_INFLICT_MODERATE_WOUNDS;
return nSpell;
}
int GetBestL3Spell(object oTarget, int nSpell)
{
if(PRCGetHasSpell(SPELL_FLAME_ARROW, oTarget)) return SPELL_FLAME_ARROW;
if(PRCGetHasSpell(SPELL_CALL_LIGHTNING, oTarget)) return SPELL_CALL_LIGHTNING;
if(PRCGetHasSpell(SPELL_FIREBALL, oTarget)) return SPELL_FIREBALL;
if(PRCGetHasSpell(SPELL_DISPLACEMENT, oTarget)) return SPELL_DISPLACEMENT;
if(PRCGetHasSpell(SPELL_DISPEL_MAGIC, oTarget)) return SPELL_DISPEL_MAGIC;
if(PRCGetHasSpell(SPELL_HASTE, oTarget)) return SPELL_HASTE;
if(PRCGetHasSpell(SPELL_SLOW, oTarget)) return SPELL_SLOW;
if(PRCGetHasSpell(SPELL_VAMPIRIC_TOUCH, oTarget)) return SPELL_VAMPIRIC_TOUCH;
if(PRCGetHasSpell(SPELL_SEARING_LIGHT, oTarget)) return SPELL_SEARING_LIGHT;
if(PRCGetHasSpell(SPELL_SCINTILLATING_SPHERE, oTarget)) return SPELL_SCINTILLATING_SPHERE;
if(PRCGetHasSpell(SPELL_MESTILS_ACID_BREATH, oTarget)) return SPELL_MESTILS_ACID_BREATH;
if(PRCGetHasSpell(SPELL_MAGIC_CIRCLE_AGAINST_LAW, oTarget)) return SPELL_MAGIC_CIRCLE_AGAINST_LAW;
if(PRCGetHasSpell(SPELL_MAGIC_CIRCLE_AGAINST_GOOD, oTarget)) return SPELL_MAGIC_CIRCLE_AGAINST_GOOD;
if(PRCGetHasSpell(SPELL_MAGIC_CIRCLE_AGAINST_EVIL, oTarget)) return SPELL_MAGIC_CIRCLE_AGAINST_EVIL;
if(PRCGetHasSpell(SPELL_MAGIC_CIRCLE_AGAINST_CHAOS, oTarget)) return SPELL_MAGIC_CIRCLE_AGAINST_CHAOS;
if(PRCGetHasSpell(SPELL_LIGHTNING_BOLT, oTarget)) return SPELL_LIGHTNING_BOLT;
if(PRCGetHasSpell(SPELL_NEGATIVE_ENERGY_BURST, oTarget)) return SPELL_NEGATIVE_ENERGY_BURST;
if(PRCGetHasSpell(SPELL_SUMMON_CREATURE_III, oTarget)) return SPELL_SUMMON_CREATURE_III;
if(PRCGetHasSpell(SPELL_KEEN_EDGE, oTarget)) return SPELL_KEEN_EDGE;
if(PRCGetHasSpell(SPELL_MAGIC_VESTMENT, oTarget)) return SPELL_MAGIC_VESTMENT;
if(PRCGetHasSpell(SPELL_DOMINATE_ANIMAL, oTarget)) return SPELL_DOMINATE_ANIMAL;
if(PRCGetHasSpell(SPELL_GLYPH_OF_WARDING, oTarget)) return SPELL_GLYPH_OF_WARDING;
if(PRCGetHasSpell(SPELL_INVISIBILITY_SPHERE, oTarget)) return SPELL_INVISIBILITY_SPHERE;
if(PRCGetHasSpell(SPELL_INVISIBILITY_PURGE, oTarget)) return SPELL_INVISIBILITY_PURGE;
if(PRCGetHasSpell(SPELL_FEAR, oTarget)) return SPELL_FEAR;
if(PRCGetHasSpell(SPELL_BLADE_THIRST, oTarget)) return SPELL_BLADE_THIRST;
if(PRCGetHasSpell(SPELL_GREATER_MAGIC_WEAPON, oTarget)) return SPELL_GREATER_MAGIC_WEAPON;
if(PRCGetHasSpell(SPELL_POISON, oTarget)) return SPELL_POISON;
if(PRCGetHasSpell(SPELL_STINKING_CLOUD, oTarget)) return SPELL_STINKING_CLOUD;
if(PRCGetHasSpell(SPELL_SPIKE_GROWTH, oTarget)) return SPELL_SPIKE_GROWTH;
if(PRCGetHasSpell(SPELL_WOUNDING_WHISPERS, oTarget)) return SPELL_WOUNDING_WHISPERS;
if(PRCGetHasSpell(SPELL_QUILLFIRE, oTarget)) return SPELL_QUILLFIRE;
if(PRCGetHasSpell(SPELL_GREATER_MAGIC_FANG, oTarget)) return SPELL_GREATER_MAGIC_FANG;
if(PRCGetHasSpell(SPELL_GUST_OF_WIND, oTarget)) return SPELL_GUST_OF_WIND;
if(PRCGetHasSpell(SPELL_INFESTATION_OF_MAGGOTS, oTarget)) return SPELL_INFESTATION_OF_MAGGOTS;
if(PRCGetHasSpell(SPELL_ANIMATE_DEAD, oTarget)) return SPELL_ANIMATE_DEAD;
if(PRCGetHasSpell(SPELL_NEUTRALIZE_POISON, oTarget)) return SPELL_NEUTRALIZE_POISON;
if(PRCGetHasSpell(SPELL_NEGATIVE_ENERGY_PROTECTION, oTarget)) return SPELL_NEGATIVE_ENERGY_PROTECTION;
if(PRCGetHasSpell(SPELL_CONTAGION, oTarget)) return SPELL_CONTAGION;
if(PRCGetHasSpell(SPELL_HEALING_STING, oTarget)) return SPELL_HEALING_STING;
if(PRCGetHasSpell(SPELL_REMOVE_DISEASE, oTarget)) return SPELL_REMOVE_DISEASE;
if(PRCGetHasSpell(SPELL_REMOVE_CURSE, oTarget)) return SPELL_REMOVE_CURSE;
if(PRCGetHasSpell(SPELL_REMOVE_BLINDNESS_AND_DEAFNESS, oTarget)) return SPELL_REMOVE_BLINDNESS_AND_DEAFNESS;
if(PRCGetHasSpell(SPELL_CONFUSION, oTarget)) return SPELL_CONFUSION;
if(PRCGetHasSpell(SPELL_PRAYER, oTarget)) return SPELL_PRAYER;
if(PRCGetHasSpell(SPELL_DARKFIRE, oTarget)) return SPELL_DARKFIRE;
if(PRCGetHasSpell(SPELL_CLAIRAUDIENCE_AND_CLAIRVOYANCE, oTarget)) return SPELL_CLAIRAUDIENCE_AND_CLAIRVOYANCE;
if(PRCGetHasSpell(SPELL_CHARM_MONSTER, oTarget)) return SPELL_CHARM_MONSTER;
if(PRCGetHasSpell(SPELL_BESTOW_CURSE, oTarget)) return SPELL_BESTOW_CURSE;
if(PRCGetHasSpell(SPELL_CURE_SERIOUS_WOUNDS, oTarget)) return SPELL_CURE_SERIOUS_WOUNDS;
if(PRCGetHasSpell(SPELL_INFLICT_SERIOUS_WOUNDS, oTarget)) return SPELL_INFLICT_SERIOUS_WOUNDS;
return nSpell;
}
int GetBestL4Spell(object oTarget, int nSpell)
{
if(PRCGetHasSpell(SPELL_ISAACS_LESSER_MISSILE_STORM, oTarget)) return SPELL_ISAACS_LESSER_MISSILE_STORM;
if(PRCGetHasSpell(SPELL_STONESKIN, oTarget)) return SPELL_STONESKIN;
if(PRCGetHasSpell(SPELL_DOMINATE_PERSON, oTarget)) return SPELL_DOMINATE_PERSON;
if(PRCGetHasSpell(SPELL_LESSER_SPELL_BREACH, oTarget)) return SPELL_LESSER_SPELL_BREACH;
if(PRCGetHasSpell(SPELL_ELEMENTAL_SHIELD, oTarget)) return SPELL_ELEMENTAL_SHIELD;
if(PRCGetHasSpell(SPELL_IMPROVED_INVISIBILITY, oTarget)) return SPELL_IMPROVED_INVISIBILITY;
if(PRCGetHasSpell(SPELL_ICE_STORM, oTarget)) return SPELL_ICE_STORM;
if(PRCGetHasSpell(SPELL_HAMMER_OF_THE_GODS, oTarget)) return SPELL_HAMMER_OF_THE_GODS;
if(PRCGetHasSpell(SPELL_SUMMON_CREATURE_IV, oTarget)) return SPELL_SUMMON_CREATURE_IV;
if(PRCGetHasSpell(SPELL_EVARDS_BLACK_TENTACLES, oTarget)) return SPELL_EVARDS_BLACK_TENTACLES;
if(PRCGetHasSpell(SPELL_MINOR_GLOBE_OF_INVULNERABILITY, oTarget)) return SPELL_MINOR_GLOBE_OF_INVULNERABILITY;
if(PRCGetHasSpell(SPELL_LEGEND_LORE, oTarget)) return SPELL_LEGEND_LORE;
if(PRCGetHasSpell(SPELL_POLYMORPH_SELF, oTarget)) return SPELL_POLYMORPH_SELF;
if(PRCGetHasSpell(SPELL_PHANTASMAL_KILLER, oTarget)) return SPELL_PHANTASMAL_KILLER;
if(PRCGetHasSpell(SPELL_DIVINE_POWER, oTarget)) return SPELL_DIVINE_POWER;
if(PRCGetHasSpell(SPELL_DEATH_WARD, oTarget)) return SPELL_DEATH_WARD;
if(PRCGetHasSpell(SPELL_FREEDOM_OF_MOVEMENT, oTarget)) return SPELL_FREEDOM_OF_MOVEMENT;
if(PRCGetHasSpell(SPELL_WAR_CRY, oTarget)) return SPELL_WAR_CRY;
if(PRCGetHasSpell(SPELL_WALL_OF_FIRE, oTarget)) return SPELL_WALL_OF_FIRE;
if(PRCGetHasSpell(SPELL_RESTORATION, oTarget)) return SPELL_RESTORATION;
if(PRCGetHasSpell(SPELL_MASS_CAMOFLAGE, oTarget)) return SPELL_MASS_CAMOFLAGE;
if(PRCGetHasSpell(SPELL_ENERVATION, oTarget)) return SPELL_ENERVATION;
if(PRCGetHasSpell(SPELL_HOLY_SWORD, oTarget)) return SPELL_HOLY_SWORD;
if(PRCGetHasSpell(SPELL_HOLD_MONSTER, oTarget)) return SPELL_HOLD_MONSTER;
if(PRCGetHasSpell(SPELL_DISMISSAL, oTarget)) return SPELL_DISMISSAL;
if(PRCGetHasSpell(SPELL_INFLICT_CRITICAL_WOUNDS, oTarget)) return SPELL_INFLICT_CRITICAL_WOUNDS;
if(PRCGetHasSpell(SPELL_CURE_CRITICAL_WOUNDS, oTarget)) return SPELL_CURE_CRITICAL_WOUNDS;
return nSpell;
}
int GetBestL5Spell(object oTarget, int nSpell)
{
if(PRCGetHasSpell(SPELL_TRUE_SEEING, oTarget)) return SPELL_TRUE_SEEING;
if(PRCGetHasSpell(SPELL_BIGBYS_INTERPOSING_HAND, oTarget)) return SPELL_BIGBYS_INTERPOSING_HAND;
if(PRCGetHasSpell(SPELL_GREATER_DISPELLING, oTarget)) return SPELL_GREATER_DISPELLING;
if(PRCGetHasSpell(SPELL_LESSER_SPELL_MANTLE, oTarget)) return SPELL_LESSER_SPELL_MANTLE;
if(PRCGetHasSpell(SPELL_SPELL_RESISTANCE, oTarget)) return SPELL_SPELL_RESISTANCE;
if(PRCGetHasSpell(SPELL_MONSTROUS_REGENERATION, oTarget)) return SPELL_MONSTROUS_REGENERATION;
if(PRCGetHasSpell(SPELL_RAISE_DEAD, oTarget)) return SPELL_RAISE_DEAD;
if(PRCGetHasSpell(SPELL_MIND_FOG, oTarget)) return SPELL_MIND_FOG;
if(PRCGetHasSpell(SPELL_SLAY_LIVING, oTarget)) return SPELL_SLAY_LIVING;
if(PRCGetHasSpell(SPELL_LESSER_PLANAR_BINDING, oTarget)) return SPELL_LESSER_PLANAR_BINDING;
if(PRCGetHasSpell(SPELL_LESSER_MIND_BLANK, oTarget)) return SPELL_LESSER_MIND_BLANK;
if(PRCGetHasSpell(SPELL_FLAME_STRIKE, oTarget)) return SPELL_FLAME_STRIKE;
if(PRCGetHasSpell(SPELL_FIREBRAND, oTarget)) return SPELL_FIREBRAND;
if(PRCGetHasSpell(SPELL_INFERNO, oTarget)) return SPELL_INFERNO;
if(PRCGetHasSpell(SPELL_CONE_OF_COLD, oTarget)) return SPELL_CONE_OF_COLD;
if(PRCGetHasSpell(SPELL_BALL_LIGHTNING, oTarget)) return SPELL_BALL_LIGHTNING;
if(PRCGetHasSpell(SPELL_ENERGY_BUFFER, oTarget)) return SPELL_ENERGY_BUFFER;
if(PRCGetHasSpell(SPELL_SUMMON_CREATURE_V, oTarget)) return SPELL_SUMMON_CREATURE_V;
if(PRCGetHasSpell(SPELL_MESTILS_ACID_SHEATH, oTarget)) return SPELL_MESTILS_ACID_SHEATH;
if(PRCGetHasSpell(SPELL_FEEBLEMIND, oTarget)) return SPELL_FEEBLEMIND;
if(PRCGetHasSpell(SPELL_ETHEREAL_VISAGE, oTarget)) return SPELL_ETHEREAL_VISAGE;
if(PRCGetHasSpell(SPELL_VINE_MINE, oTarget)) return SPELL_VINE_MINE;
if(PRCGetHasSpell(SPELL_BATTLETIDE, oTarget)) return SPELL_BATTLETIDE;
if(PRCGetHasSpell(SPELL_CLOUDKILL, oTarget)) return SPELL_CLOUDKILL;
if(PRCGetHasSpell(SPELL_AWAKEN, oTarget)) return SPELL_AWAKEN;
if(PRCGetHasSpell(SPELL_HEALING_CIRCLE, oTarget)) return SPELL_HEALING_CIRCLE;
if(PRCGetHasSpell(SPELL_CIRCLE_OF_DOOM, oTarget)) return SPELL_CIRCLE_OF_DOOM;
return nSpell;
}
int GetBestL6Spell(object oTarget, int nSpell)
{
if(PRCGetHasSpell(SPELL_ISAACS_GREATER_MISSILE_STORM, oTarget)) return SPELL_ISAACS_GREATER_MISSILE_STORM;
if(PRCGetHasSpell(SPELL_BIGBYS_FORCEFUL_HAND, oTarget)) return SPELL_BIGBYS_FORCEFUL_HAND;
if(PRCGetHasSpell(SPELL_CHAIN_LIGHTNING, oTarget)) return SPELL_CHAIN_LIGHTNING;
if(PRCGetHasSpell(SPELL_MASS_HASTE, oTarget)) return SPELL_MASS_HASTE;
if(PRCGetHasSpell(SPELL_DROWN, oTarget)) return SPELL_DROWN;
if(PRCGetHasSpell(SPELL_GREATER_STONESKIN, oTarget)) return SPELL_GREATER_STONESKIN;
if(PRCGetHasSpell(SPELL_GREATER_SPELL_BREACH, oTarget)) return SPELL_GREATER_SPELL_BREACH;
if(PRCGetHasSpell(SPELL_CIRCLE_OF_DEATH, oTarget)) return SPELL_CIRCLE_OF_DEATH;
if(PRCGetHasSpell(SPELL_GLOBE_OF_INVULNERABILITY, oTarget)) return SPELL_GLOBE_OF_INVULNERABILITY;
if(PRCGetHasSpell(SPELL_UNDEATH_TO_DEATH, oTarget)) return SPELL_UNDEATH_TO_DEATH;
if(PRCGetHasSpell(SPELL_CRUMBLE, oTarget)) return SPELL_CRUMBLE;
if(PRCGetHasSpell(SPELL_REGENERATE, oTarget)) return SPELL_REGENERATE;
if(PRCGetHasSpell(SPELL_SUMMON_CREATURE_VI, oTarget)) return SPELL_SUMMON_CREATURE_VI;
if(PRCGetHasSpell(SPELL_STONEHOLD, oTarget)) return SPELL_STONEHOLD;
if(PRCGetHasSpell(SPELL_FLESH_TO_STONE, oTarget)) return SPELL_FLESH_TO_STONE;
if(PRCGetHasSpell(SPELL_STONE_TO_FLESH, oTarget)) return SPELL_STONE_TO_FLESH;
if(PRCGetHasSpell(SPELL_TENSERS_TRANSFORMATION, oTarget)) return SPELL_TENSERS_TRANSFORMATION;
if(PRCGetHasSpell(SPELL_CREATE_UNDEAD, oTarget)) return SPELL_CREATE_UNDEAD;
if(PRCGetHasSpell(SPELL_CONTROL_UNDEAD, oTarget)) return SPELL_CONTROL_UNDEAD;
if(PRCGetHasSpell(SPELL_PLANAR_BINDING, oTarget)) return SPELL_PLANAR_BINDING;
if(PRCGetHasSpell(SPELL_PLANAR_ALLY, oTarget)) return SPELL_PLANAR_ALLY;
if(PRCGetHasSpell(SPELL_DIRGE, oTarget)) return SPELL_DIRGE;
if(PRCGetHasSpell(SPELL_BLADE_BARRIER, oTarget)) return SPELL_BLADE_BARRIER;
if(PRCGetHasSpell(SPELL_BANISHMENT, oTarget)) return SPELL_BANISHMENT;
if(PRCGetHasSpell(SPELL_ACID_FOG, oTarget)) return SPELL_ACID_FOG;
if(PRCGetHasSpell(SPELL_HEAL, oTarget)) return SPELL_HEAL;
if(PRCGetHasSpell(SPELL_HARM, oTarget)) return SPELL_HARM;
return nSpell;
}
int GetBestL7Spell(object oTarget, int nSpell)
{
if(PRCGetHasSpell(SPELL_SPELL_MANTLE, oTarget)) return SPELL_SPELL_MANTLE;
if(PRCGetHasSpell(SPELL_BIGBYS_GRASPING_HAND, oTarget)) return SPELL_BIGBYS_GRASPING_HAND;
if(PRCGetHasSpell(SPELL_FIRE_STORM, oTarget)) return SPELL_FIRE_STORM;
if(PRCGetHasSpell(SPELL_FINGER_OF_DEATH, oTarget)) return SPELL_FINGER_OF_DEATH;
if(PRCGetHasSpell(SPELL_PROTECTION_FROM_SPELLS, oTarget)) return SPELL_PROTECTION_FROM_SPELLS;
if(PRCGetHasSpell(SPELL_WORD_OF_FAITH, oTarget)) return SPELL_WORD_OF_FAITH;
if(PRCGetHasSpell(SPELL_SHADOW_SHIELD, oTarget)) return SPELL_SHADOW_SHIELD;
if(PRCGetHasSpell(SPELL_CREEPING_DOOM, oTarget)) return SPELL_CREEPING_DOOM;
if(PRCGetHasSpell(SPELL_DESTRUCTION, oTarget)) return SPELL_DESTRUCTION;
if(PRCGetHasSpell(SPELL_PRISMATIC_SPRAY, oTarget)) return SPELL_PRISMATIC_SPRAY;
if(PRCGetHasSpell(SPELL_DELAYED_BLAST_FIREBALL, oTarget)) return SPELL_DELAYED_BLAST_FIREBALL;
if(PRCGetHasSpell(SPELL_GREAT_THUNDERCLAP, oTarget)) return SPELL_GREAT_THUNDERCLAP;
if(PRCGetHasSpell(SPELL_POWER_WORD_STUN, oTarget)) return SPELL_POWER_WORD_STUN;
if(PRCGetHasSpell(SPELL_MORDENKAINENS_SWORD, oTarget)) return SPELL_MORDENKAINENS_SWORD;
if(PRCGetHasSpell(SPELL_RESURRECTION, oTarget)) return SPELL_RESURRECTION;
if(PRCGetHasSpell(SPELL_SUMMON_CREATURE_VII, oTarget)) return SPELL_SUMMON_CREATURE_VII;
if(PRCGetHasSpell(SPELL_AURA_OF_VITALITY, oTarget)) return SPELL_AURA_OF_VITALITY;
if(PRCGetHasSpell(SPELL_GREATER_RESTORATION, oTarget)) return SPELL_GREATER_RESTORATION;
return nSpell;
}
int GetBestL8Spell(object oTarget, int nSpell)
{
if(PRCGetHasSpell(SPELL_BIGBYS_CLENCHED_FIST, oTarget)) return SPELL_BIGBYS_CLENCHED_FIST;
if(PRCGetHasSpell(SPELL_HORRID_WILTING, oTarget)) return SPELL_HORRID_WILTING;
if(PRCGetHasSpell(SPELL_EARTHQUAKE, oTarget)) return SPELL_EARTHQUAKE;
if(PRCGetHasSpell(SPELL_NATURES_BALANCE, oTarget)) return SPELL_NATURES_BALANCE;
if(PRCGetHasSpell(SPELL_INCENDIARY_CLOUD, oTarget)) return SPELL_INCENDIARY_CLOUD;
if(PRCGetHasSpell(SPELL_MIND_BLANK, oTarget)) return SPELL_MIND_BLANK;
if(PRCGetHasSpell(SPELL_PREMONITION, oTarget)) return SPELL_PREMONITION;
if(PRCGetHasSpell(SPELL_SUNBURST, oTarget)) return SPELL_SUNBURST;
if(PRCGetHasSpell(SPELL_SUNBEAM, oTarget)) return SPELL_SUNBEAM;
if(PRCGetHasSpell(SPELL_MASS_CHARM, oTarget)) return SPELL_MASS_CHARM;
if(PRCGetHasSpell(SPELL_MASS_BLINDNESS_AND_DEAFNESS, oTarget)) return SPELL_MASS_BLINDNESS_AND_DEAFNESS;
if(PRCGetHasSpell(SPELL_BOMBARDMENT, oTarget)) return SPELL_BOMBARDMENT;
if(PRCGetHasSpell(SPELL_GREATER_PLANAR_BINDING, oTarget)) return SPELL_GREATER_PLANAR_BINDING;
if(PRCGetHasSpell(SPELL_SUMMON_CREATURE_VIII, oTarget)) return SPELL_SUMMON_CREATURE_VIII;
if(PRCGetHasSpell(SPELL_CREATE_GREATER_UNDEAD, oTarget)) return SPELL_CREATE_GREATER_UNDEAD;
if(PRCGetHasSpell(SPELL_BLACKSTAFF, oTarget)) return SPELL_BLACKSTAFF;
if(PRCGetHasSpell(SPELL_MASS_HEAL, oTarget)) return SPELL_MASS_HEAL;
return nSpell;
}
int GetBestL9Spell(object oTarget, int nSpell)
{
if(PRCGetHasSpell(SPELL_TIME_STOP, oTarget)) return SPELL_TIME_STOP;
if(PRCGetHasSpell(SPELL_BLACK_BLADE_OF_DISASTER, oTarget)) return SPELL_BLACK_BLADE_OF_DISASTER;
if(PRCGetHasSpell(SPELL_MORDENKAINENS_DISJUNCTION, oTarget)) return SPELL_MORDENKAINENS_DISJUNCTION;
if(PRCGetHasSpell(SPELL_GREATER_SPELL_MANTLE, oTarget)) return SPELL_GREATER_SPELL_MANTLE;
if(PRCGetHasSpell(SPELL_BIGBYS_CRUSHING_HAND, oTarget)) return SPELL_BIGBYS_CRUSHING_HAND;
if(PRCGetHasSpell(SPELL_WAIL_OF_THE_BANSHEE, oTarget)) return SPELL_WAIL_OF_THE_BANSHEE;
if(PRCGetHasSpell(SPELL_WEIRD, oTarget)) return SPELL_WEIRD;
if(PRCGetHasSpell(SPELL_METEOR_SWARM, oTarget)) return SPELL_METEOR_SWARM;
if(PRCGetHasSpell(SPELL_IMPLOSION, oTarget)) return SPELL_IMPLOSION;
if(PRCGetHasSpell(SPELL_POWER_WORD_KILL, oTarget)) return SPELL_POWER_WORD_KILL;
if(PRCGetHasSpell(SPELL_STORM_OF_VENGEANCE, oTarget)) return SPELL_STORM_OF_VENGEANCE;
if(PRCGetHasSpell(SPELL_SHAPECHANGE, oTarget)) return SPELL_SHAPECHANGE;
if(PRCGetHasSpell(SPELL_DOMINATE_MONSTER, oTarget)) return SPELL_DOMINATE_MONSTER;
if(PRCGetHasSpell(SPELL_ELEMENTAL_SWARM, oTarget)) return SPELL_ELEMENTAL_SWARM;
if(PRCGetHasSpell(SPELL_SUMMON_CREATURE_IX, oTarget)) return SPELL_SUMMON_CREATURE_IX;
if(PRCGetHasSpell(SPELL_GATE, oTarget)) return SPELL_GATE;
if(PRCGetHasSpell(SPELL_ENERGY_DRAIN, oTarget)) return SPELL_ENERGY_DRAIN;
if(PRCGetHasSpell(SPELL_UNDEATHS_ETERNAL_FOE, oTarget)) return SPELL_UNDEATHS_ETERNAL_FOE;
return nSpell;
}
int GetBestAvailableSpell(object oTarget)
{
int nBestSpell = GetBestL9Spell(oTarget, 99999);
if(nBestSpell == 99999) nBestSpell = GetBestL8Spell(oTarget, nBestSpell);
if(nBestSpell == 99999) nBestSpell = GetBestL7Spell(oTarget, nBestSpell);
if(nBestSpell == 99999) nBestSpell = GetBestL6Spell(oTarget, nBestSpell);
if(nBestSpell == 99999) nBestSpell = GetBestL5Spell(oTarget, nBestSpell);
if(nBestSpell == 99999) nBestSpell = GetBestL4Spell(oTarget, nBestSpell);
if(nBestSpell == 99999) nBestSpell = GetBestL3Spell(oTarget, nBestSpell);
if(nBestSpell == 99999) nBestSpell = GetBestL2Spell(oTarget, nBestSpell);
if(nBestSpell == 99999) nBestSpell = GetBestL1Spell(oTarget, nBestSpell);
if(nBestSpell == 99999) nBestSpell = GetBestL0Spell(oTarget, nBestSpell);
return nBestSpell;
}

View File

@@ -0,0 +1,142 @@
//::///////////////////////////////////////////////
//:: Actions include
//:: prc_inc_actions
//::///////////////////////////////////////////////
/** @file
Defines functions related to use of actions.
@author Ornedan
@date Created - 2006.01.26
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Constants */
//////////////////////////////////////////////////
/// A marker local the presence of which indicates that a creature's
/// available swift action has been used for a particular round
const string PRC_SWIFT_ACTION_MARKER = "PRC_SwiftActionUsed";
/// A marker local the presence of which indicates that a creature's
/// available move action has been used for a particular round
const string PRC_MOVE_ACTION_MARKER = "PRC_MoveActionUsed";
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Determines whether the given creature can use a swift action at this moment
* and if it can, marks that action as used.
* Conditions are that it has not used a swift action already in the last
* 6 seconds, and that that GetCanTakeFreeAction() returns TRUE.
* In addition, if a PC, it must be commandable by the player. This is in order
* to prevent abuse of instant action feats.
*
* @param oCreature Creature whose eligibility to use a swift action to test.
* @return TRUE if the creature can take a swift action now, FALSE otherwise.
*/
int TakeSwiftAction(object oCreature);
/**
* Determines whether the given creature can use a free action at this moment.
* Condition is that it is not affected by a condition that would prevent
* action queue processing.
* If the bTestControllability is set to true, this will also test for
* conditions that would prevent control by the player.
*
* @param oCreature Creature whose eligibility to use a free action to test.
* @param bTestControllability Whether to test for controllability affecting conditions.
* @return TRUE if the creature can take a free action now, FALSE otherwise.
*/
int GetCanTakeFreeAction(object oCreature, int bTestControllability = FALSE);
/**
* Determines whether the given creature can use a move action at this moment
* and if it can, marks that action as used.
* Conditions are that it has not used a move action already in the last
* 6 seconds
* In addition, if a PC, it must be commandable by the player. This is in order
* to prevent abuse of instant action feats.
*
* @param oCreature Creature whose eligibility to use a move action to test.
* @return TRUE if the creature can take a move action now, FALSE otherwise.
*/
int TakeMoveAction(object oCreature);
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
int TakeSwiftAction(object oCreature)
{
if(!GetLocalInt(oCreature, PRC_SWIFT_ACTION_MARKER) &&
GetCanTakeFreeAction(oCreature, GetIsPC(oCreature)) &&
GetCommandable(oCreature)
)
{
// Mark swift action used up for this round
SetLocalInt(oCreature, PRC_SWIFT_ACTION_MARKER, TRUE);
DelayCommand(6.0f, DeleteLocalInt(oCreature, PRC_SWIFT_ACTION_MARKER));
// Can use swift action
return TRUE;
}
// Can't use swift action
FloatingTextStringOnCreature("You have already used your swift action this round.", oCreature, FALSE);
return FALSE;
}
int GetCanTakeFreeAction(object oCreature, int bTestControllability = FALSE)
{
effect eTest = GetFirstEffect(oCreature);
int nEType;
while(GetIsEffectValid(eTest))
{
nEType = GetEffectType(eTest);
if(nEType == EFFECT_TYPE_CUTSCENE_PARALYZE ||
nEType == EFFECT_TYPE_DAZED ||
nEType == EFFECT_TYPE_PARALYZE ||
nEType == EFFECT_TYPE_PETRIFY ||
nEType == EFFECT_TYPE_SLEEP ||
nEType == EFFECT_TYPE_STUNNED ||
(bTestControllability &&
(nEType == EFFECT_TYPE_CHARMED ||
nEType == EFFECT_TYPE_CONFUSED ||
nEType == EFFECT_TYPE_DOMINATED ||
nEType == EFFECT_TYPE_FRIGHTENED ||
nEType == EFFECT_TYPE_TURNED
)
)
)
return FALSE;
// Get next effect
eTest = GetNextEffect(oCreature);
}
return TRUE;
}
int TakeMoveAction(object oCreature)
{
if(!GetLocalInt(oCreature, PRC_MOVE_ACTION_MARKER) && GetCommandable(oCreature))
{
// Mark move action used up for this round
SetLocalInt(oCreature, PRC_MOVE_ACTION_MARKER, TRUE);
DelayCommand(6.0f, DeleteLocalInt(oCreature, PRC_MOVE_ACTION_MARKER));
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectSlow(), oCreature, 4.0);
// Can use move action
return TRUE;
}
// Can't use move action
FloatingTextStringOnCreature("You have already used your move action this round.", oCreature, FALSE);
return FALSE;
}

View File

@@ -0,0 +1,568 @@
//::///////////////////////////////////////////////
//:: Array simulation include
//:: prc_inc_array
//:://////////////////////////////////////////////
/** @file
Array simulation include
This file defines a set of functions for creating
and manipulating arrays, which are implemented as
local variables on some holder object.
Notes:
* Arrays are dynamic and may be increased in size by just _set_'ing a new
element
* There are no restrictions on what is in the array (can have multiple
types in the same array)
* Arrays start at index 0
////////////////////////////////////////////////////////////////////////////////
// (c) Mr. Figglesworth 2002
// This code is licensed under beerware. You are allowed to freely use it
// and modify it in any way. Your only two obligations are: (1) at your option,
// to buy the author a beer if you ever meet him; and (2) include the
// copyright notice and license in any redistribution of this code or
// alterations of it.
//
// Full credit for how the array gets implemented goes to the guy who wrote
// the article and posted it on the NWNVault (I couldn't find your article
// to give you credit :( ). And, of course, to bioware. Great job!
////////////////////////////////////////////////////////////////////////////////
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
/**
* Creates a new array on the given storage object. If an
* array with the same name already exists, the function
* errors.
*
* @param store The object to use as holder for the array
* @param name The name of the array
* @return SDL_SUCCESS if the array was successfully created,
* one of SDL_ERROR_* on error.
*/
int array_create(object store, string name);
/**
* Deletes an array, erasing all it's entries.
*
* @param store The object which holds the array to delete
* @param name The name of the array
* @return SDL_SUCCESS if the array was successfully deleted,
* one of SDL_ERROR_* on error
*/
int array_delete(object store, string name);
/**
* Stores a string in an array.
*
* @param store The object holding the array
* @param name The name of the array
* @param i The index to store the string at
* @param entry The string to store
* @return SDL_SUCCESS if the store was successfull, SDL_ERROR_* on error.
*/
int array_set_string(object store, string name, int i, string entry);
/**
* Stores an integer in an array.
*
* @param store The object holding the array
* @param name The name of the array
* @param i The index to store the integer at
* @param entry The integer to store
* @return SDL_SUCCESS if the store was successfull, SDL_ERROR_* on error.
*/
int array_set_int(object store, string name, int i, int entry);
/**
* Stores a float in an array.
*
* @param store The object holding the array
* @param name The name of the array
* @param i The index to store the float at
* @param entry The float to store
* @return SDL_SUCCESS if the store was successfull, SDL_ERROR_* on error.
*/
int array_set_float(object store, string name, int i, float entry);
/**
* Stores an object in an array.
*
* @param store The object holding the array
* @param name The name of the array
* @param i The index to store the object at
* @param entry The object to store
* @return SDL_SUCCESS if the store was successfull, SDL_ERROR_* on error.
*/
int array_set_object(object store, string name, int i, object entry);
/**
* Gets a string from an array.
*
* @param store The object holding the array
* @param name The name of the array
* @param i The index to retrieve the string from
* @return The value contained at the index on success,
* "" on error
*/
string array_get_string(object store, string name, int i);
/**
* Gets an integer from an array.
*
* @param store The object holding the array
* @param name The name of the array
* @param i The index to retrieve the integer from
* @return The value contained at the index on success,
* 0 on error
*/
int array_get_int(object store, string name, int i);
/**
* Gets a float from an array.
*
* @param store The object holding the array
* @param name The name of the array
* @param i The index to retrieve the float from
* @return The value contained at the index on success,
* 0.0f on error
*/
float array_get_float(object store, string name, int i);
/**
* Gets an object from an array.
*
* @param store The object holding the array
* @param name The name of the array
* @param i The index to retrieve the object from
* @return The value contained at the index on success,
* OBJECT_INVALID on error
*/
object array_get_object(object store, string name, int i);
/**
* Removes all entries in the array with indexes greater than or equal to
* the new size and sets the array size to be equal to the new size.
*
* @param store The object holding the array
* @param name The name of the array
* @param size_new The new number of entries in the array
* @return SDL_SUCCESS on successful resize, SDL_ERROR_* on
* error
*/
int array_shrink(object store, string name, int size_new);
/**
* Gets the current size of the array. This is one greater
* than the index of highest indexed element the array
* has contained since the last array_shrink or the new size
* specified by the last array_shrink, whichever is greater.
*
* @param store The object holding the array
* @param name The name of the array
* @return The size of the array, or -1 if the specified
* array does not exist.
*/
int array_get_size(object store, string name);
/**
* Checks whether the given array exists.
*
* @param store The object holding the array
* @param name The name of the array
* @return TRUE if the array exists, FALSE otherwise.
*/
int array_exists(object store, string name);
/* These need to be rewritten and made less bug-prone before being taken into use.
Preferrably not necessarily have it be fucking massive square matrix, but instead
store a separate length for each x row.
int array_2d_create(object store, string name);
int array_2d_delete(object store, string name);
int array_2d_set_string(object store, string name, int i, int j, string entry);
int array_2d_set_int(object store, string name, int i, int j, int entry);
int array_2d_set_float(object store, string name, int i, int j, float entry);
int array_2d_set_object(object store, string name, int i, int j, object entry);
// returns "" or 0 on error
string array_2d_get_string(object store, string name, int i, int j);
int array_2d_get_int(object store, string name, int i, int j);
float array_2d_get_float(object store, string name, int i, int j);
object array_2d_get_object(object store, string name, int i, int j);
// changes memory usage of array (deletes x[ > size_new])
int array_2d_shrink(object store, string name, int size_new, int axis);
// gets current maximum size of array
int array_2d_get_size(object store, string name, int axis);
int array_2d_exists(object store, string name);
*/
/////////////////////////////////////
// Error Returns
/////////////////////////////////////
const int SDL_SUCCESS = 1;
const int SDL_ERROR = 1000;
const int SDL_ERROR_ALREADY_EXISTS = 1001;
const int SDL_ERROR_DOES_NOT_EXIST = 1002;
const int SDL_ERROR_OUT_OF_BOUNDS = 1003;
const int SDL_ERROR_NO_ZERO_SIZE = 1004; // Not used - Ornedan 2006.09.15
const int SDL_ERROR_NOT_VALID_OBJECT = 1005;
const int SDL_ERROR_INVALID_PARAMETER = 1006;
/////////////////////////////////////
// Implementation
/////////////////////////////////////
int array_create(object store, string name)
{
// error checking
if(!GetIsObjectValid(store))
return SDL_ERROR_NOT_VALID_OBJECT;
else if(array_exists(store, name))
return SDL_ERROR_ALREADY_EXISTS;
else
{
// Initialize the size (always one greater than the actual size)
SetLocalInt(store,name,1);
return SDL_SUCCESS;
}
}
void array_delete_loop(object store, string name, int nMin, int nMax)
{
int i = nMin;
while(i < nMin + 250 && i < nMax)
{
DeleteLocalString(store, name+"_"+IntToString(i));
// just in case, delete possible object names
DeleteLocalObject(store, name+"_"+IntToString(i)+"_OBJECT");
i++;
}
// delay continuation to avoid TMI
if(i < nMax)
DelayCommand(0.0, array_delete_loop(store, name, i, nMax));
}
int array_delete(object store, string name)
{
// error checking
int size=GetLocalInt(store,name);
if (size==0)
return SDL_ERROR_DOES_NOT_EXIST;
array_delete_loop(store, name, 0, size+5);
DeleteLocalInt(store,name);
return SDL_SUCCESS;
}
int array_set_string(object store, string name, int i, string entry)
{
int size = GetLocalInt(store,name);
if(size == 0)
return SDL_ERROR_DOES_NOT_EXIST;
if(i < 0)
return SDL_ERROR_OUT_OF_BOUNDS;
SetLocalString(store,name+"_"+IntToString(i),entry);
// save size if we've enlarged it
if(i+2>size)
SetLocalInt(store,name,i+2);
return SDL_SUCCESS;
}
int array_set_int(object store, string name, int i, int entry)
{
return array_set_string(store,name,i,IntToString(entry));
}
int array_set_float(object store, string name, int i, float entry)
{
return array_set_string(store,name,i,FloatToString(entry));
}
int array_set_object(object store, string name, int i, object entry)
{
int results = array_set_string(store, name, i, "OBJECT");
if (results == SDL_SUCCESS)
SetLocalObject(store, name + "_" + IntToString(i) + "_OBJECT", entry);
return results;
}
string array_get_string(object store, string name, int i)
{
// error checking
int size=GetLocalInt(store,name);
if (size==0 || i>size || i < 0)
return "";
return GetLocalString(store,name+"_"+IntToString(i));
}
int array_get_int(object store, string name, int i)
{
return StringToInt(array_get_string(store,name,i));
}
float array_get_float(object store, string name, int i)
{
return StringToFloat(array_get_string(store,name,i));
}
object array_get_object(object store, string name, int i)
{
if(array_get_string(store, name, i) == "OBJECT")
return GetLocalObject(store,name+"_"+IntToString(i)+"_OBJECT");
else
return OBJECT_INVALID;
}
int array_shrink(object store, string name, int size_new)
{
// Get the current size value
int size = GetLocalInt(store, name);
// Error check - non-existent array
if(size == 0)
return SDL_ERROR_DOES_NOT_EXIST;
// If the new number of elements is equal to or greater than the current number of elements, autosuccess
if((size - 1) <= size_new)
return SDL_SUCCESS;
// Delete entries that are outside the new array bounds
int i;
for(i = size_new; i < size; i++)
{
DeleteLocalString(store, name+"_"+IntToString(i));
// just in case, delete possible object names
DeleteLocalObject(store, name+"_"+IntToString(i)+"_OBJECT");
}
// Store the new size, with the +1 existence marker
SetLocalInt(store, name, size_new + 1);
return SDL_SUCCESS;
}
int array_get_size(object store, string name)
{
return GetLocalInt(store, name) - 1;
}
int array_exists(object store, string name)
{
// If the size and presence indicator local is non-zero, the array exists. Normalize it's value to TRUE / FALSE and return
return GetLocalInt(store, name) != 0;
}
/*
int array_2d_create(object store, string name)
{
// error checking
if(!GetIsObjectValid(store))
return SDL_ERROR_NOT_VALID_OBJECT;
else if(GetLocalInt(store,name))
return SDL_ERROR_ALREADY_EXISTS;
else
{
// Initialize the size (always one greater than the actual size)
SetLocalInt(store,name+"_A",1);
SetLocalInt(store,name+"_B",1);
return SDL_SUCCESS;
}
}
int array_2d_delete(object store, string name)
{
// error checking
int sizeA=GetLocalInt(store,name+"_A");
if (sizeA==0)
return SDL_ERROR_DOES_NOT_EXIST;
int sizeB=GetLocalInt(store,name+"_B");
if (sizeB==0)
return SDL_ERROR_DOES_NOT_EXIST;
int i;
int j;
for (i=0; i<sizeA+5; i++)
{
for (j=0;j<sizeB+5; j++)
{
DeleteLocalString(store,name+"_"+IntToString(i)+"_"+IntToString(j));
// just in case, delete possible object names
DeleteLocalObject(store,name+"_"+IntToString(i)+"_"+IntToString(j)+"_OBJECT");
}
}
DeleteLocalInt(store,name+"_A");
DeleteLocalInt(store,name+"_B");
return SDL_SUCCESS;
}
int array_2d_set_string(object store, string name, int i, int j, string entry)
{
int sizeA=GetLocalInt(store,name+"_A");
if (sizeA==0)
return SDL_ERROR_DOES_NOT_EXIST;
int sizeB=GetLocalInt(store,name+"_B");
if (sizeB==0)
return SDL_ERROR_DOES_NOT_EXIST;
SetLocalString(store,name+"_"+IntToString(i)+"_"+IntToString(j),entry);
// save size if we've enlarged it
if (i+2>sizeA)
SetLocalInt(store,name+"_A",i+2);
if (j+2>sizeB)
SetLocalInt(store,name+"_B",j+2);
return SDL_SUCCESS;
}
int array_2d_set_int(object store, string name, int i, int j, int entry)
{
return array_2d_set_string(store,name,i,j,IntToString(entry));
}
int array_2d_set_float(object store, string name, int i, int j, float entry)
{
return array_2d_set_string(store,name,i,j,FloatToString(entry));
}
int array_2d_set_object(object store, string name, int i, int j, object entry)
{
// object is a little more complicated.
// we want to create an object as a local variable too
if (!GetIsObjectValid(entry))
return SDL_ERROR_NOT_VALID_OBJECT;
int results=array_2d_set_string(store,name,i,j,"OBJECT");
if (results==SDL_SUCCESS)
SetLocalObject(store,name+"_"+IntToString(i)+"_"+IntToString(j)+"_OBJECT",entry);
return results;
}
string array_2d_get_string(object store, string name, int i, int j)
{
int sizeA=GetLocalInt(store,name+"_A");
if (sizeA==0 || i>sizeA)
return "";
int sizeB=GetLocalInt(store,name+"_B");
if (sizeB==0 || j>sizeB)
return "";
return GetLocalString(store,name+"_"+IntToString(i)+"_"+IntToString(j));
}
int array_2d_get_int(object store, string name, int i, int j)
{
return StringToInt(array_2d_get_string(store,name,i,j));
}
float array_2d_get_float(object store, string name, int i, int j)
{
return StringToFloat(array_2d_get_string(store,name,i,j));
}
object array_2d_get_object(object store, string name, int i, int j)
{
return GetLocalObject(store,name+"_"+IntToString(i)+"_"+IntToString(j)+"_OBJECT");
}
int array_2d_shrink(object store, string name, int size_new, int axis)
{
// error checking
int sizeA=GetLocalInt(store,name+"_A");
if (sizeA==0)
return SDL_ERROR_DOES_NOT_EXIST;
int sizeB=GetLocalInt(store,name+"_B");
if (sizeB==0)
return SDL_ERROR_DOES_NOT_EXIST;
if (axis == 1 &&
(sizeA==size_new || sizeA<size_new))
return SDL_SUCCESS;
if (axis == 2 &&
(sizeB==size_new || sizeB<size_new))
return SDL_SUCCESS;
int i; int j;
if(axis==1)
{
for (i=size_new; i<sizeA; i++)
{
for(j=0;j<sizeB+5;j++)
{
DeleteLocalString(store,name+"_"+IntToString(i)+"_"+IntToString(j));
// just in case, delete possible object names
DeleteLocalObject(store,name+"_"+IntToString(i)+"_"+IntToString(j)+"_OBJECT");
}
}
SetLocalInt(store,name+"_A",size_new+1);
return SDL_SUCCESS;
}
else if(axis==2)
{
for (j=size_new; j<sizeB; j++)
{
for(i=0;i<sizeA+5;i++)
{
DeleteLocalString(store,name+"_"+IntToString(i)+"_"+IntToString(j));
// just in case, delete possible object names
DeleteLocalObject(store,name+"_"+IntToString(i)+"_"+IntToString(j)+"_OBJECT");
}
}
SetLocalInt(store,name+"_B",size_new+1);
return SDL_SUCCESS;
}
else
return SDL_ERROR_DOES_NOT_EXIST;
}
int array_2d_get_size(object store, string name, int axis)
{
if(axis==1)
return GetLocalInt(store,name+"_A")-1;
else if(axis==2)
return GetLocalInt(store,name+"_B")-1;
else
return 0;
}
int array_2d_exists(object store, string name)
{
if (GetLocalInt(store,name+"_A")==0||GetLocalInt(store,name+"_B")==0)
return FALSE;
else
return TRUE;
}
*/
// Test main
//void main(){}

View File

@@ -0,0 +1,583 @@
//:://////////////////////////////////////////////
//:: Associate include
//:: prc_inc_assoc.nss
//:://////////////////////////////////////////////
/*
This file contains various functions for animal
companions and familiars
*/
//:://////////////////////////////////////////////
#include "inc_npc"
#include "inc_nwnx_funcs"
#include "shd_inc_shdfunc"
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
//adds associate as a henchman
void AddAssociate(object oMaster, object oAssociate);
//removes associate with unsummon vfx
void DestroyAssociate(object oAssociate);
//applies fiendiosh template
void ApplyFiendishTemplate(object oCompanion, object oCompSkin);
//applies exalted companion bonuses
void ApplyExaltedCompanion(object oCompanion, object oCompSkin);
//applies blightspawned properties
void ApplyIllmaster(object oCompanion, object oCompSkin);
//applies pseudonatural template
void ApplyPseudonatural(object oFamiliar, object oFamSkin);
//applies pnp familiar bonuses
void ApplyPnPFamiliarProperties(object oPC, object oFamiliar);
//sets up animal companion natural weapons using following scheme:
/*
Damage
Lvl Claw Bite
1 1d3 1d6
6 1d4 1d8
12 1d6 1d10
19 1d8 2d6
27 1d10 2d8
36 1d12 2d10
enhancement bonus
(Lvl - 15) / 5
*/
void SetNaturalWeaponDamage(object oCompanion, int nLvlMod = 0);
void UnsummonCompanions(object oPC);
//////////////////////////////////////////////////
/* Constants */
//////////////////////////////////////////////////
const int DISEASE_TALONAS_BLIGHT = 52;
//associate numbers as nTH parameter in GetAssociateNPC()
const int NPC_BIOWARE_COMPANION = 1; //'original' bioware familiar/companion returned by GetAssociate()
const int NPC_HENCHMAN_COMPANION = 2; //bioware familiar/companion added as hanchman
//ASSOCIATE_TYPE_FAMILIAR
const int NPC_PNP_FAMILIAR = 3;
const int NPC_BONDED_FAMILIAR = 4;
const int NPC_DN_FAMILIAR = 5;
const int NPC_MS_ELEMENTAL = 6;
//ASSOCIATE_TYPE_ANIMALCOMPANION
const int NPC_SHAMAN_COMPANION = 3;
const int NPC_UR_COMPANION = 4;
//ASSOCIATE_TYPE_SUMMONED
const int NPC_DARK_COMPANION = 2;
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
void AddAssociate(object oMaster, object oAssociate)
{
int nMaxHenchmen = GetMaxHenchmen();
SetMaxHenchmen(99);
AddHenchman(oMaster, oAssociate);
SetMaxHenchmen(nMaxHenchmen);
}
void DestroyAssociate(object oAssociate)
{
AssignCommand(oAssociate, SetIsDestroyable(TRUE));
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_UNSUMMON), GetLocation(oAssociate));
DestroyObject(oAssociate);
}
void CleanProperties(object oItem)
{
itemproperty ip = GetFirstItemProperty(oItem);
while(GetIsItemPropertyValid(ip))
{
RemoveItemProperty(oItem, ip);
ip = GetNextItemProperty(oItem);
}
}
void ApplyFiendishTemplate(object oTarget, object oCompSkin)
{
int nHD = GetHitDice(oTarget);
effect eDR;
int nResist;
if (nHD >= 12)
{
eDR = EffectDamageReduction(10, DAMAGE_POWER_PLUS_THREE);
nResist = 20;
}
else if (12 > nHD && nHD >= 8)
{
eDR = EffectDamageReduction(5, DAMAGE_POWER_PLUS_TWO);
nResist = 15;
}
else if (8 > nHD && nHD >= 4)
{
eDR = EffectDamageReduction(5, DAMAGE_POWER_PLUS_ONE);
nResist = 10;
}
else if (4 > nHD)
{
nResist = 5;
}
effect eFire = EffectDamageResistance(DAMAGE_TYPE_FIRE, nResist);
effect eCold = EffectDamageResistance(DAMAGE_TYPE_COLD, nResist);
effect eVis = EffectUltravision();
effect eLink = EffectLinkEffects(eDR, eFire);
eLink = EffectLinkEffects(eLink, eCold);
eLink = EffectLinkEffects(eLink, eVis);
eLink = SupernaturalEffect(eLink);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oTarget);
itemproperty ipIP = PRCItemPropertyBonusFeat(FEAT_TEMPLATE_FIENDISH_SMITE_GOOD);
IPSafeAddItemProperty(oCompSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
if(GetAlignmentGoodEvil(oTarget) != ALIGNMENT_EVIL)
AdjustAlignment(oTarget, ALIGNMENT_EVIL, 80, FALSE);
SetSubRace(oTarget, "Undead (Extraplanar)");
SetLocalInt(oTarget, "FiendishTemplate", 1);
}
void ApplyExaltedCompanion(object oCompanion, object oCompSkin)
{
int nHD = GetHitDice(oCompanion);
effect eDR;
int nResist;
if (nHD >= 12)
{
eDR = EffectDamageReduction(10, DAMAGE_POWER_PLUS_THREE);
nResist = 20;
}
else if (12 > nHD && nHD >= 8)
{
eDR = EffectDamageReduction(5, DAMAGE_POWER_PLUS_TWO);
nResist = 15;
}
else if (8 > nHD && nHD >= 4)
{
eDR = EffectDamageReduction(5, DAMAGE_POWER_PLUS_ONE);
nResist = 10;
}
else if (4 > nHD)
{
nResist = 5;
}
effect eAcid = EffectDamageResistance(DAMAGE_TYPE_ACID, nResist);
effect eCold = EffectDamageResistance(DAMAGE_TYPE_COLD, nResist);
effect eElec = EffectDamageResistance(DAMAGE_TYPE_ELECTRICAL, nResist);
effect eVis = EffectUltravision();
effect eLink = EffectLinkEffects(eDR, eAcid);
eLink = EffectLinkEffects(eLink, eCold);
eLink = EffectLinkEffects(eLink, eElec);
eLink = EffectLinkEffects(eLink, eVis);
eLink = SupernaturalEffect(eLink);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oCompanion);
itemproperty ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_TEMPLATE_CELESTIAL_SMITE_EVIL);
IPSafeAddItemProperty(oCompSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
if(GetAlignmentGoodEvil(oCompanion) != ALIGNMENT_GOOD)
AdjustAlignment(oCompanion, ALIGNMENT_GOOD, 80, FALSE);
SetLocalInt(oCompanion, "CelestialTemplate", 1);
}
void ApplyPseudonatural(object oFamiliar, object oFamSkin)
{
if(GetLocalInt(oFamiliar, "PseudonaturalTemplate"))
return;
int nHD = GetHitDice(oFamiliar);
int nResist;
effect eDR;
if (nHD >= 12)
{
eDR = EffectDamageReduction(10, DAMAGE_POWER_PLUS_THREE);
nResist = 20;
}
else if (12 > nHD && nHD >= 8)
{
eDR = EffectDamageReduction(5, DAMAGE_POWER_PLUS_TWO);
nResist = 15;
}
else if (8 > nHD && nHD >= 4)
{
eDR = EffectDamageReduction(5, DAMAGE_POWER_PLUS_ONE);
nResist = 10;
}
else if (4 > nHD)
{
nResist = 5;
}
effect eAcid = EffectDamageResistance(DAMAGE_TYPE_ACID, nResist);
effect eElec = EffectDamageResistance(DAMAGE_TYPE_ELECTRICAL, nResist);
effect eAC = EffectACIncrease(1,AC_NATURAL_BONUS);
effect eLink = EffectLinkEffects(eDR, eAcid);
eLink = EffectLinkEffects(eLink, eElec);
eLink = EffectLinkEffects(eLink, eAC);
eLink = SupernaturalEffect(eLink);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oFamiliar);
// itemproperty ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_TEMPLATE_PSEUDONATURAL_TRUESTRIKE);
// IPSafeAddItemProperty(oFamSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
SetLocalInt(oFamiliar, "PseudonaturalTemplate", 1);
}
void ApplyIllmaster(object oCompanion, object oCompSkin)
{
//Give the companion permanent Str +4, Con +2, Wis -2, and Cha -2
if(GetPRCSwitch(PRC_NWNX_FUNCS))
{
PRC_Funcs_ModAbilityScore(oCompanion, ABILITY_STRENGTH, 4);
PRC_Funcs_ModAbilityScore(oCompanion, ABILITY_CONSTITUTION, 2);
PRC_Funcs_ModAbilityScore(oCompanion, ABILITY_WISDOM, -2);
PRC_Funcs_ModAbilityScore(oCompanion, ABILITY_CHARISMA, -2);
}
else
{
string sFlag = "Illmaster";
SetCompositeBonus(oCompSkin, sFlag, 4, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_STR);
SetCompositeBonus(oCompSkin, sFlag, 2, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_CON);
SetCompositeBonus(oCompSkin, sFlag, 2, ITEM_PROPERTY_DECREASED_ABILITY_SCORE, IP_CONST_ABILITY_WIS);
SetCompositeBonus(oCompSkin, sFlag, 2, ITEM_PROPERTY_DECREASED_ABILITY_SCORE, IP_CONST_ABILITY_CHA);
}
//Set PLANT immunities and add low light vision
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertySpellImmunitySpecific(IP_CONST_IMMUNITYSPELL_CHARM_PERSON), oCompSkin);
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertySpellImmunitySpecific(IP_CONST_IMMUNITYSPELL_DOMINATE_PERSON), oCompSkin);
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertySpellImmunitySpecific(IP_CONST_IMMUNITYSPELL_HOLD_PERSON), oCompSkin);
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertySpellImmunitySpecific(IP_CONST_IMMUNITYSPELL_MASS_CHARM), oCompSkin);
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_MINDSPELLS), oCompSkin);
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_POISON), oCompSkin);
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_PARALYSIS), oCompSkin);
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_CRITICAL_HITS), oCompSkin);
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_DISEASE), oCompSkin);
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_BACKSTAB), oCompSkin);
AddItemProperty(DURATION_TYPE_PERMANENT, PRCItemPropertyBonusFeat(FEAT_LOWLIGHTVISION), oCompSkin);
//Compute the DC for this companion's blight touch
int iHD = GetHitDice(oCompanion);
int iCons = GetAbilityModifier(ABILITY_CONSTITUTION, oCompanion);
int iDC = 10 + (iHD / 2) + iCons;
//Create the onhit item property for causing the blight touch disease
itemproperty ipBlightTouch = ItemPropertyOnHitProps(IP_CONST_ONHIT_DISEASE, IPOnHitSaveDC(iDC), DISEASE_TALONAS_BLIGHT);
//Get the companion's creature weapons
object oBite = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oCompanion);
object oLClaw = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oCompanion);
object oRClaw = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oCompanion);
//Apply blight touch to each weapon
if (GetIsObjectValid(oBite))
IPSafeAddItemProperty(oBite, ipBlightTouch);
if (GetIsObjectValid(oLClaw))
IPSafeAddItemProperty(oLClaw, ipBlightTouch);
if (GetIsObjectValid(oRClaw))
IPSafeAddItemProperty(oRClaw, ipBlightTouch);
//Adjust alignment to Neutral Evil
if(GetAlignmentLawChaos(oCompanion) != ALIGNMENT_NEUTRAL)
AdjustAlignment(oCompanion, ALIGNMENT_NEUTRAL, 50, FALSE);
if (GetAlignmentGoodEvil(oCompanion) != ALIGNMENT_EVIL)
AdjustAlignment(oCompanion, ALIGNMENT_EVIL, 80, FALSE);
}
void WinterWolfProperties(object oCompanion, int nLevel)
{
int iStr = nLevel >= 30 ? (nLevel-30)/2 : (nLevel-4)/2;
int iDex = nLevel >= 30 ? (nLevel-31)/2 : (nLevel-5)/2;
object oCreR = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oCompanion);
if(GetPRCSwitch(PRC_NWNX_FUNCS))
{
if(iStr > 0)
PRC_Funcs_ModAbilityScore(oCompanion, ABILITY_STRENGTH, iStr);
if(iDex > 0)
PRC_Funcs_ModAbilityScore(oCompanion, ABILITY_DEXTERITY, iStr);
}
else
{
if(iStr > 0)
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyAbilityBonus(IP_CONST_ABILITY_STR, iStr), oCreR);
if(iDex > 0)
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyAbilityBonus(IP_CONST_ABILITY_DEX, iDex), oCreR);
}
int nBonusDmg;
if(nLevel > 24)
nBonusDmg = IP_CONST_DAMAGEBONUS_1d12;
else if(nLevel > 16)
nBonusDmg = IP_CONST_DAMAGEBONUS_1d10;
else if(nLevel > 7)
nBonusDmg = IP_CONST_DAMAGEBONUS_1d8;
else
nBonusDmg = IP_CONST_DAMAGEBONUS_1d6;
AddItemProperty(DURATION_TYPE_PERMANENT,ItemPropertyDamageBonus(IP_CONST_DAMAGETYPE_COLD, nBonusDmg), oCreR);
//winter wolf properties
AddItemProperty(DURATION_TYPE_PERMANENT,ItemPropertyDamageVulnerability(IP_CONST_DAMAGETYPE_FIRE, IP_CONST_DAMAGEVULNERABILITY_50_PERCENT), oCreR);
AddItemProperty(DURATION_TYPE_PERMANENT,ItemPropertyDamageImmunity(IP_CONST_DAMAGETYPE_COLD, IP_CONST_DAMAGEIMMUNITY_100_PERCENT), oCreR);
int iMax, i;
int coneAbi = nLevel / 5;
switch(coneAbi)
{
case 1 : iMax = 7; break;
case 2 : iMax = 6; break;
case 3 : iMax = 5; break;
case 4 : iMax = 4; break;
case 5 : iMax = 3; break;
case 6 : iMax = 2; break;
case 7 : iMax = 1; break;
}
if(iMax > 0)
{
for(i = 1; i <= iMax; i++)
DecrementRemainingSpellUses(oCompanion, 230);
}
}
void ApplyPnPFamiliarProperties(object oPC, object oFam)
{
int bFuncs = GetPRCSwitch(PRC_NWNX_FUNCS);
effect eBonus;
//get familiar level
int nFamLevel = GetLevelByClass(CLASS_TYPE_WIZARD, oPC)
+ GetLevelByClass(CLASS_TYPE_SORCERER, oPC)
+ GetLevelByClass(CLASS_TYPE_WITCH, oPC)
+ GetLevelByClass(CLASS_TYPE_ALIENIST, oPC)
+ GetLevelByClass(CLASS_TYPE_HEXBLADE, oPC)
+ GetLevelByClass(CLASS_TYPE_DREAD_NECROMANCER, oPC);
if (GetHasFeat(FEAT_SHADOW_FAMILIAR, oPC)) nFamLevel = GetLevelByTypeArcane(oPC) + GetShadowcasterLevel(oPC); // For the purpose of determining familiar abilities that depend on your arcane caster level,
// your levels in all classes that allow you to cast mysteries or arcane spells stack
//scaling bonuses
int nAdjustLevel = nFamLevel - GetHitDice(oFam);
int n;
for(n = 1; nAdjustLevel >= n; n++)
LevelUpHenchman(oFam, CLASS_TYPE_INVALID, TRUE);
int nACBonus = nFamLevel / 2;
int nIntBonus = nFamLevel / 2;
int nSRBonus = nFamLevel > 11 ? nFamLevel + 5 : 0;
//saving throws
int nSaveRefBonus = GetReflexSavingThrow(oPC) - GetReflexSavingThrow(oFam);
int nSaveFortBonus = GetFortitudeSavingThrow(oPC) - GetFortitudeSavingThrow(oFam);
int nSaveWillBonus = GetWillSavingThrow(oPC) - GetWillSavingThrow(oFam);
int nHPBonus;
if(bFuncs)
{
nHPBonus = GetMaxHitPoints(oPC) / 2;
int i, nBonus;
for(i = 0; i < GetPRCSwitch(FILE_END_SKILLS); i++)
{
nBonus = GetSkillRank(i, oPC) - GetSkillRank(i, oFam);
if(nBonus > 0)
PRC_Funcs_ModSkill(oFam, i, nBonus);
}
PRC_Funcs_SetBaseNaturalAC(oFam, PRC_Funcs_GetBaseNaturalAC(oFam) + nACBonus);
PRC_Funcs_ModAbilityScore(oFam, ABILITY_INTELLIGENCE, nIntBonus);
PRC_Funcs_ModSavingThrowBonus(oFam, SAVING_THROW_REFLEX, nSaveRefBonus);
PRC_Funcs_ModSavingThrowBonus(oFam, SAVING_THROW_FORT, nSaveFortBonus);
PRC_Funcs_ModSavingThrowBonus(oFam, SAVING_THROW_WILL, nSaveWillBonus);
PRC_Funcs_SetMaxHitPoints(oFam, nHPBonus);
PRC_Funcs_SetCurrentHitPoints(oFam, nHPBonus);
}
else
{
//temporary HP for the moment, have to think of a better idea later
nHPBonus = (GetMaxHitPoints(oPC) / 2) - GetMaxHitPoints(oFam);
int i, nBonus;
for(i = 0; i < GetPRCSwitch(FILE_END_SKILLS); i++)
{
nBonus = GetSkillRank(i, oPC) - GetSkillRank(i, oFam);
eBonus = EffectLinkEffects(eBonus, EffectSkillIncrease(i, nBonus));
}
eBonus = EffectLinkEffects(eBonus, EffectACIncrease(nACBonus, AC_NATURAL_BONUS));
eBonus = EffectLinkEffects(eBonus, EffectAbilityIncrease(ABILITY_INTELLIGENCE, nIntBonus));
eBonus = EffectLinkEffects(eBonus, EffectSavingThrowIncrease(SAVING_THROW_REFLEX, nSaveRefBonus));
eBonus = EffectLinkEffects(eBonus, EffectSavingThrowIncrease(SAVING_THROW_FORT, nSaveFortBonus));
eBonus = EffectLinkEffects(eBonus, EffectSavingThrowIncrease(SAVING_THROW_WILL, nSaveWillBonus));
eBonus = EffectLinkEffects(eBonus, EffectTemporaryHitpoints(nHPBonus));
}
int nABBonus = GetBaseAttackBonus(oPC) - GetBaseAttackBonus(oFam);
int nAttacks = (GetBaseAttackBonus(oPC)/5)+1;
if(nAttacks > 5)
nAttacks = 5;
SetBaseAttackBonus(nAttacks, oFam);
//effect doing
if(nSRBonus > 0) eBonus = EffectLinkEffects(eBonus, EffectSpellResistanceIncrease(nSRBonus));
eBonus = EffectLinkEffects(eBonus, EffectAttackIncrease(nABBonus));
//skills were linked earlier
eBonus = SupernaturalEffect(eBonus);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eBonus, oFam);
}
void CheckIsValidFamiliar(object oMaster, effect eBonus)
{
object oFam = GetAssociateNPC(ASSOCIATE_TYPE_FAMILIAR);
object oFamToken = GetItemPossessedBy(oMaster, "prc_pnp_familiar");
if(GetIsObjectValid(oFam))
{
if(!GetIsDead(oFam))
{
DelayCommand(30.0, CheckIsValidFamiliar(oMaster, eBonus));
return;
}
}
else
{
if(GetIsObjectValid(oFamToken))
{
DelayCommand(30.0, CheckIsValidFamiliar(oMaster, eBonus));
return;
}
}
RemoveEffect(oMaster, eBonus);
}
effect GetMasterBonus(int nFamiliarType)
{
effect eBonus;
string sFile = "prc_familiar";
string sTemp = Get2DACache(sFile, "BONUS", nFamiliarType);
int nParam1 = StringToInt(Get2DACache(sFile, "PARAM1", nFamiliarType));
int nParam2 = StringToInt(Get2DACache(sFile, "PARAM2", nFamiliarType));
if(sTemp == "sk")
eBonus = EffectSkillIncrease(nParam1, nParam2);
else if(sTemp == "sv")
eBonus = EffectSavingThrowIncrease(nParam1, nParam2);
else if(sTemp == "hp")
eBonus = EffectTemporaryHitpoints(nParam1);
return eBonus;
}
int GetCompanionBaseDamage(int nLevel, int bBite)
{
int nBite, nClaw;
if(nLevel > 35)
{
nBite = IP_CONST_MONSTERDAMAGE_2d10;
nClaw = IP_CONST_MONSTERDAMAGE_1d12;
}
else if(nLevel > 26)
{
nBite = IP_CONST_MONSTERDAMAGE_2d8;
nClaw = IP_CONST_MONSTERDAMAGE_1d10;
}
else if(nLevel > 18)
{
nBite = IP_CONST_MONSTERDAMAGE_2d6;
nClaw = IP_CONST_MONSTERDAMAGE_1d8;
}
else if(nLevel > 11)
{
nBite = IP_CONST_MONSTERDAMAGE_1d10;
nClaw = IP_CONST_MONSTERDAMAGE_1d6;
}
else if(nLevel > 5)
{
nBite = IP_CONST_MONSTERDAMAGE_1d8;
nClaw = IP_CONST_MONSTERDAMAGE_1d4;
}
else
{
nBite = IP_CONST_MONSTERDAMAGE_1d6;
nClaw = IP_CONST_MONSTERDAMAGE_1d3;
}
if(bBite)
return nBite;
return nClaw;
}
void SetNaturalWeaponDamage(object oCompanion, int nLvlMod = 0)
{
int nLevel = GetHitDice(oCompanion);
nLevel += nLvlMod;
int Enh = (nLevel - 15) / 5;
int nDamage;
//Get the companion's creature weapons
object oBite = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oCompanion);
object oLClaw = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oCompanion);
object oRClaw = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oCompanion);
//Apply properties to each weapon
if(GetIsObjectValid(oBite))
{
CleanProperties(oBite);
nDamage = GetCompanionBaseDamage(nLevel, TRUE);
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyMonsterDamage(nDamage), oBite);
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyAttackBonus(Enh), oBite);
}
if(GetIsObjectValid(oLClaw))
{
CleanProperties(oLClaw);
nDamage = GetCompanionBaseDamage(nLevel, FALSE);
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyMonsterDamage(nDamage), oLClaw);
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyAttackBonus(Enh), oLClaw);
}
if(GetIsObjectValid(oRClaw))
{
CleanProperties(oRClaw);
nDamage = GetCompanionBaseDamage(nLevel, FALSE);
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyMonsterDamage(nDamage), oRClaw);
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyAttackBonus(Enh), oRClaw);
}
}
void UnsummonCompanions(object oPC)
{
int i;
object oAsso;
for(i = 1; i <= 5; i++)
{
oAsso = GetAssociateNPC(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, i);
if(GetIsObjectValid(oAsso))
DestroyAssociate(oAsso);
}
for(i = 1; i <= 5; i++)
{
oAsso = GetAssociateNPC(ASSOCIATE_TYPE_FAMILIAR, oPC, i);
if(GetIsObjectValid(oAsso))
DestroyAssociate(oAsso);
}
}
//:: void main(){}

View File

@@ -0,0 +1,988 @@
//::///////////////////////////////////////////////
//:: Breath Weapon Include
//:: prc_inc_breath
//::///////////////////////////////////////////////
/** @file
Centralizes handling for most breath weapons for
implementing Metabreath and the like.
@author Fox
@date Created - 2008.1.19
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Structures */
//////////////////////////////////////////////////
/**
* A structure that contains common data used during power manifestation.
*/
struct breath{
/* Generic stuff */
/// The creature breathing
object oDragon;
/* Basic info */
/// The shape of the breath
int bLine;
/// The size of the breath in feet
float fRange;
/// The element of the breath
int nDamageType;
/// Type of dice
int nDiceType;
/// Number of dice
int nDiceNumber;
/// The stat relavant for DC calculating
int nDCStat;
/// Any other DC mods, like class levels for DragDis
int nOtherDCMod;
/// Save type - needed in case of Fort Save
int nSaveUsed;
/// Rounds until next use
int nRoundsUntilRecharge;
/* Metabreath */
/// Number of rounds Clinging Breaths last
int nClinging;
/// Number of rounds Lingering Breaths last
int nLingering;
/// Whether Enlarge Breath was used
int bEnlarge;
/// How much the DC is increased by Heighten Breath - max of Con
int nHeighten;
/// Whether Maximize Breath was used
int bMaximize;
/// Whether Spreading Breath was used
int bSpread;
/// Whether Tempest Breath was used
int bTempest;
/* Breath Channeling */
/// Whether Entangling Exhalation was used
int bEntangling;
/// Whether Exhaled Barrier was used
int bBarrier;
/// Whether Exhaled Immunity was used
int bExhaleImmune;
/* Special Cases */
/// Special case referance number - used for things like Pyroclastic
int nOverrideSpecial;
};
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Creates the breath struct, taking metabreath and breath channeling into account.
*
* @param oDragon The creature breathing the breath weapon
* @param bLine True if breath is a line breath, false if a cone breath
* @param fRange The range of the breath weapon in feet.
* @param nDamageType The element of the breath weapon, if it has one.
* @param nDiceType The type of damage dice for the breath weapon.
* @param nDiceNumber The number of damage dice for the breath weapon.
* @param nDCStat The constant for the stat the breath weapon uses for DC
* calculation.
* @param nOtherDCMod Any other applicable modifications to the DC.
* e.g. Dragon Disciple levels.
* @param nOverrideSpecial Indicates any special case breath weapons, like the Pyroclastic's
* split damage or Shadow's negative level breath. Defaults to 0.
* @param nBaseRecharge The die size of the recharge "lock." Defaults to d4.
* @param nSaveUsed The constant to determine the save used. Defaults to Reflex.
* Diamond Dragon uses Fort saves for cold breath for example.
*
* @return Returns a struct that describes the breath being used, including
* applicable metabreath and breath channeling feats.
*/
struct breath CreateBreath(object oDragon, int bLine, float fRange, int nDamageType, int nDiceType, int nDiceNumber, int nDCStat, int nOtherDCMod, int nOverrideSpecial = 0, int nBaseRecharge = 4, int nSaveUsed = SAVING_THROW_REFLEX);
/**
* Applies the breath effect on the targeted location. Brought into the include since
* there is so much common code.
*
* @param BreathUsed A struct describing the details of the breath weapon
* @param lTargetArea The targeted location for the breath.
* @param bLinger Determines if this breath was applied by Lingering Breath metabreath.
* Defaults to FALSE.
* @param vSource The source of a Lingering breath. This does not matter except when
* bLinger is set to TRUE.
*
*/
void ApplyBreath(struct breath BreathUsed, location lTargetArea, int bLinger = FALSE, float vSourceX = 0.0, float vSourceY = 0.0, float vSourceZ = 0.0);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
#include "prc_alterations"
//////////////////////////////////////////////////
/* Internal functions */
//////////////////////////////////////////////////
// Exhaled Immunity is different enough to break off on it's own, as it only
// applies to one creature, and nothing else happens.
void ExhaleImmunity(object oDragon, int nDamageType, location lTargetArea)
{
//since there's no "GetObjectAtLocation," grab a tiny AoE to find the creature
object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, 1.0, lTargetArea, TRUE,
OBJECT_TYPE_CREATURE, GetPosition(oDragon));
//make sure damage type is valid, default to fire for non-energy-damage-based breaths
int nImmuneType = DAMAGE_TYPE_FIRE;
if (nDamageType == DAMAGE_TYPE_ACID) nImmuneType = DAMAGE_TYPE_ACID;
else if (nDamageType == DAMAGE_TYPE_COLD) nImmuneType = DAMAGE_TYPE_COLD;
else if (nDamageType == DAMAGE_TYPE_SONIC) nImmuneType = DAMAGE_TYPE_SONIC;
else if (nDamageType == DAMAGE_TYPE_ELECTRICAL) nImmuneType = DAMAGE_TYPE_ELECTRICAL;
if((oTarget == OBJECT_INVALID) || (oTarget == oDragon))
{
SendMessageToPC(oDragon, "You must target another creature for Exhaled Immunity to work.");
return;
}
else
{
//Fire cast spell at event for the specified target
SignalEvent(oTarget, EventSpellCastAt(oDragon, GetSpellId(), FALSE));
//Determine effect delay
float fDelay = GetDistanceBetween(oDragon, oTarget)/20;
float fDuration = RoundsToSeconds(d4());
//set effects
effect eImmune = EffectDamageImmunityIncrease(nDamageType, 100);
effect eVis = EffectVisualEffect(VFX_IMP_ELEMENTAL_PROTECTION);
effect eVis2 = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE);
effect eLink = EffectLinkEffects(eImmune, eVis2);
//apply effects
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eImmune, oTarget, fDuration));
}
}
//fucntion to check for Adept breath
int IsAdeptBreath()
{
int nBreath = GetSpellId();
if(nBreath == BREATH_FIRE_CONE
|| nBreath == BREATH_FIRE_LINE
|| nBreath == BREATH_FROST_CONE
|| nBreath == BREATH_ELECTRIC_LINE
|| nBreath == BREATH_SICKENING_CONE
|| nBreath == BREATH_ACID_CONE
|| nBreath == BREATH_ACID_LINE
|| nBreath == BREATH_SLOW_CONE
|| nBreath == BREATH_WEAKENING_CONE
|| nBreath == BREATH_SLEEP_CONE
|| nBreath == BREATH_THUNDER_CONE
|| nBreath == BREATH_BAHAMUT_LINE
|| nBreath == BREATH_FORCE_LINE
|| nBreath == BREATH_PARALYZE_CONE
|| nBreath == BREATH_FIVEFOLD_TIAMAT)
return TRUE;
return FALSE;
}
int IsBreathProtected(object oDragon, object oTarget)
{
int nBPIndex = 0;
while(array_get_object(oTarget, "BreathProtected", nBPIndex) != OBJECT_INVALID)
{
if(array_get_object(oTarget, "BreathProtected", nBPIndex) == oDragon)
{
return TRUE;
}
else
nBPIndex++;
}
return FALSE;
}
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
struct breath CreateBreath(object oDragon, int bLine, float fRange, int nDamageType, int nDiceType, int nDiceNumber, int nDCStat, int nOtherDCMod, int nOverrideSpecial = 0, int nBaseRecharge = 4, int nSaveUsed = SAVING_THROW_REFLEX)
{
struct breath BreathUsed;
//gather base data
BreathUsed.oDragon = oDragon;
BreathUsed.bLine = bLine;
BreathUsed.fRange = fRange;
BreathUsed.nDamageType = nDamageType;
BreathUsed.nDiceType = nDiceType;
BreathUsed.nDiceNumber = nDiceNumber;
BreathUsed.nDCStat = nDCStat;
BreathUsed.nOtherDCMod = nOtherDCMod;
int nFinalRecharge;
switch(nBaseRecharge)
{
case 4:
nFinalRecharge = d4(); break;
case 1:
nFinalRecharge = 1; break;
default:
nFinalRecharge = 0; break;
}
BreathUsed.nRoundsUntilRecharge = nFinalRecharge;
BreathUsed.nSaveUsed = nSaveUsed;
BreathUsed.nOverrideSpecial = nOverrideSpecial;
//Energy Aura bonus checking
switch(nDamageType)
{
case DAMAGE_TYPE_ACID:
if(GetLocalInt(oDragon,"AcidEnergyAura"))
BreathUsed.nOtherDCMod += GetLocalInt(oDragon,"AcidEnergyAura");
break;
case DAMAGE_TYPE_COLD:
if(GetLocalInt(oDragon,"ColdEnergyAura"))
BreathUsed.nOtherDCMod += GetLocalInt(oDragon,"ColdEnergyAura");
break;
case DAMAGE_TYPE_ELECTRICAL:
if(GetLocalInt(oDragon,"ElecEnergyAura"))
BreathUsed.nOtherDCMod += GetLocalInt(oDragon,"ElecEnergyAura");
break;
case DAMAGE_TYPE_FIRE:
if(GetLocalInt(oDragon,"FireEnergyAura"))
BreathUsed.nOtherDCMod += GetLocalInt(oDragon,"FireEnergyAura");
}
/* Initialize metabreath/channeling tracking */
BreathUsed.nClinging = 0;
BreathUsed.nLingering = 0;
BreathUsed.bEnlarge = FALSE;
BreathUsed.nHeighten = 0;
BreathUsed.bMaximize = FALSE;
BreathUsed.bSpread = FALSE;
BreathUsed.bTempest = FALSE;
BreathUsed.bEntangling = FALSE;
BreathUsed.bBarrier = FALSE;
BreathUsed.bExhaleImmune = FALSE;
/* breath channeling */
// Whether Entangling Exhalation was used
if(GetLocalInt(oDragon, "EntangleBreath"))
BreathUsed.bEntangling = TRUE;
// Whether Exhaled Barrier was used
if(GetLocalInt(oDragon, "ExhaleBarrier"))
BreathUsed.bBarrier = TRUE;
// Whether Exhaled Immunity was used
if(GetLocalInt(oDragon, "ExhaleImmunity"))
BreathUsed.bExhaleImmune = TRUE;
//breath effect checks
//Cloud only works with 1 other effect applied
//this one handles combination with damage effects and enduring
if(GetLocalInt(oDragon, "AdeptCloudBreath")
&& !GetLocalInt(oDragon, "AdeptShapedBreath")
&& (GetSpellId() == BREATH_FIRE_CONE
|| GetSpellId() == BREATH_FROST_CONE
|| GetSpellId() == BREATH_SICKENING_CONE
|| GetSpellId() == BREATH_ACID_CONE
|| GetSpellId() == BREATH_SLOW_CONE
|| GetSpellId() == BREATH_WEAKENING_CONE
|| GetSpellId() == BREATH_SLEEP_CONE
|| GetSpellId() == BREATH_THUNDER_CONE
|| GetSpellId() == BREATH_PARALYZE_CONE))
{
BreathUsed.bSpread = TRUE;
}
//this one is Cloud + Shaped
if(GetLocalInt(oDragon, "AdeptCloudBreath")
&& GetLocalInt(oDragon, "AdeptShapedBreath")
&& !GetLocalInt(oDragon, "AdeptEnduringBreath")
&& GetSpellId() == BREATH_FIRE_CONE)
{
BreathUsed.bSpread = TRUE;
}
if(GetLocalInt(oDragon, "AdeptEnduringBreath")
&& !(GetLocalInt(oDragon, "AdeptCloudBreath") && GetLocalInt(oDragon, "AdeptShapedBreath"))
&& (GetSpellId() == BREATH_FIRE_CONE || GetSpellId() == BREATH_FIRE_LINE))
{
BreathUsed.nLingering = 1;
}
//breaths without recharge times can't use metabreath
if(BreathUsed.nRoundsUntilRecharge == 0)
return BreathUsed;
/* metabreath calculation*/
//Clinging breath - Main feat increments uses, secondary feat cancels.
if(GetLocalInt(oDragon, "ClingingBreath") > 0)
{
BreathUsed.nClinging = GetLocalInt(oDragon, "ClingingBreath");
BreathUsed.nRoundsUntilRecharge += BreathUsed.nClinging;
}
//Lingering breath - Main feat increments uses, secondary feat cancels.
if(GetLocalInt(oDragon, "LingeringBreath") > 0)
{
BreathUsed.nLingering = GetLocalInt(oDragon, "LingeringBreath");
BreathUsed.nRoundsUntilRecharge += (BreathUsed.nLingering * 2);
}
//Enlarge breath
if(GetLocalInt(oDragon, "EnlargeBreath"))
{
BreathUsed.bEnlarge = TRUE;
BreathUsed.nRoundsUntilRecharge += 1;
}
//Heighten breath - Feat increments uses, resets if incremented at max.
if(GetLocalInt(oDragon, "HeightenBreath") > 0)
{
BreathUsed.nHeighten = GetLocalInt(oDragon, "HeightenBreath");
BreathUsed.nRoundsUntilRecharge += BreathUsed.nHeighten;
}
//Maximize breath
if(GetLocalInt(oDragon, "MaximizeBreath"))
{
BreathUsed.bMaximize = TRUE;
BreathUsed.nRoundsUntilRecharge += 3;
}
//Shape breath
if(GetLocalInt(oDragon, "ShapeBreath"))
{
if(bLine) BreathUsed.bLine = FALSE;
else BreathUsed.bLine = TRUE;
BreathUsed.nRoundsUntilRecharge += 1;
}
//Spreading breath
if(GetLocalInt(oDragon, "SpreadingBreath"))
{
BreathUsed.bSpread = TRUE;
BreathUsed.nRoundsUntilRecharge += 2;
}
//Tempest breath
if(GetLocalInt(oDragon, "TempestBreath"))
{
BreathUsed.bTempest = TRUE;
BreathUsed.nRoundsUntilRecharge += 1;
}
//Recover Breath
if(GetHasFeat(FEAT_RECOVER_BREATH, oDragon)
&& (BreathUsed.nRoundsUntilRecharge > 1))
BreathUsed.nRoundsUntilRecharge += -1;
// Exhaled Barrier and Immunity don't apply Metabreath feats, so recharge time should be unaffected
if(BreathUsed.bBarrier || BreathUsed.bExhaleImmune)
BreathUsed.nRoundsUntilRecharge = nFinalRecharge;
return BreathUsed;
}
void ApplyBreath(struct breath BreathUsed, location lTargetArea, int bLinger = FALSE, float vSourceX = 0.0, float vSourceY = 0.0, float vSourceZ = 0.0)
{
//if using Exhaled Immunity, jump straight to it and ignore the rest
if(BreathUsed.bExhaleImmune)
{
ExhaleImmunity(BreathUsed.oDragon, BreathUsed.nDamageType, lTargetArea);
return;
}
//init variables
effect eBreath;
effect eVis;
float fDelay;
int nDamage = 0;
int nAdjustedDamage;
int nSaveDamageType = -1;
int nVisualType = -1;
int nEnergyAura = 0;
int bCanCling;
int nSaveDC;
int nShapedSpotsUsed = GetLocalInt(BreathUsed.oDragon, "AdeptShapedBreath") ? 0 : 4;
int nBreathShape = BreathUsed.bLine ? SHAPE_SPELLCYLINDER : SHAPE_SPELLCONE;
float fRange = FeetToMeters(BreathUsed.fRange);
int nKnockdownDC = 0;
vector vSource = Vector(vSourceX, vSourceY, vSourceZ);
vector vSourceOfBreath = bLinger ? vSource : GetPosition(BreathUsed.oDragon);
//Saving Throw setup
if (BreathUsed.nDCStat >= 10)
nSaveDC = BreathUsed.nDCStat;
else
nSaveDC = 10 + PRCMax(GetAbilityModifier(BreathUsed.nDCStat), 0) + BreathUsed.nOtherDCMod;
//Set up variables that depend on damage type
switch (BreathUsed.nDamageType)
{
case DAMAGE_TYPE_ACID:
nSaveDamageType = SAVING_THROW_TYPE_ACID;
nVisualType = VFX_IMP_ACID_S;
nEnergyAura = GetLocalInt(BreathUsed.oDragon, "AcidEnergyAura"); break;
case DAMAGE_TYPE_COLD:
nSaveDamageType = SAVING_THROW_TYPE_COLD;
nVisualType = VFX_IMP_FROST_S;
nEnergyAura = GetLocalInt(BreathUsed.oDragon, "ColdEnergyAura"); break;
case DAMAGE_TYPE_ELECTRICAL:
nSaveDamageType = SAVING_THROW_TYPE_ELECTRICITY;
nVisualType = VFX_IMP_LIGHTNING_S;
nEnergyAura = GetLocalInt(BreathUsed.oDragon, "ElecEnergyAura"); break;
case DAMAGE_TYPE_FIRE:
nSaveDamageType = SAVING_THROW_TYPE_FIRE;
nVisualType = VFX_IMP_FLAME_M;
nEnergyAura = GetLocalInt(BreathUsed.oDragon, "FireEnergyAura"); break;
case DAMAGE_TYPE_MAGICAL:
nSaveDamageType = SAVING_THROW_TYPE_NONE;
nVisualType = VFX_IMP_KNOCK; break;
case DAMAGE_TYPE_NEGATIVE:
nSaveDamageType = SAVING_THROW_TYPE_NEGATIVE;
nVisualType = VFX_IMP_NEGATIVE_ENERGY; break;
case DAMAGE_TYPE_POSITIVE:
nSaveDamageType = SAVING_THROW_TYPE_POSITIVE;
nVisualType = VFX_IMP_HOLY_AID; break;
case DAMAGE_TYPE_SONIC:
nSaveDamageType = SAVING_THROW_TYPE_SONIC;
nVisualType = VFX_IMP_SILENCE; break;
}
//apply Energy Draconic Aura bonus
if(nEnergyAura < 0) nEnergyAura = 0;
nSaveDC += nEnergyAura;
if(BreathUsed.nOverrideSpecial == BREATH_TOPAZ)
nVisualType = VFX_IMP_POISON_L;
if(BreathUsed.bBarrier)
{
//2d6 fire damage if the breath doesn't do damage
if(BreathUsed.nOverrideSpecial == BREATH_SHADOW
|| BreathUsed.nOverrideSpecial == BREATH_SLEEP
|| BreathUsed.nOverrideSpecial == BREATH_SLOW
|| BreathUsed.nOverrideSpecial == BREATH_PARALYZE
|| BreathUsed.nOverrideSpecial == BREATH_WEAKENING)
{
BreathUsed.nDiceType = 6;
BreathUsed.nDiceNumber = 2;
BreathUsed.nDamageType = DAMAGE_TYPE_FIRE;
}
//fire damage if damage isn't energy damage
if(BreathUsed.nDamageType == DAMAGE_TYPE_MAGICAL || BreathUsed.nDamageType == DAMAGE_TYPE_BLUDGEONING)
BreathUsed.nDamageType = DAMAGE_TYPE_FIRE;
//get the breath parameters and pass to the wall's scripts
SetLocalInt(BreathUsed.oDragon, "BarrierDiceType", BreathUsed.nDiceType);
SetLocalInt(BreathUsed.oDragon, "BarrierDiceNumber", BreathUsed.nDiceNumber);
SetLocalInt(BreathUsed.oDragon, "BarrierDamageType", BreathUsed.nDamageType);
//create the wall
effect eAOE = EffectAreaOfEffect(AOE_PER_WALLBREATH);
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eAOE, lTargetArea, RoundsToSeconds(d4()));
//this overrides all other breath effects, so exit
return;
}
//roll damage
switch(BreathUsed.nDiceType)
{
case 4:
nDamage = d4(BreathUsed.nDiceNumber); break;
case 6:
nDamage = d6(BreathUsed.nDiceNumber); break;
case 8:
nDamage = d8(BreathUsed.nDiceNumber); break;
case 10:
nDamage = d10(BreathUsed.nDiceNumber); break;
}
if(DEBUG) DoDebug("prc_inc_breath: Rolling damage: " + IntToString(BreathUsed.nDiceNumber)
+ "d" + IntToString(BreathUsed.nDiceType) + "= " + IntToString(nDamage));
//Shadow breath does 1 neg level instead of damage
if(BreathUsed.nOverrideSpecial == BREATH_SHADOW)
nDamage = 1;
//adjust for metabreaths
if(BreathUsed.bEnlarge)
fRange = fRange * 1.5;
if(BreathUsed.nHeighten > 0)
nSaveDC += BreathUsed.nHeighten;
if(BreathUsed.bMaximize)
nDamage = BreathUsed.nDiceType * BreathUsed.nDiceNumber;
if(BreathUsed.bSpread)
{
fRange = PRCGetCreatureSize(BreathUsed.oDragon) * 5.0;
if(fRange < 1.0) fRange = 5.0;
fRange = FeetToMeters(fRange);
nBreathShape = SHAPE_SPHERE;
lTargetArea = GetLocation(BreathUsed.oDragon);
eVis = EffectVisualEffect(VFX_FNF_DRAGBREATHGROUND);
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, lTargetArea);
}
//Lingering Breath's effects are 1/2 of normal when lingering
if(bLinger)
{
nDamage /= 2;
BreathUsed.nDiceNumber /= 2;
}
//DCs for Tempest Breath
switch(PRCGetCreatureSize(BreathUsed.oDragon))
{
case CREATURE_SIZE_LARGE:
nKnockdownDC = 15; break;
case CREATURE_SIZE_HUGE:
nKnockdownDC = 18; break;
case CREATURE_SIZE_GARGANTUAN:
nKnockdownDC = 20; break;
case CREATURE_SIZE_COLOSSAL:
nKnockdownDC = 30; break;
}
//adjust for breath channeling
if(BreathUsed.bEntangling)
nDamage = nDamage / 2;
/* Begin application */
int nObjectFilter = OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE;
//Adept's Breath of Bahamut does not affect objects
if(GetSpellId() == BREATH_BAHAMUT_LINE) nObjectFilter = OBJECT_TYPE_CREATURE;
//Get first target in spell area
object oTarget = GetFirstObjectInShape(nBreathShape, fRange, lTargetArea, TRUE, nObjectFilter, vSourceOfBreath);
if(DEBUG) DoDebug("prc_inc_breath: Target Name: " + GetName(oTarget));
while(GetIsObjectValid(oTarget))
{
if(DEBUG) DoDebug("prc_inc_breath: Valid Target: " + GetName(oTarget));
if(oTarget != BreathUsed.oDragon && !IsBreathProtected(BreathUsed.oDragon, oTarget) && spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, BreathUsed.oDragon))
{
if(DEBUG) DoDebug("prc_inc_breath: Not Self, Not Protected");
//Adjust the damage based on the Reflex Save, Evasion and Improved Evasion.
//Determine effect delay
fDelay = GetDistanceBetween(BreathUsed.oDragon, oTarget)/20;
//check for Shaped Breath effect
if(IsAdeptBreath() && (nShapedSpotsUsed < 4) && !GetIsReactionTypeHostile(oTarget) && GetLocalInt(BreathUsed.oDragon, "AdeptShapedBreath"))
{
if(DEBUG) DoDebug("prc_inc_breath: Entering Shaped Breath. Slots used: " + IntToString(nShapedSpotsUsed));
nShapedSpotsUsed++;
}
//Adept's Sickening Breath breath effect
else if(BreathUsed.nOverrideSpecial == BREATH_SICKENING)
{
if(DEBUG) DoDebug("prc_inc_breath: sickening breath attack");
//Fire cast spell at event for the specified target
SignalEvent(oTarget, EventSpellCastAt(BreathUsed.oDragon, GetSpellId()));
//2 rounds on a failed save
if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nSaveDC, SAVING_THROW_TYPE_NONE))
{
//Apply the VFX impact and effects
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_POISON_L), oTarget));
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectSickened(), oTarget, 12.0));
}
//1 round otherwise
else
{
//Apply the VFX impact and effects
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_POISON_L), oTarget));
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectSickened(), oTarget, 6.0));
}
}
//Brass alternate breath - sleep
else if(BreathUsed.nOverrideSpecial == BREATH_SLEEP)
{
if(DEBUG) DoDebug("prc_inc_breath: sleep breath attack");
//prepare effects
effect eBreath = EffectSleep();
effect eVis = EffectVisualEffect(VFX_IMP_SLEEP);
effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE);
effect eLink = EffectLinkEffects(eBreath, eDur);
//get duration
int nSleepDuration = BreathUsed.nDiceNumber;
//Fire cast spell at event for the specified target
SignalEvent(oTarget, EventSpellCastAt(BreathUsed.oDragon, GetSpellId()));
if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nSaveDC, SAVING_THROW_TYPE_NONE))
{
//Apply the VFX impact and effects
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nSleepDuration)));
SetLocalInt(oTarget, "AffectedByBreath", TRUE);
}
}
//Copper alternate breath - slow
else if(BreathUsed.nOverrideSpecial == BREATH_SLOW)
{
if(DEBUG) DoDebug("prc_inc_breath: slowing breath attack");
//prepare effects
effect eBreath = EffectSlow();
effect eVis = EffectVisualEffect(VFX_IMP_SLOW);
effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE);
effect eLink = EffectLinkEffects(eBreath, eDur);
//get duration
int nSlowDuration = BreathUsed.nDiceNumber;
//Fire cast spell at event for the specified target
SignalEvent(oTarget, EventSpellCastAt(BreathUsed.oDragon, GetSpellId()));
if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nSaveDC, SAVING_THROW_TYPE_NONE))
{
//Apply the VFX impact and effects
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nSlowDuration)));
SetLocalInt(oTarget, "AffectedByBreath", TRUE);
}
//Adept breath effect still lasts for one round if save is made
else if(IsAdeptBreath())
{
//Apply the VFX impact and effects
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(1)));
SetLocalInt(oTarget, "AffectedByBreath", TRUE);
}
}
//Gold alternate breath - drains strength
else if(BreathUsed.nOverrideSpecial == BREATH_WEAKENING)
{
if(DEBUG) DoDebug("prc_inc_breath: weakening breath attack");
//Fire cast spell at event for the specified target
SignalEvent(oTarget, EventSpellCastAt(BreathUsed.oDragon, GetSpellId()));
if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nSaveDC, SAVING_THROW_TYPE_NONE))
{
//Set Damage and VFX - Bioware Gold used VFX_IMP_REDUCE_ABILITY_SCORE originally
eVis = EffectVisualEffect(VFX_IMP_POISON_L);
//Apply the VFX impact and effects
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
//adept breath penalty only last 4 rounds on failure, gold breath has no duration
if(IsAdeptBreath())
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAbilityDecrease(ABILITY_STRENGTH, BreathUsed.nDiceNumber), oTarget, 24.0));
else
DelayCommand(fDelay, ApplyAbilityDamage(oTarget, ABILITY_STRENGTH, BreathUsed.nDiceNumber, DURATION_TYPE_PERMANENT, TRUE));
SetLocalInt(oTarget, "AffectedByBreath", TRUE);
}
//Adept breath still happens for 2 rounds on successful save
else if(IsAdeptBreath())
{
//Set Damage and VFX - Bioware Gold used VFX_IMP_REDUCE_ABILITY_SCORE originally
eVis = EffectVisualEffect(VFX_IMP_POISON_L);
//Apply the VFX impact and effects
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAbilityDecrease(ABILITY_STRENGTH, BreathUsed.nDiceNumber), oTarget, 12.0));
SetLocalInt(oTarget, "AffectedByBreath", TRUE);
}
bCanCling = TRUE;
}
//Silver alternate breath - paralyze
else if(BreathUsed.nOverrideSpecial == BREATH_PARALYZE)
{
if(DEBUG) DoDebug("prc_inc_breath: paralyzing breath attack");
//prepare effects
effect eBreath = EffectParalyze();
effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE);
effect eDur2 = EffectVisualEffect(VFX_DUR_PARALYZE_HOLD);
effect eParal = EffectVisualEffect(VFX_DUR_PARALYZED);
effect eLink = EffectLinkEffects(eBreath, eDur);
eLink = EffectLinkEffects(eLink, eDur2);
eLink = EffectLinkEffects(eLink, eParal);
//get duration
int nParalDuration = BreathUsed.nDiceNumber;
//Fire cast spell at event for the specified target
SignalEvent(oTarget, EventSpellCastAt(BreathUsed.oDragon, GetSpellId()));
if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nSaveDC, SAVING_THROW_TYPE_NONE))
{
//Apply the VFX impact and effects
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nParalDuration)));
SetLocalInt(oTarget, "AffectedByBreath", TRUE);
}
}
//Shadow Dragon breath - drains levels
else if(BreathUsed.nOverrideSpecial == BREATH_SHADOW)
{
if(DEBUG) DoDebug("prc_inc_breath: shadow breath attack");
//Fire cast spell at event for the specified target
SignalEvent(oTarget, EventSpellCastAt(BreathUsed.oDragon, GetSpellId()));
int nLevelDrain = PRCGetReflexAdjustedDamage(nDamage, oTarget, nSaveDC, SAVING_THROW_TYPE_NEGATIVE);
if (nLevelDrain > 0)
{
//Set Damage and VFX
eBreath = EffectNegativeLevel(nLevelDrain);
eVis = EffectVisualEffect(VFX_IMP_NEGATIVE_ENERGY);
//Apply the VFX impact and effects
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eBreath, oTarget));
SetLocalInt(oTarget, "AffectedByBreath", TRUE);
}
}
//Swift Wing Breath of Life - Positive to Undead only, heals living creatures
else if(BreathUsed.nOverrideSpecial == BREATH_SWIFT_WING)
{
if(DEBUG) DoDebug("prc_inc_breath: swift wing breath attack");
if(MyPRCGetRacialType(oTarget) == RACIAL_TYPE_UNDEAD || (GetHasFeat(FEAT_TOMB_TAINTED_SOUL, oTarget) && GetAlignmentGoodEvil(oTarget) != ALIGNMENT_GOOD))
{
//Fire cast spell at event for the specified target
SignalEvent(oTarget, EventSpellCastAt(BreathUsed.oDragon, GetSpellId()));
nAdjustedDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nSaveDC, SAVING_THROW_TYPE_POSITIVE);
if (nAdjustedDamage > 0)
{
//Set Damage and VFX
eBreath = EffectDamage(nAdjustedDamage, BreathUsed.nDamageType);
eVis = EffectVisualEffect(VFX_IMP_SUNSTRIKE);
//Apply the VFX impact and effects
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eBreath, oTarget));
SetLocalInt(oTarget, "AffectedByBreath", TRUE);
bCanCling = TRUE;
}
}
}
//normal damaging-type breath
else
{
//Fire cast spell at event for the specified target
SignalEvent(oTarget, EventSpellCastAt(BreathUsed.oDragon, GetSpellId()));
if(DEBUG) DoDebug("prc_inc_breath: normal breath attack");
if(BreathUsed.nSaveUsed == SAVING_THROW_FORT)
{
nAdjustedDamage = nDamage;
//make a fort save
if(PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nSaveDC, nSaveDamageType))
{
//Mettle is Evasion for Fort saves
if (GetHasMettle(oTarget, SAVING_THROW_FORT))
nAdjustedDamage = 0;
nAdjustedDamage /= 2;
}
}
else
nAdjustedDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nSaveDC, nSaveDamageType);
if (nAdjustedDamage > 0)
{
if(DEBUG) DoDebug("prc_inc_breath: Damage > 0");
//Set Damage and VFX
if(BreathUsed.nOverrideSpecial == BREATH_PYROCLASTIC)
{
int chSaveth;
int chVisual;
int eleRoll;
int nNumDice = d2();
//Sets the random Element factor of the Chaos Dragons Breath Weapon.
//Affects damage, saving throw, and impact visual.
if (nNumDice==1)
{
chSaveth = SAVING_THROW_TYPE_SONIC;
chVisual = VFX_IMP_SILENCE;
}
else if (nNumDice==2)
{
chSaveth = SAVING_THROW_TYPE_FIRE;
chVisual = VFX_IMP_FLAME_M;
}
if(GetLocalInt(oTarget, "DragonWard"))
nAdjustedDamage -= 40;
effect eBreath1 = EffectDamage(nAdjustedDamage/2, DAMAGE_TYPE_FIRE);
effect eBreath2 = EffectDamage(nAdjustedDamage/2, DAMAGE_TYPE_SONIC);
eBreath = EffectLinkEffects(eBreath1, eBreath2);
eVis = EffectVisualEffect(chVisual);
}
else
{
if(GetLocalInt(oTarget, "DragonWard"))
nAdjustedDamage -= 20;
eBreath = EffectDamage(nAdjustedDamage, BreathUsed.nDamageType);
eVis = EffectVisualEffect(nVisualType);
}
//Apply the VFX impact and effects
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eBreath, oTarget));
SetLocalInt(oTarget, "AffectedByBreath", TRUE);
bCanCling = TRUE;
}
}
//Knockdown check for Tempest Breath
if(BreathUsed.bTempest && (PRCGetCreatureSize(BreathUsed.oDragon) > CREATURE_SIZE_MEDIUM))
{
if(DEBUG) DoDebug("prc_inc_breath: tempest breath attack");
if(PRCGetCreatureSize(BreathUsed.oDragon) - PRCGetCreatureSize(oTarget) > 1)
{
if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nKnockdownDC, SAVING_THROW_TYPE_NONE))
{
effect eWindblown = EffectKnockdown();
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eWindblown, oTarget, 6.0));
}
}
}
//Breath of Life healing
if(oTarget != BreathUsed.oDragon && BreathUsed.nOverrideSpecial == BREATH_SWIFT_WING && MyPRCGetRacialType(oTarget) != RACIAL_TYPE_UNDEAD && MyPRCGetRacialType(oTarget) != RACIAL_TYPE_CONSTRUCT
&& !(GetHasFeat(FEAT_TOMB_TAINTED_SOUL, oTarget) && GetAlignmentGoodEvil(oTarget) != ALIGNMENT_GOOD))
{
if(DEBUG) DoDebug("prc_inc_breath: breath of life");
//Fire cast spell at event for the specified target
SignalEvent(oTarget, EventSpellCastAt(BreathUsed.oDragon, GetSpellId(), FALSE));
//Adjust the damage based on the Reflex Save, Evasion and Improved Evasion.
//Determine effect delay
fDelay = GetDistanceBetween(BreathUsed.oDragon, oTarget)/20;
int nHeal = BreathUsed.nDiceNumber;
//Warforged are only healed for half
if(GetIsWarforged(oTarget)) nHeal /= 2;
eBreath = EffectHeal(nHeal);
effect eHealVis = EffectVisualEffect(VFX_IMP_HEALING_S);
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eBreath, oTarget));
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eHealVis, oTarget));
}
//Entangling Exhalation
if(GetLocalInt(oTarget, "AffectedByBreath") && BreathUsed.bEntangling)
{
if(DEBUG) DoDebug("prc_inc_breath: entangling breath attack");
effect eEntangled = EffectEntangle();
effect eEntangleVis = EffectVisualEffect(VFX_DUR_ENTANGLE);
eEntangled = EffectLinkEffects(eEntangled, eEntangleVis);
int nEntangleRounds = d4();
//only does damage if the original breath did damage
if(BreathUsed.nDamageType > 0)
{
effect eDamage = EffectDamage(d6(), BreathUsed.nDamageType);
switch(nEntangleRounds)
{
case 4:
DelayCommand(fDelay + RoundsToSeconds(4), ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget));
case 3:
DelayCommand(fDelay + RoundsToSeconds(3), ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget));
case 2:
DelayCommand(fDelay + RoundsToSeconds(2), ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget));
case 1:
DelayCommand(fDelay + RoundsToSeconds(1), ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget)); break;
}
}
//but always entangles if the breath affects the target
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEntangled, oTarget, RoundsToSeconds(nEntangleRounds)));
}
DeleteLocalInt(oTarget, "AffectedByBreath");
//Clinging Breath check
if(BreathUsed.nClinging > 0 && bCanCling)
{
if(DEBUG) DoDebug("prc_inc_breath: clinging breath attack");
int nCount;
int AdjustedAbilityDamage = BreathUsed.nDiceNumber;
for(nCount = 0; nCount < BreathUsed.nClinging; nCount++)
{
float fNewDelay = RoundsToSeconds(nCount + 1);
if(BreathUsed.nOverrideSpecial == BREATH_WEAKENING)
{
AdjustedAbilityDamage /= 2;
DelayCommand(fNewDelay, ApplyAbilityDamage(oTarget, ABILITY_STRENGTH, BreathUsed.nDiceNumber, DURATION_TYPE_PERMANENT, TRUE));
if(AdjustedAbilityDamage = 1) nCount = BreathUsed.nClinging;
}
nAdjustedDamage /= 2;
if(BreathUsed.nOverrideSpecial == BREATH_PYROCLASTIC)
{
if(nAdjustedDamage < 3) nCount = BreathUsed.nClinging;
effect eBreath1 = EffectDamage(nAdjustedDamage/2, DAMAGE_TYPE_FIRE);
effect eBreath2 = EffectDamage(nAdjustedDamage/2, DAMAGE_TYPE_SONIC);
effect eAfterBreath = EffectLinkEffects(eBreath1, eBreath2);
DelayCommand(fNewDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eAfterBreath, oTarget));
}
else
{
if(nAdjustedDamage < 2) nCount = BreathUsed.nClinging;
effect eAfterBreath = EffectDamage(nAdjustedDamage, BreathUsed.nDamageType);
DelayCommand(fNewDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eAfterBreath, oTarget));
}
DelayCommand(fNewDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
}
}
}
//Get next target in spell area
if(DEBUG) DoDebug("prc_inc_breath: Next target");
oTarget = GetNextObjectInShape(nBreathShape, fRange, lTargetArea, TRUE, nObjectFilter, vSourceOfBreath);
}
//Lingering Breath check
if(BreathUsed.nLingering > 0)
{
int nCount;
int nLingerDuration = BreathUsed.nLingering;
BreathUsed.nLingering = 0;
BreathUsed.nClinging = 0;
vector vOrigin = GetPosition(BreathUsed.oDragon);
effect eGroundVis = EffectVisualEffect(VFX_FNF_DRAGBREATHGROUND);
for(nCount = 0; nCount < nLingerDuration; nCount++)
{
float fNewDelay = RoundsToSeconds(nCount + 1);
DelayCommand(fNewDelay, ApplyBreath(BreathUsed, lTargetArea, TRUE, vOrigin.x, vOrigin.y, vOrigin.z));
DelayCommand(fNewDelay, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eGroundVis, lTargetArea));
}
}
}
void PRCPlayDragonBattleCry()
{
if(d100() > 50)
{
PlayVoiceChat(VOICE_CHAT_BATTLECRY1);
}
else
{
PlayVoiceChat(VOICE_CHAT_BATTLECRY2);
}
}

View File

@@ -0,0 +1,92 @@
/* For burning spells to use in abilities */
#include "prc_inc_spells"
#include "prc_getbest_inc"
//////////////////////////////////////////////////
/* Function Prototypes */
//////////////////////////////////////////////////
// Burns a spell of the selected spell level
// Spell level picked by prc_burnselect.nss
//
// Returns FALSE if it failed, or the spell level if it worked
int BurnSpell(object oPC);
// Burns a spell of the highest spell level the character has
//
// Returns FALSE if it failed, or the spell if it worked
int BurnBestSpell(object oPC);
int BurnSpell(object oPC)
{
int nSpellLevel = GetLocalInt(oPC, "BurnSpellLevel");
int nSpell;
if (nSpellLevel == 0)
nSpell = GetBestL0Spell(oPC, -1);
else if (nSpellLevel == 1)
nSpell = GetBestL1Spell(oPC, -1);
else if (nSpellLevel == 2)
nSpell = GetBestL2Spell(oPC, -1);
else if (nSpellLevel == 3)
nSpell = GetBestL3Spell(oPC, -1);
else if (nSpellLevel == 4)
nSpell = GetBestL4Spell(oPC, -1);
else if (nSpellLevel == 5)
nSpell = GetBestL5Spell(oPC, -1);
else if (nSpellLevel == 6)
nSpell = GetBestL6Spell(oPC, -1);
else if (nSpellLevel == 7)
nSpell = GetBestL7Spell(oPC, -1);
else if (nSpellLevel == 8)
nSpell = GetBestL8Spell(oPC, -1);
else if (nSpellLevel == 9)
nSpell = GetBestL9Spell(oPC, -1);
if (nSpell == -1)
{
FloatingTextStringOnCreature("You have no spells remaining of the selected level", oPC, FALSE);
return FALSE;
}
if (DEBUG) FloatingTextStringOnCreature("Burning SpellID "+IntToString(nSpell), oPC, FALSE);
PRCDecrementRemainingSpellUses(oPC, nSpell);
if(GetLocalInt(oPC, "ReserveFeatsRunning"))
DelayCommand(0.1f, ExecuteScript("prc_reservefeat", oPC));
return nSpellLevel;
}
int BurnBestSpell(object oPC)
{
int nSpell = GetBestL9Spell(oPC, -1);
if (nSpell == -1)
nSpell = GetBestL8Spell(oPC, -1);
if (nSpell == -1)
nSpell = GetBestL7Spell(oPC, -1);
if (nSpell == -1)
nSpell = GetBestL6Spell(oPC, -1);
if (nSpell == -1)
nSpell = GetBestL5Spell(oPC, -1);
if (nSpell == -1)
nSpell = GetBestL4Spell(oPC, -1);
if (nSpell == -1)
nSpell = GetBestL3Spell(oPC, -1);
if (nSpell == -1)
nSpell = GetBestL2Spell(oPC, -1);
if (nSpell == -1)
nSpell = GetBestL1Spell(oPC, -1);
if (nSpell == -1)
nSpell = GetBestL0Spell(oPC, -1);
if (nSpell == -1)
{
FloatingTextStringOnCreature("You have no spells remaining", oPC, FALSE);
return FALSE;
}
if (DEBUG) FloatingTextStringOnCreature("Burning SpellID "+IntToString(nSpell), oPC, FALSE);
PRCDecrementRemainingSpellUses(oPC, nSpell);
if(GetLocalInt(oPC, "ReserveFeatsRunning"))
DelayCommand(0.1f, ExecuteScript("prc_reservefeat", oPC));
return nSpell;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,117 @@
//::///////////////////////////////////////////////
//:: Chat Command include
//:: prc_inc_chat
//::///////////////////////////////////////////////
const string PRC_CHAT_HOOK_ACTIVE = "prc_chat_hook";
const string PRC_CHAT_HOOK_SCRIPT = "prc_chat_script";
const string PRC_PLAYER_RESPONSE = "prc_player_response";
void AddChatEventHook(object oPC, string sScriptToCall, float fDur = 0.0f);
struct _prc_inc_WordInfo{
int nWordStart;
int nWordLength;
};
//we assume that sDivider is always 1 character
struct _prc_inc_WordInfo GetStringWordInfo(string sString, int nWordToGet, string sDivider = " ")
{
struct _prc_inc_WordInfo info;
// Safety checks
if(sString == "")
return info;
if(sDivider == "")
sDivider = " ";
int nStrLength = GetStringLength(sString);
nWordToGet--;
// Start with the first word.
int nCurrentWord = 0;
int nCurrentStart = 0;
int nCurrentEnd = FindSubString(sString, sDivider);
// Advance to the specified element.
while (nCurrentWord < nWordToGet && nCurrentEnd > -1)
{
nCurrentWord++;
nCurrentStart = nCurrentEnd + 1;
nCurrentEnd = FindSubString(sString, sDivider, nCurrentStart);
}
// Adjust the end point if this is the last element.
if (nCurrentEnd == -1) nCurrentEnd = nStrLength;
if (nCurrentWord >= nWordToGet)
{
info.nWordStart = nCurrentStart;
info.nWordLength = nCurrentEnd-nCurrentStart;
}
return info;
}
string GetStringWord(string sString, int nWordToGet, string sDivider = " ")
{
struct _prc_inc_WordInfo info = GetStringWordInfo(sString, nWordToGet, sDivider);
return GetSubString(sString, info.nWordStart, info.nWordLength);
}
string GetStringWordToEnd(string sString, int nWordToGet, string sDivider = " ")
{
struct _prc_inc_WordInfo info = GetStringWordInfo(sString, nWordToGet, sDivider);
return GetSubString(sString, info.nWordStart, GetStringLength(sString)-info.nWordStart);
}
//Returns TRUE if sPrefix matches sWord or some part of the beginning of sWord
/*int GetStringMatchesAbbreviation(string sString, string sAbbreviationPattern)
{
int nShortestAbbreviation = FindSubString(sAbbreviationPattern, "-");
if(nShortestAbbreviation > 0)
sAbbreviationPattern = GetStringLeft(sAbbreviationPattern, nShortestAbbreviation) + GetStringRight(sAbbreviationPattern, GetStringLength(sAbbreviationPattern)-(nShortestAbbreviation+1));
else if (nShortestAbbreviation == 0)
{
sAbbreviationPattern = GetStringRight(sAbbreviationPattern, GetStringLength(sAbbreviationPattern)-1);
nShortestAbbreviation = GetStringLength(sAbbreviationPattern);
}
else
nShortestAbbreviation = GetStringLength(sAbbreviationPattern);
if(GetStringLength(sString) >= nShortestAbbreviation)
return GetStringLeft(sAbbreviationPattern, GetStringLength(sString)) == sString;
else
return FALSE;
}*/
int GetStringMatchesAbbreviation(string sString, string sAbbreviationPattern)
{
string sTest;
int iAbbrevEnd = FindSubString(sAbbreviationPattern, "-");
if(iAbbrevEnd == -1)
sTest = sAbbreviationPattern;
else
sTest = GetSubString(sAbbreviationPattern, 0, iAbbrevEnd);
return FindSubString(sString, sTest) == 0;
}
void HelpText(object oPC, string sString)
{
SendMessageToPC(oPC, PRC_TEXT_WHITE + sString + "</c>");
}
void _clear_chat_vars(object oPC)
{
DeleteLocalInt(oPC, PRC_CHAT_HOOK_ACTIVE);
DeleteLocalString(oPC, PRC_CHAT_HOOK_SCRIPT);
}
void AddChatEventHook(object oPC, string sScriptToCall, float fDur = 0.0f)
{
SetLocalInt(oPC, PRC_CHAT_HOOK_ACTIVE, TRUE);
SetLocalString(oPC, PRC_CHAT_HOOK_SCRIPT, sScriptToCall);
if(fDur > 0.0f) DelayCommand(fDur, _clear_chat_vars(oPC));
}

View File

@@ -0,0 +1,828 @@
//::///////////////////////////////////////////////
//:: Debug Command include
//:: prc_inc_chat_dm.nss
//::///////////////////////////////////////////////
#include "prc_alterations"
#include "prc_inc_chat"
#include "prc_inc_shifting" //For _prc_inc_EffectString, etc.
#include "prc_inc_util"
#include "psi_inc_ppoints"
/*
execute
setlocalvar
dellocalvar
set
xp
level
gold
abil
skill
mod
xp
gold
abilit
skill
*/
const string CMD_CHK_PP = "checkp-owerpoints";
const string CMD_CHK_SS = "checks-pellslots";
const string CMD_EXECUTE = "dm_exec-ute";
const string CMD_VARIABLE = "dm_var-iable";
const string CMD_PC = "pc";
const string CMD_MODULE = "mod-ule";
const string CMD_LOCAL = "loc-al";
const string CMD_PERSISTANT = "per-sistant";
const string CMD_INFORMATION = "dm_info-rmation";
const string CMD_ABILITIES = "abil-ities";
const string CMD_EFFECTS = "eff-ects";
const string CMD_PROPERTIES = "prop-erties";
const string CMD_SKILLS = "skil-ls";
const string CMD_CHANGE = "dm_change";
const string CMD_ABILITY = "abil-ity";
const string CMD_STR = "str-ength";
const string CMD_DEX = "dex-terity";
const string CMD_CON = "con-stitution";
const string CMD_INT = "int-elligence";
const string CMD_WIS = "wis-dom";
const string CMD_CHA = "cha-risma";
const string CMD_LEVEL = "level";
const string CMD_XP = "xp";
const string CMD_GOLD = "gold";
const string CMD_BY = "by";
const string CMD_TO = "to";
const string CMD_SPAWN = "dm_spawn";
const string CMD_CREATURE = "creature";
const string CMD_ITEM = "item";
const string CMD_RELEVEL = "dm_relevel";
const string CMD_SPECIAL = "dm_special";
const string CMD_REST = "rest";
const string CMD_HANDLE_FORCE_REST_1 = "handle";
const string CMD_HANDLE_FORCE_REST_2 = "force-d";
const string CMD_HANDLE_FORCE_REST_3 = "rest-ing";
int Debug_ProcessChatCommand_Help(object oPC, string sCommand)
{
string sCommandName = GetStringWord(sCommand, 2);
int nLevel = sCommandName != "";
int bResult = FALSE;
if(!nLevel)
{
HelpText(oPC, "=== DM COMMANDS");
HelpText(oPC, "");
}
if(GetStringMatchesAbbreviation(sCommandName, CMD_EXECUTE) || !nLevel)
{
if(nLevel)
{
bResult = TRUE;
HelpText(oPC, "=== DM COMMAND: " + CMD_EXECUTE);
HelpText(oPC, "");
}
HelpText(oPC, "~~" + CMD_EXECUTE + " <script-name>");
HelpText(oPC, "");
}
if(GetStringMatchesAbbreviation(sCommandName, CMD_VARIABLE) || !nLevel)
{
if (nLevel)
{
bResult = TRUE;
HelpText(oPC, "=== DM COMMAND: " + CMD_VARIABLE);
HelpText(oPC, "");
}
HelpText(oPC, "~~" + CMD_VARIABLE + " <optional:target> <optional:duration> <type> get <varname>");
if (nLevel)
HelpText(oPC, " Print the value of the specified local variable");
HelpText(oPC, "~~" + CMD_VARIABLE + " <optional:target> <optional:duration> <type> set <varname> <value>");
if (nLevel)
{
HelpText(oPC, " Set the value of the specified local variable and print the old value");
HelpText(oPC, " <target> can be one of: " + CMD_PC + ", " + CMD_MODULE + " (default:" + CMD_PC + " )");
HelpText(oPC, " <duration> can be one of: " + CMD_LOCAL + ", " + CMD_PERSISTANT + " (default: " + CMD_LOCAL + ")");
HelpText(oPC, " <type> can be one of: int, string");
}
HelpText(oPC, "");
}
if(GetStringMatchesAbbreviation(sCommandName, CMD_INFORMATION) || !nLevel)
{
if (nLevel)
{
bResult = TRUE;
HelpText(oPC, "=== DM COMMAND: " + CMD_INFORMATION);
HelpText(oPC, "");
}
HelpText(oPC, "~~" + CMD_INFORMATION + " " + CMD_ABILITIES);
if (nLevel)
HelpText(oPC, " Print the STR, DEX, CON, INT, WIS, and CHA of the PC");
HelpText(oPC, "~~" + CMD_INFORMATION + " " + CMD_EFFECTS);
if (nLevel)
HelpText(oPC, " Print all effects that have been applied to the PC");
HelpText(oPC, "~~" + CMD_INFORMATION + " " + CMD_PROPERTIES);
if (nLevel)
HelpText(oPC, " Print the item properties of all items the PC has equipped");
HelpText(oPC, "~~" + CMD_INFORMATION + " " + CMD_SKILLS);
if (nLevel)
HelpText(oPC, " Print the number of ranks that the PC has in each skill");
HelpText(oPC, "");
}
if(GetStringMatchesAbbreviation(sCommandName, CMD_CHANGE) || !nLevel)
{
if (nLevel)
{
bResult = TRUE;
HelpText(oPC, "=== DM COMMAND: " + CMD_CHANGE + " <what> <ONE:to|by> <value>");
HelpText(oPC, "");
}
HelpText(oPC, "~~" + CMD_CHANGE + " " + CMD_LEVEL + " " + CMD_TO + " <value>");
HelpText(oPC, "~~" + CMD_CHANGE + " " + CMD_LEVEL + " " + CMD_BY + " <amount>");
if (nLevel)
{
HelpText(oPC, " Adjust the PC's level as specified (must be 1-40)");
}
HelpText(oPC, "");
HelpText(oPC, "~~" + CMD_CHANGE + " " + CMD_XP + " " + CMD_TO + " <value>");
HelpText(oPC, "~~" + CMD_CHANGE + " " + CMD_XP + " " + CMD_BY + " <amount>");
if (nLevel)
{
HelpText(oPC, " Adjust the PC's XP as specified");
}
HelpText(oPC, "");
HelpText(oPC, "~~" + CMD_CHANGE + " " + CMD_GOLD + " " + CMD_TO + " <value>");
HelpText(oPC, "~~" + CMD_CHANGE + " " + CMD_GOLD + " " + CMD_BY + " <amount>");
if (nLevel)
{
HelpText(oPC, " Adjust the PC's gold as specified");
}
HelpText(oPC, "");
HelpText(oPC, "~~" + CMD_CHANGE + " " + CMD_ABILITY + " <ability-name> " + CMD_TO + " <value> (requires NWNX funcs)");
HelpText(oPC, "~~" + CMD_CHANGE + " " + CMD_ABILITY + " <ability-name> " + CMD_BY + " <value> (requires NWNX funcs)");
if (nLevel)
{
HelpText(oPC, " Adjust the PC's abilities as specified");
HelpText(oPC, " <ability-name> can be: " + CMD_STR + ", " + CMD_DEX + ", " + CMD_CON + ", " + CMD_INT + ", " + CMD_WIS + ", or " + CMD_CHA);
}
HelpText(oPC, "");
}
if(GetStringMatchesAbbreviation(sCommandName, CMD_SPAWN) || !nLevel)
{
if (nLevel)
{
bResult = TRUE;
HelpText(oPC, "=== DM COMMAND: " + CMD_SPAWN);
HelpText(oPC, "");
}
HelpText(oPC, "~~" + CMD_SPAWN + " " + CMD_CREATURE + " <resref>");
if (nLevel)
{
HelpText(oPC, " Spawn the specified creature in the same location as the PC.");
HelpText(oPC, " It will be treated as a summoned creature--i.e., under the PC's control.");
}
HelpText(oPC, "~~" + CMD_SPAWN + " " + CMD_ITEM + " <resref>");
if (nLevel)
{
HelpText(oPC, " Spawn the specified item in the same location as the PC");
HelpText(oPC, " Use: ~~" + CMD_SPAWN + " " + CMD_ITEM + "prc_target to spawn chat command target widget.");
}
HelpText(oPC, "");
}
if(GetStringMatchesAbbreviation(sCommandName, CMD_RELEVEL) || !nLevel)
{
if (nLevel)
{
bResult = TRUE;
HelpText(oPC, "=== DM COMMAND: " + CMD_RELEVEL + " <level>");
HelpText(oPC, "");
}
HelpText(oPC, "~~" + CMD_RELEVEL + " <level>");
if (nLevel)
{
HelpText(oPC, " Relevel the PC starting from the specified level.");
HelpText(oPC, " The final result is a PC with exactly the same XP as before,");
HelpText(oPC, " but with the feats, skills, etc. reselected starting with the specified level.");
}
HelpText(oPC, "");
}
if(GetStringMatchesAbbreviation(sCommandName, CMD_SPECIAL) || !nLevel)
{
if (nLevel)
{
bResult = TRUE;
HelpText(oPC, "=== DM COMMAND: " + CMD_SPECIAL);
HelpText(oPC, "");
}
HelpText(oPC, "~~" + CMD_SPECIAL + " " + CMD_REST);
if (nLevel)
{
HelpText(oPC, " Instantly rest the PC");
}
HelpText(oPC, "~~" + CMD_SPECIAL + " " + CMD_HANDLE_FORCE_REST_1 + " " + CMD_HANDLE_FORCE_REST_2 + " " + CMD_HANDLE_FORCE_REST_3);
if (nLevel)
{
HelpText(oPC, " Tell PRC that the module force rests PCs.");
HelpText(oPC, " Forced resting restores feat uses and spell uses for Bioware spellbooks,");
HelpText(oPC, " but does not restore spell uses for PRC conversation-based spellbooks,");
HelpText(oPC, " and may cause problems with some other PRC features.");
HelpText(oPC, " Start a detector that detects forced resting and fixes");
HelpText(oPC, " these issues automatically.");
}
HelpText(oPC, "");
}
return bResult;
}
void _prc_inc_DoLocalVar(object oTarget, object oPC, string sCommand, int nNextArg)
{
string sDataType = GetStringWord(sCommand, nNextArg++);
string sCommandName = GetStringWord(sCommand, nNextArg++);
if (sCommandName != "get" && sCommandName != "set")
{
DoDebug("Unrecognized command (expected 'get' or 'set'): " + sCommandName);
return;
}
string sVarName = GetStringWord(sCommand, nNextArg++);
if (sVarName == "")
{
DoDebug("Invalid variable name: '" + sCommandName + "'");
return;
}
string sVarValue = GetStringWordToEnd(sCommand, nNextArg);
if (sDataType == "string")
{
string sValue = GetLocalString(oTarget, sVarName);
DoDebug("Value: '" + sValue + "'");
if (sCommandName == "set")
{
SetLocalString(oTarget, sVarName, sVarValue);
DoDebug("New Value: '" + sVarValue + "'");
}
}
else if (sDataType == "int")
{
int nValue = GetLocalInt(oTarget, sVarName);
DoDebug("Value: " + IntToString(nValue));
if (sCommandName == "set")
{
if(DEBUG || GetIsDM(oPC))
{
int nVarValue = StringToInt(sVarValue);
if (sVarValue == IntToString(nVarValue))
{
SetLocalInt(oTarget, sVarName, nVarValue);
DoDebug("New Value: " + sVarValue);
}
else
DoDebug("Can't set integer variable to non-integer value: " +sVarValue);
}
else
DoDebug("This command only works if DEBUG = TRUE");
}
}
else
{
DoDebug("Unrecognized data type: " + sDataType);
}
}
void _prc_inc_DoPersistantVar(object oTarget, object oPC, string sCommand, int nNextArg)
{
string sDataType = GetStringWord(sCommand, nNextArg++);
string sCommandName = GetStringWord(sCommand, nNextArg++);
if (sCommandName != "get" && sCommandName != "set")
{
DoDebug("Unrecognized command (expected 'get' or 'set'): " + sCommandName);
return;
}
string sVarName = GetStringWord(sCommand, nNextArg++);
if (sVarName == "")
{
DoDebug("Invalid variable name: '" + sCommandName + "'");
return;
}
string sVarValue = GetStringWordToEnd(sCommand, nNextArg++);
if (sDataType == "string")
{
string sValue = GetPersistantLocalString(oTarget, sVarName);
DoDebug("Value: '" + sValue + "'");
if (sCommandName == "set")
SetPersistantLocalString(oTarget, sVarName, sVarValue);
}
else if (sDataType == "int")
{
int nValue = GetPersistantLocalInt(oTarget, sVarName);
DoDebug("Value: " + IntToString(nValue));
if (sCommandName == "set")
{
if(DEBUG || GetIsDM(oPC))
{
int nVarValue = StringToInt(sVarValue);
if (sVarValue == IntToString(nVarValue))
SetPersistantLocalInt(oTarget, sVarName, nVarValue);
else
DoDebug("Can't set integer variable to non-integer value: " +sVarValue);
}
else
DoDebug("This command only works if DEBUG = TRUE");
}
}
else
{
DoDebug("Unrecognized data type: " + sDataType);
}
}
void _prc_inc_DumpItemProperty(string sPrefix, itemproperty iProp, object oPC)
{
int nDurationType = GetItemPropertyDurationType(iProp);
string sPropString = _prc_inc_ItemPropertyString(iProp);
if(sPropString != "")
{
if (nDurationType == DURATION_TYPE_TEMPORARY)
sPropString = GetStringByStrRef(57473+0x01000000) + sPropString; //"TEMPORARY: "
DoDebug(sPrefix + sPropString);
}
}
void _prc_inc_DumpAllItemProperties(string sPrefix, object oItem, object oPC)
{
if(GetIsObjectValid(oItem))
{
itemproperty iProp = GetFirstItemProperty(oItem);
while(GetIsItemPropertyValid(iProp))
{
_prc_inc_DumpItemProperty(sPrefix, iProp, oPC);
iProp = GetNextItemProperty(oItem);
}
}
}
int _prc_inc_XPToLevel(int nXP)
{
float fXP = IntToFloat(nXP);
float fLevel = (sqrt(8 * fXP / 1000 + 1) + 1) / 2;
return FloatToInt(fLevel);
}
int _prc_inc_LevelToXP(int nLevel)
{
return (nLevel * (nLevel - 1)) * 500;
}
void DoPrintSummon(object oPC, string sResRef)
{
object oCreature = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC);
if (GetIsObjectValid(oCreature))
HelpText(oPC, "Created creature: " + GetName(oCreature));
else
HelpText(oPC, "Failed to create creature--invalid resref?: " + sResRef);
}
void DoSummon(object oPC, string sResRef)
{
effect eSummon = EffectSummonCreature(sResRef);
ApplyEffectAtLocation(DURATION_TYPE_PERMANENT, eSummon, GetLocation(oPC));
AssignCommand(oPC, DoPrintSummon(oPC, sResRef));
}
int Debug_ProcessChatCommand(object oPC, string sCommand)
{
string sCommandName = GetStringWord(sCommand, 1);
int bResult = FALSE;
object oTarget = GetLocalObject(oPC, "prc_chatcmd_target");
if(!GetIsObjectValid(oTarget))
oTarget = oPC;
//Handle the commands we recognize no matter what, but only execute them if DEBUG is TRUE
if(GetStringMatchesAbbreviation(sCommandName, CMD_EXECUTE))
{
bResult = TRUE;
if (DEBUG || GetIsDM(oPC))
{
string sScript = GetStringWord(sCommand, 2);
HelpText(oPC, "Executing script: " + sScript);
ExecuteScript(sScript, oTarget);
}
else
HelpText(oPC, "This command only works if DEBUG = TRUE");
}
else if (GetStringMatchesAbbreviation(sCommandName, CMD_VARIABLE))
{
bResult = TRUE;
int nNextArg = 2;
string sVarType = GetStringWord(sCommand, nNextArg++);
if(GetStringMatchesAbbreviation(sVarType, CMD_MODULE))
{
sVarType = GetStringWord(sCommand, nNextArg++);
oTarget = GetModule();
}
else if(GetStringMatchesAbbreviation(sVarType, CMD_PC))
{
sVarType = GetStringWord(sCommand, nNextArg++);
oTarget = oPC;
}
if(GetStringMatchesAbbreviation(sVarType, CMD_LOCAL))
_prc_inc_DoLocalVar(oTarget, oPC, sCommand, nNextArg);
else if(GetStringMatchesAbbreviation(sVarType, CMD_PERSISTANT))
_prc_inc_DoPersistantVar(oTarget, oPC, sCommand, nNextArg);
else
_prc_inc_DoLocalVar(oTarget, oPC, sCommand, nNextArg);
}
else if(GetStringMatchesAbbreviation(sCommandName, CMD_INFORMATION))
{
bResult = TRUE;
string sInfoType = GetStringWord(sCommand, 2);
if (GetStringMatchesAbbreviation(sInfoType, CMD_ABILITIES))
{
HelpText(oPC, "====== ABILITIES ======");
HelpText(oPC, "=== The first number is the base score; the second is the modified score, which includes bonuses and penalties from gear, etc.");
HelpText(oPC, "=== STR: " + IntToString(GetAbilityScore(oTarget, ABILITY_STRENGTH, TRUE)) + " / " + IntToString(GetAbilityScore(oTarget, ABILITY_STRENGTH, FALSE)));
HelpText(oPC, "=== DEX: " + IntToString(GetAbilityScore(oTarget, ABILITY_DEXTERITY, TRUE)) + " / " + IntToString(GetAbilityScore(oTarget, ABILITY_DEXTERITY, FALSE)));
HelpText(oPC, "=== CON: " + IntToString(GetAbilityScore(oTarget, ABILITY_CONSTITUTION, TRUE)) + " / " + IntToString(GetAbilityScore(oTarget, ABILITY_CONSTITUTION, FALSE)));
HelpText(oPC, "=== INT: " + IntToString(GetAbilityScore(oTarget, ABILITY_INTELLIGENCE, TRUE)) + " / " + IntToString(GetAbilityScore(oTarget, ABILITY_INTELLIGENCE, FALSE)));
HelpText(oPC, "=== WIS: " + IntToString(GetAbilityScore(oTarget, ABILITY_WISDOM, TRUE)) + " / " + IntToString(GetAbilityScore(oTarget, ABILITY_WISDOM, FALSE)));
HelpText(oPC, "=== CHA: " + IntToString(GetAbilityScore(oTarget, ABILITY_CHARISMA, TRUE)) + " / " + IntToString(GetAbilityScore(oTarget, ABILITY_CHARISMA, FALSE)));
if (GetPersistantLocalInt(oTarget, SHIFTER_ISSHIFTED_MARKER) && GetPRCSwitch(PRC_NWNX_FUNCS))
{
int iSTR = GetPersistantLocalInt(oTarget, "Shifting_NWNXSTRAdjust");
int iDEX = GetPersistantLocalInt(oTarget, "Shifting_NWNXDEXAdjust");
int iCON = GetPersistantLocalInt(oTarget, "Shifting_NWNXCONAdjust");
HelpText(oPC, "=== The first number is the base score when unshifted; the second is the modified score when unshifted.");
HelpText(oPC, "=== STR: " + IntToString(GetAbilityScore(oTarget, ABILITY_STRENGTH, TRUE)-iSTR) + " / " + IntToString(GetAbilityScore(oTarget, ABILITY_STRENGTH, FALSE)-iSTR));
HelpText(oPC, "=== DEX: " + IntToString(GetAbilityScore(oTarget, ABILITY_DEXTERITY, TRUE)-iDEX) + " / " + IntToString(GetAbilityScore(oTarget, ABILITY_DEXTERITY, FALSE)-iDEX));
HelpText(oPC, "=== CON: " + IntToString(GetAbilityScore(oTarget, ABILITY_CONSTITUTION, TRUE)-iCON) + " / " + IntToString(GetAbilityScore(oTarget, ABILITY_CONSTITUTION, FALSE)-iCON));
}
}
else if (GetStringMatchesAbbreviation(sInfoType, CMD_EFFECTS))
{
HelpText(oPC, "====== EFFECTS ======");
effect eEffect = GetFirstEffect(oTarget);
while(GetIsEffectValid(eEffect))
{
if (GetEffectType(eEffect) == EFFECT_TYPE_INVALIDEFFECT)
{
//An effect with type EFFECT_TYPE_INVALID is added for each item property
//They are also added for a couple of other things (Knockdown, summons, etc.)
//Just skip these
}
else
{
string sEffectString = _prc_inc_EffectString(eEffect);
if(sEffectString != "")
HelpText(oPC, "=== " + sEffectString);
}
eEffect = GetNextEffect(oTarget);
}
}
else if (GetStringMatchesAbbreviation(sInfoType, CMD_PROPERTIES))
{
HelpText(oPC, "====== PROPERTIES ======");
HelpText(oPC, "====== CREATURE");
_prc_inc_DumpAllItemProperties("=== ", oTarget, oPC);
if(GetObjectType(oTarget) == OBJECT_TYPE_CREATURE)
{
HelpText(oPC, "====== CREATURE HIDE");
_prc_inc_DumpAllItemProperties("=== ", GetItemInSlot(INVENTORY_SLOT_CARMOUR, oTarget), oPC);
HelpText(oPC, "====== RIGHT CREATURE WEAPON");
_prc_inc_DumpAllItemProperties("=== ", GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oTarget), oPC);
HelpText(oPC, "====== LEFT CREATURE WEAPON");
_prc_inc_DumpAllItemProperties("=== ", GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oTarget), oPC);
HelpText(oPC, "====== SPECIAL CREATURE WEAPON");
_prc_inc_DumpAllItemProperties("=== ", GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oTarget), oPC);
HelpText(oPC, "====== RIGHT HAND");
_prc_inc_DumpAllItemProperties("=== ", GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget), oPC);
HelpText(oPC, "====== LEFT HAND");
_prc_inc_DumpAllItemProperties("=== ", GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget), oPC);
HelpText(oPC, "====== CHEST");
_prc_inc_DumpAllItemProperties("=== ", GetItemInSlot(INVENTORY_SLOT_CHEST, oTarget), oPC);
HelpText(oPC, "====== HEAD");
_prc_inc_DumpAllItemProperties("=== ", GetItemInSlot(INVENTORY_SLOT_HEAD, oTarget), oPC);
HelpText(oPC, "====== CLOAK");
_prc_inc_DumpAllItemProperties("=== ", GetItemInSlot(INVENTORY_SLOT_CLOAK, oTarget), oPC);
HelpText(oPC, "====== ARMS");
_prc_inc_DumpAllItemProperties("=== ", GetItemInSlot(INVENTORY_SLOT_ARMS, oTarget), oPC);
HelpText(oPC, "====== BELT");
_prc_inc_DumpAllItemProperties("=== ", GetItemInSlot(INVENTORY_SLOT_BELT, oTarget), oPC);
HelpText(oPC, "====== BOOTS");
_prc_inc_DumpAllItemProperties("=== ", GetItemInSlot(INVENTORY_SLOT_BOOTS, oTarget), oPC);
HelpText(oPC, "====== RIGHT HAND RING");
_prc_inc_DumpAllItemProperties("=== ", GetItemInSlot(INVENTORY_SLOT_RIGHTRING, oTarget), oPC);
HelpText(oPC, "====== LEFT HAND RING");
_prc_inc_DumpAllItemProperties("=== ", GetItemInSlot(INVENTORY_SLOT_LEFTRING, oTarget), oPC);
HelpText(oPC, "====== NECK");
_prc_inc_DumpAllItemProperties("=== ", GetItemInSlot(INVENTORY_SLOT_NECK, oTarget), oPC);
HelpText(oPC, "====== ARROWS");
_prc_inc_DumpAllItemProperties("=== ", GetItemInSlot(INVENTORY_SLOT_ARROWS, oTarget), oPC);
HelpText(oPC, "====== BOLTS");
_prc_inc_DumpAllItemProperties("=== ", GetItemInSlot(INVENTORY_SLOT_BOLTS, oTarget), oPC);
HelpText(oPC, "====== BULLETS");
_prc_inc_DumpAllItemProperties("=== ", GetItemInSlot(INVENTORY_SLOT_BULLETS, oTarget), oPC);
}
}
else if (GetStringMatchesAbbreviation(sInfoType, CMD_SKILLS))
{
HelpText(oPC, "====== SKILLS ======");
HelpText(oPC, "=== The first number is the base score; the second is the modified score, which includes bonuses and penalties from gear, etc.");
int i = 0;
string sSkillName;
while((sSkillName = Get2DACache("skills", "Name", i)) != "")
{
sSkillName = GetStringByStrRef(StringToInt(sSkillName));
HelpText(oPC, "=== " + sSkillName + ": " + IntToString(GetSkillRank(i, oTarget, TRUE)) + " / " + IntToString(GetSkillRank(i, oTarget, FALSE)));
i += 1;
}
}
else
HelpText(oPC, "Unrecognized information request: " + sInfoType);
}
else if (GetStringMatchesAbbreviation(sCommandName, CMD_CHANGE))
{
bResult = TRUE;
if(!DEBUG && !GetIsDM(oPC))
HelpText(oPC, "This command only works if DEBUG = TRUE");
else
{
string sChangeWhat = GetStringWord(sCommand, 2);
string sChangeHow = GetStringWord(sCommand, 3);
string sNumber = GetStringWord(sCommand, 4);
int nNumber = StringToInt(sNumber);
if (GetStringMatchesAbbreviation(sChangeWhat, CMD_LEVEL))
{
if (sNumber != IntToString(nNumber))
HelpText(oPC, "Unrecognized level: " + sNumber);
else
{
if (GetStringMatchesAbbreviation(sChangeHow, CMD_BY))
{
int nCurrentLevel = _prc_inc_XPToLevel(GetXP(oTarget));
if (nCurrentLevel > 40)
nCurrentLevel = 40;
nNumber = nCurrentLevel + nNumber;
if (nNumber < 1)
nNumber = 1;
else if (nNumber > 40)
nNumber = 40;
SetXP(oTarget, _prc_inc_LevelToXP(nNumber));
}
else if (GetStringMatchesAbbreviation(sChangeHow, CMD_TO))
{
if (nNumber < 1)
nNumber = 1;
else if (nNumber > 40)
nNumber = 40;
SetXP(oTarget, _prc_inc_LevelToXP(nNumber));
}
else
HelpText(oPC, "Unrecognized word: " + sChangeHow);
}
}
else if (GetStringMatchesAbbreviation(sChangeWhat, CMD_XP))
{
if (sNumber != IntToString(nNumber))
HelpText(oPC, "Unrecognized xp: " + sNumber);
else
{
if (GetStringMatchesAbbreviation(sChangeHow, CMD_BY))
{
nNumber = GetXP(oTarget) + nNumber;
if (nNumber < 0)
nNumber = 0;
SetXP(oTarget, nNumber);
}
else if (GetStringMatchesAbbreviation(sChangeHow, CMD_TO))
{
if (nNumber < 0)
nNumber = 0;
SetXP(oTarget, nNumber);
}
else
HelpText(oPC, "Unrecognized word: " + sChangeHow);
}
}
else if (GetStringMatchesAbbreviation(sChangeWhat, CMD_GOLD))
{
if (sNumber != IntToString(nNumber))
HelpText(oPC, "Unrecognized gold amount: " + sNumber);
else
{
if (GetStringMatchesAbbreviation(sChangeHow, CMD_BY))
{
if (nNumber > 0)
GiveGoldToCreature(oTarget, nNumber);
else if (nNumber < 0)
AssignCommand(oPC, TakeGoldFromCreature(-nNumber, oTarget, TRUE));
}
else if (GetStringMatchesAbbreviation(sChangeHow, CMD_TO))
{
nNumber = nNumber - GetGold(oTarget);
if (nNumber > 0)
GiveGoldToCreature(oTarget, nNumber);
else if (nNumber < 0)
AssignCommand(oPC, TakeGoldFromCreature(-nNumber, oTarget, TRUE));
}
else
HelpText(oPC, "Unrecognized word: " + sChangeHow);
}
}
/* else if (GetStringMatchesAbbreviation(sChangeWhat, CMD_ABILITY))
{
if (!GetPRCSwitch(PRC_NWNX_FUNCS))
HelpText(oPC, "This command only works if NWNX funcs is installed");
else
{
sChangeWhat = GetStringWord(sCommand, 3);
sChangeHow = GetStringWord(sCommand, 4);
sNumber = GetStringWord(sCommand, 5);
nNumber = StringToInt(sNumber);
if (sNumber != IntToString(nNumber))
HelpText(oPC, "Unrecognized ability value: " + sNumber);
else
{
if (GetStringMatchesAbbreviation(sChangeWhat, CMD_STR))
{
if (GetStringMatchesAbbreviation(sChangeHow, CMD_BY))
nNumber += GetAbilityScore(oTarget, ABILITY_STRENGTH, TRUE);
if (nNumber < 3 || nNumber > 255)
HelpText(oPC, "Invalid " + CMD_STR + " value (must be between 3 and 255): " + sChangeWhat);
else
{
if (nNumber > 100 - 12)
HelpText(oPC, "NOTE: having a total " + CMD_STR + " above 100 can cause problems (the weight that you can carry goes to 0)");
_prc_inc_shifting_SetSTR(oTarget, nNumber);
}
}
else if (GetStringMatchesAbbreviation(sChangeWhat, CMD_DEX))
{
if (GetStringMatchesAbbreviation(sChangeHow, CMD_BY))
nNumber += GetAbilityScore(oTarget, ABILITY_DEXTERITY, TRUE);
if (nNumber < 3 || nNumber > 255)
HelpText(oPC, "Invalid " + CMD_DEX + " value (must be between 3 and 255): " + sChangeWhat);
else
_prc_inc_shifting_SetDEX(oTarget, nNumber);
}
else if (GetStringMatchesAbbreviation(sChangeWhat, CMD_CON))
{
if (GetStringMatchesAbbreviation(sChangeHow, CMD_BY))
nNumber += GetAbilityScore(oTarget, ABILITY_CONSTITUTION, TRUE);
if (nNumber < 3 || nNumber > 255)
HelpText(oPC, "Invalid " + CMD_CON + " value (must be between 3 and 255): " + sChangeWhat);
else
_prc_inc_shifting_SetCON(oTarget, nNumber);
}
else if (GetStringMatchesAbbreviation(sChangeWhat, CMD_INT))
{
if (GetStringMatchesAbbreviation(sChangeHow, CMD_BY))
nNumber += GetAbilityScore(oTarget, ABILITY_INTELLIGENCE, TRUE);
if (nNumber < 3 || nNumber > 255)
HelpText(oPC, "Invalid " + CMD_INT + " value (must be between 3 and 255): " + sChangeWhat);
else
_prc_inc_shifting_SetINT(oTarget, nNumber);
}
else if (GetStringMatchesAbbreviation(sChangeWhat, CMD_WIS))
{
if (GetStringMatchesAbbreviation(sChangeHow, CMD_BY))
nNumber += GetAbilityScore(oTarget, ABILITY_WISDOM, TRUE);
if (nNumber < 3 || nNumber > 255)
HelpText(oPC, "Invalid " + CMD_WIS + " value (must be between 3 and 255): " + sChangeWhat);
else
_prc_inc_shifting_SetWIS(oTarget, nNumber);
}
else if (GetStringMatchesAbbreviation(sChangeWhat, CMD_CHA))
{
if (GetStringMatchesAbbreviation(sChangeHow, CMD_BY))
nNumber += GetAbilityScore(oTarget, ABILITY_CHARISMA, TRUE);
if (nNumber < 3 || nNumber > 255)
HelpText(oPC, "Invalid " + CMD_CHA + " value (must be between 3 and 255): " + sChangeWhat);
else
_prc_inc_shifting_SetCHA(oTarget, nNumber);
}
else
HelpText(oPC, "Unrecognized ability to change: " + sChangeWhat);
}
}
}
*/
else
{
HelpText(oPC, "Unrecognized value to change: " + sChangeWhat);
}
}
}
else if (GetStringMatchesAbbreviation(sCommandName, CMD_SPAWN))
{
bResult = TRUE;
if (!DEBUG && !GetIsDM(oPC))
HelpText(oPC, "This command only works if DEBUG = TRUE");
else
{
string sSpawnType = GetStringWord(sCommand, 2);
string sResRef = GetStringWord(sCommand, 3);
if (GetStringMatchesAbbreviation(sSpawnType, CMD_CREATURE))
{
AssignCommand(oPC, DoSummon(oPC, sResRef));
}
else if (GetStringMatchesAbbreviation(sSpawnType, CMD_ITEM))
{
object oItem = CreateItemOnObject(sResRef, oTarget);
SetIdentified(oItem, TRUE);
if(GetIsObjectValid(oItem))
HelpText(oPC, "Created item: " + GetName(oItem));
else
HelpText(oPC, "Faild to create item--invalid resref?: " + sResRef);
}
else
HelpText(oPC, "Unrecognized spawn type: " + sSpawnType);
}
}
else if (GetStringMatchesAbbreviation(sCommandName, CMD_RELEVEL))
{
bResult = TRUE;
if (!DEBUG)
HelpText(oPC, "This command only works if DEBUG = TRUE");
else
{
string sNumber = GetStringWord(sCommand, 2);
int nNumber = StringToInt(sNumber);
int nStartXP = GetXP(oTarget);
int nStartLevel = _prc_inc_XPToLevel(nStartXP);
if (sNumber != IntToString(nNumber))
HelpText(oPC, "Unrecognized level: " + sNumber);
else if (nNumber > nStartLevel)
HelpText(oPC, "Nothing to do: specified level is higher than current level.");
else
{
if (nNumber < 1)
nNumber = 1;
SetXP(oTarget, _prc_inc_LevelToXP(nNumber-1)); //Level down to the the level before the 1st we want to change
SetXP(oTarget, nStartXP); //Level back up to our starting XP
}
}
}
else if (GetStringMatchesAbbreviation(sCommandName, CMD_SPECIAL))
{
bResult = TRUE;
string sSpecialCommandName = GetStringWord(sCommand, 2);
if (GetStringMatchesAbbreviation(sSpecialCommandName, CMD_REST))
{
if (!DEBUG)
HelpText(oPC, "This command only works if DEBUG = TRUE");
else
PRCForceRest(oTarget);
}
else if (GetStringMatchesAbbreviation(sSpecialCommandName, CMD_HANDLE_FORCE_REST_1) &&
GetStringMatchesAbbreviation(GetStringWord(sCommand, 3), CMD_HANDLE_FORCE_REST_2) &&
GetStringMatchesAbbreviation(GetStringWord(sCommand, 4), CMD_HANDLE_FORCE_REST_3)
)
{
StartForcedRestDetector(oTarget);
}
}
else if(GetStringMatchesAbbreviation(sCommandName, CMD_CHK_PP))
{
bResult = TRUE;
TellCharacterPowerPointStatus(oPC);
}
return bResult;
}

View File

@@ -0,0 +1,125 @@
//::///////////////////////////////////////////////
//:: Debug Command include
//:: prc_inc_chat_pow.nss
//::///////////////////////////////////////////////
/*
Command summary:
~~pow [value]
Set Power Attack to the specified value
[value can be 0-5 for Power Attack, 0-24 for Improved Power Attack]
~~pow [value] [q1|q2|q3]
Set Power Attack for the specified quickslot to the specified value
[value can be 0-5 for Power Attack, 0-24 for Improved Power Attack]
*/
#include "prc_inc_chat"
const string CMD_POWER_ATTACK = "pow-erattack";
const string QS1_VAR_NAME = "PRC_PowerAttackQuickselect_2797";
const string QS2_VAR_NAME = "PRC_PowerAttackQuickselect_2798";
const string QS3_VAR_NAME = "PRC_PowerAttackQuickselect_2799";
int PowerAttack_ProcessChatCommand_Help(object oPC, string sCommand)
{
string sCommandName = GetStringWord(sCommand, 2);
int nLevel = sCommandName != "";
int bResult = FALSE;
if (!nLevel)
{
HelpText(oPC, "=== PRC POWER ATTACK COMMANDS");
HelpText(oPC, "");
}
if(GetStringMatchesAbbreviation(sCommandName, CMD_POWER_ATTACK) || !nLevel)
{
if (nLevel)
{
bResult = TRUE;
HelpText(oPC, "=== POWER ATTACK COMMAND: " + CMD_POWER_ATTACK);
HelpText(oPC, "");
}
HelpText(oPC, "~~" + CMD_POWER_ATTACK + " <ONE:q1|q2|q3>");
if (nLevel)
HelpText(oPC, " Prints the current setting for the specified quickslot.");
HelpText(oPC, "~~" + CMD_POWER_ATTACK + " <ONE:q1|q2|q3> <value>");
if (nLevel)
HelpText(oPC, " Set the specified quickslot to the given value.");
HelpText(oPC, "");
}
//TODO: add a command to set the power attack value correctly without the quickslot
//To work correctly with the existing power attack code, the effects need to be added within a spell so that the
//spell id can be recorded and later used to remove them.
return bResult;
}
int PowerAttack_ProcessChatCommand(object oPC, string sCommand)
{
int bResult = FALSE;
string sCommandName = GetStringWord(sCommand, 1);
string sNewValue = GetStringWord(sCommand, 2);
int nNewValue = StringToInt(sNewValue);
if(GetStringMatchesAbbreviation(sCommandName, CMD_POWER_ATTACK))
{
bResult = TRUE;
string sQuickslot = GetStringWord(sCommand, 2);
string sNewValue = GetStringWord(sCommand, 3);
if (sNewValue == "")
{
if (sQuickslot == "q1")
HelpText(oPC, "Power Attack Quickslot 1: " + IntToString(GetPersistantLocalInt(oPC, QS1_VAR_NAME)));
else if (sQuickslot == "q2")
HelpText(oPC, "Power Attack Quickslot 2: " + IntToString(GetPersistantLocalInt(oPC, QS2_VAR_NAME)));
else if (sQuickslot == "q3")
HelpText(oPC, "Power Attack Quickslot 3: " + IntToString(GetPersistantLocalInt(oPC, QS3_VAR_NAME)));
else
HelpText(oPC, "Invalid Power Attack Quickslot Number: " + sQuickslot);
}
else
{
int nNewValue = StringToInt(sNewValue);
if (sNewValue != IntToString(nNewValue))
HelpText(oPC, "Power Attack value is not a number: " + sNewValue);
else if (nNewValue < 0)
HelpText(oPC, "Value is too small for Power Attack: " + sNewValue);
else if (!GetHasFeat(FEAT_POWER_ATTACK, oPC))
HelpText(oPC, "Power Attack feat required for value: " + sNewValue);
else if (nNewValue > 5 && !GetHasFeat(FEAT_IMPROVED_POWER_ATTACK, oPC))
HelpText(oPC, "Improved Power Attack feat required for value: " + sNewValue);
else if (nNewValue > 24)
HelpText(oPC, "Value is too large for Improved Power Attack: " + sNewValue);
else
{
if (sQuickslot == "q1")
{
SetPersistantLocalInt(oPC, QS1_VAR_NAME, nNewValue);
HelpText(oPC, "Power Attack Quickslot 1 set to: " + IntToString(nNewValue));
}
else if (sQuickslot == "q2")
{
SetPersistantLocalInt(oPC, QS2_VAR_NAME, nNewValue);
HelpText(oPC, "Power Attack Quickslot 2 set to: " + IntToString(nNewValue));
}
else if (sQuickslot == "q3")
{
SetPersistantLocalInt(oPC, QS3_VAR_NAME, nNewValue);
HelpText(oPC, "Power Attack Quickslot 3 set to: " + IntToString(nNewValue));
}
else
HelpText(oPC, "Invalid Power Attack Quickslot Number: " + sQuickslot);
}
}
}
return bResult;
}

View File

@@ -0,0 +1,220 @@
//::///////////////////////////////////////////////
//:: PnP Shifter Chat Command include
//:: prc_inc_chat_shf
//::///////////////////////////////////////////////
#include "prc_inc_chat"
#include "prc_inc_shifting"
const string CMD_GREATER_WILDSHAPE = "gw";
const string CMD_SHIFT = "s-hift";
const string CMD_EPIC_SHIFT = "e-pic";
const string CMD_UNSHIFT = "u-nshift";
const string CMD_LIST = "l-ist";
const string CMD_INFO = "i-nfo";
const string CMD_MARK = "mark";
const string CMD_UNMARK = "unmark";
const string CMD_DELETE = "delete";
int PnPShifter_ProcessChatCommand_Help(object oPC, string sCommand)
{
string sCommandName = GetStringWord(sCommand, 2);
int nLevel = sCommandName != "";
int bResult = FALSE;
if (!nLevel)
{
HelpText(oPC, "=== PNP SHIFTER COMMANDS");
HelpText(oPC, "");
}
if(GetStringMatchesAbbreviation(sCommandName, CMD_GREATER_WILDSHAPE) || !nLevel)
{
if (nLevel)
{
bResult = TRUE;
HelpText(oPC, "=== PNP SHIFTER COMMAND: " + CMD_GREATER_WILDSHAPE + " (Greater Wildshape)");
HelpText(oPC, "");
}
HelpText(oPC, "~~" + CMD_GREATER_WILDSHAPE + " " + CMD_LIST + " <shape-name>");
if (nLevel)
HelpText(oPC, " Lists known shapes that match <shape-name>; if <shape-name> is omitted, lists all known shapes.");
HelpText(oPC, "~~" + CMD_GREATER_WILDSHAPE + " " + CMD_INFO + " <shape-name>");
if (nLevel)
HelpText(oPC, " Lists shapes that match <shape-name>; if an unambiguous match is found, prints information about it.");
HelpText(oPC, "~~" + CMD_GREATER_WILDSHAPE + " " + CMD_SHIFT + " <shape-name>");
if (nLevel)
HelpText(oPC, " Searches for shapes that match <shape-name>; if an unambiguous match is found, shifts into it.");
HelpText(oPC, "~~" + CMD_GREATER_WILDSHAPE + " " + CMD_EPIC_SHIFT + " <shape-name>");
if (nLevel)
HelpText(oPC, " Searches for shapes that match <shape-name>; if an unambiguous match is found, epic shifts into it.");
HelpText(oPC, "~~" + CMD_GREATER_WILDSHAPE + " " + CMD_UNSHIFT);
if (nLevel)
HelpText(oPC, " Unshifts back into true form.");
HelpText(oPC, "~~" + CMD_GREATER_WILDSHAPE + " " + CMD_MARK + " <shape-name>");
if (nLevel)
HelpText(oPC, " Marks the specified shape for deletion.");
HelpText(oPC, "~~" + CMD_GREATER_WILDSHAPE + " " + CMD_UNMARK + " <shape-name>");
if (nLevel)
HelpText(oPC, " Removes the shape's deletion mark, if any.");
HelpText(oPC, "~~" + CMD_GREATER_WILDSHAPE + " " + CMD_DELETE + " yes");
if (nLevel)
HelpText(oPC, " Deletes all shapes marked for deletion. Note that the word 'yes' is required as part of the command in order to confirm the deletion.");
if (nLevel)
{
HelpText(oPC, "");
HelpText(oPC, "'" + CMD_GREATER_WILDSHAPE + "' stands for 'Greater Wildshape'");
HelpText(oPC, "<shape-name> must match a known shape, is case-insenstive, and can be:");
HelpText(oPC, " '.': matches the shape the PC is currently shifted into");
HelpText(oPC, " A number: matches the shape with the given number. The numbers can be found found using command '~~gw list''.");
HelpText(oPC, " 'Q1' through 'Q10': matches the shape in the specified quickslot");
HelpText(oPC, " A resref: if you don't know what this means, ignore this option. The resref can be found found using command '~~gw list'.");
HelpText(oPC, " Part of the name of a shape:");
HelpText(oPC, " If there is exactly one exact match, that will be used.");
HelpText(oPC, " Otherwise, if there is exactly one shape whose name starts with <shape-name>, that will be used.");
HelpText(oPC, " Otherwise, if there is exactly one shape whose name contains <shape-name>, that will be used.");
HelpText(oPC, " Otherwise, no shape matches and nothing will happen.");
}
HelpText(oPC, "");
}
return bResult;
}
void _prc_inc_ChatShift(object oPC, string sShapeName, int bEpic)
{
//See if a valid shape was specified
if(sShapeName == "")
return;
string sResRef = FindResRefFromString(oPC, SHIFTER_TYPE_SHIFTER, sShapeName, FALSE);
if(sResRef == "")
return;
//Make sure we're not affected by a condition that prevents shifting
effect eTest = GetFirstEffect(oPC);
int nEType;
while(GetIsEffectValid(eTest))
{
nEType = GetEffectType(eTest);
if(nEType == EFFECT_TYPE_CUTSCENE_PARALYZE
|| nEType == EFFECT_TYPE_DAZED
|| nEType == EFFECT_TYPE_PARALYZE
|| nEType == EFFECT_TYPE_PETRIFY
|| nEType == EFFECT_TYPE_SLEEP
|| nEType == EFFECT_TYPE_STUNNED)
return;
eTest = GetNextEffect(oPC);
}
//If we have at least one use of a suitable feat remaining, shift
int nPaidFeat = GWSPay(oPC, bEpic);
if(nPaidFeat)
{
if(!ShiftIntoResRef(oPC, SHIFTER_TYPE_SHIFTER, sResRef, bEpic))
GWSRefund(oPC, nPaidFeat);
}
else
FloatingTextStrRefOnCreature(16828373, oPC, FALSE); // "You didn't have (Epic) Greater Wildshape uses available."
}
void _prc_inc_ListShapes(object oShifter, int nShifterType, string sFindString)
{
FindResRefFromString(oShifter, nShifterType, sFindString, TRUE);
}
void _prc_inc_ChatMark(object oPC, string sShapeName, int bMark)
{
if (sShapeName == "")
return;
string sResRef = FindResRefFromString(oPC, SHIFTER_TYPE_SHIFTER, sShapeName, FALSE);
if (sResRef == "")
return;
int nIndex = _prc_inc_shifting_GetIsTemplateStored(oPC, SHIFTER_TYPE_SHIFTER, sResRef);
if (!nIndex)
return;
SetStoredTemplateDeleteMark(oPC, SHIFTER_TYPE_SHIFTER, nIndex-1, bMark);
}
int PnPShifter_ProcessChatCommand(object oPC, string sCommand)
{
if(!GetLevelByClass(CLASS_TYPE_PNP_SHIFTER, oPC))
return FALSE;
int bResult = FALSE;
if(GetStringWord(sCommand, 1) == CMD_GREATER_WILDSHAPE)
{
bResult = TRUE;
string sWord = GetStringWord(sCommand, 2);
object oTemplate;
string sShape, sResRef;
if(GetStringMatchesAbbreviation(sWord, CMD_SHIFT))
{
sShape = GetStringWordToEnd(sCommand, 3);
_prc_inc_ChatShift(oPC, sShape, FALSE);
}
else if(GetStringMatchesAbbreviation(sWord, CMD_EPIC_SHIFT))
{
sShape = GetStringWordToEnd(sCommand, 3);
_prc_inc_ChatShift(oPC, sShape, TRUE);
}
else if(GetStringMatchesAbbreviation(sWord, CMD_UNSHIFT))
{
UnShift(oPC);
}
else if(GetStringMatchesAbbreviation(sWord, CMD_LIST))
{
sShape = GetStringWordToEnd(sCommand, 3);
DelayCommand(0.0f, _prc_inc_ListShapes(oPC, SHIFTER_TYPE_SHIFTER, sShape));
}
else if(GetStringMatchesAbbreviation(sWord, CMD_INFO))
{
sShape = GetStringWordToEnd(sCommand, 3);
if(sShape != "")
{
sResRef = FindResRefFromString(oPC, SHIFTER_TYPE_SHIFTER, sShape, FALSE);
if(sResRef != "")
{
oTemplate = _prc_inc_load_template_from_resref(sResRef, GetHitDice(oPC));
if(GetIsObjectValid(oTemplate))
{
DelayCommand(0.0, _prc_inc_PrintShape(oPC, oTemplate, FALSE));
DelayCommand(10.0, MyDestroyObject(oTemplate));
}
}
}
}
else if(GetStringMatchesAbbreviation(sWord, CMD_MARK))
{
sShape = GetStringWordToEnd(sCommand, 3);
_prc_inc_ChatMark(oPC, sShape, TRUE);
HelpText(oPC, "Shape marked for deletion");
}
else if(GetStringMatchesAbbreviation(sWord, CMD_UNMARK))
{
sShape = GetStringWordToEnd(sCommand, 3);
_prc_inc_ChatMark(oPC, sShape, FALSE);
HelpText(oPC, "Shape no longer marked for deletion");
}
else if(GetStringMatchesAbbreviation(sWord, CMD_DELETE))
{
if (GetStringWordToEnd(sCommand, 3) == "yes")
{
DelayCommand(0.0f, DeleteMarkedStoredTemplates(oPC, SHIFTER_TYPE_SHIFTER));
HelpText(oPC, "Marked shapes deleted");
}
else
HelpText(oPC, "Marked shapes not deleted: please enter 'yes' after the word 'delete' to confirm");
}
else
{
HelpText(oPC, "Unrecognize " + CMD_GREATER_WILDSHAPE + " command: " + sWord);
}
}
return bResult;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,757 @@
/* Core functions taken from high up the branch
which are needed lower. */
//:: Updated for .35 by Jaysyn 2023/03/10
//////////////////////////////////////////////////
/* Function Prototypes */
//////////////////////////////////////////////////
//:: Returns true if oCaster's race can naturally cast sorcerer spells.
int GetIsRHDSorcerer(object oCaster = OBJECT_SELF);
//:: Returns true if oCaster's race can naturally cast bard spells.
int GetIsRHDBard(object oCaster = OBJECT_SELF);
// wrapper for getspelltargetlocation
location PRCGetSpellTargetLocation(object oCaster = OBJECT_SELF);
// Avoids adding passive spellcasting to the character's action queue by
// creating an object specifically to cast the spell on the character.
//
// NOTE: The spell script must refer to the PC as PRCGetSpellTargetObject()
// otherwise this function WILL NOT WORK. Do not make any assumptions
// about the PC being OBJECT_SELF.
void ActionCastSpellOnSelf(int iSpell, int nMetaMagic = METAMAGIC_NONE, object oTarget = OBJECT_SELF);
// This is a wrapper function that causes OBJECT_SELF to fire the defined spell
// at the defined level. The target is automatically the object or location
// that the user selects. Useful for SLA's to perform the casting of a true
// spell. This is useful because:
//
// 1) If the original's spell script is updated, so is this one.
// 2) The spells are identified as the true spell. That is, they ARE the true spell.
// 3) Spellhooks (such as item crafting) that can only identify true spells
// will easily work.
//
// This function should only be used when SLA's are meant to simulate true
// spellcasting abilities, such as those seen when using feats with subradials
// to simulate spellbooks.
void ActionCastSpell(int iSpell, int iCasterLev = 0, int iBaseDC = 0, int iTotalDC = 0,
int nMetaMagic = METAMAGIC_NONE, int nClass = CLASS_TYPE_INVALID,
int bUseOverrideTargetLocation=FALSE, int bUseOverrideTargetObject=FALSE,
object oOverrideTarget=OBJECT_INVALID, int bInstantCast=TRUE, int bUseOverrideMetaMagic=FALSE);
/**
* Checks whether the given creature is committing an action, or
* under such effects that cause a breach of concentration.
*
* @param oConcentrator The creature to test
* @return TRUE if concentration is broken, FALSE otherwise
*/
int GetBreakConcentrationCheck(object oConcentrator);
/**
* Checks for breaks in concentration for an ongoing effect, and removes
* the effect if concentration is broken.
*
* @param oCaster The creature who cast the effect
* @param SpellID The id of the spell the effect belongs to
* @param oTarget The creature or object that is the target of the effect
* @param nDuration The duration the effect lasts in seconds.
*/
void CheckConcentrationOnEffect(object oCaster, int SpellID, object oTarget, int nDuration);
// gets the spell level adjustment to the nMetaMagic, including boni from the Improved Metamagic (epic) feat
int GetMetaMagicSpellLevelAdjustment(int nMetaMagic);
// Returns true if a spellcaster
int GetIsBioSpellCastClass(int nClass);
// Returns true for spell casters with spellbooks
int GetIsNSBClass(int nClass);
// returns the spelllevel of nSpell as it can be cast by oCreature
int PRCGetSpellLevel(object oCreature, int nSpell);
// returns if a character should be using the newspellbook when casting
int UseNewSpellBook(object oCreature);
// wrapper for GetHasSpell, works for newspellbook 'fake' spells too
// should return 0 if called with a normal spell when a character should be using the newspellbook
int PRCGetHasSpell(int nRealSpellID, object oCreature = OBJECT_SELF);
// checks if oPC knows the specified spell
// only works for classes that use the PRC spellbook, there is currently no way to do this for Bioware spellcasters
int PRCGetIsRealSpellKnown(int nRealSpellID, object oPC = OBJECT_SELF);
// checks if oPC knows the specified spell
// only works for classes that use the PRC spellbook, there is currently no way to do this for Bioware spellcasters
// this will only check the spellbook of the class specified
int PRCGetIsRealSpellKnownByClass(int nRealSpellID, int nClass, object oPC = OBJECT_SELF);
//routes to action cast spell, but puts a wrapper around to tell other functions its a
//SLA, so dont craft etc
//also defaults the totalDC to 10+spellevel+chamod
// moved from prc_inc_racial
void DoRacialSLA(int nSpellID, int nCasterlevel = 0, int nTotalDC = 0, int bInstantCast = FALSE);
/**
* Deletes a stored manifestation structure.
*
* @param oObject The object on which the structure is stored
* @param sName The name under which the structure is stored
*/
void DeleteLocalManifestation(object oObject, string sName);
/**
* Deletes a stored mystery structure.
*
* @param oObject The object on which the structure is stored
* @param sName The name under which the structure is stored
*/
void DeleteLocalMystery(object oObject, string sName);
//////////////////////////////////////////////////
/* Constants */
//////////////////////////////////////////////////
// metamagic spell level adjustments for Bioware provided metamagic feats
const int METAMAGIC_EXTEND_LEVEL = 1;
const int METAMAGIC_SILENT_LEVEL = 1;
const int METAMAGIC_STILL_LEVEL = 1;
const int METAMAGIC_EMPOWER_LEVEL = 2;
const int METAMAGIC_MAXIMIZE_LEVEL = 3;
const int METAMAGIC_QUICKEN_LEVEL = 4;
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
#include "lookup_2da_spell"
#include "inc_lookups"
#include "prc_inc_damage"
#include "prc_inc_sb_const" // Spell Book Constants
#include "x0_i0_position"
/*
access to prc_inc_nwscript via prc_inc_damage
access to PRCGetSpell* via prc_inc_damage
*/
//////////////////////////////////////////////////
/* Function Definitions */
//////////////////////////////////////////////////
//:: Returns true if oCaster's race can naturally cast sorcerer spells.
int GetIsRHDSorcerer(object oCaster = OBJECT_SELF)
{
int nRace = GetRacialType(oCaster);
return (nRace == RACIAL_TYPE_ARANEA ||
nRace == RACIAL_TYPE_ARKAMOI ||
nRace == RACIAL_TYPE_DRIDER ||
nRace == RACIAL_TYPE_HOBGOBLIN_WARSOUL ||
nRace == RACIAL_TYPE_MARRUTACT ||
nRace == RACIAL_TYPE_RAKSHASA ||
nRace == RACIAL_TYPE_REDSPAWN_ARCANISS);
}
//:: Returns true if oCaster's race can naturally cast bard spells.
int GetIsRHDBard(object oCaster = OBJECT_SELF)
{
int nRace = GetRacialType(oCaster);
return (nRace == RACIAL_TYPE_GLOURA);
}
//wrapper for GetSpellTargetLocation()
location PRCGetSpellTargetLocation(object oCaster = OBJECT_SELF)
{
// check if there is an override location on the module, and return that
// bioware did not define a LOCATION_INVALID const, so we must signal a valid override location by setting a local int on the module
if(GetLocalInt(GetModule(), PRC_SPELL_TARGET_LOCATION_OVERRIDE))
{
if (DEBUG) DoDebug("PRCGetSpellTargetLocation: found override target location on module");
return GetLocalLocation(GetModule(), PRC_SPELL_TARGET_LOCATION_OVERRIDE);
}
// check if there is an override location on the caster, and return that
// bioware did not define a LOCATION_INVALID const, so we signal a valid override location by setting a local int on oCaster
if (GetLocalInt(oCaster, PRC_SPELL_TARGET_LOCATION_OVERRIDE))
{
if (DEBUG) DoDebug("PRCGetSpellTargetLocation: found override target location on caster "+GetName(oCaster));
return GetLocalLocation(oCaster, PRC_SPELL_TARGET_LOCATION_OVERRIDE);
}
// The rune/gem/skull always targets the one who activates it.
object oItem = PRCGetSpellCastItem(oCaster);
if(GetIsObjectValid(oItem) && (GetResRef(oItem) == "prc_rune_1" ||
GetResRef(oItem) == "prc_skulltalis" || GetTag(oItem) == "prc_attunegem"))
return GetLocation(GetItemPossessor(oItem));
if (GetLocalInt(oCaster, "BlackLabyrinth") && d10() < 3)
return GenerateNewLocationFromLocation(GetSpellTargetLocation(), FeetToMeters(5.0*d4()), IntToFloat(Random(360)), IntToFloat(Random(360)));
// if we made it here, we must use Bioware's function
return GetSpellTargetLocation();
}
void ActionCastSpellOnSelf(int iSpell, int nMetaMagic = METAMAGIC_NONE, object oTarget = OBJECT_SELF)
{
if(!GetIsObjectValid(oTarget)) oTarget = OBJECT_SELF;
object oCastingObject = CreateObject(OBJECT_TYPE_PLACEABLE, "x0_rodwonder", GetLocation(oTarget));
AssignCommand(oCastingObject, ActionCastSpellAtObject(iSpell, oTarget, nMetaMagic, TRUE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE));
if (DEBUG) DoDebug("ActionCastSpellOnSelf: Casting Spell "+IntToString(iSpell)+" on "+GetName(oTarget));
DestroyObject(oCastingObject, 6.0);
}
void ActionCastSpell(int iSpell, int iCasterLev = 0, int iBaseDC = 0, int iTotalDC = 0,
int nMetaMagic = METAMAGIC_NONE, int nClass = CLASS_TYPE_INVALID,
int bUseOverrideTargetLocation=FALSE, int bUseOverrideTargetObject=FALSE,
object oOverrideTarget=OBJECT_INVALID, int bInstantCast=TRUE, int bUseOverrideMetaMagic=FALSE)
{
//if its a hostile spell, clear the action queue
//this stops people stacking hostile spells to be instacast
//at the end, for example when coming out of invisibility
// X - hope this is not needed if spells are cast normally
//if(Get2DACache("spells", "HostileSetting", iSpell) == "1" && bInstantCast)
// ClearAllActions();
object oTarget = PRCGetSpellTargetObject();
location lLoc = PRCGetSpellTargetLocation();
//set the overriding values
if (iCasterLev != 0)
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_CASTERLEVEL_OVERRIDE, iCasterLev));
if (iTotalDC != 0)
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_DC_TOTAL_OVERRIDE, iTotalDC));
if (iBaseDC != 0)
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_DC_BASE_OVERRIDE, iBaseDC));
if (nClass != CLASS_TYPE_INVALID)
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_CASTERCLASS_OVERRIDE, nClass));
if (bUseOverrideMetaMagic)
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_METAMAGIC_OVERRIDE, nMetaMagic));
else if (nMetaMagic != METAMAGIC_NONE)
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_METAMAGIC_ADJUSTMENT, nMetaMagic));
if (bUseOverrideTargetLocation)
{
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_SPELL_TARGET_LOCATION_OVERRIDE, TRUE));
//location must be set outside of this function at the moment
//cant pass a location into a function as an optional parameter
//go bioware for not defining an invalid location constant
}
if (bUseOverrideTargetObject)
{
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_SPELL_TARGET_OBJECT_OVERRIDE, TRUE));
ActionDoCommand(SetLocalObject(OBJECT_SELF, PRC_SPELL_TARGET_OBJECT_OVERRIDE, oOverrideTarget));
}
ActionDoCommand(SetLocalInt(OBJECT_SELF, "UsingActionCastSpell", TRUE));
if(DEBUG) DoDebug("ActionCastSpell SpellId: " + IntToString(iSpell));
if(DEBUG) DoDebug("ActionCastSpell Caster Level: " + IntToString(iCasterLev));
if(DEBUG) DoDebug("ActionCastSpell Base DC: " + IntToString(iBaseDC));
if(DEBUG) DoDebug("ActionCastSpell Total DC: " + IntToString(iTotalDC));
if(DEBUG) DoDebug("ActionCastSpell Metamagic: " + IntToString(nMetaMagic));
if(DEBUG) DoDebug("ActionCastSpell Caster Class: " + IntToString(nClass));
if(DEBUG) DoDebug("ActionCastSpell Target: " + GetName(oTarget));
if(DEBUG) DoDebug("ActionCastSpell Override Target: " + GetName(oOverrideTarget));
//cast the spell
if (GetIsObjectValid(oOverrideTarget))
ActionCastSpellAtObject(iSpell, oOverrideTarget, nMetaMagic, TRUE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstantCast);
else if (GetIsObjectValid(oTarget))
ActionCastSpellAtObject(iSpell, oTarget, nMetaMagic, TRUE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstantCast);
else
ActionCastSpellAtLocation(iSpell, lLoc, nMetaMagic, TRUE, PROJECTILE_PATH_TYPE_DEFAULT, bInstantCast);
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, "UsingActionCastSpell"));
//clean up afterwards
if(bInstantCast)//give scripts time to read the variables
{
if (iCasterLev != 0)
ActionDoCommand(DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_CASTERLEVEL_OVERRIDE)));
if (iTotalDC != 0)
ActionDoCommand(DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_DC_TOTAL_OVERRIDE)));
if (iBaseDC != 0)
ActionDoCommand(DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_DC_BASE_OVERRIDE)));
if (nClass != CLASS_TYPE_INVALID)
ActionDoCommand(DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_CASTERCLASS_OVERRIDE)));
if (nMetaMagic != METAMAGIC_NONE)
ActionDoCommand(DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_METAMAGIC_OVERRIDE)));
if (bUseOverrideTargetLocation)
{
ActionDoCommand(DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_SPELL_TARGET_LOCATION_OVERRIDE)));
//location must be set outside of this function at the moment
//cant pass a location into a function as an optional parameter
//go bioware for not defining an invalid location constant
}
if (bUseOverrideTargetObject)
{
ActionDoCommand(DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_SPELL_TARGET_OBJECT_OVERRIDE)));
ActionDoCommand(DelayCommand(1.0, DeleteLocalObject(OBJECT_SELF, PRC_SPELL_TARGET_OBJECT_OVERRIDE)));
}
}
else
{
if (iCasterLev != 0)
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_CASTERLEVEL_OVERRIDE));
if (iTotalDC != 0)
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_DC_TOTAL_OVERRIDE));
if (iBaseDC != 0)
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_DC_BASE_OVERRIDE));
if (nClass != CLASS_TYPE_INVALID)
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_CASTERCLASS_OVERRIDE));
if (bUseOverrideMetaMagic)
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_METAMAGIC_OVERRIDE));
else if (nMetaMagic != METAMAGIC_NONE)
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_METAMAGIC_ADJUSTMENT));
if (bUseOverrideTargetLocation)
{
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_SPELL_TARGET_LOCATION_OVERRIDE));
//location must be set outside of this function at the moment
//cant pass a location into a function as an optional parameter
//go bioware for not defining an invalid location constant
}
if (bUseOverrideTargetObject)
{
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_SPELL_TARGET_OBJECT_OVERRIDE));
ActionDoCommand(DeleteLocalObject(OBJECT_SELF, PRC_SPELL_TARGET_OBJECT_OVERRIDE));
}
}
/*
//The problem with this approace is that the effects are then applies by the original spell, which could go wrong. What to do?
SetLocalInt(OBJECT_SELF, PRC_SPELLID_OVERRIDE, GetSpellId());
DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_SPELLID_OVERRIDE));
string sScript = Get2DACache("spells", "ImpactScript", iSpell);
ExecuteScript(sScript, OBJECT_SELF);
*/
}
int GetBreakConcentrationCheck(object oConcentrator)
{
if (GetHasSpellEffect(VESTIGE_DAHLVERNAR, oConcentrator) && !GetLocalInt(oConcentrator, "PactQuality"+IntToString(VESTIGE_DAHLVERNAR))) return TRUE;
int nAction = GetCurrentAction(oConcentrator);
// creature doing anything that requires attention and breaks concentration
if (nAction == ACTION_DISABLETRAP || nAction == ACTION_TAUNT ||
nAction == ACTION_PICKPOCKET || nAction == ACTION_ATTACKOBJECT ||
nAction == ACTION_COUNTERSPELL || nAction == ACTION_FLAGTRAP ||
nAction == ACTION_CASTSPELL || nAction == ACTION_ITEMCASTSPELL)
{
return TRUE;
}
//suffering a mental effect
effect e1 = GetFirstEffect(oConcentrator);
int nType;
while (GetIsEffectValid(e1))
{
nType = GetEffectType(e1);
if (nType == EFFECT_TYPE_STUNNED || nType == EFFECT_TYPE_PARALYZE ||
nType == EFFECT_TYPE_SLEEP || nType == EFFECT_TYPE_FRIGHTENED ||
nType == EFFECT_TYPE_PETRIFY || nType == EFFECT_TYPE_CONFUSED ||
nType == EFFECT_TYPE_DOMINATED || nType == EFFECT_TYPE_POLYMORPH)
{
return TRUE;
}
e1 = GetNextEffect(oConcentrator);
}
// add to on damage event
AddEventScript(oConcentrator, EVENT_VIRTUAL_ONDAMAGED, "prc_od_conc", FALSE, FALSE);
if(GetLocalInt(oConcentrator, "CONC_BROKEN")) // won't be set first time around regardless
{
DeleteLocalInt(oConcentrator, "CONC_BROKEN"); // reset for next spell
return TRUE;
}
return FALSE;
}
void CheckConcentrationOnEffect(object oCaster, int SpellID, object oTarget, int nDuration)
{
int nDur = GetLocalInt(oCaster, "Conc" + IntToString(SpellID));
if(GetBreakConcentrationCheck(oCaster) == TRUE && nDur < nDuration)
{
FloatingTextStringOnCreature("*Concentration Broken*", oCaster);
DeleteLocalInt(oCaster, "Conc" + IntToString(SpellID));
PRCRemoveSpellEffects(SpellID, oCaster, oTarget);
}
else if(nDur < nDuration)
{
SetLocalInt(oCaster, "Conc" + IntToString(SpellID), nDur + 3);
DelayCommand(3.0, CheckConcentrationOnEffect(oCaster, SpellID, oTarget, nDuration));
}
else
{
DeleteLocalInt(oCaster, "Conc" + IntToString(SpellID));
}
}
int PRCGetSpellLevelForClass(int nSpell, int nClass)
{
string sSpellLevel = "";
if (nClass == CLASS_TYPE_WIZARD || nClass == CLASS_TYPE_SORCERER)
sSpellLevel = Get2DACache("spells", "Wiz_Sorc", nSpell);
else if (nClass == CLASS_TYPE_RANGER)
sSpellLevel = Get2DACache("spells", "Ranger", nSpell);
else if (nClass == CLASS_TYPE_PALADIN)
sSpellLevel = Get2DACache("spells", "Paladin", nSpell);
else if (nClass == CLASS_TYPE_DRUID)
sSpellLevel = Get2DACache("spells", "Druid", nSpell);
else if (nClass == CLASS_TYPE_CLERIC || nClass == CLASS_TYPE_UR_PRIEST || nClass == CLASS_TYPE_OCULAR)
sSpellLevel = Get2DACache("spells", "Cleric", nSpell);
else if (nClass == CLASS_TYPE_BARD)
sSpellLevel = Get2DACache("spells", "Bard", nSpell);
else if (nClass == CLASS_TYPE_CULTIST_SHATTERED_PEAK)
sSpellLevel = Get2DACache("spells", "Cultist", nSpell);
else if (nClass == CLASS_TYPE_NENTYAR_HUNTER)
sSpellLevel = Get2DACache("spells", "Nentyar", nSpell);
else if (nClass == CLASS_TYPE_SHADOWLORD)
sSpellLevel = Get2DACache("spells", "Telflammar", nSpell);
else if (nClass == CLASS_TYPE_SLAYER_OF_DOMIEL)
sSpellLevel = Get2DACache("spells", "Domiel", nSpell);
else if (nClass == CLASS_TYPE_SOHEI)
sSpellLevel = Get2DACache("spells", "Sohei", nSpell);
else if (nClass == CLASS_TYPE_VASSAL)
sSpellLevel = Get2DACache("spells", "Bahamut", nSpell);
else if (nClass == CLASS_TYPE_BLACKGUARD)
sSpellLevel = Get2DACache("spells", "Blackguard", nSpell);
else if (nClass == CLASS_TYPE_KNIGHT_CHALICE)
sSpellLevel = Get2DACache("spells", "Chalice", nSpell);
else if (nClass == CLASS_TYPE_KNIGHT_MIDDLECIRCLE)
sSpellLevel = Get2DACache("spells", "MiddleCircle", nSpell);
else if (nClass == CLASS_TYPE_SOLDIER_OF_LIGHT)
sSpellLevel = Get2DACache("spells", "SoLight", nSpell);
else if (nClass == CLASS_TYPE_BLIGHTER)
sSpellLevel = Get2DACache("spells", "Blighter", nSpell);
else if (nClass == CLASS_TYPE_HEALER)
sSpellLevel = Get2DACache("spells", "Healer", nSpell);
else if (nClass == CLASS_TYPE_SHAMAN)
sSpellLevel = Get2DACache("spells", "Shaman", nSpell);
else if (nClass == CLASS_TYPE_INVALID)
sSpellLevel = Get2DACache("spells", "Innate", nSpell);
if (sSpellLevel != "")
return StringToInt(sSpellLevel);
// 2009-9-21: Support real spell ID's. -N-S
// PRCGetSpellLevel() is called several times in the Bioware spellhooking script.
// That means it will always pass a "real" spell ID to this function, but new-spellbook users won't have the real spell!
// GetSpellLevel() takes the fake spell ID, so this function was always failing.
//int nSpellLevel = GetSpellLevel(nSpell, nClass);
int nSpellLevel = -1;
int nSpellbookID = RealSpellToSpellbookID(nClass, nSpell);
if (nSpellbookID == -1)
nSpellLevel = GetSpellLevel(nSpell, nClass);
else
{
string sFile = GetFileForClass(nClass);
string sSpellLevel = Get2DACache(sFile, "Level", nSpellbookID);
if (sSpellLevel != "")
nSpellLevel = StringToInt(sSpellLevel);
}
return nSpellLevel;
}
// returns the spelllevel of nSpell as it can be cast by oCreature
int PRCGetSpellLevel(object oCreature, int nSpell)
{
/*if (!PRCGetHasSpell(nSpell, oCreature))
return -1;*/
int nClass = PRCGetLastSpellCastClass();
int nSpellLevel = PRCGetSpellLevelForClass(nSpell, nClass);
if (nSpellLevel != -1)
return nSpellLevel;
int i;
for (i=1;i<=8;i++)
{
nClass = GetClassByPosition(i, oCreature);
int nCharLevel = GetLevelByClass(nClass, oCreature);
if (nCharLevel)
{
nSpellLevel = PRCGetSpellLevelForClass(nSpell, nClass);
if (nSpellLevel != -1)
return nSpellLevel;
}
}
//return innate level
return StringToInt(Get2DACache("spells", "Innate", nSpell));
}
// gets the spell level adjustment to the nMetaMagic, including boni from the Improved Metamagic (epic) feat
int GetMetaMagicSpellLevelAdjustment(int nMetaMagic)
{
int nAdj;
if (nMetaMagic == 0) return nAdj;
if (nMetaMagic & METAMAGIC_EXTEND) nAdj += METAMAGIC_EXTEND_LEVEL;
if (nMetaMagic & METAMAGIC_SILENT) nAdj += METAMAGIC_SILENT_LEVEL;
if (nMetaMagic & METAMAGIC_STILL) nAdj += METAMAGIC_STILL_LEVEL;
if (nMetaMagic & METAMAGIC_EMPOWER) nAdj += METAMAGIC_EMPOWER_LEVEL;
if (nMetaMagic & METAMAGIC_MAXIMIZE) nAdj += METAMAGIC_MAXIMIZE_LEVEL;
if (nMetaMagic & METAMAGIC_QUICKEN) nAdj += METAMAGIC_QUICKEN_LEVEL;
return nAdj;
}
int GetIsBioSpellCastClass(int nClass)
{
return nClass == CLASS_TYPE_WIZARD
|| nClass == CLASS_TYPE_SORCERER && !GetIsRHDSorcerer()
|| nClass == CLASS_TYPE_BARD && !GetIsRHDBard()
|| nClass == CLASS_TYPE_CLERIC
|| nClass == CLASS_TYPE_HEALER
|| nClass == CLASS_TYPE_BLIGHTER
|| nClass == CLASS_TYPE_BLACKGUARD
|| nClass == CLASS_TYPE_UR_PRIEST
|| nClass == CLASS_TYPE_OCULAR
|| nClass == CLASS_TYPE_SLAYER_OF_DOMIEL
|| nClass == CLASS_TYPE_CULTIST_SHATTERED_PEAK
|| nClass == CLASS_TYPE_NENTYAR_HUNTER
|| nClass == CLASS_TYPE_SHADOWLORD
|| nClass == CLASS_TYPE_SOHEI
|| nClass == CLASS_TYPE_SOLDIER_OF_LIGHT
|| nClass == CLASS_TYPE_VASSAL
|| nClass == CLASS_TYPE_KNIGHT_MIDDLECIRCLE
|| nClass == CLASS_TYPE_KNIGHT_CHALICE
|| nClass == CLASS_TYPE_SHAMAN
|| nClass == CLASS_TYPE_DRUID
|| nClass == CLASS_TYPE_PALADIN
|| nClass == CLASS_TYPE_RANGER;
}
int GetIsNSBClass(int nClass)
{
return !GetIsBioSpellCastClass(nClass)
&& GetSpellbookTypeForClass(nClass) != SPELLBOOK_TYPE_INVALID;
}
// returns if a character should be using the newspellbook when casting
int UseNewSpellBook(object oCreature)
{
int i;
for (i = 1; i <= 8; i++)
{
int nClass = GetClassByPosition(i, oCreature);
if(GetIsNSBClass(nClass))
return TRUE;
}
// Special case
if(GetLevelByClass(CLASS_TYPE_ULTIMATE_MAGUS, oCreature))
return TRUE;
int nPrimaryArcane = GetPrimaryArcaneClass(oCreature);
//check they have bard/sorc in first arcane slot
if(nPrimaryArcane != CLASS_TYPE_BARD && nPrimaryArcane != CLASS_TYPE_SORCERER)
return FALSE;
//check they have arcane PrC or Draconic Breath/Arcane Grace
if(!GetArcanePRCLevels(oCreature, nPrimaryArcane)
&& !(GetHasFeat(FEAT_DRACONIC_GRACE, oCreature) || GetHasFeat(FEAT_DRACONIC_BREATH, oCreature)))
return FALSE;
//check if the newspellbooks are disabled
if((GetPRCSwitch(PRC_SORC_DISALLOW_NEWSPELLBOOK) && nPrimaryArcane == CLASS_TYPE_SORCERER) ||
(GetPRCSwitch(PRC_BARD_DISALLOW_NEWSPELLBOOK) && nPrimaryArcane == CLASS_TYPE_BARD))
return FALSE;
//check they have bard/sorc levels
if(!GetLevelByClass(CLASS_TYPE_BARD) && !GetLevelByClass(CLASS_TYPE_SORCERER))
return FALSE;
//at this point, they should be using the new spellbook
return TRUE;
}
// wrapper for GetHasSpell, works for newspellbook 'fake' spells too (and metamagic)
// should return 0 if called with a normal spell when a character should be using the newspellbook
int PRCGetHasSpell(int nRealSpellID, object oCreature = OBJECT_SELF)
{
if(!PRCGetIsRealSpellKnown(nRealSpellID, oCreature))
return 0;
int nUses = GetHasSpell(nRealSpellID, oCreature);
int nClass, nSpellbookID, nCount, nMeta, i, j;
int nSpellbookType, nSpellLevel;
string sFile, sFeat;
for(i = 1; i <= 8; i++)
{
nClass = GetClassByPosition(i, oCreature);
sFile = GetFileForClass(nClass);
nSpellbookType = GetSpellbookTypeForClass(nClass);
nSpellbookID = RealSpellToSpellbookID(nClass, nRealSpellID);
nMeta = RealSpellToSpellbookIDCount(nClass, nRealSpellID);
if (nSpellbookID != -1)
{ //non-spellbook classes should return -1
for(j = nSpellbookID; j <= nSpellbookID + nMeta; j++)
{
sFeat = Get2DACache(sFile, "ReqFeat", j);
if(sFeat != "")
{
if(!GetHasFeat(StringToInt(sFeat), oCreature))
continue;
}
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(nCount > 0)
{
nUses += nCount;
}
}
else if(nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS)
{
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(nCount > 0)
{
nUses += nCount;
}
}
}
}
}
if(DEBUG) DoDebug("PRCGetHasSpell: RealSpellID = " + IntToString(nRealSpellID) + ", Uses = " + IntToString(nUses));
return nUses;
}
// checks if oPC knows the specified spell
// only works for classes that use the PRC spellbook, there is currently no way to do this for Bioware spellcasters
int PRCGetIsRealSpellKnown(int nRealSpellID, object oPC = OBJECT_SELF)
{
if(GetHasSpell(nRealSpellID, oPC)) //FUGLY HACK: bioware class having uses of the spell
return TRUE; // means they know the spell (close enough)
int nClass;
int nClassSlot = 1;
while(nClassSlot <= 8)
{
nClass = GetClassByPosition(nClassSlot, oPC);
if(GetIsDivineClass(nClass) || GetIsArcaneClass(nClass))
if(PRCGetIsRealSpellKnownByClass(nRealSpellID, nClass, oPC))
return TRUE;
nClassSlot++;
}
// got here means no match
return FALSE;
}
// checks if oPC knows the specified spell
// only works for classes that use the PRC spellbook, there is currently no way to do this for Bioware spellcasters
// this will only check the spellbook of the class specified
int PRCGetIsRealSpellKnownByClass(int nRealSpellID, int nClass, object oPC = OBJECT_SELF)
{
// check for whether bard and sorc are using the prc spellbooks
if (nClass == CLASS_TYPE_BARD || nClass == CLASS_TYPE_SORCERER)
{
if(!UseNewSpellBook(oPC))
return FALSE;
}
// get the cls_spell_***.2da index for the real spell
int nSpellbookSpell = RealSpellToSpellbookID(nClass, nRealSpellID);
// if the spell does not exist in the spellbook, return FALSE
if (nSpellbookSpell == -1)
return FALSE;
// next check if the PC is high enough level to know the spell
string sFile = GetFileForClass(nClass);
int nSpellLevel = -1;
string sSpellLevel = Get2DACache(sFile, "Level", nSpellbookSpell);
if (sSpellLevel != "")
nSpellLevel = StringToInt(sSpellLevel);
if ((GetLevelByClass(nClass) < nSpellLevel) || nSpellLevel == -1)
return FALSE; // not high enough level
// at this stage, prepared casters know the spell and only spontaneous classes need checking
// there are exceptions and these need hardcoding:
if((GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_PREPARED) && nClass != CLASS_TYPE_ARCHIVIST)
return TRUE;
// spontaneous casters have all their known spells as hide feats
// get the featID of the spell
int nFeatID = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookSpell));
if (GetHasFeat(nFeatID, oPC))
return TRUE;
return FALSE;
}
//routes to action cast spell, but puts a wrapper around to tell other functions its a
//SLA, so dont craft etc
//also defaults th totalDC to 10+spellevel+chamod
//this is Base DC, not total DC. SLAs are still spells, so spell focus should still apply.
void DoRacialSLA(int nSpellID, int nCasterlevel = 0, int nTotalDC = 0, int bInstantCast = FALSE)
{
if(DEBUG) DoDebug("Spell DC passed to DoRacialSLA: " + IntToString(nTotalDC));
if(nTotalDC == 0)
nTotalDC = 10
+StringToInt(Get2DACache("spells", "Innate", nSpellID))
+GetAbilityModifier(ABILITY_CHARISMA);
ActionDoCommand(SetLocalInt(OBJECT_SELF, "SpellIsSLA", TRUE));
if(DEBUG) DoDebug("Spell DC entered in ActionCastSpell: " + IntToString(nTotalDC));
ActionCastSpell(nSpellID, nCasterlevel, 0, nTotalDC, METAMAGIC_NONE, CLASS_TYPE_INVALID, FALSE, FALSE, OBJECT_INVALID, bInstantCast);
//ActionCastSpell(nSpellID, nCasterlevel, 0, nTotalDC);
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, "SpellIsSLA"));
}
void DeleteLocalManifestation(object oObject, string sName)
{
DeleteLocalObject(oObject, sName + "_oManifester");
DeleteLocalInt(oObject, sName + "_bCanManifest");
DeleteLocalInt(oObject, sName + "_nPPCost");
DeleteLocalInt(oObject, sName + "_nPsiFocUsesRemain");
DeleteLocalInt(oObject, sName + "_nManifesterLevel");
DeleteLocalInt(oObject, sName + "_nSpellID");
DeleteLocalInt(oObject, sName + "_nTimesAugOptUsed_1");
DeleteLocalInt(oObject, sName + "_nTimesAugOptUsed_2");
DeleteLocalInt(oObject, sName + "_nTimesAugOptUsed_3");
DeleteLocalInt(oObject, sName + "_nTimesAugOptUsed_4");
DeleteLocalInt(oObject, sName + "_nTimesAugOptUsed_5");
DeleteLocalInt(oObject, sName + "_nTimesGenericAugUsed");
DeleteLocalInt(oObject, sName + "_bChain");
DeleteLocalInt(oObject, sName + "_bEmpower");
DeleteLocalInt(oObject, sName + "_bExtend");
DeleteLocalInt(oObject, sName + "_bMaximize");
DeleteLocalInt(oObject, sName + "_bSplit");
DeleteLocalInt(oObject, sName + "_bTwin");
DeleteLocalInt(oObject, sName + "_bWiden");
DeleteLocalInt(oObject, sName + "_bQuicken");
}
void DeleteLocalMystery(object oObject, string sName)
{
DeleteLocalObject(oObject, sName + "_oShadow");
DeleteLocalInt(oObject, sName + "_bCanMyst");
DeleteLocalInt(oObject, sName + "_nShadowcasterLevel");
DeleteLocalInt(oObject, sName + "_nMystId");
DeleteLocalInt(oObject, sName + "_nPen");
DeleteLocalInt(oObject, sName + "_bIgnoreSR");
DeleteLocalInt(oObject, sName + "_bEmpower");
DeleteLocalInt(oObject, sName + "_bExtend");
DeleteLocalInt(oObject, sName + "_bMaximize");
DeleteLocalInt(oObject, sName + "_bQuicken");
DeleteLocalInt(oObject, sName + "_nSaveDC");
DeleteLocalFloat(oObject, sName + "_fDur");
}
//::void main (){}

View File

@@ -0,0 +1,397 @@
//::///////////////////////////////////////////////
//:: Ability Damage application
//:: prc_inc_damage
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Internal constants */
//////////////////////////////////////////////////
const string VIRTUAL_ABILITY_SCORE = "PRC_Virtual_Ability_Score_";
const string UbHealable_ABILITY_DAMAGE = "PRC_UbHealableAbilityDamage_";
const string ABILITY_DAMAGE_SPECIALS = "PRC_Ability_Damage_Special_Effects_Flags";
const string ABILITY_DAMAGE_MONITOR = "PRC_Ability_Monitor";
const int ABILITY_DAMAGE_EFFECT_PARALYZE = 1;
const int ABILITY_DAMAGE_EFFECT_KNOCKDOWN = 2;
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Gets the amount of ubHealable ability damage suffered by the creature to given ability
*
* @param oTarget The creature whose ubHealable ability damage to examine
* @param nAbility One of the ABILITY_* constants
*/
int GetUnHealableAbilityDamage(object oTarget, int nAbility);
/**
* Removes the specified amount of normally unHealable ability damage from the target
*
* @param oTarget The creature to restore
* @param nAbility Ability to restore, one of the ABILITY_* constants
* @param nAmount Amount to restore the ability by, should be > 0 for the function
* to have any effect
*/
void RecoverUnHealableAbilityDamage(object oTarget, int nAbility, int nAmount);
/**
* Applies the ability damage to the given target. Handles the virtual loss of
* ability scores below 3 and the effects of reaching 0 and making the damage
* ubHealable by standard means if requested.
*
*
* @param oTarget The creature about to take ability damage
* @param nAbility One of the ABILITY_* constants
* @param nAmount How much to reduce the ability score by
* @param nDurationType One of the DURATION_TYPE_* contants
* @param bHealable Whether the damage is healable by normal means or not.
* Implemented by applying the damage as an iprop on the hide
*
* The following are passed to SPApplyEffectToObject:
* @param fDuration If temporary, the duration. If this is -1.0, the damage
* will be applied so that it wears off at the rate of 1 point
* per ingame day.
* @param bDispellable Is the effect dispellable? If FALSE, the system will delay
* the application of the effect a short moment (10ms) to break
* spellID association. This will make effects from the same
* source stack with themselves.
* @param oSource Object causing the ability damage
*/
void ApplyAbilityDamage(object oTarget, int nAbility, int nAmount, int nDurationType, int bHealable = TRUE,
float fDuration = 0.0f, int bDispellable = FALSE, object oSource = OBJECT_SELF);
// Similar funcionality to ApplyAbilityDamage() but used only for alcohol effects
// If you add new Alcohol effects or modify ApplyAbilityDamage() function, you
// should update this function as well.
void ApplyAlcoholEffect(object oTarget, int nAmount, float fDuration);
/**
* Sets the values of ability decrease on target's hide to be the same as the value
* tracked on the target object itself. This is called with delay from ScrubPCSkin()
* in order to synchronise the tracked value of ubHealable damage with that actually
* present on the hide.
* Please call this if you do similar operations on the hide.
*
* @param oTarget The creature whose hide and tracked value to synchronise.
*/
void ReApplyUnhealableAbilityDamage(object oTarget);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
//#include "prc_inc_racial"
#include "prc_effect_inc"
#include "inc_item_props"
//////////////////////////////////////////////////
/* Function defintions */
//////////////////////////////////////////////////
void ApplyAbilityDamage(object oTarget, int nAbility, int nAmount, int nDurationType, int bHealable = TRUE,
float fDuration = 0.0f, int bDispellable = FALSE, object oSource = OBJECT_SELF)
{
// Immunity check
if(GetIsImmune(oTarget, IMMUNITY_TYPE_ABILITY_DECREASE, oSource))
return;
if (GetLocalInt(oTarget, "IncarnumDefenseCE") && nAbility == ABILITY_STRENGTH)
return;
if (GetIsMeldBound(oTarget, MELD_VITALITY_BELT) == CHAKRA_WAIST && nAbility == ABILITY_CONSTITUTION)
return;
if (GetHasSpellEffect(VESTIGE_DAHLVERNAR, oTarget) && nAbility == ABILITY_WISDOM && GetLocalInt(oTarget, "ExploitVestige") != VESTIGE_DAHLVERNAR_MAD_SOUL)
return;
// Strongheart Vest reduces by Essentia amount + 1. If it's bound, reduces ability drain as well
if (GetHasSpellEffect(MELD_STRONGHEART_VEST, oTarget) && bHealable)
{
int nEssentia = GetEssentiaInvested(oTarget, MELD_STRONGHEART_VEST);
nAmount = nAmount - (nEssentia + 1);
// If there's no damage, jump out.
if (0 >= nAmount) return;
}
else if (GetIsMeldBound(oTarget, MELD_STRONGHEART_VEST) == CHAKRA_WAIST && !bHealable)
{
int nEssentia = GetEssentiaInvested(oTarget, MELD_STRONGHEART_VEST);
nAmount = nAmount - (nEssentia + 1);
// If there's no damage, jump out.
if (0 >= nAmount) return;
}
// Get the value of the stat before anything is done
int nStartingValue = GetAbilityScore(oTarget, nAbility);
// First, apply the whole damage as an effect
//SendMessageToPC(GetFirstPC(), "Applying " + IntToString(nAmount) + " damage to stat " + IntToString(nAbility));
if(bHealable)
{
// Is the damage temporary and specified to heal at the PnP rate
if(nDurationType == DURATION_TYPE_TEMPORARY && fDuration == -1.0f)
{
int i;
for(i = 1; i <= nAmount; i++)
DelayCommand(0.01f, ApplyEffectToObject(nDurationType, bDispellable ? TagEffect(EffectAbilityDecrease(nAbility, 1), IntToString(nAbility)+IntToString(1)) : TagEffect(SupernaturalEffect(EffectAbilityDecrease(nAbility, 1)), IntToString(nAbility)+IntToString(1)), oTarget, HoursToSeconds(24) * i));
}
else if(!bDispellable)
{
DelayCommand(0.01f, ApplyEffectToObject(nDurationType, TagEffect(SupernaturalEffect(EffectAbilityDecrease(nAbility, nAmount)), IntToString(nAbility)+IntToString(nAmount)), oTarget, fDuration));
}
else
{
ApplyEffectToObject(nDurationType, TagEffect(EffectAbilityDecrease(nAbility, nAmount), IntToString(nAbility)+IntToString(nAmount)), oTarget, fDuration);
}
}
// Non-healable damage
else
{
int nIPType;
int nTotalAmount;
string sVarName = "PRC_UbHealableAbilityDamage_";
switch(nAbility)
{
case ABILITY_STRENGTH: nIPType = IP_CONST_ABILITY_STR; sVarName += "STR"; break;
case ABILITY_DEXTERITY: nIPType = IP_CONST_ABILITY_DEX; sVarName += "DEX"; break;
case ABILITY_CONSTITUTION: nIPType = IP_CONST_ABILITY_CON; sVarName += "CON"; break;
case ABILITY_INTELLIGENCE: nIPType = IP_CONST_ABILITY_INT; sVarName += "INT"; break;
case ABILITY_WISDOM: nIPType = IP_CONST_ABILITY_WIS; sVarName += "WIS"; break;
case ABILITY_CHARISMA: nIPType = IP_CONST_ABILITY_CHA; sVarName += "CHA"; break;
default:
WriteTimestampedLogEntry("Unknown nAbility passed to ApplyAbilityDamage: " + IntToString(nAbility));
return;
}
// Sum the damage being added with damage that was present previously
nTotalAmount = GetLocalInt(oTarget, sVarName) + nAmount;
// Apply the damage
SetCompositeBonus(GetPCSkin(oTarget), sVarName, nTotalAmount, ITEM_PROPERTY_DECREASED_ABILITY_SCORE, nIPType);
// Also store the amount of damage on the PC itself so it can be restored at a later date.
SetLocalInt(oTarget, sVarName, nTotalAmount);
// Schedule recovering if the damage is temporary
if(nDurationType == DURATION_TYPE_TEMPORARY)
{
// If the damage is specified to heal at the PnP rate, schedule one point to heal per day
if(fDuration == -1.0f)
{
int i;
for(i = 1; i <= nAmount; i++)
DelayCommand(HoursToSeconds(24) * i, RecoverUnHealableAbilityDamage(oTarget, nAbility, 1));
}
// Schedule everything to heal at once
else
DelayCommand(fDuration, RecoverUnHealableAbilityDamage(oTarget, nAbility, nAmount));
}
}
// The system is off by default
if(!GetPRCSwitch(PRC_PNP_ABILITY_DAMAGE_EFFECTS))
return;
// If the target is at the minimum supported by NWN, check if they have had their ability score reduced below already
if(nStartingValue == 3)
nStartingValue = GetLocalInt(oTarget, VIRTUAL_ABILITY_SCORE + IntToString(nAbility)) ?
GetLocalInt(oTarget, VIRTUAL_ABILITY_SCORE + IntToString(nAbility)) - 1 :
nStartingValue;
// See if any of the damage goes into the virtual area of score < 3
if(nStartingValue - nAmount < 3)
{
int nVirtual = nStartingValue - nAmount;
if(nVirtual < 0) nVirtual = 0;
// Mark the virtual value
SetLocalInt(oTarget, VIRTUAL_ABILITY_SCORE + IntToString(nAbility), nVirtual + 1);
// Cause effects for being at 0
if(nVirtual == 0)
{
// Apply the effects
switch(nAbility)
{
// Lying down
case ABILITY_STRENGTH:
case ABILITY_INTELLIGENCE:
case ABILITY_WISDOM:
case ABILITY_CHARISMA:
// Do not apply duplicate effects
/*if(!(GetLocalInt(oTarget, ABILITY_DAMAGE_SPECIALS) & ABILITY_DAMAGE_EFFECT_PARALYZE))
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectCutsceneParalyze(), oTarget);*/
if(!(GetLocalInt(oTarget, ABILITY_DAMAGE_SPECIALS) & ABILITY_DAMAGE_EFFECT_KNOCKDOWN))
{
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectKnockdown(), oTarget, 9999.0f);
SetLocalInt(oTarget, ABILITY_DAMAGE_SPECIALS, GetLocalInt(oTarget, ABILITY_DAMAGE_SPECIALS) | ABILITY_DAMAGE_EFFECT_KNOCKDOWN);
}
//break;
// Paralysis
case ABILITY_DEXTERITY:
// Do not apply duplicate effects
if(!(GetLocalInt(oTarget, ABILITY_DAMAGE_SPECIALS) & ABILITY_DAMAGE_EFFECT_PARALYZE))
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectCutsceneParalyze(), oTarget);
SetLocalInt(oTarget, ABILITY_DAMAGE_SPECIALS, GetLocalInt(oTarget, ABILITY_DAMAGE_SPECIALS) | ABILITY_DAMAGE_EFFECT_PARALYZE);
}
break;
// Death
case ABILITY_CONSTITUTION:
// Non-constitution score critters avoid this one
if(!(MyPRCGetRacialType(oTarget) == RACIAL_TYPE_UNDEAD ||
MyPRCGetRacialType(oTarget) == RACIAL_TYPE_CONSTRUCT
) )
{
DeathlessFrenzyCheck(oTarget);
ApplyEffectToObject(DURATION_TYPE_INSTANT, SupernaturalEffect(EffectDeath()), oTarget);
}
break;
default:
WriteTimestampedLogEntry("Unknown nAbility passed to ApplyAbilityDamage: " + IntToString(nAbility));
return;
}
// Start the monitor HB if it is not active yet
if(GetThreadState(ABILITY_DAMAGE_MONITOR, oTarget) == THREAD_STATE_DEAD)
SpawnNewThread(ABILITY_DAMAGE_MONITOR, "prc_abil_monitor", 1.0f, oTarget);
// Note the ability score for monitoring
SetLocalInt(oTarget, ABILITY_DAMAGE_MONITOR, GetLocalInt(oTarget, ABILITY_DAMAGE_MONITOR) | (1 << nAbility));
}
}
}
void ApplyAlcoholEffect(object oTarget, int nAmount, float fDuration)
{
// Immunity check
if(GetIsImmune(oTarget, IMMUNITY_TYPE_ABILITY_DECREASE))
return;
// Get the value of the stat before anything is done
int nStartingValue = GetAbilityScore(oTarget, ABILITY_INTELLIGENCE);
// First, apply the whole damage as an effect
DelayCommand(0.01f, AssignCommand(GetPCSkin(oTarget), ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(EffectAbilityDecrease(ABILITY_INTELLIGENCE, nAmount)), oTarget, fDuration)));
// The system is off by default
if(!GetPRCSwitch(PRC_PNP_ABILITY_DAMAGE_EFFECTS))
return;
// If the target is at the minimum supported by NWN, check if they have had their ability score reduced below already
if(nStartingValue == 3)
nStartingValue = GetLocalInt(oTarget, VIRTUAL_ABILITY_SCORE + IntToString(ABILITY_INTELLIGENCE)) ?
GetLocalInt(oTarget, VIRTUAL_ABILITY_SCORE + IntToString(ABILITY_INTELLIGENCE)) - 1 :
nStartingValue;
// See if any of the damage goes into the virtual area of score < 3
if(nStartingValue - nAmount < 3)
{
int nVirtual = nStartingValue - nAmount;
if(nVirtual < 0) nVirtual = 0;
// Mark the virtual value
SetLocalInt(oTarget, VIRTUAL_ABILITY_SCORE + IntToString(ABILITY_INTELLIGENCE), nVirtual + 1);
// Cause effects for being at 0
if(!nVirtual)
{
// Do not apply duplicate effects
/*if(!(GetLocalInt(oTarget, ABILITY_DAMAGE_SPECIALS) & ABILITY_DAMAGE_EFFECT_PARALYZE))
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectCutsceneParalyze(), oTarget);*/
if(!(GetLocalInt(oTarget, ABILITY_DAMAGE_SPECIALS) & ABILITY_DAMAGE_EFFECT_KNOCKDOWN))
{
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectKnockdown(), oTarget, 9999.0f);
SetLocalInt(oTarget, ABILITY_DAMAGE_SPECIALS, GetLocalInt(oTarget, ABILITY_DAMAGE_SPECIALS) | ABILITY_DAMAGE_EFFECT_KNOCKDOWN);
}
// Start the monitor HB if it is not active yet
if(GetThreadState(ABILITY_DAMAGE_MONITOR, oTarget) == THREAD_STATE_DEAD)
SpawnNewThread(ABILITY_DAMAGE_MONITOR, "prc_abil_monitor", 1.0f, oTarget);
// Note the ability score for monitoring
SetLocalInt(oTarget, ABILITY_DAMAGE_MONITOR, GetLocalInt(oTarget, ABILITY_DAMAGE_MONITOR) | (1 << ABILITY_INTELLIGENCE));
}
}
}
void ReApplyUnhealableAbilityDamage(object oTarget)
{
object oSkin = GetPCSkin(oTarget);
SetCompositeBonus(oSkin, "PRC_UbHealableAbilityDamage_STR",
GetLocalInt(oTarget, "PRC_UbHealableAbilityDamage_STR"),
ITEM_PROPERTY_DECREASED_ABILITY_SCORE, IP_CONST_ABILITY_STR);
SetCompositeBonus(oSkin, "PRC_UbHealableAbilityDamage_DEX",
GetLocalInt(oTarget, "PRC_UbHealableAbilityDamage_DEX"),
ITEM_PROPERTY_DECREASED_ABILITY_SCORE, IP_CONST_ABILITY_DEX);
SetCompositeBonus(oSkin, "PRC_UbHealableAbilityDamage_CON",
GetLocalInt(oTarget, "PRC_UbHealableAbilityDamage_CON"),
ITEM_PROPERTY_DECREASED_ABILITY_SCORE, IP_CONST_ABILITY_CON);
SetCompositeBonus(oSkin, "PRC_UbHealableAbilityDamage_INT",
GetLocalInt(oTarget, "PRC_UbHealableAbilityDamage_INT"),
ITEM_PROPERTY_DECREASED_ABILITY_SCORE, IP_CONST_ABILITY_INT);
SetCompositeBonus(oSkin, "PRC_UbHealableAbilityDamage_WIS",
GetLocalInt(oTarget, "PRC_UbHealableAbilityDamage_WIS"),
ITEM_PROPERTY_DECREASED_ABILITY_SCORE, IP_CONST_ABILITY_WIS);
SetCompositeBonus(oSkin, "PRC_UbHealableAbilityDamage_CHA",
GetLocalInt(oTarget, "PRC_UbHealableAbilityDamage_CHA"),
ITEM_PROPERTY_DECREASED_ABILITY_SCORE, IP_CONST_ABILITY_CHA);
}
int GetUnHealableAbilityDamage(object oTarget, int nAbility)
{
int nIPType;
string sVarName = "PRC_UbHealableAbilityDamage_";
switch(nAbility)
{
case ABILITY_STRENGTH: sVarName += "STR"; break;
case ABILITY_DEXTERITY: sVarName += "DEX"; break;
case ABILITY_CONSTITUTION: sVarName += "CON"; break;
case ABILITY_INTELLIGENCE: sVarName += "INT"; break;
case ABILITY_WISDOM: sVarName += "WIS"; break;
case ABILITY_CHARISMA: sVarName += "CHA"; break;
default:
WriteTimestampedLogEntry("Unknown nAbility passed to GetUnHealableAbilityDamage: " + IntToString(nAbility));
return FALSE;
}
return GetLocalInt(oTarget, sVarName);
}
void RecoverUnHealableAbilityDamage(object oTarget, int nAbility, int nAmount)
{
// Sanity check, one should not be able to cause more damage via this function, ApplyAbilityDamage() is for that.
if(nAmount < 0) return;
int nIPType, nNewVal;
string sVarName = "PRC_UbHealableAbilityDamage_";
switch(nAbility)
{
case ABILITY_STRENGTH: nIPType = IP_CONST_ABILITY_STR; sVarName += "STR"; break;
case ABILITY_DEXTERITY: nIPType = IP_CONST_ABILITY_DEX; sVarName += "DEX"; break;
case ABILITY_CONSTITUTION: nIPType = IP_CONST_ABILITY_CON; sVarName += "CON"; break;
case ABILITY_INTELLIGENCE: nIPType = IP_CONST_ABILITY_INT; sVarName += "INT"; break;
case ABILITY_WISDOM: nIPType = IP_CONST_ABILITY_WIS; sVarName += "WIS"; break;
case ABILITY_CHARISMA: nIPType = IP_CONST_ABILITY_CHA; sVarName += "CHA"; break;
default:
WriteTimestampedLogEntry("Unknown nAbility passed to ApplyAbilityDamage: " + IntToString(nAbility));
return;
}
nNewVal = GetLocalInt(oTarget, sVarName) - nAmount;
if(nNewVal < 0) nNewVal = 0;
SetCompositeBonus(GetPCSkin(oTarget), sVarName, nNewVal, ITEM_PROPERTY_DECREASED_ABILITY_SCORE, nIPType);
SetLocalInt(oTarget, sVarName, nNewVal);
}

View File

@@ -0,0 +1,260 @@
//::///////////////////////////////////////////////
//:: Magic descriptors and subschools include
//:: prc_inc_descrptr
//::///////////////////////////////////////////////
/** @file prc_inc_descrptr
A set of constants and functions for managing
spell's / power's / other stuffs's descriptors
and sub{school|discipline|whatever}s.
The functions SetDescriptor() and SetSubschool()
should be called at the beginning of the
spellscript, before spellhook or equivalent.
The values are stored on the module object and
are automatically cleaned up after script
execution terminates (ie, DelayCommand(0.0f)).
This is a potential gotcha, as the descriptor
and subschool data will no longer be available
during the spell's delayed operations. An
ugly workaround would be to set the descriptor
values again in such cases.
If you come up with an elegant solution, please
try to generalise it and change this as needed.
@author Ornedan
@date Created - 2006.06.30
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Constants */
//////////////////////////////////////////////////
// The descriptor and subschool constants are bit flags for easy combination and lookup
const int DESCRIPTOR_ACID = 0x00001;
const int DESCRIPTOR_AIR = 0x00002;
const int DESCRIPTOR_CHAOTIC = 0x00004;
const int DESCRIPTOR_COLD = 0x00008;
const int DESCRIPTOR_DARKNESS = 0x00010;
const int DESCRIPTOR_DEATH = 0x00020;
const int DESCRIPTOR_EARTH = 0x00040;
const int DESCRIPTOR_ELECTRICITY = 0x00080;
const int DESCRIPTOR_EVIL = 0x00100;
const int DESCRIPTOR_FEAR = 0x00200;
const int DESCRIPTOR_FIRE = 0x00400;
const int DESCRIPTOR_FORCE = 0x00800;
const int DESCRIPTOR_GOOD = 0x01000;
const int DESCRIPTOR_LANGUAGEDEPENDENT = 0x02000;
const int DESCRIPTOR_LAWFUL = 0x04000;
const int DESCRIPTOR_LIGHT = 0x08000;
const int DESCRIPTOR_MINDAFFECTING = 0x10000;
const int DESCRIPTOR_SONIC = 0x20000;
const int DESCRIPTOR_WATER = 0x40000;
// update if any of elemental descriptors change!
// int DESCRIPTOR_ELEMENTAL = DESCRIPTOR_ACID | DESCRIPTOR_COLD | DESCRIPTOR_ELECTRICITY | DESCRIPTOR_FIRE | DESCRIPTOR_SONIC;
const int DESCRIPTOR_ELEMENTAL = 0x20489;
const int SUBSCHOOL_CALLING = 0x00001;
const int SUBSCHOOL_CHARM = 0x00002;
const int SUBSCHOOL_COMPULSION = 0x00004;
const int SUBSCHOOL_CREATION = 0x00008;
const int SUBSCHOOL_FIGMENT = 0x00010;
const int SUBSCHOOL_GLAMER = 0x00020;
const int SUBSCHOOL_HEALING = 0x00040;
const int SUBSCHOOL_PATTERN = 0x00080;
const int SUBSCHOOL_PHANTASM = 0x00100;
const int SUBSCHOOL_POLYMORPH = 0x00200;
const int SUBSCHOOL_SCRYING = 0x00400;
const int SUBSCHOOL_SHADOW = 0x00800;
const int SUBSCHOOL_SUMMONING = 0x01000;
const int SUBSCHOOL_TELEPORTATION = 0x02000;
const string PRC_DESCRIPTOR = "PRC_Descriptor";
const string PRC_SUBSCHOOL = "PRC_Subschool";
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Sets the descriptor of currently being cast spell / power / whatever
* to be the given value. This should be called before spellhook / powerhook
* / whateverhook.
*
* If the magic in question has multiple descriptors, they should be OR'd together.
* For example, Phantasmal Killer would call the function thus:
* SetDescriptor(DESCRIPTOR_FEAR | DESCRIPTOR_MINDAFFECTING);
*
* This will override values set in prc_spells.2da
*
* @param nfDescriptorFlags The descriptors of a spell / power / X being currently used
*/
void SetDescriptor(int nfDescriptorFlags, object oPC = OBJECT_SELF);
/**
* Sets the subschool / subdiscipline / subwhatever of currently being cast
* spell / power / whatever to be the given value. This should be called before
* spellhook / powerhook / whateverhook.
*
* If the magic in question has multiple subschools, they should be OR'd together.
* For example, Mislead would call the function thus:
* SetDescriptor(SUBSCHOOL_FIGMENT | SUBSCHOOL_GLAMER);
*
* This will override values set in prc_spells.2da
*
* @param nfSubschoolFlags The subschools of a spell / power / X being currently used
*/
void SetSubschool(int nfSubschoolFlags, object oPC = OBJECT_SELF);
/**
* Tests whether a magic being currently used has the given descriptor.
*
* NOTE: Multiple descriptors may be tested for at once. If so, the return value
* will be true only if all the descriptors tested for are present. Doing so is
* technically a misuse of this function.
*
*
* @param nSpellID row number of tested spell in spells.2da
* @param nDescriptorFlag The descriptor to test for
* @return TRUE if the magic being used has the given descriptor(s), FALSE otherwise
*/
int GetHasDescriptor(int nSpellID, int nDescriptorFlag);
/**
* Returns TRUE if given spell has one of the elemental descriptors
* (acid, cold, electricity, fire or sonic)
*
* @param nSpellID row number of tested spell in spells.2da
* @return ID of elemental descriptor or FALSE
*/
int GetIsElementalSpell(int nSpellID, int nDescriptor = -1);
/**
* Tests whether a magic being currently used is of the given subschool.
*
* NOTE: Multiple subschools may be tested for at once. If so, the return value
* will be true only if all the subschools tested for are present. Doing so is
* technically a misuse of this function.
*
*
* @param nSpellID row number of tested spell in spells.2da
* @param nDescriptorFlag The subschool to test for
* @return TRUE if the magic being used is of the given subschool(s), FALSE otherwise
*/
int GetIsOfSubschool(int nSpellID, int nSubschoolFlag);
/**
* Returns an integer value containing the bitflags of descriptors set in prc_spells.2da
* for a given SpellID
*
* @param nSpellID row number of tested spell in spells.2da
* @return The converted raw integer value from prc_spells.2da
*/
int GetDescriptorFlags(int nSpellID);
/**
* Returns an integer value containing the bitflags of subschools set in prc_spells.2da
* for a given SpellID
*
* @param nSpellID row number of tested spell in spells.2da
* @return The converted raw integer value from prc_spells.2da
*/
int GetSubschoolFlags(int nSpellID);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
#include "inc_2dacache" // already has access via inc_utility
//#include "inc_utility"
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
void SetDescriptor(int nfDescriptorFlags, object oPC = OBJECT_SELF)
{
// Store the value
SetLocalInt(oPC, PRC_DESCRIPTOR, nfDescriptorFlags);
// Queue cleanup. No duplicacy checks, this function is not particularly likely to be called more than once anyway
DelayCommand(0.0f, DeleteLocalInt(oPC, PRC_DESCRIPTOR));
}
void SetSubschool(int nfSubschoolFlags, object oPC = OBJECT_SELF)
{
// Store the value
SetLocalInt(oPC, PRC_SUBSCHOOL, nfSubschoolFlags);
// Queue cleanup. No duplicacy checks, this function is not particularly likely to be called more than once anyway
DelayCommand(0.0f, DeleteLocalInt(oPC, PRC_SUBSCHOOL));
}
int GetHasDescriptor(int nSpellID, int nDescriptorFlag)
{
//check for descriptor override
int nDescriptor = GetLocalInt(OBJECT_SELF, PRC_DESCRIPTOR);
if(!nDescriptor)
nDescriptor = GetDescriptorFlags(nSpellID);
if(nDescriptorFlag & DESCRIPTOR_ELEMENTAL)
{
return nDescriptorFlag & GetIsElementalSpell(nSpellID, nDescriptor);
}
return nDescriptor & nDescriptorFlag;
}
int GetIsElementalSpell(int nSpellID, int nDescriptor = -1)
{
if(nDescriptor == -1)
{
//check for descriptor override
nDescriptor = GetLocalInt(OBJECT_SELF, PRC_DESCRIPTOR);
if(!nDescriptor)
nDescriptor = GetDescriptorFlags(nSpellID);
}
int nMastery = GetLocalInt(OBJECT_SELF, "archmage_mastery_elements");
//mastery of elements is active
if(nMastery)
{
switch(nMastery)
{
case DAMAGE_TYPE_ACID: return DESCRIPTOR_ACID;
case DAMAGE_TYPE_COLD: return DESCRIPTOR_COLD;
case DAMAGE_TYPE_ELECTRICAL: return DESCRIPTOR_ELECTRICITY;
case DAMAGE_TYPE_FIRE: return DESCRIPTOR_FIRE;
case DAMAGE_TYPE_SONIC: return DESCRIPTOR_SONIC;
}
}
return nDescriptor & DESCRIPTOR_ELEMENTAL;
}
int GetIsOfSubschool(int nSpellID, int nSubschoolFlag)
{
//check for subschool override
int nSubschool = GetLocalInt(OBJECT_SELF, PRC_SUBSCHOOL);
if(!nSubschool)
nSubschool = GetSubschoolFlags(nSpellID);
return (nSubschool & nSubschoolFlag);
}
int GetDescriptorFlags(int nSpellID)
{
return HexToInt(Get2DACache("prc_spells", "Descriptor", nSpellID));
}
int GetSubschoolFlags(int nSpellID)
{
return HexToInt(Get2DACache("prc_spells", "Subschool", nSpellID));
}
// Test main
//void main(){}

View File

@@ -0,0 +1,586 @@
//::///////////////////////////////////////////////
//:: PRC Bonus Domains
//:: prc_inc_domain.nss
//:://////////////////////////////////////////////
//:: Handles all of the code for bonus domains.
//:://////////////////////////////////////////////
//:: Created By: Stratovarius.
//:: Created On: August 31st, 2005
//:://////////////////////////////////////////////
//:: Updated for .35 by Jaysyn 2023/03/10
// Function returns the domain in the input slot.
// A person can have a maximum of 5 bonus domains.
int GetBonusDomain(object oPC, int nSlot);
// Function will add a bonus domain to the stored list on the character.
void AddBonusDomain(object oPC, int nDomain);
// Uses the slot and level to find the appropriate spell, then casts it using ActionCastSpell
// It will also decrement a spell from that level
// If the domain does not have an appropriate spell for that level, an error message appears and nothing happens
void CastDomainSpell(object oPC, int nSlot, int nLevel);
// Takes the domain and spell level and uses it to find the appropriate spell.
// Right now it uses 2da reads on the domains.2da, although it could be scripted if desired.
int GetDomainSpell(int nDomain, int nLevel, object oPC);
// Takes the spell level, and returns the radial feat for that level.
// Used in case there is no spell of the appropriate level.
int SpellLevelToFeat(int nLevel);
// Will return the domain name as a string
// This is used to tell a PC what domains he has in what slot
string GetDomainName(int nDomain);
// This is the starter function, and fires from Enter and Levelup
// It checks all of the bonus domain feats, and gives the PC the correct domains
void CheckBonusDomains(object oPC);
// Returns the spell to be burned for CastDomainSpell
int GetBurnableSpell(object oPC, int nLevel);
// Returns the Domain Power feat
int GetDomainFeat(int nDomain);
// Returns the Uses per day of the feat entered
int GetDomainFeatUsesPerDay(int nFeat, object oPC);
// This counts down the number of times a domain has been used in a day
// Returns TRUE if the domain use is valid
// Returns FALSE if the player is out of uses per day
int DecrementDomainUses(int nDomain, object oPC);
// Used to determine which domain has cast the Turn Undead spell
// Returns the domain constant
int GetTurningDomain(int nSpell);
// Checks to see if the player has a domain.
// Looks for the domain power constants since every domain has those
int GetHasDomain(object oPC, int nDomain);
// Cleans the ints that limit the domain spells to being cast 1/day
void BonusDomainRest(object oPC);
//#include "prc_inc_clsfunc"
#include "prc_alterations"
#include "prc_getbest_inc"
#include "inc_dynconv"
int GetBonusDomain(object oPC, int nSlot)
{
/*string sName = "PRCBonusDomain" + IntToString(nSlot);
// Return value in case there is nothing in the slot
int nDomain = 0;
nDomain = GetPersistantLocalInt(oPC, sName);*/
return GetPersistantLocalInt(oPC, "PRCBonusDomain" + IntToString(nSlot));
}
void AddBonusDomain(object oPC, int nDomain)
{
//if(DEBUG) DoDebug("AddBonusDomain is running.");
// Loop through the domain slots to see if there is an open one.
int nSlot = 1;
int nTest = GetBonusDomain(oPC, nSlot);
while(nTest > 0 && 5 >= nSlot)
{
nSlot += 1;
// If the test domain and the domain to be added are the same
// shut down the function, since you don't want to add a domain twice.
if(nTest == nDomain)
{
//FloatingTextStringOnCreature("You already have this domain as a bonus domain.", oPC, FALSE);
return;
}
nTest = GetBonusDomain(oPC, nSlot);
}
// If you run out of slots, display message and end function
if (nSlot > 5)
{
FloatingTextStringOnCreature("You have more than 5 bonus domains, your last domain is lost.", oPC, FALSE);
return;
}
// If we're here, we know we have an open slot, so we add the domain into it.
string sName = "PRCBonusDomain" + IntToString(nSlot);
SetPersistantLocalInt(oPC, sName, nDomain);
FloatingTextStringOnCreature("You have " + GetStringByStrRef(StringToInt(Get2DACache("prc_domains", "Name", nDomain - 1))) + " as a bonus domain", oPC, FALSE);
}
int TestSpellTarget(object oPC, object oTarget, int nSpell)
{
int nTargetType = ~(HexToInt(Get2DACache("spells", "TargetType", nSpell)));
if(oTarget == oPC && nTargetType & 1)
{
SendMessageToPC(oPC, "You cannot target yourself!");
return FALSE;
}
else if(GetIsObjectValid(oTarget))
{
int nObjectType = GetObjectType(oTarget);
if(nObjectType == OBJECT_TYPE_CREATURE && nTargetType & 2)
{
SendMessageToPC(oPC, "You cannot target creatures");
return FALSE;
}
else if(nObjectType == OBJECT_TYPE_ITEM && nTargetType & 8)
{
SendMessageToPC(oPC, "You cannot target items");
return FALSE;
}
else if(nObjectType == OBJECT_TYPE_DOOR && nTargetType & 16)
{
SendMessageToPC(oPC, "You cannot target doors");
return FALSE;
}
else if(nObjectType == OBJECT_TYPE_PLACEABLE && nTargetType & 32)
{
SendMessageToPC(oPC, "You cannot target placeables");
return FALSE;
}
}
else if(nTargetType & 4)
{
SendMessageToPC(oPC, "You cannot target locations");
return FALSE;
}
return TRUE;
}
// Classes using new spellbook systems are handeled separately
int GetIsBioDivineClass(int nClass)
{
return nClass == CLASS_TYPE_CLERIC
|| nClass == CLASS_TYPE_DRUID
|| nClass == CLASS_TYPE_PALADIN
|| nClass == CLASS_TYPE_SHAMAN
|| nClass == CLASS_TYPE_UR_PRIEST
|| nClass == CLASS_TYPE_RANGER;
}
void CastDomainSpell(object oPC, int nSlot, int nLevel)
{
if(GetLocalInt(oPC, "DomainCastSpell" + IntToString(nLevel))) //Already cast a spell of this level?
{
FloatingTextStringOnCreature("You have already cast your domain spell for level " + IntToString(nLevel), oPC, FALSE);
return;
}
int nSpell = GetDomainSpell(GetBonusDomain(oPC, nSlot), nLevel, oPC);
// If there is no spell for that level, you cant cast it.
if(nSpell == -1)
return;
// Subradial spells are handled through conversation
int bSubRadial = Get2DACache("spells", "SubRadSpell1", nSpell) != "";
// Domain casting feats use generic targeting, so check if spell can be cast at selected target
object oTarget = GetSpellTargetObject();
if(!bSubRadial && !TestSpellTarget(oPC, oTarget, nSpell))
return;
int nClass, nCount, nMetamagic = METAMAGIC_NONE;
// Mystic is a special case - checked first
if(GetLevelByClass(CLASS_TYPE_MYSTIC, oPC) || GetLevelByClass(CLASS_TYPE_NIGHTSTALKER, oPC))
{
// Mystics can use metamagic with domain spells
nClass = GetLevelByClass(CLASS_TYPE_MYSTIC, oPC) ? CLASS_TYPE_MYSTIC : CLASS_TYPE_NIGHTSTALKER;
nMetamagic = GetLocalInt(oPC, "MetamagicFeatAdjust");
int nSpellLevel = nLevel;
if(nMetamagic)
{
//Need to check if metamagic can be applied to a spell
int nMetaTest;
int nMetaType = HexToInt(Get2DACache("spells", "MetaMagic", nSpell));
switch(nMetamagic)
{
case METAMAGIC_NONE: nMetaTest = 1; break; //no need to change anything
case METAMAGIC_EMPOWER: nMetaTest = nMetaType & 1; nSpellLevel += 2; break;
case METAMAGIC_EXTEND: nMetaTest = nMetaType & 2; nSpellLevel += 1; break;
case METAMAGIC_MAXIMIZE: nMetaTest = nMetaType & 4; nSpellLevel += 3; break;
case METAMAGIC_QUICKEN: nMetaTest = nMetaType & 8; nSpellLevel += 4; break;
case METAMAGIC_SILENT: nMetaTest = nMetaType & 16; nSpellLevel += 1; break;
case METAMAGIC_STILL: nMetaTest = nMetaType & 32; nSpellLevel += 1; break;
}
if(!nMetaTest)//can't use selected metamagic with this spell
{
nMetamagic = METAMAGIC_NONE;
ActionDoCommand(SendMessageToPC(oPC, "You can't use "+GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpell)))+"with selected metamagic."));
nSpellLevel = nLevel;
}
else if(nLevel > 9)//now test the spell level
{
nMetamagic = METAMAGIC_NONE;
ActionDoCommand(SendMessageToPC(oPC, "Modified spell level is to high! Casting spell without metamagic"));
nSpellLevel = nLevel;
}
else if(GetLocalInt(oPC, "PRC_metamagic_state") == 1)
SetLocalInt(oPC, "MetamagicFeatAdjust", 0);
}
nCount = persistant_array_get_int(oPC, "NewSpellbookMem_" + IntToString(CLASS_TYPE_MYSTIC), nSpellLevel);
// we can't cast metamagiced version of the spell - assuming that player want to cast the spell anyway
if(!nCount)
nCount = persistant_array_get_int(oPC, "NewSpellbookMem_" + IntToString(CLASS_TYPE_MYSTIC), nLevel);
// Do we have slots available?
if(nCount)
{
// Prepare to cast the spell
nLevel = nSpellLevel;//correct the spell level if we're using metamagic
SetLocalInt(oPC, "NSB_Class", nClass);
SetLocalInt(oPC, "NSB_SpellLevel", nLevel);
}
}
// checking 'newspellbook' classes is much faster than checking bioware spellbooks
if(!nCount)
{
int n;
for(n = 1; n < 9; n++)
{
nClass = GetClassByPosition(n, oPC);
// Check to see if you can burn a spell of that slot or if the person has already
// cast all of their level X spells for the day
if(!GetIsBioDivineClass(nClass))
{
int nSpellbook = GetSpellbookTypeForClass(nClass);
if(nSpellbook == SPELLBOOK_TYPE_SPONTANEOUS)
{
nCount = persistant_array_get_int(oPC, "NewSpellbookMem_" + IntToString(nClass), nLevel);
if(nCount)
{// Prepare to cast the spell
SetLocalInt(oPC, "NSB_Class", nClass);
SetLocalInt(oPC, "NSB_SpellLevel", nLevel);
}
}
else if(nSpellbook == SPELLBOOK_TYPE_PREPARED)
{
string sArray = "NewSpellbookMem_"+IntToString(nClass);
string sIDX = "SpellbookIDX" + IntToString(nLevel) + "_" + IntToString(nClass);
int i, nSpellbookID, nMax = persistant_array_get_size(oPC, sIDX);
for(i = 0; i < nMax; i++)
{
nSpellbookID = persistant_array_get_int(oPC, sIDX, i);
nCount = persistant_array_get_int(oPC, sArray, nSpellbookID);
if(nCount)
{
SetLocalInt(oPC, "NSB_Class", nClass);
SetLocalInt(oPC, "NSB_SpellbookID", nSpellbookID);
break;
}
}
}
}
if(nCount)
//we have found valid spell slot, no point in running this loop again
break;
}
}
// test bioware spellbooks
if(!nCount)
{
nCount = GetBurnableSpell(oPC, nLevel) + 1;//fix for Acid Fog spell
if(nCount)
{
SetLocalInt(oPC, "Domain_BurnableSpell", nCount);
nClass = GetPrimaryDivineClass(oPC);
}
}
//No spell left to burn? Tell the player that.
if(!nCount)
{
FloatingTextStringOnCreature("You have no spells left to trade for a domain spell.", oPC, FALSE);
return;
}
SetLocalInt(oPC, "DomainCast", nLevel);
if(bSubRadial)
{
SetLocalInt(oPC, "DomainOrigSpell", nSpell);
SetLocalInt(oPC, "DomainCastClass", nClass);
SetLocalObject(oPC, "DomainTarget", oTarget);
SetLocalLocation(oPC, "DomainTarget", GetSpellTargetLocation());
StartDynamicConversation("prc_domain_conv", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
}
else
{
if(nMetamagic & METAMAGIC_QUICKEN)
{
//Adding Auto-Quicken III for one round - deleted after casting is finished.
object oSkin = GetPCSkin(oPC);
int nCastDur = StringToInt(Get2DACache("spells", "ConjTime", nSpell)) + StringToInt(Get2DACache("spells", "CastTime", nSpell));
itemproperty ipAutoQuicken = ItemPropertyBonusFeat(IP_CONST_NSB_AUTO_QUICKEN);
ActionDoCommand(AddItemProperty(DURATION_TYPE_TEMPORARY, ipAutoQuicken, oSkin, nCastDur/1000.0f));
}
int nDC = 10 + nLevel + GetDCAbilityModForClass(nClass, oPC);
ActionCastSpell(nSpell, 0, nDC, 0, nMetamagic, nClass, FALSE, FALSE, OBJECT_INVALID, FALSE);
ActionDoCommand(DeleteLocalInt(oPC, "DomainCast"));
}
}
int GetDomainSpell(int nDomain, int nLevel, object oPC)
{
// The -1 on nDomains is to adjust from a base 1 to a base 0 system.
string sSpell = Get2DACache("prc_domains", "Level_" + IntToString(nLevel), (nDomain - 1));
if (DEBUG) DoDebug("Domain Spell: " + sSpell);
//if (DEBUG) DoDebug("GetDomainSpell has fired");
int nSpell = -1;
if(sSpell == "")
{
FloatingTextStringOnCreature("You do not have a domain spell of that level.", oPC, FALSE);
//int nFeat = SpellLevelToFeat(nLevel);
//IncrementRemainingFeatUses(oPC, nFeat);
}
else
{
nSpell = StringToInt(sSpell);
}
return nSpell;
}
int SpellLevelToFeat(int nLevel)
{
switch(nLevel)
{
case 1: return FEAT_CAST_DOMAIN_LEVEL_ONE;
case 2: return FEAT_CAST_DOMAIN_LEVEL_TWO;
case 3: return FEAT_CAST_DOMAIN_LEVEL_THREE;
case 4: return FEAT_CAST_DOMAIN_LEVEL_FOUR;
case 5: return FEAT_CAST_DOMAIN_LEVEL_FIVE;
case 6: return FEAT_CAST_DOMAIN_LEVEL_SIX;
case 7: return FEAT_CAST_DOMAIN_LEVEL_SEVEN;
case 8: return FEAT_CAST_DOMAIN_LEVEL_EIGHT;
case 9: return FEAT_CAST_DOMAIN_LEVEL_NINE;
}
return -1;
}
string GetDomainName(int nDomain)
{
string sName;
// Check that the domain slot is not empty
if(nDomain)
{
sName = Get2DACache("prc_domains", "Name", (nDomain - 1));
sName = GetStringByStrRef(StringToInt(sName));
}
else
sName = GetStringByStrRef(6497); // "Empty Slot"
return sName;
}
void CheckBonusDomains(object oPC)
{
int nBonusDomain, nDomainFeat;
int nSlot = 1;
while(nSlot < 6)
{
nBonusDomain = GetBonusDomain(oPC, nSlot);
nDomainFeat = GetDomainFeat(nBonusDomain);
if(!GetHasFeat(nDomainFeat, oPC)) SetPersistantLocalInt(oPC, "PRCBonusDomain" + IntToString(nSlot), 0);
//SendMessageToPC(oPC, "PRCBonusDomain"+IntToString(nSlot)" = "+IntToString(nBonusDomain));
//SendMessageToPC(oPC, "PRCBonusDomain"+IntToString(nSlot)" feat = "+IntToString(GetDomainFeat(nDomainFeat)));
nSlot += 1;
}
if (GetHasFeat(FEAT_BONUS_DOMAIN_AIR, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_AIR);
if (GetHasFeat(FEAT_BONUS_DOMAIN_ANIMAL, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_ANIMAL);
if (GetHasFeat(FEAT_BONUS_DOMAIN_DEATH, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_DEATH);
if (GetHasFeat(FEAT_BONUS_DOMAIN_DESTRUCTION, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_DESTRUCTION);
if (GetHasFeat(FEAT_BONUS_DOMAIN_EARTH, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_EARTH);
if (GetHasFeat(FEAT_BONUS_DOMAIN_EVIL, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_EVIL);
if (GetHasFeat(FEAT_BONUS_DOMAIN_FIRE, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_FIRE);
if (GetHasFeat(FEAT_BONUS_DOMAIN_GOOD, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_GOOD);
if (GetHasFeat(FEAT_BONUS_DOMAIN_HEALING, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_HEALING);
if (GetHasFeat(FEAT_BONUS_DOMAIN_KNOWLEDGE, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_KNOWLEDGE);
if (GetHasFeat(FEAT_BONUS_DOMAIN_MAGIC, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_MAGIC);
if (GetHasFeat(FEAT_BONUS_DOMAIN_PLANT, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_PLANT);
if (GetHasFeat(FEAT_BONUS_DOMAIN_PROTECTION, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_PROTECTION);
if (GetHasFeat(FEAT_BONUS_DOMAIN_STRENGTH, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_STRENGTH);
if (GetHasFeat(FEAT_BONUS_DOMAIN_SUN, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_SUN);
if (GetHasFeat(FEAT_BONUS_DOMAIN_TRAVEL, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_TRAVEL);
if (GetHasFeat(FEAT_BONUS_DOMAIN_TRICKERY, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_TRICKERY);
if (GetHasFeat(FEAT_BONUS_DOMAIN_WAR, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_WAR);
if (GetHasFeat(FEAT_BONUS_DOMAIN_WATER, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_WATER);
if (GetHasFeat(FEAT_BONUS_DOMAIN_DARKNESS, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_DARKNESS);
if (GetHasFeat(FEAT_BONUS_DOMAIN_STORM, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_STORM);
if (GetHasFeat(FEAT_BONUS_DOMAIN_METAL, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_METAL);
if (GetHasFeat(FEAT_BONUS_DOMAIN_PORTAL, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_PORTAL);
if (GetHasFeat(FEAT_BONUS_DOMAIN_FORCE, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_FORCE);
if (GetHasFeat(FEAT_BONUS_DOMAIN_SLIME, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_SLIME);
if (GetHasFeat(FEAT_BONUS_DOMAIN_TYRANNY, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_TYRANNY);
if (GetHasFeat(FEAT_BONUS_DOMAIN_DOMINATION, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_DOMINATION);
if (GetHasFeat(FEAT_BONUS_DOMAIN_SPIDER, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_SPIDER);
if (GetHasFeat(FEAT_BONUS_DOMAIN_UNDEATH, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_UNDEATH);
if (GetHasFeat(FEAT_BONUS_DOMAIN_TIME, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_TIME);
if (GetHasFeat(FEAT_BONUS_DOMAIN_DWARF, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_DWARF);
if (GetHasFeat(FEAT_BONUS_DOMAIN_CHARM, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_CHARM);
if (GetHasFeat(FEAT_BONUS_DOMAIN_ELF, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_ELF);
if (GetHasFeat(FEAT_BONUS_DOMAIN_FAMILY, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_FAMILY);
if (GetHasFeat(FEAT_BONUS_DOMAIN_FATE, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_FATE);
if (GetHasFeat(FEAT_BONUS_DOMAIN_GNOME, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_GNOME);
if (GetHasFeat(FEAT_BONUS_DOMAIN_ILLUSION, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_ILLUSION);
if (GetHasFeat(FEAT_BONUS_DOMAIN_HATRED, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_HATRED);
if (GetHasFeat(FEAT_BONUS_DOMAIN_HALFLING, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_HALFLING);
if (GetHasFeat(FEAT_BONUS_DOMAIN_NOBILITY, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_NOBILITY);
if (GetHasFeat(FEAT_BONUS_DOMAIN_OCEAN, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_OCEAN);
if (GetHasFeat(FEAT_BONUS_DOMAIN_ORC, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_ORC);
if (GetHasFeat(FEAT_BONUS_DOMAIN_RENEWAL, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_RENEWAL);
if (GetHasFeat(FEAT_BONUS_DOMAIN_RETRIBUTION, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_RETRIBUTION);
if (GetHasFeat(FEAT_BONUS_DOMAIN_RUNE, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_RUNE);
if (GetHasFeat(FEAT_BONUS_DOMAIN_SPELLS, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_SPELLS);
if (GetHasFeat(FEAT_BONUS_DOMAIN_SCALEYKIND, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_SCALEYKIND);
if (GetHasFeat(FEAT_BONUS_DOMAIN_BLIGHTBRINGER, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_BLIGHTBRINGER);
if (GetHasFeat(FEAT_BONUS_DOMAIN_DRAGON, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_DRAGON);
if (GetHasFeat(FEAT_BONUS_DOMAIN_COLD, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_COLD);
if (GetHasFeat(FEAT_BONUS_DOMAIN_WINTER, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_WINTER);
//if (DEBUG) FloatingTextStringOnCreature("Check Bonus Domains is running", oPC, FALSE);
}
int GetBurnableSpell(object oPC, int nLevel)
{
int nBurnableSpell = -1;
if (nLevel == 1) nBurnableSpell = GetBestL1Spell(oPC, nBurnableSpell);
else if (nLevel == 2) nBurnableSpell = GetBestL2Spell(oPC, nBurnableSpell);
else if (nLevel == 3) nBurnableSpell = GetBestL3Spell(oPC, nBurnableSpell);
else if (nLevel == 4) nBurnableSpell = GetBestL4Spell(oPC, nBurnableSpell);
else if (nLevel == 5) nBurnableSpell = GetBestL5Spell(oPC, nBurnableSpell);
else if (nLevel == 6) nBurnableSpell = GetBestL6Spell(oPC, nBurnableSpell);
else if (nLevel == 7) nBurnableSpell = GetBestL7Spell(oPC, nBurnableSpell);
else if (nLevel == 8) nBurnableSpell = GetBestL8Spell(oPC, nBurnableSpell);
else if (nLevel == 9) nBurnableSpell = GetBestL9Spell(oPC, nBurnableSpell);
return nBurnableSpell;
}
int GetDomainFeat(int nDomain)
{
// The -1 on nDomain is to adjust from a base 1 to a base 0 system.
// Returns the domain power feat
return StringToInt(Get2DACache("domains", "GrantedFeat", nDomain - 1));
}
int GetDomainFeatUsesPerDay(int nFeat, object oPC)
{
int nUses = StringToInt(Get2DACache("feat", "USESPERDAY", nFeat));
// These are the domains that have ability based uses per day
if (nUses == 33)
{
// The Strength domain, which uses Strength when the Cleric has Kord levels
// Without Kord levels, its 1 use per day
if(nFeat == FEAT_STRENGTH_DOMAIN_POWER)
{
nUses = 1;
if(GetLevelByClass(CLASS_TYPE_MIGHTY_CONTENDER_KORD, oPC)) nUses = GetAbilityModifier(ABILITY_STRENGTH, oPC);
// Catching exceptions
if(nUses < 1) nUses = 1;
}
if(nFeat == FEAT_SUN_DOMAIN_POWER)
{
if(GetHasFeat(FEAT_BONUS_DOMAIN_SUN, oPC) && GetLevelByClass(CLASS_TYPE_MYSTIC, oPC))
{
nUses = GetHasFeat(FEAT_EXTRA_TURNING, oPC) ? 7 : 3;
nUses += GetAbilityModifier(ABILITY_CHARISMA, oPC);
}
else
nUses = 1;
}
// All other ones so far are the Charisma based turning domains
nUses = 3 + GetAbilityModifier(ABILITY_CHARISMA, oPC);
}
return nUses;
}
int DecrementDomainUses(int nDomain, object oPC)
{
int nReturn = TRUE;
int nUses = GetLocalInt(oPC, "BonusDomainUsesPerDay" + GetDomainName(nDomain));
// If there is still a valid use left, remove it
if (nUses >= 1) SetLocalInt(oPC, "BonusDomainUsesPerDay" + GetDomainName(nDomain), (nUses - 1));
// Tell the player how many uses he has left
else // He has no more uses for the day
{
nReturn = FALSE;
}
FloatingTextStringOnCreature("You have " + IntToString(nUses - 1) + " uses per day left of the " + GetDomainName(nDomain) + " power.", oPC, FALSE);
return nReturn;
}
int GetTurningDomain(int nSpell)
{
switch(nSpell)
{
case SPELL_TURN_REPTILE: return PRC_DOMAIN_SCALEYKIND;
case SPELL_TURN_OOZE: return PRC_DOMAIN_SLIME;
case SPELL_TURN_SPIDER: return PRC_DOMAIN_SPIDER;
case SPELL_TURN_PLANT: return PRC_DOMAIN_PLANT;
case SPELL_TURN_AIR: return PRC_DOMAIN_AIR;
case SPELL_TURN_EARTH: return PRC_DOMAIN_EARTH;
case SPELL_TURN_FIRE: return PRC_DOMAIN_FIRE;
case SPELL_TURN_WATER: return PRC_DOMAIN_WATER;
case SPELL_TURN_BLIGHTSPAWNED: return PRC_DOMAIN_BLIGHTBRINGER;
}
return -1;
}
int GetHasDomain(object oPC, int nDomain)
{
// Get the domain power feat for the appropriate domain
int nFeat = GetDomainFeat(nDomain);
return GetHasFeat(nFeat, oPC);
}
void BonusDomainRest(object oPC)
{
// Bonus Domain ints that limit you to casting 1/day per level
int i;
for (i = 1; i < 10; i++)
{
DeleteLocalInt(oPC, "DomainCastSpell" + IntToString(i));
}
// This is code to stop you from using the Domain per day abilities more than you should be able to
int i2;
// Highest domain constant is 62
for (i2 = 1; i2 < 63; i2++)
{
// This is to ensure they only get the ints set for the domains they do have
if (GetHasDomain(oPC, i2))
{
// Store the number of uses a day here
SetLocalInt(oPC, "BonusDomainUsesPerDay" + GetDomainName(i2), GetDomainFeatUsesPerDay(GetDomainFeat(i2), oPC));
}
}
}
int GetDomainCasterLevel(object oPC)
{
return GetLevelByClass(CLASS_TYPE_CLERIC, oPC)
+ GetLevelByClass(CLASS_TYPE_MYSTIC, oPC)
+ GetLevelByClass(CLASS_TYPE_SHAMAN, oPC)
+ GetLevelByClass(CLASS_TYPE_TEMPLAR, oPC)
+ GetLevelByClass(CLASS_TYPE_BLIGHTLORD, oPC)
+ GetLevelByClass(CLASS_TYPE_CONTEMPLATIVE, oPC)
+ GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oPC);
}

View File

@@ -0,0 +1,188 @@
// Metabreath Feats - Not implemented yet.
/** const int FEAT_CLINGING_BREATH = 5000;
const int FEAT_LINGERING_BREATH = 5001;
const int FEAT_ENLARGE_BREATH = 5002;
const int FEAT_HEIGHTEN_BREATH = 5003;
const int FEAT_MAXIMIZE_BREATH = 5004;
const int FEAT_QUICKEN_BREATH = 5005;
const int FEAT_RECOVER_BREATH = 5006;
const int FEAT_SHAPE_BREATH = 5007;
const int FEAT_SPLIT_BREATH = 5008;
const int FEAT_SPREADING_BREATH = 5009;
const int FEAT_EXTEND_SPREADING_BREATH = 5010;
const int FEAT_TEMPEST_BREATH = 5011; **/
// Dragon Shaman Aura flag
//const int DRAGON_SHAMAN_AURA_ACTIVE = 5000;
#include "prc_inc_nwscript"
int GetIsDragonblooded(object oPC);
// returns the damage type of dragon that the PC has a totem for. Checks for the presence of the
// various feats that are present indicating such. This is necessary for determining the type
// of breath weapon and the type of damage immunity.
int GetDragonDamageType(int nTotem);
// Used to create a flag on the caster and store the Aura currently being run.
//int StartDragonShamanAura(object oCaster, int nSpellId);
// Resets the available ToV points; for use after rest or on enter.
void ResetTouchOfVitality(object oPC);
// Applies any metabreath feats that the dragon shaman may have to his breathweapon
//int ApplyMetaBreathFeatMods( int nDuration, object oCaster );
int GetIsDragonblooded(object oPC)
{
int nRace = GetRacialType(oPC);
if(nRace == RACIAL_TYPE_KOBOLD
|| nRace == RACIAL_TYPE_SPELLSCALE
|| nRace == RACIAL_TYPE_DRAGONBORN
|| nRace == RACIAL_TYPE_STONEHUNTER_GNOME
|| nRace == RACIAL_TYPE_SILVERBROW_HUMAN
|| nRace == RACIAL_TYPE_FORESTLORD_ELF
|| nRace == RACIAL_TYPE_FIREBLOOD_DWARF
|| nRace == RACIAL_TYPE_GLIMMERSKIN_HALFING
|| nRace == RACIAL_TYPE_FROSTBLOOD_ORC
|| nRace == RACIAL_TYPE_SUNSCORCH_HOBGOBLIN
|| nRace == RACIAL_TYPE_VILETOOTH_LIZARDFOLK)
return TRUE;
if(GetLevelByClass(CLASS_TYPE_DRAGON_DISCIPLE, oPC) > 9)
return TRUE;
if(GetHasFeat(FEAT_DRAGONTOUCHED, oPC)
|| GetHasFeat(FEAT_DRACONIC_DEVOTEE, oPC)
|| GetHasFeat(FEAT_DRAGON, oPC)
|| GetHasFeat(DRAGON_BLOODED, oPC))
return TRUE;
//Draconic Heritage qualifies for dragonblood
if(GetHasFeat(FEAT_DRACONIC_HERITAGE_BK, oPC)
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_BL, oPC)
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_GR, oPC)
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_RD, oPC)
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_WH, oPC)
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_AM, oPC)
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_CR, oPC)
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_EM, oPC)
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_SA, oPC)
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_TP, oPC)
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_BS, oPC)
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_BZ, oPC)
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_CP, oPC)
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_GD, oPC)
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_SR, oPC))
return TRUE;
return FALSE;
}
int GetDragonDamageType(int nTotem)
{
int nDamageType = nTotem == FEAT_DRAGONSHAMAN_BLACK ? DAMAGE_TYPE_ACID:
nTotem == FEAT_DRAGONSHAMAN_BLUE ? DAMAGE_TYPE_ELECTRICAL:
nTotem == FEAT_DRAGONSHAMAN_BRASS ? DAMAGE_TYPE_FIRE:
nTotem == FEAT_DRAGONSHAMAN_BRONZE ? DAMAGE_TYPE_ELECTRICAL:
nTotem == FEAT_DRAGONSHAMAN_COPPER ? DAMAGE_TYPE_ACID:
nTotem == FEAT_DRAGONSHAMAN_GOLD ? DAMAGE_TYPE_FIRE:
nTotem == FEAT_DRAGONSHAMAN_GREEN ? DAMAGE_TYPE_ACID:
nTotem == FEAT_DRAGONSHAMAN_RED ? DAMAGE_TYPE_FIRE:
nTotem == FEAT_DRAGONSHAMAN_SILVER ? DAMAGE_TYPE_COLD:
nTotem == FEAT_DRAGONSHAMAN_WHITE ? DAMAGE_TYPE_COLD:
-1;
return nDamageType;
}
void ResetTouchOfVitality(object oPC)
{
if(GetHasFeat(FEAT_DRAGONSHAMAN_TOUCHVITALITY, oPC))
{
int nChaBonus = GetAbilityModifier(ABILITY_CHARISMA, oPC);
if(nChaBonus < 0) nChaBonus = 0;
int nVitPoints = 2 * GetLevelByClass(CLASS_TYPE_DRAGON_SHAMAN, oPC) * nChaBonus;
SetLocalInt(oPC, "DRAGON_SHAMAN_TOUCH_REMAIN", nVitPoints);
string sMes = "Healing power: " + IntToString(nVitPoints) + " points.";
FloatingTextStringOnCreature(sMes, oPC, FALSE);
}
if(GetHasFeat(FEAT_ABERRANT_DURABLE_FORM, oPC))
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectTemporaryHitpoints(GetAberrantFeatCount(oPC)), oPC);
}
int GetMarshalAuraPower(object oPC)
{
int iMarshalLevel = GetLevelByClass(CLASS_TYPE_MARSHAL, oPC);
int nBonus;
if(iMarshalLevel > 19)
nBonus = iMarshalLevel / 5;
else if(iMarshalLevel > 13)
nBonus = 3;
else if(iMarshalLevel > 6)
nBonus = 2;
else if(iMarshalLevel > 1)
nBonus = 1;
return nBonus;
}
int GetDragonShamanAuraPower(object oPC)
{
int iDragonShamanLevel = GetLevelByClass(CLASS_TYPE_DRAGON_SHAMAN, oPC);
int nBonus = (iDragonShamanLevel / 5) + 1;
return nBonus;
}
int GetExtraAuraPower(object oPC)
{
int nBonus;
if(GetIsDragonblooded(oPC))
{
int nHD = GetHitDice(oPC);
if(nHD > 19)
nBonus = 4;
else if(nHD > 13)
nBonus = 3;
else if(nHD > 6)
nBonus = 2;
else
nBonus = 1;
}
return nBonus;
}
int GetAuraBonus(object oPC)
{
int nAuraBonus = GetDragonShamanAuraPower(oPC);
int nMarshalBonus = GetMarshalAuraPower(oPC);
int nExtraBonus = GetExtraAuraPower(oPC);
if(nMarshalBonus > nAuraBonus)
nAuraBonus = nMarshalBonus;
if(nExtraBonus > nAuraBonus)
nAuraBonus = nExtraBonus;
return nAuraBonus;
}
object GetAuraObject(object oShaman, string sTag)
{
location lTarget = GetLocation(oShaman);
object oAura = GetFirstObjectInShape(SHAPE_SPHERE, 1.0f, lTarget, FALSE, OBJECT_TYPE_AREA_OF_EFFECT);
while(GetIsObjectValid(oAura))
{
if((GetAreaOfEffectCreator(oAura) == oShaman) //was cast by shaman
&& GetTag(oAura) == sTag //it's a draconic aura
&& !GetLocalInt(oAura, "SpellID")) //and was not setup before
{
return oAura;
}
oAura = GetNextObjectInShape(SHAPE_SPHERE, 1.0f, lTarget, FALSE, OBJECT_TYPE_AREA_OF_EFFECT);
}
return OBJECT_INVALID;
}

View File

@@ -0,0 +1,92 @@
//:://////////////////////////////////////////////
//:: Drug system functions
//:: prc_inc_drugfunc
//:://////////////////////////////////////////////
/** @file
A bunch of functions common to the drug
scripts.
@author Ornedan
@data Created 2006.05.29
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Structures */
//////////////////////////////////////////////////
//////////////////////////////////////////////////
/* Constants */
//////////////////////////////////////////////////
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Increments the overdose tracking counter by one for the given drug and queues
* decrementing it by one after the given period.
* The value of this counter is what will be returned by GetHasOverdosed().
*
*/
void IncrementOverdoseTracker(object oDrugUser, string sODIdentifier, float fODPeriod);
/**
* Checks if the given drug user is currently in the overdose period of the given drug.
* The value returned is the number of drug uses in the overdose period of which is
* currently active.
*
* @param oDrugUser A creature using a drug.
* @param sODIdentifier The name of the drug's overdose identifier.
* @return The current value of the overdose variable - how many drug uses of
* the given drug are right now in their overdose period.
*/
int GetOverdoseCounter(object oDrugUser, string sODIdentifier);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
//////////////////////////////////////////////////
/* Internal functions */
//////////////////////////////////////////////////
/** Internal function.
* Implements the decrementing of the overdose counters.
*
* @param oDrugUser A creature using a drug.
* @param sODIdentifier The name of the drug's overdose identifier.
*/
void _prc_inc_drugfunc_DecrementOverdoseTracker(object oDrugUser, string sODIdentifier)
{
// Delete the variable if decrementing would it would make it 0
if(GetLocalInt(oDrugUser, sODIdentifier) <= 1)
DeleteLocalInt(oDrugUser, sODIdentifier);
else
SetLocalInt(oDrugUser, sODIdentifier, GetLocalInt(oDrugUser, sODIdentifier) - 1);
}
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
void IncrementOverdoseTracker(object oDrugUser, string sODIdentifier, float fODPeriod)
{
SetLocalInt(oDrugUser, sODIdentifier, GetLocalInt(oDrugUser, sODIdentifier) + 1);
DelayCommand(fODPeriod, _prc_inc_drugfunc_DecrementOverdoseTracker(oDrugUser, sODIdentifier));
}
int GetOverdoseCounter(object oDrugUser, string sODIdentifier)
{
return GetLocalInt(oDrugUser, sODIdentifier);
}
// Test main
//void main(){}

Some files were not shown because too many files have changed in this diff Show More