From 42894064d830433dd490eb2b4e3d7f0dba495a60 Mon Sep 17 00:00:00 2001 From: Jaysyn904 <68194417+Jaysyn904@users.noreply.github.com> Date: Wed, 24 Dec 2025 15:20:02 -0500 Subject: [PATCH] 2025/12/24 Update Hooked up new GUI module event. Updated PRC8 includes. Updated "_removed". Updated nasher.cfg --- nasher.cfg | 24 +- src/_removed/nw_s2_animalcom.nss | 28 + src/_removed/nw_s2_familiar.nss | 28 + .../original spells/nw_s0_burnhand.nss | 112 + .../original spells/nw_s0_calllghtn.nss | 166 + .../original spells/nw_s0_chlightn.nss | 255 ++ .../original spells/nw_s0_conecold.nss | 100 + .../original spells/nw_s0_delfirebal.nss | 132 + .../original spells/nw_s0_eleswarm.nss | 70 + .../original spells/nw_s0_fireball.nss | 175 + .../original spells/nw_s0_firestrm.nss | 174 + .../original spells/nw_s0_flmarrow.nss | 111 + .../original spells/nw_s0_flmlash.nss | 91 + .../original spells/nw_s0_flmstrike.nss | 177 + .../original spells/nw_s0_icestorm.nss | 171 + .../original spells/nw_s0_implosion.nss | 131 + .../original spells/nw_s0_inccloud.nss | 72 + .../original spells/nw_s0_incclouda.nss | 81 + .../original spells/nw_s0_inccloudb.nss | 65 + .../original spells/nw_s0_inccloudc.nss | 93 + .../original spells/nw_s0_lghtnbolt.nss | 181 + .../original spells/nw_s0_metswarm.nss | 167 + .../original spells/nw_s0_prisspray.nss | 213 ++ .../original spells/nw_s0_rayfrost.nss | 86 + .../original spells/nw_s0_searlght.nss | 127 + .../original spells/nw_s0_sndburst.nss | 161 + .../original spells/nw_s0_stormvenc.nss | 147 + .../original spells/nw_s0_stormveng.nss | 123 + src/_removed/original spells/nw_s0_summon.nss | 367 ++ .../original spells/nw_s0_summon1.nss | 64 + .../original spells/nw_s0_summon2.nss | 65 + .../original spells/nw_s0_summon3.nss | 63 + .../original spells/nw_s0_summon4.nss | 60 + .../original spells/nw_s0_summon5.nss | 61 + .../original spells/nw_s0_summon6.nss | 99 + .../original spells/nw_s0_summon7.nss | 148 + .../original spells/nw_s0_summon8.nss | 129 + .../original spells/nw_s0_summon9.nss | 89 + .../original spells/nw_s0_sunbeam.nss | 138 + .../original spells/nw_s0_wailbansh.nss | 156 + .../original spells/nw_s0_wallfire.nss | 59 + .../original spells/nw_s0_wallfirea.nss | 73 + .../original spells/nw_s0_wallfirec.nss | 90 + .../original spells/x0_s0_bombard.nss | 177 + src/_removed/original spells/x0_s0_drown.nss | 93 + .../original spells/x0_s0_earthquake.nss | 166 + .../original spells/x0_s0_elecjolt.nss | 48 + .../original spells/x0_s0_firebrand.nss | 42 + src/_removed/original spells/x0_s0_flare.nss | 56 + .../original spells/x0_s0_gustwind.nss | 105 + .../original spells/x0_s0_inferno.nss | 110 + .../original spells/x0_s0_ironhorn.nss | 168 + .../original spells/x0_s0_sunburst.nss | 223 ++ .../original spells/x2_s0_combust.nss | 210 ++ .../original spells/x2_s0_elecloop.nss | 153 + .../original spells/x2_s0_grtthdclp.nss | 173 + .../original spells/x2_s0_hellinfern.nss | 141 + .../original spells/x2_s0_horiboom.nss | 157 + .../original spells/x2_s0_scntsphere.nss | 112 + src/hakpak/ghost_prc8_top/2da/classes.2da | 56 +- src/hakpak/ghost_prc8_top/2da/racialtypes.2da | 4 +- .../ghost_prc8_top/nss/nw_s0_burnhand.ncs | Bin 0 -> 229310 bytes .../ghost_prc8_top/nss/nw_s0_burnhand.nss | 109 + .../ghost_prc8_top/nss/nw_s0_calllghtn.ncs | Bin 0 -> 232901 bytes .../ghost_prc8_top/nss/nw_s0_calllghtn.nss | 190 + .../ghost_prc8_top/nss/nw_s0_chlightn.ncs | Bin 0 -> 232126 bytes .../ghost_prc8_top/nss/nw_s0_chlightn.nss | 277 ++ .../ghost_prc8_top/nss/nw_s0_conecold.nss | 137 + .../ghost_prc8_top/nss/nw_s0_delfirebal.nss | 123 + .../ghost_prc8_top/nss/nw_s0_eleswarm.nss | 203 + .../ghost_prc8_top/nss/nw_s0_fireball.nss | 168 + .../ghost_prc8_top/nss/nw_s0_firestrm.nss | 170 + .../ghost_prc8_top/nss/nw_s0_flmarrow.nss | 110 + .../ghost_prc8_top/nss/nw_s0_flmlash.nss | 114 + .../ghost_prc8_top/nss/nw_s0_flmstrike.ncs | Bin 0 -> 229572 bytes .../ghost_prc8_top/nss/nw_s0_flmstrike.nss | 108 + .../ghost_prc8_top/nss/nw_s0_icestorm.nss | 198 + .../ghost_prc8_top/nss/nw_s0_implosion.nss | 152 + .../ghost_prc8_top/nss/nw_s0_inccloud.nss | 65 + .../ghost_prc8_top/nss/nw_s0_incclouda.nss | 85 + .../ghost_prc8_top/nss/nw_s0_inccloudb.nss | 71 + .../ghost_prc8_top/nss/nw_s0_inccloudc.nss | 111 + .../ghost_prc8_top/nss/nw_s0_lghtnbolt.nss | 142 + .../ghost_prc8_top/nss/nw_s0_metswarm.nss | 123 + .../ghost_prc8_top/nss/nw_s0_sndburst.nss | 167 + .../ghost_prc8_top/nss/nw_s0_stormvenc.nss | 115 + .../ghost_prc8_top/nss/nw_s0_stormveng.nss | 113 + .../ghost_prc8_top/nss/nw_s0_summon.nss | 311 ++ .../ghost_prc8_top/nss/nw_s0_sunbeam.nss | 160 + .../ghost_prc8_top/nss/nw_s0_wailbansh.nss | 173 + .../ghost_prc8_top/nss/nw_s0_wallfire.nss | 63 + .../ghost_prc8_top/nss/nw_s0_wallfirea.nss | 83 + .../ghost_prc8_top/nss/nw_s0_wallfirec.nss | 111 + .../ghost_prc8_top/nss/x0_s0_bombard.nss | 192 + .../ghost_prc8_top/nss/x0_s0_earthquake.nss | 201 + .../ghost_prc8_top/nss/x0_s0_firebrand.nss | 239 ++ .../ghost_prc8_top/nss/x0_s0_gustwind.nss | 158 + .../ghost_prc8_top/nss/x0_s0_inferno.nss | 155 + .../ghost_prc8_top/nss/x0_s0_ironhorn.nss | 178 + .../ghost_prc8_top/nss/x0_s0_sunburst.nss | 244 ++ .../ghost_prc8_top/nss/x2_s0_combust.nss | 156 + .../ghost_prc8_top/nss/x2_s0_elecloop.nss | 174 + .../ghost_prc8_top/nss/x2_s0_grtthdclp.nss | 116 + .../ghost_prc8_top/nss/x2_s0_hellinfern.nss | 151 + .../ghost_prc8_top/nss/x2_s0_horiboom.nss | 186 + .../ghost_prc8_top/nss/x2_s0_scntsphere.nss | 106 + src/include/inc_dynconv.nss | 60 +- src/include/inc_epicspelldef.nss | 143 +- src/include/inc_epicspellfnc.nss | 4 +- src/include/inc_epicspells.nss | 11 +- src/include/inc_infusion.nss | 481 +++ src/include/inc_item_props.nss | 55 +- src/include/inc_lookups.nss | 42 +- src/include/inc_newspellbook.nss | 165 +- src/include/inc_npc.nss | 178 +- src/include/inc_rand_equip.nss | 1 + src/include/inc_rend.nss | 1 + src/include/inc_sp_gain_mem.nss | 11 +- src/include/inc_switch_setup.nss | 108 +- src/include/inv_inc_blast.nss | 1 + src/include/inv_inc_invknown.nss | 3 + src/include/inv_inc_invoke.nss | 2 +- src/include/inv_invokehook.nss | 10 + src/include/moi_inc_moifunc.nss | 7 +- src/include/nw_inc_gff.nss | 623 ++++ src/include/nw_inc_nui.nss | 852 ++--- src/include/pnp_shft_poly.nss | 585 ++- src/include/prc_add_spell_dc.nss | 2 + src/include/prc_add_spl_pen.nss | 4 +- src/include/prc_class_const.nss | 5 +- src/include/prc_craft_inc.nss | 23 +- src/include/prc_effect_inc.nss | 82 +- src/include/prc_feat_const.nss | 114 +- src/include/prc_getbest_inc.nss | 3 +- src/include/prc_inc_breath.nss | 2 + src/include/prc_inc_castlvl.nss | 131 +- src/include/prc_inc_chat_pow.nss | 1 + src/include/prc_inc_clsfunc.nss | 8 +- src/include/prc_inc_combat.nss | 42 +- src/include/prc_inc_combmove.nss | 48 +- src/include/prc_inc_core.nss | 9 +- src/include/prc_inc_descrptr.nss | 4 +- src/include/prc_inc_factotum.nss | 22 +- src/include/prc_inc_fork.nss | 103 +- src/include/prc_inc_function.nss | 12 +- src/include/prc_inc_hextor.nss | 2 + src/include/prc_inc_itmrstr.nss | 2 + src/include/prc_inc_json.nss | 1993 ++++++++++ src/include/prc_inc_material.nss | 21 +- src/include/prc_inc_nat_hb.nss | 264 +- src/include/prc_inc_natweap.nss | 26 + src/include/prc_inc_nwscript.nss | 5 +- src/include/prc_inc_onhit.nss | 21 +- src/include/prc_inc_shifting.nss | 4 +- src/include/prc_inc_size.nss | 154 + src/include/prc_inc_skills.nss | 19 +- src/include/prc_inc_spells.nss | 126 +- src/include/prc_inc_switch.nss | 158 +- src/include/prc_inc_turning.nss | 34 +- src/include/prc_inc_unarmed.nss | 402 +- src/include/prc_inc_wpnrest.nss | 299 +- src/include/prc_ipfeat_const.nss | 13 +- src/include/prc_misc_const.nss | 4 + src/include/prc_nui_com_inc.nss | 615 +++ src/include/prc_nui_consts.nss | 60 +- src/include/prc_nui_lv_inc.nss | 3316 +++++++++++++++++ ...{prc_nui_sc_inc.nss => prc_nui_sb_inc.nss} | 357 +- ...rc_nui_scd_inc.nss => prc_nui_sbd_inc.nss} | 12 +- src/include/prc_sp_func.nss | 18 + src/include/prc_spell_const.nss | 120 +- src/include/prc_spellf_inc.nss | 6 +- src/include/prc_template_con.nss | 1 + src/include/prc_weap_apt.nss | 4 +- src/include/prc_x2_craft.nss | 744 +++- src/include/prc_x2_itemprop.nss | 161 +- src/include/prcsp_archmaginc.nss | 1 + src/include/psi_inc_ac_spawn.nss | 1 + src/include/psi_inc_core.nss | 398 +- src/include/psi_inc_metapsi.nss | 1 + src/include/psi_inc_powknown.nss | 6 +- src/include/psi_inc_ppoints.nss | 11 +- src/include/psi_inc_psicraft.nss | 3 +- src/include/psi_inc_psifunc.nss | 30 +- src/include/psi_inc_pwresist.nss | 1 + src/include/psi_spellhook.nss | 10 + src/include/shd_inc_mystknwn.nss | 6 +- src/include/shd_inc_shdfunc.nss | 7 +- src/include/shd_mysthook.nss | 15 +- src/include/tob_inc_tobfunc.nss | 1 + src/include/tob_movehook.nss | 10 +- src/include/true_inc_truespk.nss | 3 + src/include/true_inc_trufunc.nss | 1 + src/include/true_inc_truknwn.nss | 1 + src/include/true_utterhook.nss | 11 + src/include/x2_inc_spellhook.nss | 209 +- src/include/x3_inc_horse.nss | 5 +- src/module/git/wildernessenc001.git.json | 2 +- 197 files changed, 25660 insertions(+), 1516 deletions(-) create mode 100644 src/_removed/nw_s2_animalcom.nss create mode 100644 src/_removed/nw_s2_familiar.nss create mode 100644 src/_removed/original spells/nw_s0_burnhand.nss create mode 100644 src/_removed/original spells/nw_s0_calllghtn.nss create mode 100644 src/_removed/original spells/nw_s0_chlightn.nss create mode 100644 src/_removed/original spells/nw_s0_conecold.nss create mode 100644 src/_removed/original spells/nw_s0_delfirebal.nss create mode 100644 src/_removed/original spells/nw_s0_eleswarm.nss create mode 100644 src/_removed/original spells/nw_s0_fireball.nss create mode 100644 src/_removed/original spells/nw_s0_firestrm.nss create mode 100644 src/_removed/original spells/nw_s0_flmarrow.nss create mode 100644 src/_removed/original spells/nw_s0_flmlash.nss create mode 100644 src/_removed/original spells/nw_s0_flmstrike.nss create mode 100644 src/_removed/original spells/nw_s0_icestorm.nss create mode 100644 src/_removed/original spells/nw_s0_implosion.nss create mode 100644 src/_removed/original spells/nw_s0_inccloud.nss create mode 100644 src/_removed/original spells/nw_s0_incclouda.nss create mode 100644 src/_removed/original spells/nw_s0_inccloudb.nss create mode 100644 src/_removed/original spells/nw_s0_inccloudc.nss create mode 100644 src/_removed/original spells/nw_s0_lghtnbolt.nss create mode 100644 src/_removed/original spells/nw_s0_metswarm.nss create mode 100644 src/_removed/original spells/nw_s0_prisspray.nss create mode 100644 src/_removed/original spells/nw_s0_rayfrost.nss create mode 100644 src/_removed/original spells/nw_s0_searlght.nss create mode 100644 src/_removed/original spells/nw_s0_sndburst.nss create mode 100644 src/_removed/original spells/nw_s0_stormvenc.nss create mode 100644 src/_removed/original spells/nw_s0_stormveng.nss create mode 100644 src/_removed/original spells/nw_s0_summon.nss create mode 100644 src/_removed/original spells/nw_s0_summon1.nss create mode 100644 src/_removed/original spells/nw_s0_summon2.nss create mode 100644 src/_removed/original spells/nw_s0_summon3.nss create mode 100644 src/_removed/original spells/nw_s0_summon4.nss create mode 100644 src/_removed/original spells/nw_s0_summon5.nss create mode 100644 src/_removed/original spells/nw_s0_summon6.nss create mode 100644 src/_removed/original spells/nw_s0_summon7.nss create mode 100644 src/_removed/original spells/nw_s0_summon8.nss create mode 100644 src/_removed/original spells/nw_s0_summon9.nss create mode 100644 src/_removed/original spells/nw_s0_sunbeam.nss create mode 100644 src/_removed/original spells/nw_s0_wailbansh.nss create mode 100644 src/_removed/original spells/nw_s0_wallfire.nss create mode 100644 src/_removed/original spells/nw_s0_wallfirea.nss create mode 100644 src/_removed/original spells/nw_s0_wallfirec.nss create mode 100644 src/_removed/original spells/x0_s0_bombard.nss create mode 100644 src/_removed/original spells/x0_s0_drown.nss create mode 100644 src/_removed/original spells/x0_s0_earthquake.nss create mode 100644 src/_removed/original spells/x0_s0_elecjolt.nss create mode 100644 src/_removed/original spells/x0_s0_firebrand.nss create mode 100644 src/_removed/original spells/x0_s0_flare.nss create mode 100644 src/_removed/original spells/x0_s0_gustwind.nss create mode 100644 src/_removed/original spells/x0_s0_inferno.nss create mode 100644 src/_removed/original spells/x0_s0_ironhorn.nss create mode 100644 src/_removed/original spells/x0_s0_sunburst.nss create mode 100644 src/_removed/original spells/x2_s0_combust.nss create mode 100644 src/_removed/original spells/x2_s0_elecloop.nss create mode 100644 src/_removed/original spells/x2_s0_grtthdclp.nss create mode 100644 src/_removed/original spells/x2_s0_hellinfern.nss create mode 100644 src/_removed/original spells/x2_s0_horiboom.nss create mode 100644 src/_removed/original spells/x2_s0_scntsphere.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_burnhand.ncs create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_burnhand.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_calllghtn.ncs create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_calllghtn.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_chlightn.ncs create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_chlightn.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_conecold.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_delfirebal.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_eleswarm.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_fireball.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_firestrm.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_flmarrow.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_flmlash.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_flmstrike.ncs create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_flmstrike.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_icestorm.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_implosion.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_inccloud.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_incclouda.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_inccloudb.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_inccloudc.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_lghtnbolt.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_metswarm.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_sndburst.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_stormvenc.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_stormveng.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_summon.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_sunbeam.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_wailbansh.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_wallfire.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_wallfirea.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/nw_s0_wallfirec.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/x0_s0_bombard.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/x0_s0_earthquake.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/x0_s0_firebrand.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/x0_s0_gustwind.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/x0_s0_inferno.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/x0_s0_ironhorn.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/x0_s0_sunburst.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/x2_s0_combust.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/x2_s0_elecloop.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/x2_s0_grtthdclp.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/x2_s0_hellinfern.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/x2_s0_horiboom.nss create mode 100644 src/hakpak/ghost_prc8_top/nss/x2_s0_scntsphere.nss create mode 100644 src/include/inc_infusion.nss create mode 100644 src/include/nw_inc_gff.nss create mode 100644 src/include/prc_inc_json.nss create mode 100644 src/include/prc_inc_size.nss create mode 100644 src/include/prc_nui_com_inc.nss create mode 100644 src/include/prc_nui_lv_inc.nss rename src/include/{prc_nui_sc_inc.nss => prc_nui_sb_inc.nss} (76%) rename src/include/{prc_nui_scd_inc.nss => prc_nui_sbd_inc.nss} (93%) diff --git a/nasher.cfg b/nasher.cfg index d014653..3399623 100644 --- a/nasher.cfg +++ b/nasher.cfg @@ -231,9 +231,16 @@ description = "PRC8 version of C2 - The Ghost Tower of Inverness." filter = "prc_nui_sc_inc.nss" filter = "prc_nui_scd_inc.nss" filter = "prc_nui_consts.nss" - filter = "nw_inc_nui" + filter = "nw_inc_nui.nss" filter = "xchst_inc.nss" - + filter = "prc_nui_sbd_inc.nss" + filter = "prc_nui_sb_inc.nss" + filter = "prc_nui_lv_inc.nss" + filter = "prc_nui_com_inc.nss" + filter = "prc_inc_size.nss" + filter = "prc_inc_json.nss" + filter = "prc_inc_gff.nss" + filter = "inc_infusion.nss" [target] name = "abysshak" file = "aby01_ele_fancy.hak" @@ -462,8 +469,15 @@ description = "PRC8 merge hakpak for PRC8 version of C2 - The Ghost Tower of Inv 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" - + filter = "nw_inc_nui.nss" + filter = "xchst_inc.nss" + filter = "prc_nui_sbd_inc.nss" + filter = "prc_nui_sb_inc.nss" + filter = "prc_nui_lv_inc.nss" + filter = "prc_nui_com_inc.nss" + filter = "prc_inc_size.nss" + filter = "prc_inc_json.nss" + filter = "prc_inc_gff.nss" + filter = "inc_infusion.nss" [target.rules] "*" = "src/hakpak/ghost_prc8_top/$ext" \ No newline at end of file diff --git a/src/_removed/nw_s2_animalcom.nss b/src/_removed/nw_s2_animalcom.nss new file mode 100644 index 0000000..db28c17 --- /dev/null +++ b/src/_removed/nw_s2_animalcom.nss @@ -0,0 +1,28 @@ +//:://///////////////////////////////////////////// +//:: Summon Animal Companion +//:: NW_S2_AnimalComp +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + This spell summons a Druid's animal companion +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Sept 27, 2001 +//::////////////////////////////////////////////// + +void main() +{ + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + //Spell fails if caster is underwater. + if (nInt == 1) + { + FloatingTextStringOnCreature("You cannot summon your companion underwater!", oPC); + } + if (nInt != 1) + { + //Summons companion if PC is on land. + SummonAnimalCompanion(); + } +} diff --git a/src/_removed/nw_s2_familiar.nss b/src/_removed/nw_s2_familiar.nss new file mode 100644 index 0000000..dca3f3a --- /dev/null +++ b/src/_removed/nw_s2_familiar.nss @@ -0,0 +1,28 @@ +//:://///////////////////////////////////////////// +//:: Summon Familiar +//:: NW_S2_Familiar +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + This spell summons an Arcane casters familiar +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Sept 27, 2001 +//::////////////////////////////////////////////// + +void main() +{ + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + //Spell fails if caster is underwater. + if (nInt == 1) + { + FloatingTextStringOnCreature("You cannot summon your familiar underwater!", oPC); + } + if (nInt != 1) + { + //Summons companion if PC is on land. + SummonFamiliar(); + } +} diff --git a/src/_removed/original spells/nw_s0_burnhand.nss b/src/_removed/original spells/nw_s0_burnhand.nss new file mode 100644 index 0000000..9e95ddd --- /dev/null +++ b/src/_removed/original spells/nw_s0_burnhand.nss @@ -0,0 +1,112 @@ +//:://///////////////////////////////////////////// +//:: Burning Hands +//:: NW_S0_BurnHand +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* +// A thin sheet of searing flame shoots from your +// outspread fingertips. You must hold your hands +// with your thumbs touching and your fingers spread +// The sheet of flame is about as thick as your thumbs. +// Any creature in the area of the flames suffers +// 1d4 points of fire damage per your caster level +// (maximum 5d4). +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 5, 2001 +//::////////////////////////////////////////////// +//:: Last Updated On: April 5th, 2001 +//:: VFX Pass By: Preston W, On: June 20, 2001 +//:: Update Pass By: Preston W, On: July 23, 2001 + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + object oPC = GetFirstPC(); + object oCaster = OBJECT_SELF; + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Spell will fail if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Burning Hands' will not work underwater!", oPC); + return; + } +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more +*/ + +if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + float fDist; + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + int nMetaMagic = GetMetaMagicFeat(); + int nDamage; + object oTarget; + effect eFire; + //Declare and assign personal impact visual effect. + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_S); + //Limit Maximum caster level to keep damage to spell specifications. + if (nCasterLevel > 5) + { + nCasterLevel = 5; + } + //Cycle through the targets within the spell shape until an invalid object is captured. + if (nInt != 1) + { + //Declare the spell shape, size and the location. Capture the first target object in the shape. + oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 10.0, GetSpellTargetLocation(), TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + + while(GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + //Signal spell cast at event to fire. + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_BURNING_HANDS)); + //Calculate the delay time on the application of effects based on the distance + //between the caster and the target + fDist = GetDistanceBetween(OBJECT_SELF, oTarget)/20; + //Make SR check, and appropriate saving throw. + if(!MyResistSpell(OBJECT_SELF, oTarget, fDist) && oTarget != OBJECT_SELF) + { + nDamage = d4(nCasterLevel); + //Enter Metamagic conditions + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 4 * nCasterLevel;//Damage is at max + } + else if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + (nDamage/2); //Damage/Healing is +50% + } + //Run the damage through the various reflex save and evasion feats + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_FIRE); + eFire = EffectDamage(nDamage, DAMAGE_TYPE_FIRE); + if(nDamage > 0) + { + // Apply effects to the currently selected target. + DelayCommand(fDist, ApplyEffectToObject(DURATION_TYPE_INSTANT, eFire, oTarget)); + DelayCommand(fDist, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + } + //Select the next target within the spell shape. + oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 10.0, GetSpellTargetLocation(), TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } + } +} diff --git a/src/_removed/original spells/nw_s0_calllghtn.nss b/src/_removed/original spells/nw_s0_calllghtn.nss new file mode 100644 index 0000000..f1f13de --- /dev/null +++ b/src/_removed/original spells/nw_s0_calllghtn.nss @@ -0,0 +1,166 @@ +//:://///////////////////////////////////////////// +//:: Call Lightning +//:: NW_S0_CallLghtn.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + This spells smites an area around the caster + with bolts of lightning which strike all enemies. + Bolts do 1d10 per level up 10d10 +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: May 22, 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 20, 2001 + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + object oCaster = OBJECT_SELF; + int nCasterLvl = GetCasterLevel(oCaster); + int nMetaMagic = GetMetaMagicFeat(); + int nDamage; + float fDelay; + effect eVis = EffectVisualEffect(VFX_IMP_LIGHTNING_M); + effect eDam; + //Get the spell target location as opposed to the spell target. + location lTarget = GetSpellTargetLocation(); + //Limit Caster level for the purposes of damage + if (nCasterLvl > 10) + { + nCasterLvl = 10; + } + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Call Lightning' will not work underwater!", oPC); + return; + } + //Declare the spell shape, size and the location. Capture the first target object in the shape. + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, OBJECT_SELF)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_FIREBALL)); + //Get the distance between the explosion and the target to calculate delay + fDelay = GetRandomDelay(0.4, 1.75); + if (!MyResistSpell(OBJECT_SELF, oTarget, fDelay)) + { + //Roll damage for each target + nDamage = d6(nCasterLvl); + //Resolve metamagic + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 6 * nCasterLvl; + } + else if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + nDamage / 2; + } + //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_ELECTRICITY); + //Set the damage effect + eDam = EffectDamage(nDamage, DAMAGE_TYPE_ELECTRICAL); + if(nDamage > 0) + { + // Apply effects to the currently selected target. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + //This visual effect is applied to the target object not the location as above. This visual effect + //represents the flame that erupts on the target not on the ground. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + } + //Select the next target within the spell shape. + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Call Lightning' has caused a cave-in!", oPC)); + } +} diff --git a/src/_removed/original spells/nw_s0_chlightn.nss b/src/_removed/original spells/nw_s0_chlightn.nss new file mode 100644 index 0000000..a2e4dd5 --- /dev/null +++ b/src/_removed/original spells/nw_s0_chlightn.nss @@ -0,0 +1,255 @@ +//:://///////////////////////////////////////////// +//:: Chain Lightning +//:: NW_S0_ChLightn +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + The primary target is struck with 1d6 per caster, + 1/2 with a reflex save. 1 secondary target per + level is struck for 1d6 / 2 caster levels. No + repeat targets can be chosen. +*/ +//::////////////////////////////////////////////// +//:: Created By: Brennon Holmes +//:: Created On: March 8, 2001 +//::////////////////////////////////////////////// +//:: Last Updated By: Preston Watamaniuk, On: April 26, 2001 +//:: Update Pass By: Preston W, On: July 26, 2001 + +/* +bugfix by Kovi 2002.07.28 +- successful saving throw and (improved) evasion was ignored for + secondary targets, +- all secondary targets suffered exactly the same damage +2002.08.25 +- primary target was not effected +*/ + +#include "x0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + object oCaster = OBJECT_SELF; + int nDoOnce = 0; + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + int nDamage = d6(nCasterLevel); + int nDamStrike; + int nNumAffected = 0; + int nMetaMagic = GetMetaMagicFeat(); + //Declare lightning effect connected the casters hands + effect eLightning = EffectBeam(VFX_BEAM_LIGHTNING, OBJECT_SELF, BODY_NODE_HAND);; + effect eVis = EffectVisualEffect(VFX_IMP_LIGHTNING_S); + effect eDamage; + object oFirstTarget = GetSpellTargetObject(); + object oHolder; + object oTarget; + location lSpellLocation; + //Limit caster level + if (nCasterLevel > 20) + { + nCasterLevel = 20; + } + //Enter Metamagic conditions + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 6 * nCasterLevel;//Damage is at max + } + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + (nDamage/2); //Damage/is +50% + } + //Damage the initial target + if (spellsIsTarget(oFirstTarget, SPELL_TARGET_SELECTIVEHOSTILE, OBJECT_SELF)) + { + //Fire cast spell at event for the specified target + SignalEvent(oFirstTarget, EventSpellCastAt(OBJECT_SELF, SPELL_CHAIN_LIGHTNING)); + //Make an SR Check + if (!MyResistSpell(OBJECT_SELF, oFirstTarget)) + { + //Adjust damage via Reflex Save or Evasion or Improved Evasion + nDamStrike = GetReflexAdjustedDamage(nDamage, oFirstTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_ELECTRICITY); + //Set the damage effect for the first target + eDamage = EffectDamage(nDamStrike, DAMAGE_TYPE_ELECTRICAL); + //Apply damage to the first target and the VFX impact. + if(nDamStrike > 0) + { + //Apply the VFX impact and damage effect (reflected upon PC) + if ((nInt == 1)&&(nDoOnce != 1)) + { + ApplyEffectToObject(DURATION_TYPE_INSTANT,eDamage,oCaster); + ApplyEffectToObject(DURATION_TYPE_INSTANT,eVis,oCaster); + FloatingTextStringOnCreature("The spell 'Chain Lightning' is reflected underwater!", oPC); + nDoOnce = 1; + } + ApplyEffectToObject(DURATION_TYPE_INSTANT,eDamage,oFirstTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT,eVis,oFirstTarget); + } + } + } + //Apply the lightning stream effect to the first target, connecting it with the caster + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eLightning,oFirstTarget,0.5); + + + //Reinitialize the lightning effect so that it travels from the first target to the next target + eLightning = EffectBeam(VFX_BEAM_LIGHTNING, oFirstTarget, BODY_NODE_CHEST); + + + float fDelay = 0.2; + int nCnt = 0; + + + // * + // * Secondary Targets + // * + + + //Get the first target in the spell shape + oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(oFirstTarget), TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + while (GetIsObjectValid(oTarget) && nCnt < nCasterLevel) + { + //Make sure the caster's faction is not hit and the first target is not hit + if (oTarget != oFirstTarget && spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, OBJECT_SELF) && oTarget != OBJECT_SELF) + { + //Connect the new lightning stream to the older target and the new target + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eLightning,oTarget,0.5)); + + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_CHAIN_LIGHTNING)); + //Do an SR check + if (!MyResistSpell(OBJECT_SELF, oTarget, fDelay)) + { + + nDamage = d6(nCasterLevel) ; + + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 6 * nCasterLevel;//Damage is at max + } + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + (nDamage/2); //Damage/is +50% + } + //Adjust damage via Reflex Save or Evasion or Improved Evasion + nDamStrike = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_ELECTRICITY); + //Apply the damage and VFX impact to the current target + eDamage = EffectDamage(nDamStrike /2, DAMAGE_TYPE_ELECTRICAL); + if(nDamStrike > 0) //age > 0) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT,eDamage,oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT,eVis,oTarget)); + } + } + oHolder = oTarget; + + //change the currect holder of the lightning stream to the current target + if (GetObjectType(oTarget) == OBJECT_TYPE_CREATURE) + { + eLightning = EffectBeam(VFX_BEAM_LIGHTNING, oHolder, BODY_NODE_CHEST); + } + else + { + // * April 2003 trying to make sure beams originate correctly + effect eNewLightning = EffectBeam(VFX_BEAM_LIGHTNING, oHolder, BODY_NODE_CHEST); + if(GetIsEffectValid(eNewLightning)) + { + eLightning = eNewLightning; + } + } + + fDelay = fDelay + 0.1f; + } + //Count the number of targets that have been hit. + if(GetObjectType(oTarget) == OBJECT_TYPE_CREATURE) + { + nCnt++; + } + + // April 2003: Setting the new origin for the beam + // oFirstTarget = oTarget; + + //Get the next target in the shape. + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(oFirstTarget), TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } + //Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Chain Lightning' has caused a cave-in!", oPC)); + } + } diff --git a/src/_removed/original spells/nw_s0_conecold.nss b/src/_removed/original spells/nw_s0_conecold.nss new file mode 100644 index 0000000..aa3b874 --- /dev/null +++ b/src/_removed/original spells/nw_s0_conecold.nss @@ -0,0 +1,100 @@ +//:://///////////////////////////////////////////// +//:: Cone of Cold +//:: NW_S0_ConeCold +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* +// Cone of cold creates an area of extreme cold, +// originating at your hand and extending outward +// in a cone. It drains heat, causing 1d6 points of +// cold damage per caster level (maximum 15d6). +*/ +//::////////////////////////////////////////////// +//:: Created By: Noel Borstad +//:: Created On: 10/18/02000 +//::////////////////////////////////////////////// +//:: Last Updated By: Aidan Scanlan On: April 11, 2001 +//:: Update Pass By: Preston W, On: July 25, 2001 + +float SpellDelay (object oTarget, int nShape); + +#include "X0_I0_SPELLS" +void main() +{ + //Declare major variables + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + object oCaster = OBJECT_SELF; + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + int nMetaMagic = GetMetaMagicFeat(); + int nDamage; + float fDelay; + location lTargetLocation = GetSpellTargetLocation(); + object oTarget; + //Limit Caster level for the purposes of damage. + if (nCasterLevel > 15) + { + nCasterLevel = 15; + } + //Declare the spell shape, size and the location. Capture the first target object in the shape. + oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 11.0, lTargetLocation, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while(GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + // March 2003. Removed this as part of the reputation pass + // if((GetSpellId() == 340 && !GetIsFriend(oTarget)) || GetSpellId() == 25) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_CONE_OF_COLD)); + //Get the distance between the target and caster to delay the application of effects + fDelay = GetDistanceBetween(OBJECT_SELF, oTarget)/20.0; + //Make SR check, and appropriate saving throw(s). + if(!MyResistSpell(OBJECT_SELF, oTarget, fDelay) && (oTarget != OBJECT_SELF)) + { + //Detemine damage + nDamage = d6(nCasterLevel); + //Enter Metamagic conditions + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 6 * nCasterLevel;//Damage is at max + } + else if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + (nDamage/2); //Damage/Healing is +50% + } + //Adjust damage according to Reflex Save, Evasion or Improved Evasion + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_COLD); + + // Apply effects to the currently selected target. + effect eCold = EffectDamage(nDamage, DAMAGE_TYPE_COLD); + effect eVis = EffectVisualEffect(VFX_IMP_FROST_L); + if(nDamage > 0) + { + //Apply the VFX impact and damage effect (reflected upon PC) + if (nInt == 1) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oCaster)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eCold, oCaster)); + FloatingTextStringOnCreature("The spell 'Cone of Cold' is reflected underwater!", oPC); + } + //Apply delayed effects + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eCold, oTarget)); + } + } + } + } + //Select the next target within the spell shape. + oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 11.0, lTargetLocation, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } + // TK added for cheat casting + if (GetLocalInt(OBJECT_SELF, "AI_CHEAT_CASTING")) + { + // shades = 158 + DecrementRemainingSpellUses(OBJECT_SELF, 158); + DeleteLocalInt(OBJECT_SELF, "AI_CHEAT_CASTING"); + } +} + diff --git a/src/_removed/original spells/nw_s0_delfirebal.nss b/src/_removed/original spells/nw_s0_delfirebal.nss new file mode 100644 index 0000000..aee5eed --- /dev/null +++ b/src/_removed/original spells/nw_s0_delfirebal.nss @@ -0,0 +1,132 @@ +//:://///////////////////////////////////////////// +//:: Delayed Blast Fireball +//:: NW_S0_DelFirebal.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + The caster creates a trapped area which detects + the entrance of enemy creatures into 3 m area + around the spell location. When tripped it + causes a fiery explosion that does 1d6 per + caster level up to a max of 20d6 damage. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: July 27, 2001 +//::////////////////////////////////////////////// + +#include "x2_inc_spellhook" + +void main() +{ + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Delayed Blast Fireball' will not work underwater!", oPC); + return; + } +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables including Area of Effect Object + effect eAOE = EffectAreaOfEffect(AOE_PER_DELAY_BLAST_FIREBALL); + location lTarget = GetSpellTargetLocation(); + int nDuration = GetCasterLevel(OBJECT_SELF) / 2; + //Create an instance of the AOE Object using the Apply Effect function + if (nInt != 1) + { + //Make sure the duration is at least one round + if (nDuration == 0) + { + nDuration = 1; + } + int nMetaMagic = GetMetaMagicFeat(); + //Check Extend metamagic feat. + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2;//Duration is +100% + } + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eAOE, lTarget, RoundsToSeconds(nDuration)); + } +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Delayed Blast Fireball' has caused a cave-in!", oPC)); + } +} + + diff --git a/src/_removed/original spells/nw_s0_eleswarm.nss b/src/_removed/original spells/nw_s0_eleswarm.nss new file mode 100644 index 0000000..ca4319c --- /dev/null +++ b/src/_removed/original spells/nw_s0_eleswarm.nss @@ -0,0 +1,70 @@ +//:://///////////////////////////////////////////// +//:: Elemental Swarm +//:: NW_S0_EleSwarm.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + This spell creates a conduit from the caster + to the elemental planes. The first elemental + summoned is a 24 HD Air elemental. Whenever an + elemental dies it is replaced by the next + elemental in the chain Air, Earth, Water, Fire +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 12, 2001 +//::////////////////////////////////////////////// +//:: Update Pass By: Preston W, On: July 30, 2001 + +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + int nMetaMagic = GetMetaMagicFeat(); + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + int nDuration = GetCasterLevel(OBJECT_SELF); + nDuration = 24; + effect eSummon; + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_3); + //Check for metamagic duration + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration * 2; //Duration is +100% + } + //Set the summoning effect + eSummon = EffectSwarm(FALSE, "NW_SW_AIRGREAT", "NW_SW_WATERGREAT","NW_SW_EARTHGREAT","NW_SW_FIREGREAT"); + //Spell fails if caster is underwater. + if (nInt == 1) + { + eSummon = EffectSwarm(FALSE, "NW_SW_WATERGREAT", "NW_SW_WATERGREAT","NW_SW_WATERGREAT","NW_SW_WATERGREAT"); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eSummon, OBJECT_SELF, HoursToSeconds(nDuration)); + } + //Apply the summon effect + if (nInt != 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eSummon, OBJECT_SELF, HoursToSeconds(nDuration)); + } +} + diff --git a/src/_removed/original spells/nw_s0_fireball.nss b/src/_removed/original spells/nw_s0_fireball.nss new file mode 100644 index 0000000..00b912e --- /dev/null +++ b/src/_removed/original spells/nw_s0_fireball.nss @@ -0,0 +1,175 @@ +//:://///////////////////////////////////////////// +//:: Fireball +//:: NW_S0_Fireball +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* +// A fireball is a burst of flame that detonates with +// a low roar and inflicts 1d6 points of damage per +// caster level (maximum of 10d6) to all creatures +// within the area. Unattended objects also take +// damage. The explosion creates almost no pressure. +*/ +//::////////////////////////////////////////////// +//:: Created By: Noel Borstad +//:: Created On: Oct 18 , 2000 +//::////////////////////////////////////////////// +//:: Last Updated By: Preston Watamaniuk, On: April 6, 2001 +//:: Last Updated By: AidanScanlan, On: April 11, 2001 +//:: Last Updated By: Preston Watamaniuk, On: May 25, 2001 + +#include "nw_i0_2q4luskan" +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nUA = GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Spell fails if caster is underwater. + if (nUA == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Fireball' will not work underwater!", oPC); + return; + } +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + int nCasterLvl = GetCasterLevel(oCaster); + int nMetaMagic = GetMetaMagicFeat(); + int nDamage; + float fDelay; + effect eExplode = EffectVisualEffect(VFX_FNF_FIREBALL); + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_M); + effect eDam; + //Get the spell target location as opposed to the spell target. + location lTarget = GetSpellTargetLocation(); + //Limit Caster level for the purposes of damage + if (nCasterLvl > 10) + { + nCasterLvl = 10; + } + //Apply the fireball explosion at the location captured above. + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, lTarget); + //Declare the spell shape, size and the location. Capture the first target object in the shape. + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget)) + { + if((GetSpellId() == 341) || GetSpellId() == 58) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_FIREBALL)); + //Get the distance between the explosion and the target to calculate delay + fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oTarget))/20; + if (!MyResistSpell(OBJECT_SELF, oTarget, fDelay)) + { + //Roll damage for each target + nDamage = d6(nCasterLvl); + //Resolve metamagic + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 6 * nCasterLvl; + } + else if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + nDamage / 2; + } + //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_FIRE); + //Set the damage effect + eDam = EffectDamage(nDamage, DAMAGE_TYPE_FIRE); + if(nDamage > 0) + { + // Apply effects to the currently selected target. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + //This visual effect is applied to the target object not the location as above. This visual effect + //represents the flame that erupts on the target not on the ground. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + } + //Select the next target within the spell shape. + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Fireball' has caused a cave-in!", oPC)); + } + +} + diff --git a/src/_removed/original spells/nw_s0_firestrm.nss b/src/_removed/original spells/nw_s0_firestrm.nss new file mode 100644 index 0000000..3140cc2 --- /dev/null +++ b/src/_removed/original spells/nw_s0_firestrm.nss @@ -0,0 +1,174 @@ +//:://///////////////////////////////////////////// +//:: Fire Storm +//:: NW_S0_FireStm +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Creates a zone of destruction around the caster + within which all living creatures are pummeled + with fire. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 11, 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 21, 2001 + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Fire Storm' will not work underwater!", oPC); + return; + } +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + int nMetaMagic; + int nDamage; + int nDamage2; + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + if(nCasterLevel > 20) + { + nCasterLevel == 20; + } + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_M); + effect eFireStorm = EffectVisualEffect(VFX_FNF_FIRESTORM); + float fDelay; + //Normal spell effects. + if (nInt != 1) + { + //Apply Fire and Forget Visual in the area; + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eFireStorm, GetLocation(OBJECT_SELF)); + //Declare the spell shape, size and the location. Capture the first target object in the shape. + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(OBJECT_SELF), OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while(GetIsObjectValid(oTarget)) + { + //This spell smites everyone who is more than 2 meters away from the caster. + //if (GetDistanceBetween(oTarget, OBJECT_SELF) > 2.0) + //{ + if (spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, OBJECT_SELF) && oTarget != OBJECT_SELF) + { + fDelay = GetRandomDelay(1.5, 2.5); + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_FIRE_STORM)); + //Make SR check, and appropriate saving throw(s). + if (!MyResistSpell(OBJECT_SELF, oTarget, fDelay)) + { + //Roll Damage + nDamage = d6(nCasterLevel); + //Enter Metamagic conditions + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 6 * nCasterLevel;//Damage is at max + } + else if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + (nDamage/2);//Damage/Healing is +50% + } + //Save versus both holy and fire damage + nDamage2 = GetReflexAdjustedDamage(nDamage/2, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_DIVINE); + nDamage = GetReflexAdjustedDamage(nDamage/2, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_FIRE); + if(nDamage > 0) + { + // Apply effects to the currently selected target. For this spell we have used + //both Divine and Fire damage. + effect eDivine = EffectDamage(nDamage2, DAMAGE_TYPE_DIVINE); + effect eFire = EffectDamage(nDamage, DAMAGE_TYPE_FIRE); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eFire, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDivine, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + //} + } + //Select the next target within the spell shape. + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(OBJECT_SELF), OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } + } +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Fire Storm' has caused a cave-in!", oPC)); + } +} diff --git a/src/_removed/original spells/nw_s0_flmarrow.nss b/src/_removed/original spells/nw_s0_flmarrow.nss new file mode 100644 index 0000000..497b836 --- /dev/null +++ b/src/_removed/original spells/nw_s0_flmarrow.nss @@ -0,0 +1,111 @@ +//:://///////////////////////////////////////////// +//:: Flame Arrow +//:: NW_S0_FlmArrow +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Fires a stream of fiery arrows at the selected + target that do 4d6 damage per arrow. 1 Arrow + per 4 levels is created. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Sept 20, 2001 +//:: Updated By: Georg Zoeller, Aug 18 2003: Uncapped +//::////////////////////////////////////////////// + +#include "NW_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ +object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Flame Arrow' will not work underwater!", oPC); + return; + } +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables ( fDist / (3.0f * log( fDist ) + 2.0f) ) + object oTarget = GetSpellTargetObject(); + int nCasterLvl = GetCasterLevel(OBJECT_SELF); + int nDamage = 0; + int nMetaMagic = GetMetaMagicFeat(); + int nCnt; + effect eMissile; + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_S); + int nMissiles = (nCasterLvl)/4; + float fDist = GetDistanceBetween(OBJECT_SELF, oTarget); + float fDelay = fDist/(3.0 * log(fDist) + 2.0); + //Limit missiles to five + if(nMissiles == 0) + { + nMissiles = 1; + } + /* Uncapped because PHB does list any cap and we now got epic levels + else if (nMissiles > 5) + { + nMissiles = 5; + }*/ + //Normal spell effects. + if (nInt != 1) + { + if(!GetIsReactionTypeFriendly(oTarget)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_FLAME_ARROW)); + //Apply a single damage hit for each missile instead of as a single mass + //Make SR Check + for (nCnt = 1; nCnt <= nMissiles; nCnt++) + { + if(!MyResistSpell(OBJECT_SELF, oTarget, fDelay)) + { + + //Roll damage + int nDam = d6(4) + 1; + //Enter Metamagic conditions + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDam = 24;//Damage is at max + } + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDam = nDam + nDam/2; //Damage/Healing is +50% + } + nDam = GetReflexAdjustedDamage(nDam, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_FIRE); + //Set damage effect + effect eDam = EffectDamage(nDam, DAMAGE_TYPE_FIRE); + //Apply the MIRV and damage effect + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eVis, oTarget)); + + } + // * May 2003: Make it so the arrow always appears, even if resisted + eMissile = EffectVisualEffect(VFX_IMP_MIRV_FLAME); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eMissile, oTarget); + } + } + } +} + diff --git a/src/_removed/original spells/nw_s0_flmlash.nss b/src/_removed/original spells/nw_s0_flmlash.nss new file mode 100644 index 0000000..2882638 --- /dev/null +++ b/src/_removed/original spells/nw_s0_flmlash.nss @@ -0,0 +1,91 @@ +//:://///////////////////////////////////////////// +//:: Flame Lash +//:: NW_S0_FlmLash.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Creates a whip of fire that targets a single + individual +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Nov 21, 2001 +//::////////////////////////////////////////////// + +#include "NW_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Flame Lash' will not work underwater!", oPC); + return; + } +/* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oTarget = GetSpellTargetObject(); + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + int nMetaMagic = GetMetaMagicFeat(); + if(nCasterLevel > 3) + { + nCasterLevel = (nCasterLevel-3)/2; + } + int nDamage = d6(2 + nCasterLevel); + + //Enter Metamagic conditions + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 6 * (2 + nCasterLevel);//Damage is at max + } + else if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + (nDamage/2); //Damage/Healing is +50% + } + //Normal spell effects. + if (nInt != 1) + { + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_S); + effect eRay = EffectBeam(VFX_BEAM_FIRE_LASH, OBJECT_SELF, BODY_NODE_HAND); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eRay, oTarget, 1.7); + + if(!GetIsReactionTypeFriendly(oTarget)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_FLAME_LASH)); + if (!MyResistSpell(OBJECT_SELF, oTarget, 1.0)) + { + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_FIRE); + effect eDam = EffectDamage(nDamage, DAMAGE_TYPE_FIRE); + if(nDamage > 0) + { + //Apply the VFX impact and effects + DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + } + } + } + } +} diff --git a/src/_removed/original spells/nw_s0_flmstrike.nss b/src/_removed/original spells/nw_s0_flmstrike.nss new file mode 100644 index 0000000..fca55da --- /dev/null +++ b/src/_removed/original spells/nw_s0_flmstrike.nss @@ -0,0 +1,177 @@ +//:://///////////////////////////////////////////// +//:: Flame Strike +//:: NW_S0_FlmStrike +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* +// A flame strike is a vertical column of divine fire +// roaring downward. The spell deals 1d6 points of +// damage per level, to a maximum of 15d6. Half the +// damage is fire damage, but the rest of the damage +// results directly from divine power and is therefore +// not subject to protection from elements (fire), +// fire shield (chill shield), etc. +*/ +//::////////////////////////////////////////////// +//:: Created By: Noel Borstad +//:: Created On: Oct 19, 2000 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 20, 2001 +//:: Update Pass By: Preston W, On: Aug 1, 2001 + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Flame Strike' will not work underwater!", oPC); + return; + } +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oTarget; + int nCasterLvl = GetCasterLevel(OBJECT_SELF); + int nDamage, nDamage2; + int nMetaMagic = GetMetaMagicFeat(); + effect eStrike = EffectVisualEffect(VFX_IMP_DIVINE_STRIKE_FIRE); + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_S); + effect eHoly; + effect eFire; + //Limit caster level for the purposes of determining damage. + if (nCasterLvl > 15) + { + nCasterLvl = 15; + } + + if (nInt != 1) + { + //Declare the spell shape, size and the location. Capture the first target object in the shape. + oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, GetSpellTargetLocation(), FALSE, OBJECT_TYPE_CREATURE|OBJECT_TYPE_PLACEABLE|OBJECT_TYPE_DOOR); + //Apply the location impact visual to the caster location instead of caster target creature. + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eStrike, GetSpellTargetLocation()); + //Cycle through the targets within the spell shape until an invalid object is captured. + while ( GetIsObjectValid(oTarget) ) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_FLAME_STRIKE)); + //Make SR check, and appropriate saving throw(s). + if (!MyResistSpell(OBJECT_SELF, oTarget, 0.6)) + { + nDamage = d6(nCasterLvl); + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 6 * nCasterLvl; + } + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + (nDamage/2); + } + //Adjust the damage based on Reflex Save, Evasion and Improved Evasion + nDamage2 = GetReflexAdjustedDamage(nDamage/2, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_DIVINE); + nDamage = GetReflexAdjustedDamage(nDamage/2, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_FIRE); + //Make a faction check so that only enemies receieve the full brunt of the damage. + if(!GetIsFriend(oTarget)) + { + eHoly = EffectDamage(nDamage2,DAMAGE_TYPE_DIVINE); + DelayCommand(0.6, ApplyEffectToObject(DURATION_TYPE_INSTANT, eHoly, oTarget)); + } + // Apply effects to the currently selected target. + eFire = EffectDamage(nDamage,DAMAGE_TYPE_FIRE); + if(nDamage > 0) + { + DelayCommand(0.6, ApplyEffectToObject(DURATION_TYPE_INSTANT, eFire, oTarget)); + DelayCommand(0.6, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + } + //Select the next target within the spell shape. + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM,GetSpellTargetLocation(), FALSE, OBJECT_TYPE_CREATURE|OBJECT_TYPE_PLACEABLE|OBJECT_TYPE_DOOR); + } + } +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Flame Strike' has caused a cave-in!", oPC)); + } +} diff --git a/src/_removed/original spells/nw_s0_icestorm.nss b/src/_removed/original spells/nw_s0_icestorm.nss new file mode 100644 index 0000000..34ba052 --- /dev/null +++ b/src/_removed/original spells/nw_s0_icestorm.nss @@ -0,0 +1,171 @@ +//:://///////////////////////////////////////////// +//:: Ice Storm +//:: NW_S0_IceStorm +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Everyone in the area takes 3d6 Bludgeoning + and 2d6 Cold damage. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Sept 12, 2001 +//::////////////////////////////////////////////// + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + object oCaster = OBJECT_SELF; + int nCasterLvl = GetCasterLevel(oCaster); + int nMetaMagic = GetMetaMagicFeat(); + int nDamage, nDamage2, nDamage3; + int nVariable = nCasterLvl/3; + float fDelay; + effect eExplode = EffectVisualEffect(VFX_FNF_ICESTORM); //USE THE ICESTORM FNF + effect eVis = EffectVisualEffect(VFX_IMP_FROST_S); + effect eDam,eDam2, eDam3; + //Get the spell target location as opposed to the spell target. + location lTarget = GetSpellTargetLocation(); + //Apply the ice storm VFX at the location captured above. + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, lTarget); + //Declare the spell shape, size and the location. Capture the first target object in the shape. + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + fDelay = GetRandomDelay(0.75, 2.25); + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_ICE_STORM)); + if (!MyResistSpell(OBJECT_SELF, oTarget, fDelay)) + { + //Roll damage for each target + nDamage = d6(3); + nDamage2 = d6(2); + nDamage3 = d6(nVariable); + //Resolve metamagic + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 18; + nDamage2 = 12; + nDamage3 = 6 * nVariable; + } + else if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + (nDamage / 2); + nDamage2 = nDamage2 + (nDamage2 / 2); + nDamage3 = nDamage3 + (nDamage3 / 2); + } + nDamage2 = nDamage2 + nDamage3; + //Set the damage effect + eDam = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING); + eDam2 = EffectDamage(nDamage2, DAMAGE_TYPE_COLD); + //Apply the VFX impact and damage effect (reflected upon PC) + if (nInt == 1) + { + //Apply the ice storm VFX at the location captured above. + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, GetLocation(oCaster)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oCaster)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam2, oCaster)); + //This visual effect is applied to the target object not the location as above. This visual effect + //represents the impact that erupts on the target not on the ground. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oCaster)); + FloatingTextStringOnCreature("The spell 'Ice Storm' is reflected underwater!", oPC); + } + // Apply effects to the currently selected target. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam2, oTarget)); + //This visual effect is applied to the target object not the location as above. This visual effect + //represents the impact that erupts on the target not on the ground. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + //Select the next target within the spell shape. + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Ice Storm' has caused a cave-in!", oPC)); + } +} + diff --git a/src/_removed/original spells/nw_s0_implosion.nss b/src/_removed/original spells/nw_s0_implosion.nss new file mode 100644 index 0000000..a420cdb --- /dev/null +++ b/src/_removed/original spells/nw_s0_implosion.nss @@ -0,0 +1,131 @@ +//:://///////////////////////////////////////////// +//:: Implosion +//:: NW_S0_Implosion.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + All persons within a 5ft radius of the spell must + save at +3 DC or die. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 13, 2001 +//::////////////////////////////////////////////// + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oPC = GetFirstPC(); + object oTarget; + effect eDeath = EffectDeath(TRUE); + eDeath = SupernaturalEffect(eDeath); + effect eImplode= EffectVisualEffect(VFX_FNF_IMPLOSION); + float fDelay; + //Apply the implose effect + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImplode, GetSpellTargetLocation()); + //Get the first target in the shape + oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, GetSpellTargetLocation()); + while (GetIsObjectValid(oTarget)) + { + if (oTarget != OBJECT_SELF && spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_IMPLOSION)); + fDelay = GetRandomDelay(0.4, 1.2); + //Make SR check + if (!MyResistSpell(OBJECT_SELF, oTarget, fDelay)) + { + //Make Reflex save + if(!MySavingThrow(SAVING_THROW_FORT, oTarget, GetSpellSaveDC()+3, SAVING_THROW_TYPE_DEATH, OBJECT_SELF, fDelay)) + { + //Apply death effect and the VFX impact + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDeath, oTarget)); + } + } + } + //Get next target in the shape + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, GetSpellTargetLocation()); + } +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Implosion' has caused a cave-in!", oPC)); + } +} + diff --git a/src/_removed/original spells/nw_s0_inccloud.nss b/src/_removed/original spells/nw_s0_inccloud.nss new file mode 100644 index 0000000..ca367ec --- /dev/null +++ b/src/_removed/original spells/nw_s0_inccloud.nss @@ -0,0 +1,72 @@ +//:://///////////////////////////////////////////// +//:: Incendiary Cloud +//:: NW_S0_IncCloud.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Person within the AoE take 4d6 fire damage + per round. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: May 17, 2001 +//::////////////////////////////////////////////// + +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables, including the Area of Effect object. + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + effect eAOE = EffectAreaOfEffect(AOE_PER_FOGFIRE); + //Capture the spell target location so that the AoE object can be created. + location lTarget = GetSpellTargetLocation(); + int nDuration = GetCasterLevel(OBJECT_SELF); + effect eImpact = EffectVisualEffect(260); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Incendiary Cloud' will not work underwater!", oPC); + return; + } + //Normal spell effects. + if (nInt != 1) + { + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpact, lTarget); + if(nDuration < 1) + { + nDuration = 1; + } + int nMetaMagic = GetMetaMagicFeat(); + //Check for metamagic extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + //Create the object at the location so that the objects scripts will start working. + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eAOE, lTarget, RoundsToSeconds(nDuration)); + } +} + diff --git a/src/_removed/original spells/nw_s0_incclouda.nss b/src/_removed/original spells/nw_s0_incclouda.nss new file mode 100644 index 0000000..7b6ba93 --- /dev/null +++ b/src/_removed/original spells/nw_s0_incclouda.nss @@ -0,0 +1,81 @@ +//:://///////////////////////////////////////////// +//:: Incendiary Cloud +//:: NW_S0_IncCloud.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Person within the AoE take 4d6 fire damage + per round. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: May 17, 2001 +//::////////////////////////////////////////////// +//:: March 2003: Removed movement speed penalty +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + + //Declare major variables + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + int nMetaMagic = GetMetaMagicFeat(); + int nDamage; + effect eDam; + object oTarget; + //Declare and assign personal impact visual effect. + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_S); + // effect eSpeed = EffectMovementSpeedDecrease(50); + effect eVis2 = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); + effect eLink = eVis2; //EffectLinkEffects(eSpeed, eVis2); + float fDelay; + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Incendiary Cloud' will not work underwater!", oPC); + return; + } + //Normal spell effects. + if (nInt != 1) + { + //Capture the first target object in the shape. + oTarget = GetEnteringObject(); + //Declare the spell shape, size and the location. + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, GetAreaOfEffectCreator())) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_INCENDIARY_CLOUD)); + //Make SR check, and appropriate saving throw(s). + if(!MyResistSpell(GetAreaOfEffectCreator(), oTarget, fDelay)) + { + fDelay = GetRandomDelay(0.5, 2.0); + //Roll damage. + nDamage = d6(4); + //Enter Metamagic conditions + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 24;//Damage is at max + } + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + (nDamage/2); //Damage/Healing is +50% + } + //Adjust damage for Reflex Save, Evasion and Improved Evasion + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_FIRE, GetAreaOfEffectCreator()); + // Apply effects to the currently selected target. + eDam = EffectDamage(nDamage, DAMAGE_TYPE_FIRE); + if(nDamage > 0) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + // ApplyEffectToObject(DURATION_TYPE_PERMANENT, eSpeed, oTarget); + } + } +} diff --git a/src/_removed/original spells/nw_s0_inccloudb.nss b/src/_removed/original spells/nw_s0_inccloudb.nss new file mode 100644 index 0000000..cbb77fc --- /dev/null +++ b/src/_removed/original spells/nw_s0_inccloudb.nss @@ -0,0 +1,65 @@ +//:://///////////////////////////////////////////// +//:: Incendiary Cloud: On Exit +//:: NW_S0_IncCloudB.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + All creatures within the AoE take 2d6 acid damage + per round and upon entering if they fail a Fort Save + their movement is halved. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: May 17, 2001 +//::////////////////////////////////////////////// +//:: Update Pass By: Preston W, On: July 20, 2001 + +#include "x2_inc_spellhook" + +void main() +{ + + //Declare major variables + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Get the object that is exiting the AOE + object oTarget = GetExitingObject(); + int bValid = FALSE; + effect eAOE; + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Incendiary Cloud' will not work underwater!", oPC); + return; + } + //Normal spell effects. + if (nInt != 1) + { + if(GetHasSpellEffect(SPELL_INCENDIARY_CLOUD, oTarget)) + { + //Search through the valid effects on the target. + eAOE = GetFirstEffect(oTarget); + while (GetIsEffectValid(eAOE) && bValid == FALSE) + { + if (GetEffectCreator(eAOE) == GetAreaOfEffectCreator()) + { + if(GetEffectType(eAOE) == EFFECT_TYPE_MOVEMENT_SPEED_DECREASE) + { + //If the effect was created by the Acid_Fog then remove it + if(GetEffectSpellId(eAOE) == SPELL_INCENDIARY_CLOUD) + { + RemoveEffect(oTarget, eAOE); + bValid = TRUE; + } + } + } + //Get next effect on the target + eAOE = GetNextEffect(oTarget); + } + } + } +} + diff --git a/src/_removed/original spells/nw_s0_inccloudc.nss b/src/_removed/original spells/nw_s0_inccloudc.nss new file mode 100644 index 0000000..86f4b41 --- /dev/null +++ b/src/_removed/original spells/nw_s0_inccloudc.nss @@ -0,0 +1,93 @@ +//:://///////////////////////////////////////////// +//:: Incendiary Cloud +//:: NW_S0_IncCloudC.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Objects within the AoE take 4d6 fire damage + per round. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: May 17, 2001 +//::////////////////////////////////////////////// +//:: Updated By: GeorgZ 2003-08-21: Now affects doors and placeables as well +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + + //Declare major variables + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + int nMetaMagic = GetMetaMagicFeat(); + int nDamage; + effect eDam; + object oTarget; + //Declare and assign personal impact visual effect. + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_S); + float fDelay; + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Incendiary Cloud' will not work underwater!", oPC); + return; + } + //Normal spell effects. + if (nInt != 1) + { + //Capture the first target object in the shape. + //-------------------------------------------------------------------------- + // GZ 2003-Oct-15 + // When the caster is no longer there, all functions calling + // GetAreaOfEffectCreator will fail. Its better to remove the barrier then + //-------------------------------------------------------------------------- + if (!GetIsObjectValid(GetAreaOfEffectCreator())) + { + DestroyObject(OBJECT_SELF); + return; + } + + + oTarget = GetFirstInPersistentObject(OBJECT_SELF,OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + //Declare the spell shape, size and the location. + while(GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, GetAreaOfEffectCreator())) + { + fDelay = GetRandomDelay(0.5, 2.0); + //Make SR check, and appropriate saving throw(s). + if(!MyResistSpell(GetAreaOfEffectCreator(), oTarget, fDelay)) + { + SignalEvent(oTarget, EventSpellCastAt(GetAreaOfEffectCreator(), SPELL_INCENDIARY_CLOUD)); + //Roll damage. + nDamage = d6(4); + //Enter Metamagic conditions + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 24;//Damage is at max + } + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + (nDamage/2); //Damage/Healing is +50% + } + //Adjust damage for Reflex Save, Evasion and Improved Evasion + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(),SAVING_THROW_TYPE_FIRE, GetAreaOfEffectCreator()); + // Apply effects to the currently selected target. + eDam = EffectDamage(nDamage, DAMAGE_TYPE_FIRE); + if(nDamage > 0) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + } + //Select the next target within the spell shape. + oTarget = GetNextInPersistentObject(OBJECT_SELF,OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } + } +} diff --git a/src/_removed/original spells/nw_s0_lghtnbolt.nss b/src/_removed/original spells/nw_s0_lghtnbolt.nss new file mode 100644 index 0000000..41beb5b --- /dev/null +++ b/src/_removed/original spells/nw_s0_lghtnbolt.nss @@ -0,0 +1,181 @@ +//:://///////////////////////////////////////////// +//:: Lightning Bolt +//:: NW_S0_LightnBolt +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Does 1d6 per level in a 5ft tube for 30m +*/ +//::////////////////////////////////////////////// +//:: Created By: Noel Borstad +//:: Created On: March 8, 2001 +//::////////////////////////////////////////////// +//:: Last Updated By: Preston Watamaniuk, On: May 2, 2001 + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oPC = GetFirstPC(); + object oCaster = OBJECT_SELF; + int nDoOnce = 0; + int nInt=GetLocalInt(oPC, "Underwater"); + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + //Limit caster level + if (nCasterLevel > 10) + { + nCasterLevel = 10; + } + int nDamage; + int nMetaMagic = GetMetaMagicFeat(); + //Set the lightning stream to start at the caster's hands + effect eLightning = EffectBeam(VFX_BEAM_LIGHTNING, OBJECT_SELF, BODY_NODE_HAND); + effect eVis = EffectVisualEffect(VFX_IMP_LIGHTNING_S); + effect eDamage; + object oTarget = GetSpellTargetObject(); + location lTarget = GetLocation(oTarget); + object oNextTarget, oTarget2; + float fDelay; + int nCnt = 1; + + oTarget2 = GetNearestObject(OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, OBJECT_SELF, nCnt); + while(GetIsObjectValid(oTarget2) && GetDistanceToObject(oTarget2) <= 30.0) + { + //Get first target in the lightning area by passing in the location of first target and the casters vector (position) + oTarget = GetFirstObjectInShape(SHAPE_SPELLCYLINDER, 30.0, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, GetPosition(OBJECT_SELF)); + while (GetIsObjectValid(oTarget)) + { + //Exclude the caster from the damage effects + if (oTarget != OBJECT_SELF && oTarget2 == oTarget) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_LIGHTNING_BOLT)); + //Make an SR check + if (!MyResistSpell(OBJECT_SELF, oTarget)) + { + //Roll damage + nDamage = d6(nCasterLevel); + //Enter Metamagic conditions + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 6 * nCasterLevel;//Damage is at max + } + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + (nDamage/2); //Damage/Healing is +50% + } + //Adjust damage based on Reflex Save, Evasion and Improved Evasion + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(),SAVING_THROW_TYPE_ELECTRICITY); + //Set damage effect + eDamage = EffectDamage(nDamage, DAMAGE_TYPE_ELECTRICAL); + if(nDamage > 0) + { + fDelay = GetSpellEffectDelay(GetLocation(oTarget), oTarget); + //Apply the VFX impact and damage effect (reflected upon PC) + if ((nInt == 1)&&(nDoOnce != 1)) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT,eDamage,oCaster)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT,eVis,oCaster)); + FloatingTextStringOnCreature("The spell 'Lightning Bolt' is reflected underwater!", oPC); + nDoOnce = 1; + } + //Normal spell effects. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT,eDamage,oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT,eVis,oTarget)); + } + } + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eLightning,oTarget,1.0); + //Set the currect target as the holder of the lightning effect + oNextTarget = oTarget; + eLightning = EffectBeam(VFX_BEAM_LIGHTNING, oNextTarget, BODY_NODE_CHEST); + } + } + //Get the next object in the lightning cylinder + oTarget = GetNextObjectInShape(SHAPE_SPELLCYLINDER, 30.0, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, GetPosition(OBJECT_SELF)); + } + nCnt++; + oTarget2 = GetNearestObject(OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, OBJECT_SELF, nCnt); + } +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Lightning Bolt' has caused a cave-in!", oPC)); + } +} + diff --git a/src/_removed/original spells/nw_s0_metswarm.nss b/src/_removed/original spells/nw_s0_metswarm.nss new file mode 100644 index 0000000..42bb264 --- /dev/null +++ b/src/_removed/original spells/nw_s0_metswarm.nss @@ -0,0 +1,167 @@ +//:://///////////////////////////////////////////// +//:: Meteor Swarm +//:: NW_S0_MetSwarm +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Everyone in a 50ft radius around the caster + takes 20d6 fire damage. Those within 6ft of the + caster will take no damage. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: May 24 , 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 22, 2001 + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + int nMetaMagic; + int nDamage; + effect eFire; + effect eMeteor = EffectVisualEffect(VFX_FNF_METEOR_SWARM); + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_M); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Meteor Swarm' will not work underwater!", oPC); + return; + } + //Normal spell effects. + if (nInt != 1) + { + //Apply the meteor swarm VFX area impact + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eMeteor, GetLocation(OBJECT_SELF)); + //Get first object in the spell area + float fDelay; + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(OBJECT_SELF)); + while(GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF) && oTarget != OBJECT_SELF) + { + fDelay = GetRandomDelay(); + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_METEOR_SWARM)); + //Make sure the target is outside the 2m safe zone + if (GetDistanceBetween(oTarget, OBJECT_SELF) > 2.0) + { + //Make SR check + if (!MyResistSpell(OBJECT_SELF, oTarget, 0.5)) + { + //Roll damage + nDamage = d6(20); + + //Enter Metamagic conditions + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 120;//Damage is at max + } + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + (nDamage/2); //Damage/Healing is +50% + } + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(),SAVING_THROW_TYPE_FIRE); + //Set the damage effect + eFire = EffectDamage(nDamage, DAMAGE_TYPE_FIRE); + if(nDamage > 0) + { + //Apply damage effect and VFX impact. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eFire, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + } + } + //Get next target in the spell area + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(OBJECT_SELF)); + } + } +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Meteor Swarm' has caused a cave-in!", oPC)); + } +} + diff --git a/src/_removed/original spells/nw_s0_prisspray.nss b/src/_removed/original spells/nw_s0_prisspray.nss new file mode 100644 index 0000000..7d84d6b --- /dev/null +++ b/src/_removed/original spells/nw_s0_prisspray.nss @@ -0,0 +1,213 @@ +//:://///////////////////////////////////////////// +//:: Prismatic Spray +//:: [NW_S0_PrisSpray.nss] +//:: Copyright (c) 2000 Bioware Corp. +//::////////////////////////////////////////////// +//:: Sends out a prismatic cone that has a random +//:: effect for each target struck. +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Dec 19, 2000 +//::////////////////////////////////////////////// +//:: Last Updated By: Preston Watamaniuk, On: April 11, 2001 +//:: Last Updated By: Aidan Scanlan On: April 11, 2001 +//:: Last Updated By: Preston Watamaniuk, On: June 11, 2001 + +int ApplyPrismaticEffect(int nEffect, object oTarget); + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + object oTarget; + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + int nMetaMagic = GetMetaMagicFeat(); + int nRandom; + int nHD; + int nVisual; + effect eVisual; + int bTwoEffects; + //Set the delay to apply to effects based on the distance to the target + float fDelay = 0.5 + GetDistanceBetween(OBJECT_SELF, oTarget)/20; + //Get first target in the spell area + oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 11.0, GetSpellTargetLocation()); + while (GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_PRISMATIC_SPRAY)); + //Make an SR check + if (!MyResistSpell(OBJECT_SELF, oTarget, fDelay) && (oTarget != OBJECT_SELF)) + { + //Blind the target if they are less than 9 HD + nHD = GetHitDice(oTarget); + if (nHD <= 8) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectBlindness(), oTarget, RoundsToSeconds(nCasterLevel)); + } + //Determine if 1 or 2 effects are going to be applied + nRandom = d8(); + if(nRandom == 8) + { + //Get the visual effect + nVisual = ApplyPrismaticEffect(Random(7) + 1, oTarget); + nVisual = ApplyPrismaticEffect(Random(7) + 1, oTarget); + } + else + { + //Get the visual effect + nVisual = ApplyPrismaticEffect(nRandom, oTarget); + } + //Set the visual effect + if(nVisual != 0) + { + eVisual = EffectVisualEffect(nVisual); + //Apply the visual effect + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVisual, oTarget)); + } + } + } + //Get next target in the spell area + oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 11.0, GetSpellTargetLocation()); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// ApplyPrismaticEffect +/////////////////////////////////////////////////////////////////////////////// +/* Given a reference integer and a target, this function will apply the effect + of corresponding prismatic cone to the target. To have any effect the + reference integer (nEffect) must be from 1 to 7.*/ +/////////////////////////////////////////////////////////////////////////////// +// Created By: Aidan Scanlan On: April 11, 2001 +/////////////////////////////////////////////////////////////////////////////// + +int ApplyPrismaticEffect(int nEffect, object oTarget) +{ + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "UnderwaterArea"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + int nDamage; + effect ePrism; + effect eVis; + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); + effect eLink; + int nVis; + float fDelay = 0.5 + GetDistanceBetween(OBJECT_SELF, oTarget)/20; + //Based on the random number passed in, apply the appropriate effect and set the visual to + //the correct constant + switch(nEffect) + { + case 1://fire + nDamage = 20; + nVis = VFX_IMP_FLAME_S; + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(),SAVING_THROW_TYPE_FIRE); + ePrism = EffectDamage(nDamage, DAMAGE_TYPE_FIRE); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("That effect of 'Prismatic Spray' will not work underwater!", oPC); + } + //Normal spell effects. + if (nInt != 1) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, ePrism, oTarget)); + } + break; + case 2: //Acid + nDamage = 40; + nVis = VFX_IMP_ACID_L; + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(),SAVING_THROW_TYPE_ACID); + ePrism = EffectDamage(nDamage, DAMAGE_TYPE_ACID); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, ePrism, oTarget)); + break; + case 3: //Electricity + nDamage = 80; + nVis = VFX_IMP_LIGHTNING_S; + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(),SAVING_THROW_TYPE_ELECTRICITY); + ePrism = EffectDamage(nDamage, DAMAGE_TYPE_ELECTRICAL); + //Spell reflects on caster if underwater. + if (nInt == 1) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, ePrism, oCaster)); + FloatingTextStringOnCreature("That effect of 'Prismatic Spray' is reflected underwater!", oPC); + } + //Normal spell effects. + if (nInt != 1) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, ePrism, oTarget)); + } + break; + case 4: //Poison + { + effect ePoison = EffectPoison(POISON_BEBILITH_VENOM); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, ePoison, oTarget)); + } + break; + case 5: //Paralyze + { + effect eDur2 = EffectVisualEffect(VFX_DUR_PARALYZED); + if (MySavingThrow(SAVING_THROW_FORT, oTarget, GetSpellSaveDC()) == 0) + { + ePrism = EffectParalyze(); + eLink = EffectLinkEffects(eDur, ePrism); + eLink = EffectLinkEffects(eLink, eDur2); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(10))); + } + } + break; + case 6: //Confusion + { + effect eMind = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DISABLED); + ePrism = EffectConfused(); + eLink = EffectLinkEffects(eMind, ePrism); + eLink = EffectLinkEffects(eLink, eDur); + + if (!/*Will Save*/ MySavingThrow(SAVING_THROW_WILL, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_MIND_SPELLS, OBJECT_SELF, fDelay)) + { + nVis = VFX_IMP_CONFUSION_S; + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(10))); + } + } + break; + case 7: //Death + { + if (!/*Will Save*/ MySavingThrow(SAVING_THROW_WILL, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_DEATH, OBJECT_SELF, fDelay)) + { + //nVis = VFX_IMP_DEATH; + ePrism = EffectDeath(); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, ePrism, oTarget)); + } + } + break; + } + return nVis; +} + diff --git a/src/_removed/original spells/nw_s0_rayfrost.nss b/src/_removed/original spells/nw_s0_rayfrost.nss new file mode 100644 index 0000000..b7415a9 --- /dev/null +++ b/src/_removed/original spells/nw_s0_rayfrost.nss @@ -0,0 +1,86 @@ +//:://///////////////////////////////////////////// +//:: Ray of Frost +//:: [NW_S0_RayFrost.nss] +//:: Copyright (c) 2000 Bioware Corp. +//::////////////////////////////////////////////// +/* + If the caster succeeds at a ranged touch attack + the target takes 1d4 damage. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: feb 4, 2001 +//::////////////////////////////////////////////// +//:: Bug Fix: Andrew Nobbs, April 17, 2003 +//:: Notes: Took out ranged attack roll. +//::////////////////////////////////////////////// + + +#include "NW_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oPC = GetFirstPC(); + object oCaster = OBJECT_SELF; + int nInt=GetLocalInt(oPC, "Underwater"); + object oTarget = GetSpellTargetObject(); + int nMetaMagic = GetMetaMagicFeat(); + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + int nDam = d4(1) + 1; + effect eDam; + effect eVis = EffectVisualEffect(VFX_IMP_FROST_S); + effect eRay = EffectBeam(VFX_BEAM_COLD, OBJECT_SELF, BODY_NODE_HAND); + + if(!GetIsReactionTypeFriendly(oTarget)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_RAY_OF_FROST)); + eRay = EffectBeam(VFX_BEAM_COLD, OBJECT_SELF, BODY_NODE_HAND); + //Make SR Check + if(!MyResistSpell(OBJECT_SELF, oTarget)) + { + //Enter Metamagic conditions + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDam = 5 ;//Damage is at max + } + else if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDam = nDam + nDam/2; //Damage/Healing is +50% + } + //Set damage effect + eDam = EffectDamage(nDam, DAMAGE_TYPE_COLD); + //Apply the VFX impact and damage effect (reflected upon PC) + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oCaster); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oCaster); + FloatingTextStringOnCreature("The spell 'Ray of Frost' is reflected underwater!", oPC); + } + //Normal spell effects. + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); + } + } + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eRay, oTarget, 1.7); +} diff --git a/src/_removed/original spells/nw_s0_searlght.nss b/src/_removed/original spells/nw_s0_searlght.nss new file mode 100644 index 0000000..3794418 --- /dev/null +++ b/src/_removed/original spells/nw_s0_searlght.nss @@ -0,0 +1,127 @@ +//:://///////////////////////////////////////////// +//:: Searing Light +//:: s_SearLght.nss +//:: Copyright (c) 2000 Bioware Corp. +//::////////////////////////////////////////////// +//:: Focusing holy power like a ray of the sun, you project +//:: a blast of light from your open palm. You must succeed +//:: at a ranged touch attack to strike your target. A creature +//:: struck by this ray of light suffers 1d8 points of damage +//:: per two caster levels (maximum 5d8). Undead creatures suffer +//:: 1d6 points of damage per caster level (maximum 10d6), and +//:: undead creatures particularly vulnerable to sunlight, such +//:: as vampires, suffer 1d8 points of damage per caster level +//:: (maximum 10d8). Constructs and inanimate objects suffer only +//:: 1d6 points of damage per two caster levels (maximum 5d6). +//::////////////////////////////////////////////// +//:: Created By: Keith Soleski +//:: Created On: 02/05/2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 25, 2001 + +#include "NW_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Searing Light' will not work underwater!", oPC); + return; + } +/* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oTarget = GetSpellTargetObject(); + int nMetaMagic = GetMetaMagicFeat(); + int nCasterLevel = GetCasterLevel(oCaster); + int nDamage; + int nMax; + effect eDam; + effect eVis = EffectVisualEffect(VFX_IMP_SUNSTRIKE); + effect eRay = EffectBeam(VFX_BEAM_HOLY, OBJECT_SELF, BODY_NODE_HAND); + + if (nInt != 1) + { + if(!GetIsReactionTypeFriendly(oTarget)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_SEARING_LIGHT)); + eRay = EffectBeam(VFX_BEAM_HOLY, OBJECT_SELF, BODY_NODE_HAND); + //Make an SR Check + if (!MyResistSpell(oCaster, oTarget)) + { + //Limit caster level + if (nCasterLevel > 10) + { + nCasterLevel = 10; + } + //Check for racial type undead + if (GetRacialType(oTarget) == RACIAL_TYPE_UNDEAD) + { + nDamage = d6(nCasterLevel); + nMax = 6; + } + //Check for racial type construct + else if (GetRacialType(oTarget) == RACIAL_TYPE_CONSTRUCT) + { + nCasterLevel /= 2; + if(nCasterLevel == 0) + { + nCasterLevel = 1; + } + nDamage = d6(nCasterLevel); + nMax = 6; + } + else + { + nCasterLevel = nCasterLevel/2; + if(nCasterLevel == 0) + { + nCasterLevel = 1; + } + nDamage = d8(nCasterLevel); + nMax = 8; + } + + //Make metamagic checks + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = nMax * nCasterLevel; + } + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + (nDamage/2); + } + //Set the damage effect + eDam = EffectDamage(nDamage, DAMAGE_TYPE_DIVINE); + //Apply the damage effect and VFX impact + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); + DelayCommand(0.5, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + //ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eRay, oTarget, 1.0); + } + } + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eRay, oTarget, 1.7); + } +} + diff --git a/src/_removed/original spells/nw_s0_sndburst.nss b/src/_removed/original spells/nw_s0_sndburst.nss new file mode 100644 index 0000000..73eb764 --- /dev/null +++ b/src/_removed/original spells/nw_s0_sndburst.nss @@ -0,0 +1,161 @@ +//:://///////////////////////////////////////////// +//:: [Sound Burst] +//:: [NW_S0_SndBurst.nss] +//:: Copyright (c) 2000 Bioware Corp. +//::////////////////////////////////////////////// +//:: Does 1d8 damage to all creatures in a 10ft +//:: radius. Will save or the creature is stunned +//:: for 1 round. +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Jan 31, 2001 +//::////////////////////////////////////////////// +//:: Last Updated By: Georg Z, Oct. 2003 + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + + /* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + */ + + if (!X2PreSpellCastCode()) + { + return; + } + // End of Spell Cast Hook + + + //Declare major variables + object oTarget; + object oPC = GetFirstPC(); + object oCaster = OBJECT_SELF; + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + int nMetaMagic = GetMetaMagicFeat(); + int nDamage; + effect eStun = EffectStunned(); + effect eVis = EffectVisualEffect(VFX_IMP_SONIC); + effect eFNF = EffectVisualEffect(VFX_FNF_SOUND_BURST); + effect eMind = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_NEGATIVE); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); + int nInt=GetLocalInt(oPC, "Underwater"); + + effect eLink = EffectLinkEffects(eStun, eMind); + eLink = EffectLinkEffects(eLink, eDur); + + effect eDam; + location lLoc = GetSpellTargetLocation(); + int nDC = GetSpellSaveDC(); + //Apply the FNF to the spell location + ApplyEffectAtLocation(DURATION_TYPE_INSTANT,eFNF, lLoc); + //Get the first target in the spell area + oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, lLoc); + while (GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_SOUND_BURST)); + //Make a SR check + if(!MyResistSpell(OBJECT_SELF, oTarget)) + { + //Roll damage + nDamage = d8(); + //Make a Will roll to avoid being stunned + if(!/*Will Save*/ MySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_SONIC)) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(2)); + } + //Make meta magic checks + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 8; + } + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + (nDamage/2); + } + //Set the damage effect + eDam = EffectDamage(nDamage, DAMAGE_TYPE_SONIC); + //Apply the VFX impact and damage effect + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis,oCaster); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam,oCaster); + FloatingTextStringOnCreature("The spell 'Sound Burst' is reflected underwater!", oPC); + } + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis,oTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam,oTarget); + } + } + //Get the next target in the spell area + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, lLoc); + } +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Sound Burst' has caused a cave-in!", oPC)); + } +} + diff --git a/src/_removed/original spells/nw_s0_stormvenc.nss b/src/_removed/original spells/nw_s0_stormvenc.nss new file mode 100644 index 0000000..58e3e9d --- /dev/null +++ b/src/_removed/original spells/nw_s0_stormvenc.nss @@ -0,0 +1,147 @@ +//:://///////////////////////////////////////////// +//:: Storm of Vengeance: Heartbeat +//:: NW_S0_StormVenC.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Creates an AOE that decimates the enemies of + the cleric over a 30ft radius around the caster +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Nov 8, 2001 +//::////////////////////////////////////////////// + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + + //Declare major variables + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + effect eAcid = EffectDamage(d6(3), DAMAGE_TYPE_ACID); + effect eElec = EffectDamage(d6(6), DAMAGE_TYPE_ELECTRICAL); + effect eStun = EffectStunned(); + effect eVisAcid = EffectVisualEffect(VFX_IMP_ACID_S); + effect eVisElec = EffectVisualEffect(VFX_IMP_LIGHTNING_M); + effect eVisStun = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DISABLED); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); + effect eLink = EffectLinkEffects(eStun, eVisStun); + eLink = EffectLinkEffects(eLink, eDur); + float fDelay; + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Storm of Vengeance' will not work underwater!", oPC); + return; + } + //Normal spell effects. + if (nInt != 1) + { + //Get first target in spell area + object oTarget = GetFirstInPersistentObject(OBJECT_SELF,OBJECT_TYPE_CREATURE); + while(GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, GetAreaOfEffectCreator())) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(GetAreaOfEffectCreator(), SPELL_STORM_OF_VENGEANCE)); + //Make an SR Check + fDelay = GetRandomDelay(0.5, 2.0); + if(MyResistSpell(GetAreaOfEffectCreator(), oTarget, fDelay) == 0) + { + //Make a saving throw check + // * if the saving throw is made they still suffer acid damage. + // * if they fail the saving throw, they suffer Electrical damage too + if(MySavingThrow(SAVING_THROW_REFLEX, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_ELECTRICITY, GetAreaOfEffectCreator(), fDelay)) + { + //Apply the VFX impact and effects + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVisAcid, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eAcid, oTarget)); + if (d2()==1) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVisElec, oTarget)); + } + } + else + { + //Apply the VFX impact and effects + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVisAcid, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eAcid, oTarget)); + //Apply the VFX impact and effects + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVisElec, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eElec, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(2))); + } + } + } + //Get next target in spell area + oTarget = GetNextInPersistentObject(OBJECT_SELF,OBJECT_TYPE_CREATURE); + } + } +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Storm of Vengeance' has caused a cave-in!", oPC)); + } +} diff --git a/src/_removed/original spells/nw_s0_stormveng.nss b/src/_removed/original spells/nw_s0_stormveng.nss new file mode 100644 index 0000000..3f96aab --- /dev/null +++ b/src/_removed/original spells/nw_s0_stormveng.nss @@ -0,0 +1,123 @@ +//:://///////////////////////////////////////////// +//:: Storm of Vengeance +//:: NW_S0_StormVeng.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Creates an AOE that decimates the enemies of + the cleric over a 30ft radius around the caster +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Nov 8, 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 25, 2001 + +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables including Area of Effect Object + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + effect eAOE = EffectAreaOfEffect(AOE_PER_STORM); + effect eVis = EffectVisualEffect(VFX_FNF_STORM); + location lTarget = GetSpellTargetLocation(); + + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Storm of Vengeance' will not work underwater!", oPC); + return; + } + //Normal spell effects. + if (nInt != 1) + { + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, lTarget); + //Create an instance of the AOE Object using the Apply Effect function + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eAOE, lTarget, RoundsToSeconds(10)); + } +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Storm of Vengeance' has caused a cave-in!", oPC)); + } +} + + diff --git a/src/_removed/original spells/nw_s0_summon.nss b/src/_removed/original spells/nw_s0_summon.nss new file mode 100644 index 0000000..c7e0e0c --- /dev/null +++ b/src/_removed/original spells/nw_s0_summon.nss @@ -0,0 +1,367 @@ +//:://///////////////////////////////////////////// +//:: Summon Creature Series +//:: NW_S0_Summon +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Carries out the summoning of the appropriate + creature for the Summon Monster Series of spells + 1 to 9 +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Jan 8, 2002 +//::////////////////////////////////////////////// + +effect SetSummonEffect(int nSpellID); + +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + int nSpellID = GetSpellId(); + int nDuration = GetCasterLevel(OBJECT_SELF); + nDuration = 24; + if(nDuration == 1) + { + nDuration = 2; + } + effect eSummon = SetSummonEffect(nSpellID); + + //Make metamagic check for extend + int nMetaMagic = GetMetaMagicFeat(); + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + //Apply the VFX impact and summon effect + + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), HoursToSeconds(nDuration)); +} + + +effect SetSummonEffect(int nSpellID) +{ + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + int nFNF_Effect; + int nRoll = d3(); + string sSummon; + if(GetHasFeat(FEAT_ANIMAL_DOMAIN_POWER)) //WITH THE ANIMAL DOMAIN + { + if(nSpellID == SPELL_SUMMON_CREATURE_I) + { + nFNF_Effect = VFX_FNF_SUMMON_MONSTER_1; + if (nInt == 1) + { + sSummon = "marinebeetle2"; + } + else sSummon = "NW_S_BOARDIRE"; + } + else if(nSpellID == SPELL_SUMMON_CREATURE_II) + { + nFNF_Effect = VFX_FNF_SUMMON_MONSTER_1; + if (nInt == 1) + { + sSummon = "marinebeetle"; + } + else sSummon = "NW_S_WOLFDIRE"; + } + else if(nSpellID == SPELL_SUMMON_CREATURE_III) + { + nFNF_Effect = VFX_FNF_SUMMON_MONSTER_1; + if (nInt == 1) + { + sSummon = "marinebeetle"; + } + else sSummon = "NW_S_SPIDDIRE"; + } + else if(nSpellID == SPELL_SUMMON_CREATURE_IV) + { + nFNF_Effect = VFX_FNF_SUMMON_MONSTER_2; + if (nInt == 1) + { + sSummon = "giantseaspider"; + } + else sSummon = "NW_S_beardire"; + } + else if(nSpellID == SPELL_SUMMON_CREATURE_V) + { + nFNF_Effect = VFX_FNF_SUMMON_MONSTER_2; + if (nInt == 1) + { + sSummon = "giantseaspider"; + } + else sSummon = "NW_S_diretiger"; + } + else if(nSpellID == SPELL_SUMMON_CREATURE_VI) + { + nFNF_Effect = VFX_FNF_SUMMON_MONSTER_3; + switch (nRoll) + { + case 1: + if (nInt == 1) + { + sSummon = "giantcrab"; + } + else sSummon = "NW_S_AIRHUGE"; + break; + + case 2: + if (nInt == 1) + { + sSummon = "giantcrab"; + } + else sSummon = "NW_S_WATERHUGE"; + break; + + case 3: + if (nInt == 1) + { + sSummon = "giantcrab"; + } + else sSummon = "NW_S_FIREHUGE"; + break; + } + } + else if(nSpellID == SPELL_SUMMON_CREATURE_VII) + { + nFNF_Effect = VFX_FNF_SUMMON_MONSTER_3; + switch (nRoll) + { + case 1: + if (nInt == 1) + { + sSummon = "NW_S_WATERGREAT"; + } + else sSummon = "NW_S_AIRGREAT"; + break; + + case 2: + sSummon = "NW_S_WATERGREAT"; + break; + + case 3: + if (nInt == 1) + { + sSummon = "NW_S_WATERGREAT"; + } + else sSummon = "NW_S_FIREGREAT"; + break; + } + } + else if(nSpellID == SPELL_SUMMON_CREATURE_VIII) + { + nFNF_Effect = VFX_FNF_SUMMON_MONSTER_3; + switch (nRoll) + { + case 1: + if (nInt == 1) + { + sSummon = "NW_S_WATERELDER"; + } + else sSummon = "NW_S_AIRELDER"; + break; + + case 2: + sSummon = "NW_S_WATERELDER"; + break; + + case 3: + if (nInt == 1) + { + sSummon = "NW_S_WATERELDER"; + } + else sSummon = "NW_S_FIREELDER"; + break; + } + } + else if(nSpellID == SPELL_SUMMON_CREATURE_IX) + { + nFNF_Effect = VFX_FNF_SUMMON_MONSTER_3; + switch (nRoll) + { + case 1: + if (nInt == 1) + { + sSummon = "NW_S_WATERELDER"; + } + else sSummon = "NW_S_AIRELDER"; + break; + + case 2: + sSummon = "NW_S_WATERELDER"; + break; + + case 3: + if (nInt == 1) + { + sSummon = "NW_S_WATERELDER"; + } + else sSummon = "NW_S_FIREELDER"; + break; + } + } + } + else //WITOUT THE ANIMAL DOMAIN + { + if(nSpellID == SPELL_SUMMON_CREATURE_I) + { + nFNF_Effect = VFX_FNF_SUMMON_MONSTER_1; + if (nInt == 1) + { + sSummon = "marinebeetle1"; + } + else sSummon = "NW_S_badgerdire"; + } + else if(nSpellID == SPELL_SUMMON_CREATURE_II) + { + nFNF_Effect = VFX_FNF_SUMMON_MONSTER_1; + if (nInt == 1) + { + sSummon = "marinebeetle2"; + } + else sSummon = "NW_S_BOARDIRE"; + } + else if(nSpellID == SPELL_SUMMON_CREATURE_III) + { + nFNF_Effect = VFX_FNF_SUMMON_MONSTER_1; + if (nInt == 1) + { + sSummon = "marinebeetle"; + } + else sSummon = "NW_S_WOLFDIRE"; + } + else if(nSpellID == SPELL_SUMMON_CREATURE_IV) + { + nFNF_Effect = VFX_FNF_SUMMON_MONSTER_2; + if (nInt == 1) + { + sSummon = "giantseaspider"; + } + else sSummon = "NW_S_SPIDDIRE"; + } + else if(nSpellID == SPELL_SUMMON_CREATURE_V) + { + nFNF_Effect = VFX_FNF_SUMMON_MONSTER_2; + if (nInt == 1) + { + sSummon = "giantseaspider"; + } + else sSummon = "NW_S_beardire"; + } + else if(nSpellID == SPELL_SUMMON_CREATURE_VI) + { + nFNF_Effect = VFX_FNF_SUMMON_MONSTER_2; + if (nInt == 1) + { + sSummon = "giantcrab"; + } + else sSummon = "NW_S_diretiger"; + } + else if(nSpellID == SPELL_SUMMON_CREATURE_VII) + { + nFNF_Effect = VFX_FNF_SUMMON_MONSTER_3; + switch (nRoll) + { + case 1: + if (nInt == 1) + { + sSummon = "NW_S_WATERHUGE"; + } + else sSummon = "NW_S_AIRHUGE"; + break; + + case 2: + sSummon = "NW_S_WATERHUGE"; + break; + + case 3: + if (nInt == 1) + { + sSummon = "NW_S_WATERHUGE"; + } + else sSummon = "NW_S_FIREHUGE"; + break; + } + } + else if(nSpellID == SPELL_SUMMON_CREATURE_VIII) + { + nFNF_Effect = VFX_FNF_SUMMON_MONSTER_3; + switch (nRoll) + { + case 1: + if (nInt == 1) + { + sSummon = "NW_S_WATERGREAT"; + } + else sSummon = "NW_S_AIRGREAT"; + break; + + case 2: + sSummon = "NW_S_WATERGREAT"; + break; + + case 3: + if (nInt == 1) + { + sSummon = "NW_S_WATERGREAT"; + } + else sSummon = "NW_S_FIREGREAT"; + break; + } + } + else if(nSpellID == SPELL_SUMMON_CREATURE_IX) + { + nFNF_Effect = VFX_FNF_SUMMON_MONSTER_3; + switch (nRoll) + { + case 1: + if (nInt == 1) + { + sSummon = "NW_S_WATERELDER"; + } + else sSummon = "NW_S_AIRELDER"; + break; + + case 2: + sSummon = "NW_S_WATERELDER"; + break; + + case 3: + if (nInt == 1) + { + sSummon = "NW_S_WATERELDER"; + } + else sSummon = "NW_S_FIREELDER"; + break; + } + } + } + //effect eVis = EffectVisualEffect(nFNF_Effect); + //ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, GetSpellTargetLocation()); + effect eSummonedMonster = EffectSummonCreature(sSummon, nFNF_Effect); + return eSummonedMonster; +} + diff --git a/src/_removed/original spells/nw_s0_summon1.nss b/src/_removed/original spells/nw_s0_summon1.nss new file mode 100644 index 0000000..5148d60 --- /dev/null +++ b/src/_removed/original spells/nw_s0_summon1.nss @@ -0,0 +1,64 @@ +//:://///////////////////////////////////////////// +//:: Summon Monster I +//:: NW_S0_Summon1 +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Summons a dire badger to fight for the character +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 12 , 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 25, 2001 + +#include "x2_inc_spellhook" +void main() +{ + + /* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + + */ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + + // End of Spell Cast Hook + + + //Declare major variables + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + int nMetaMagic = GetMetaMagicFeat(); + int nDuration = GetCasterLevel(OBJECT_SELF); + effect eSummon; + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_1); + //Make metamagic check for extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + if (nInt == 1) + { + eSummon = EffectSummonCreature("marinebeetle1"); + } + else + { + eSummon = EffectSummonCreature("NW_S_badgerdire"); + if(GetHasFeat(FEAT_ANIMAL_DOMAIN_POWER)) + { + eSummon = EffectSummonCreature("NW_S_BOARDIRE"); + } + } + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), TurnsToSeconds(nDuration)); +} + diff --git a/src/_removed/original spells/nw_s0_summon2.nss b/src/_removed/original spells/nw_s0_summon2.nss new file mode 100644 index 0000000..6955b8f --- /dev/null +++ b/src/_removed/original spells/nw_s0_summon2.nss @@ -0,0 +1,65 @@ +//:://///////////////////////////////////////////// +//:: Summon Monster II +//:: NW_S0_Summon2 +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Summons a dire boar to fight for the character +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 12 , 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 25, 2001 +#include "x2_inc_spellhook" +void main() +{ + + + /* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + + */ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + + // End of Spell Cast Hook + + + + //Declare major variables + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + int nMetaMagic = GetMetaMagicFeat(); + int nDuration = GetCasterLevel(OBJECT_SELF); + effect eSummon; + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_1); + if (nInt == 1) + { + eSummon = EffectSummonCreature("marinebeetle2"); + } + else + { + eSummon = EffectSummonCreature("NW_S_BOARDIRE"); + if(GetHasFeat(FEAT_ANIMAL_DOMAIN_POWER)) + { + eSummon = EffectSummonCreature("NW_S_WOLFDIRE"); + } + } + //Make metamagic check for extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), TurnsToSeconds(nDuration)); +} + diff --git a/src/_removed/original spells/nw_s0_summon3.nss b/src/_removed/original spells/nw_s0_summon3.nss new file mode 100644 index 0000000..6e4e924 --- /dev/null +++ b/src/_removed/original spells/nw_s0_summon3.nss @@ -0,0 +1,63 @@ +//:://///////////////////////////////////////////// +//:: Summon Monster III +//:: NW_S0_Summon3 +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Summons a dire wolf to fight for the character +*/ +//::////////////////////////////////////////////// +//:: Created By: Brenon Holmes +//:: Created On: Dec 10 , 2000 +//::////////////////////////////////////////////// +//:: Last Updated By: Preston Watamaniuk, On: April 12, 2001 +//:: VFX Pass By: Preston W, On: June 25, 2001 + +#include "x2_inc_spellhook" +void main() +{ + + /* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + + */ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + + // End of Spell Cast Hook + + //Declare major variables + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + int nMetaMagic = GetMetaMagicFeat(); + int nDuration = GetCasterLevel(OBJECT_SELF); + effect eSummon; + if (nInt == 1) + { + eSummon = EffectSummonCreature("marinebeetle"); + } + else + { + eSummon = EffectSummonCreature("NW_S_WOLFDIRE"); + if(GetHasFeat(FEAT_ANIMAL_DOMAIN_POWER)) + { + eSummon = EffectSummonCreature("NW_S_SPIDDIRE"); + } + } + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_1); + //Make metamagic check for extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), TurnsToSeconds(nDuration)); +} diff --git a/src/_removed/original spells/nw_s0_summon4.nss b/src/_removed/original spells/nw_s0_summon4.nss new file mode 100644 index 0000000..e735b38 --- /dev/null +++ b/src/_removed/original spells/nw_s0_summon4.nss @@ -0,0 +1,60 @@ +//:://///////////////////////////////////////////// +//:: Summon Monster IV +//:: NW_S0_Summon4 +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Summons a Sword Spider to fight for the character +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 12, 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 25, 2001 + + +#include "x2_inc_spellhook" +void main() +{ + + /* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + + */ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + + // End of Spell Cast Hook + + //Declare major variables + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + int nMetaMagic = GetMetaMagicFeat(); + int nDuration = GetCasterLevel(OBJECT_SELF); + effect eSummon = EffectSummonCreature("NW_S_SPIDDIRE"); + if(GetHasFeat(FEAT_ANIMAL_DOMAIN_POWER)) + { + eSummon = EffectSummonCreature("NW_S_DIRETIGER"); + } + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_2); + //Make metamagic check for extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + if (nInt == 1) + { + eSummon = EffectSummonCreature("giantseaspider"); + } + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), TurnsToSeconds(nDuration)); +} + diff --git a/src/_removed/original spells/nw_s0_summon5.nss b/src/_removed/original spells/nw_s0_summon5.nss new file mode 100644 index 0000000..6db4770 --- /dev/null +++ b/src/_removed/original spells/nw_s0_summon5.nss @@ -0,0 +1,61 @@ +//:://///////////////////////////////////////////// +//:: Summon Monster V +//:: NW_S0_Summon5 +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Summons a dire spider to fight for the character +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 12 , 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 25, 2001 + +#include "x2_inc_spellhook" +void main() +{ + /* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + + */ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + + // End of Spell Cast Hook + + + //Declare major variables + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + int nMetaMagic = GetMetaMagicFeat(); + int nDuration = GetCasterLevel(OBJECT_SELF); + effect eSummon = EffectSummonCreature("NW_S_diretiger"); + if(GetHasFeat(FEAT_ANIMAL_DOMAIN_POWER)) + { + eSummon = EffectSummonCreature("NW_S_beardire"); + } + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_2); + //Make metamagic check for extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + if (nInt == 1) + { + effect eSummon = EffectSummonCreature("giantseaspider"); + } + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), TurnsToSeconds(nDuration)); + +} diff --git a/src/_removed/original spells/nw_s0_summon6.nss b/src/_removed/original spells/nw_s0_summon6.nss new file mode 100644 index 0000000..0db8d81 --- /dev/null +++ b/src/_removed/original spells/nw_s0_summon6.nss @@ -0,0 +1,99 @@ +//:://///////////////////////////////////////////// +//:: Summon Monster VI +//:: NW_S0_Summon6 +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Summons a dire bear to fight for the character +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 12, 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 25, 2001 + +#include "x2_inc_spellhook" +void main() +{ + + /* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + + */ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + + // End of Spell Cast Hook + + //Declare major variables + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + int nMetaMagic = GetMetaMagicFeat(); + int nDuration = GetCasterLevel(OBJECT_SELF); + effect eSummon = EffectSummonCreature("NW_S_beardire"); + if (nInt == 1) + { + effect eSummon = EffectSummonCreature("giantcrab"); + } + if(GetHasFeat(FEAT_ANIMAL_DOMAIN_POWER)) + { + int nRoll = d4(); + switch (nRoll) + { + case 1: + if (nInt == 1) + { + eSummon = EffectSummonCreature("NW_S_WATERHUGE"); + } + if (nInt != 1) + { + eSummon = EffectSummonCreature("NW_S_AIRHUGE"); + } + break; + + case 2: + eSummon = EffectSummonCreature("NW_S_WATERHUGE"); + break; + + case 3: + if (nInt == 1) + { + eSummon = EffectSummonCreature("NW_S_WATERHUGE"); + } + if (nInt != 1) + { + eSummon = EffectSummonCreature("NW_S_EARTHHUGE"); + } + break; + + case 4: + if (nInt == 1) + { + eSummon = EffectSummonCreature("NW_S_WATERHUGE"); + } + if (nInt != 1) + { + eSummon = EffectSummonCreature("NW_S_FIREHUGE"); + } + break; + } + } + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_2); + //Make metamagic check for extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), TurnsToSeconds(nDuration)); +} diff --git a/src/_removed/original spells/nw_s0_summon7.nss b/src/_removed/original spells/nw_s0_summon7.nss new file mode 100644 index 0000000..c7412e5 --- /dev/null +++ b/src/_removed/original spells/nw_s0_summon7.nss @@ -0,0 +1,148 @@ +//:://///////////////////////////////////////////// +//:: Summon Monster VII +//:: NW_S0_Summon7 +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Summons a Minogon to fight for the character +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 12, 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 25, 2001 + +#include "x2_inc_spellhook" +void main() +{ + /* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + + */ + + if (!X2PreSpellCastCode()) + { +// If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + + // End of Spell Cast Hook + + //Declare major variables + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + int nMetaMagic = GetMetaMagicFeat(); + int nDuration = GetCasterLevel(OBJECT_SELF); + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_3); + effect eSummon; + int nRoll = d4(); + if(GetHasFeat(FEAT_ANIMAL_DOMAIN_POWER)) + { + switch (nRoll) + { + case 1: + if (nInt == 1) + { + eSummon = EffectSummonCreature("NW_S_WATELDER"); + } + else + { + eSummon = EffectSummonCreature("NW_S_AIRGREAT"); + } + break; + + case 2: + if (nInt == 1) + { + eSummon = EffectSummonCreature("NW_S_WATELDER"); + } + else + { + eSummon = EffectSummonCreature("NW_S_WATERGREAT"); + } + break; + + case 3: + if (nInt == 1) + { + eSummon = EffectSummonCreature("NW_S_WATELDER"); + } + else + { + eSummon = EffectSummonCreature("NW_S_EARTHGREAT"); + } + break; + + case 4: + if (nInt == 1) + { + eSummon = EffectSummonCreature("NW_S_WATELDER"); + } + else + { + eSummon = EffectSummonCreature("NW_S_FIREGREAT"); + } + break; + } + } + else + { + switch (nRoll) + { + case 1: + if (nInt == 1) + { + eSummon = EffectSummonCreature("NW_S_WATERGREAT"); + } + else + { + eSummon = EffectSummonCreature("NW_S_AIRHUGE"); + } + break; + + case 2: + if (nInt == 1) + { + eSummon = EffectSummonCreature("NW_S_WATERGREAT"); + } + else + { + eSummon = EffectSummonCreature("NW_S_WATERHUGE"); + } + break; + + case 3: + if (nInt == 1) + { + eSummon = EffectSummonCreature("NW_S_WATERGREAT"); + } + else + { + eSummon = EffectSummonCreature("NW_S_EARTHHUGE"); + } + break; + + case 4: + if (nInt == 1) + { + eSummon = EffectSummonCreature("NW_S_WATERGREAT"); + } + else + { + eSummon = EffectSummonCreature("NW_S_FIREHUGE"); + } + break; + } + } + //Make metamagic check for extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), TurnsToSeconds(nDuration)); +} diff --git a/src/_removed/original spells/nw_s0_summon8.nss b/src/_removed/original spells/nw_s0_summon8.nss new file mode 100644 index 0000000..b068b8a --- /dev/null +++ b/src/_removed/original spells/nw_s0_summon8.nss @@ -0,0 +1,129 @@ +//:://///////////////////////////////////////////// +//:: Summon Monster VIII +//:: NW_S0_Summon8 +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Summons a greater earth elemental to fight for the character +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 12, 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 25, 2001 + +#include "x2_inc_spellhook" +void main() +{ + /* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + + */ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + + // End of Spell Cast Hook + + //Declare major variables + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + int nMetaMagic = GetMetaMagicFeat(); + int nDuration = GetCasterLevel(OBJECT_SELF); + effect eSummon; + int nRoll = d4(); + if(GetHasFeat(FEAT_ANIMAL_DOMAIN_POWER)) + { + switch (nRoll) + { + case 1: + if (nInt == 1) + { + eSummon = EffectSummonCreature("NW_S_WATERELDER"); + } + if (nInt != 1) + { + eSummon = EffectSummonCreature("NW_S_AIRELDER"); + } + break; + + case 2: + eSummon = EffectSummonCreature("NW_S_WATERELDER"); + break; + + case 3: + if (nInt == 1) + { + eSummon = EffectSummonCreature("NW_S_WATERELDER"); + } + if (nInt != 1) + { + eSummon = EffectSummonCreature("NW_S_EARTHELDER"); + } + break; + + case 4: + if (nInt == 1) + { + eSummon = EffectSummonCreature("NW_S_WATERELDER"); + } + if (nInt != 1) + { + eSummon = EffectSummonCreature("NW_S_FIREELDER"); + } + break; + + } + } + else + { + switch (nRoll) + { + case 1: + if (nInt == 1) + { + eSummon = EffectSummonCreature("NW_S_WATERGREAT"); + } + if (nInt != 1) + { + eSummon = EffectSummonCreature("NW_S_AIRGREAT"); + } + break; + + case 2: + eSummon = EffectSummonCreature("NW_S_WATERGREAT"); + break; + + case 3: + eSummon = EffectSummonCreature("NW_S_EARTHGREAT"); + break; + + case 4: + if (nInt == 1) + { + eSummon = EffectSummonCreature("NW_S_EARTHGREAT"); + } + if (nInt != 1) + { + eSummon = EffectSummonCreature("NW_S_FIREGREAT"); + } + break; + } + } + + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_3); + //Make metamagic check for extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), TurnsToSeconds(nDuration)); +} diff --git a/src/_removed/original spells/nw_s0_summon9.nss b/src/_removed/original spells/nw_s0_summon9.nss new file mode 100644 index 0000000..bdbacbd --- /dev/null +++ b/src/_removed/original spells/nw_s0_summon9.nss @@ -0,0 +1,89 @@ +//:://///////////////////////////////////////////// +//:: Summon Monster IX +//:: NW_S0_Summon9 +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Summons a elder elemental to fight for the character +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 12, 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 25, 2001 + +#include "x2_inc_spellhook" +void main() +{ + + /* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + + */ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + + // End of Spell Cast Hook + //Declare major variables + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + int nMetaMagic = GetMetaMagicFeat(); + int nDuration = GetCasterLevel(OBJECT_SELF); + effect eSummon; + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_3); + int nRoll = d4(); + switch (nRoll) + { + case 1: + if (nInt == 1) + { + eSummon = EffectSummonCreature("NW_S_WATERELDER"); + } + if (nInt != 1) + { + eSummon = EffectSummonCreature("NW_S_AIRELDER"); + } + break; + + case 2: + eSummon = EffectSummonCreature("NW_S_WATERELDER"); + break; + + case 3: + if (nInt == 1) + { + eSummon = EffectSummonCreature("NW_S_WATERELDER"); + } + if (nInt != 1) + { + eSummon = EffectSummonCreature("NW_S_EARTHELDER"); + } + break; + + case 4: + if (nInt == 1) + { + eSummon = EffectSummonCreature("NW_S_WATERELDER"); + } + if (nInt != 1) + { + eSummon = EffectSummonCreature("NW_S_FIREELDER"); + } + break; + } + //Make metamagic check for extend + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + //Apply the VFX impact and summon effect + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, GetSpellTargetLocation()); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), TurnsToSeconds(nDuration)); +} diff --git a/src/_removed/original spells/nw_s0_sunbeam.nss b/src/_removed/original spells/nw_s0_sunbeam.nss new file mode 100644 index 0000000..e15b108 --- /dev/null +++ b/src/_removed/original spells/nw_s0_sunbeam.nss @@ -0,0 +1,138 @@ +//:://///////////////////////////////////////////// +//:: Sunbeam +//:: s_Sunbeam.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +//:: All creatures in the beam are struck blind and suffer 4d6 points of damage. (A successful +//:: Reflex save negates the blindness and reduces the damage by half.) Creatures to whom sunlight +//:: is harmful or unnatural suffer double damage. +//:: +//:: Undead creatures caught within the ray are dealt 1d6 points of damage per caster level +//:: (maximum 20d6), or half damage if a Reflex save is successful. In addition, the ray results in +//:: the total destruction of undead creatures specifically affected by sunlight if they fail their saves. +//::////////////////////////////////////////////// +//:: Created By: Keith Soleski +//:: Created On: Feb 22, 2001 +//::////////////////////////////////////////////// +//:: Last Modified By: Keith Soleski, On: March 21, 2001 +//:: VFX Pass By: Preston W, On: June 25, 2001 + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Sunbeam' will not work underwater!", oPC); + return; + } +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + int nMetaMagic = GetMetaMagicFeat(); + effect eVis = EffectVisualEffect(VFX_IMP_DEATH); + effect eVis2 = EffectVisualEffect(VFX_IMP_SUNSTRIKE); + effect eStrike = EffectVisualEffect(VFX_FNF_SUNBEAM); + effect eDam; + effect eBlind = EffectBlindness(); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); + effect eLink = EffectLinkEffects(eBlind, eDur); + + int nCasterLevel= GetCasterLevel(OBJECT_SELF); + int nDamage; + int nOrgDam; + int nMax; + float fDelay; + int nBlindLength = 3; + //Limit caster level + if (nCasterLevel > 20) + { + nCasterLevel = 20; + } + //Normal spell effects. + if (nInt != 1) + { + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eStrike, GetSpellTargetLocation()); + //Get the first target in the spell area + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetSpellTargetLocation()); + while(GetIsObjectValid(oTarget)) + { + // Make a faction check + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + fDelay = GetRandomDelay(1.0, 2.0); + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_SUNBEAM)); + //Make an SR check + if ( ! MyResistSpell(OBJECT_SELF, oTarget, 1.0)) + { + //Check if the target is an undead + if (GetRacialType(oTarget) == RACIAL_TYPE_UNDEAD) + { + //Roll damage and save + nDamage = d6(nCasterLevel); + nMax = 6; + } + else + { + //Roll damage and save + nDamage = d6(3); + nOrgDam = nDamage; + nMax = 6; + nCasterLevel = 3; + //Get the adjusted damage due to Reflex Save, Evasion or Improved Evasion + } + + //Do metamagic checks + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = nMax * nCasterLevel; + } + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + (nDamage/2); + } + + //Check that a reflex save was made. + if(MySavingThrow(SAVING_THROW_REFLEX, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_DIVINE, OBJECT_SELF, 1.0) == 0) + { + DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nBlindLength))); + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, 0, SAVING_THROW_TYPE_DIVINE); + } + //Set damage effect + eDam = EffectDamage(nDamage, DAMAGE_TYPE_DIVINE); + if(nDamage > 0) + { + //Apply the damage effect and VFX impact + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis2, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + } + } + } + //Get the next target in the spell area + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetSpellTargetLocation()); + } + } +} diff --git a/src/_removed/original spells/nw_s0_wailbansh.nss b/src/_removed/original spells/nw_s0_wailbansh.nss new file mode 100644 index 0000000..43b6911 --- /dev/null +++ b/src/_removed/original spells/nw_s0_wailbansh.nss @@ -0,0 +1,156 @@ +//:://///////////////////////////////////////////// +//:: Wail of the Banshee +//:: NW_S0_WailBansh +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + You emit a terrible scream that kills enemy creatures who hear it + The spell affects up to one creature per caster level. Creatures + closest to the point of origin are affected first. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Dec 12, 2000 +//::////////////////////////////////////////////// +//:: Last Updated By: Preston Watamaniuk, On: April 11, 2001 +//:: VFX Pass By: Preston W, On: June 25, 2001 + + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oPC = GetFirstPC(); + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + int nToAffect = nCasterLevel; + object oTarget; + float fTargetDistance; + float fDelay; + location lTarget; + effect eVis = EffectVisualEffect(VFX_IMP_DEATH); + effect eWail = EffectVisualEffect(VFX_FNF_WAIL_O_BANSHEES); + int nCnt = 1; + //Apply the FNF VFX impact + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eWail, GetSpellTargetLocation()); + //Get the closet target from the spell target location + oTarget = GetSpellTargetObject(); // direct target + if (!GetIsObjectValid(oTarget)) + oTarget = GetNearestObjectToLocation(OBJECT_TYPE_CREATURE, GetSpellTargetLocation(), nCnt); + while (nCnt <= nToAffect) + { + lTarget = GetLocation(oTarget); + //Get the distance of the target from the center of the effect + fDelay = GetRandomDelay(3.0, 4.0);// + fTargetDistance = GetDistanceBetweenLocations(GetSpellTargetLocation(), lTarget); + //Check that the current target is valid and closer than 10.0m + if(GetIsObjectValid(oTarget) && fTargetDistance <= 10.0) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, OBJECT_SELF)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_WAIL_OF_THE_BANSHEE)); + //Make SR check + if(!MyResistSpell(OBJECT_SELF, oTarget)) //, 0.1)) + { + //Make a fortitude save to avoid death + if(!MySavingThrow(SAVING_THROW_FORT, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_DEATH)) //, OBJECT_SELF, 3.0)) + { + //Apply the delay VFX impact and death effect + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + effect eDeath = EffectDeath(); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDeath, oTarget)); // no delay + } + } + } + } + else + { + //Kick out of the loop + nCnt = nToAffect; + } + //Increment the count of creatures targeted + nCnt++; + //Get the next closest target in the spell target location. + oTarget = GetNearestObjectToLocation(OBJECT_TYPE_CREATURE, GetSpellTargetLocation(), nCnt); + } +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Wail of the Banshee' has caused a cave-in!", oPC)); + } +} diff --git a/src/_removed/original spells/nw_s0_wallfire.nss b/src/_removed/original spells/nw_s0_wallfire.nss new file mode 100644 index 0000000..7c40330 --- /dev/null +++ b/src/_removed/original spells/nw_s0_wallfire.nss @@ -0,0 +1,59 @@ +//:://///////////////////////////////////////////// +//:: Wall of Fire +//:: NW_S0_WallFire.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Creates a wall of fire that burns any creature + entering the area around the wall. Those moving + through the AOE are burned for 4d6 fire damage +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: July 17, 2001 +//::////////////////////////////////////////////// + +void main() +{ + //Declare major variables + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Declare Area of Effect object using the appropriate constant + effect eAOE = EffectAreaOfEffect(AOE_PER_WALLFIRE); + //Get the location where the wall is to be placed. + location lTarget = GetSpellTargetLocation(); + int nDuration = GetCasterLevel(OBJECT_SELF) / 2; + if(nDuration == 0) + { + nDuration = 1; + } + int nMetaMagic = GetMetaMagicFeat(); + + //Check fort metamagic + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration *2; //Duration is +100% + } + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Wall of Fire' will not work underwater!", oPC); + return; + } + //Normal spell effects. + if (nInt != 1) + { + //Create the Area of Effect Object declared above. + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eAOE, lTarget, RoundsToSeconds(nDuration)); + // TK added for cheat casting + if (GetLocalInt(OBJECT_SELF, "AI_CHEAT_CASTING")) + { + // shades = 158 + DecrementRemainingSpellUses(OBJECT_SELF, 158); + DeleteLocalInt(OBJECT_SELF, "AI_CHEAT_CASTING"); + } + } +} diff --git a/src/_removed/original spells/nw_s0_wallfirea.nss b/src/_removed/original spells/nw_s0_wallfirea.nss new file mode 100644 index 0000000..10ce9df --- /dev/null +++ b/src/_removed/original spells/nw_s0_wallfirea.nss @@ -0,0 +1,73 @@ +//:://///////////////////////////////////////////// +//:: Wall of Fire: On Enter +//:: NW_S0_WallFireA.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Person within the AoE take 4d6 fire damage + per round. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: May 17, 2001 +//::////////////////////////////////////////////// + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + + //Declare major variables + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + int nMetaMagic = GetMetaMagicFeat(); + int nDamage; + effect eDam; + object oTarget; + //Declare and assign personal impact visual effect. + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_M); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Wall of Fire' will not work underwater!", oPC); + return; + } + //Normal spell effects. + if (nInt != 1) + { + //Capture the first target object in the shape. + oTarget = GetEnteringObject(); + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, GetAreaOfEffectCreator())) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_WALL_OF_FIRE)); + //Make SR check, and appropriate saving throw(s). + if(!MyResistSpell(GetAreaOfEffectCreator(), oTarget)) + { + //Roll damage. + nDamage = d6(4); + //Enter Metamagic conditions + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 24;//Damage is at max + } + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + (nDamage/2); //Damage/Healing is +50% + } + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_FIRE); + if(nDamage > 0) + { + // Apply effects to the currently selected target. + eDam = EffectDamage(nDamage, DAMAGE_TYPE_FIRE); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + } + } + } + } +} diff --git a/src/_removed/original spells/nw_s0_wallfirec.nss b/src/_removed/original spells/nw_s0_wallfirec.nss new file mode 100644 index 0000000..e07e377 --- /dev/null +++ b/src/_removed/original spells/nw_s0_wallfirec.nss @@ -0,0 +1,90 @@ +//:://///////////////////////////////////////////// +//:: Wall of Fire: Heartbeat +//:: NW_S0_WallFireA.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Person within the AoE take 4d6 fire damage + per round. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: May 17, 2001 +//::////////////////////////////////////////////// + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + + //Declare major variables + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + int nMetaMagic = GetMetaMagicFeat(); + int nDamage; + effect eDam; + object oTarget; + //Declare and assign personal impact visual effect. + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_M); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Wall of Fire' will not work underwater!", oPC); + return; + } + //Normal spell effects. + if (nInt != 1) + { + //Capture the first target object in the shape. + //-------------------------------------------------------------------------- + // GZ 2003-Oct-15 + // When the caster is no longer there, all functions calling + // GetAreaOfEffectCreator will fail. Its better to remove the barrier then + //-------------------------------------------------------------------------- + if (!GetIsObjectValid(GetAreaOfEffectCreator())) + { + DestroyObject(OBJECT_SELF); + return; + } + + oTarget = GetFirstInPersistentObject(OBJECT_SELF,OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + //Declare the spell shape, size and the location. + while(GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, GetAreaOfEffectCreator())) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_WALL_OF_FIRE)); + //Make SR check, and appropriate saving throw(s). + if(!MyResistSpell(GetAreaOfEffectCreator(), oTarget)) + { + //Roll damage. + nDamage = d6(4); + //Enter Metamagic conditions + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 24;//Damage is at max + } + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + (nDamage/2); //Damage/Healing is +50% + } + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_FIRE); + if(nDamage > 0) + { + // Apply effects to the currently selected target. + eDam = EffectDamage(nDamage, DAMAGE_TYPE_FIRE); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eVis, oTarget, 1.0); + } + } + } + //Select the next target within the spell shape. + oTarget = GetNextInPersistentObject(OBJECT_SELF,OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } + } +} diff --git a/src/_removed/original spells/x0_s0_bombard.nss b/src/_removed/original spells/x0_s0_bombard.nss new file mode 100644 index 0000000..155bfcc --- /dev/null +++ b/src/_removed/original spells/x0_s0_bombard.nss @@ -0,0 +1,177 @@ +//:://///////////////////////////////////////////// +//:: Bombardment +//:: X0_S0_Bombard +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* +// Rocks fall from sky +// 1d8 damage/level to a max of 10d8 +// Reflex save for half +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 22 2002 +//::////////////////////////////////////////////// +//:: Last Updated By: Andrew Nobbs May 01, 2003 + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + object oCaster = OBJECT_SELF; + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Bombardment' will not work underwater!", oPC); + return; + } +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + int nCasterLvl = GetCasterLevel(oCaster); + int nMetaMagic = GetMetaMagicFeat(); + int nDamage; + float fDelay; + effect eExplode = EffectVisualEffect(VFX_FNF_METEOR_SWARM); + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_M); + effect eDam; + //Get the spell target location as opposed to the spell target. + location lTarget = GetSpellTargetLocation(); + //Limit Caster level for the purposes of damage + if (nCasterLvl > 10) + { + nCasterLvl = 10; + } + //Normal spell effects. + if (nInt != 1) + { + //Apply the fireball explosion at the location captured above. + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, lTarget); + //Declare the spell shape, size and the location. Capture the first target object in the shape. + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget)) + { + if(spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF) == TRUE) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + //Get the distance between the explosion and the target to calculate delay + fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oTarget))/20; + if (!MyResistSpell(OBJECT_SELF, oTarget, fDelay)) + { + //Roll damage for each target + nDamage = d8(nCasterLvl); + //Resolve metamagic + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 8 * nCasterLvl; + } + else if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + nDamage / 2; + } + //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_ALL); + //Set the damage effect + eDam = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING); + if(nDamage > 0) + { + + // Apply effects to the currently selected target. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + //This visual effect is applied to the target object not the location as above. This visual effect + //represents the flame that erupts on the target not on the ground. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + } + //Select the next target within the spell shape. + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } + } +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Bombardment' has caused a cave-in!", oPC)); + } +} + + + + diff --git a/src/_removed/original spells/x0_s0_drown.nss b/src/_removed/original spells/x0_s0_drown.nss new file mode 100644 index 0000000..4b3560b --- /dev/null +++ b/src/_removed/original spells/x0_s0_drown.nss @@ -0,0 +1,93 @@ +//:://///////////////////////////////////////////// +//:: Drown +//:: [X0_S0_Drown.nss] +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* + if the creature fails a FORT throw. + Does not work against Undead, Constructs, or Elementals. + +January 2003: + - Changed to instant kill the target. +May 2003: + - Changed damage to 90% of current HP, instead of instant kill. + +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 26 2002 +//::////////////////////////////////////////////// +//:: Last Update By: Andrew Nobbs May 01, 2003 + +#include "NW_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Drown' is pointless underwater!", oPC); + return; + } +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oTarget = GetSpellTargetObject(); + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + int nDam = GetCurrentHitPoints(oTarget); + //Set visual effect + effect eVis = EffectVisualEffect(VFX_IMP_FROST_S); + effect eDam; +//Normal spell effects. +if (nInt != 1) +{ + //Check faction of target + if(!GetIsReactionTypeFriendly(oTarget)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, 437)); + //Make SR Check + if(!MyResistSpell(OBJECT_SELF, oTarget)) + { + // * certain racial types are immune + if ((GetRacialType(oTarget) != RACIAL_TYPE_CONSTRUCT) + &&(GetRacialType(oTarget) != RACIAL_TYPE_UNDEAD) + &&(GetRacialType(oTarget) != RACIAL_TYPE_ELEMENTAL)) + { + //Make a fortitude save + if(!MySavingThrow(SAVING_THROW_FORT, oTarget, GetSpellSaveDC())) + { + nDam = FloatToInt(nDam * 0.9); + eDam = EffectDamage(nDam, DAMAGE_TYPE_BLUDGEONING); + //Apply the VFX impact and damage effect + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); + + } + } + } + } + } +} + diff --git a/src/_removed/original spells/x0_s0_earthquake.nss b/src/_removed/original spells/x0_s0_earthquake.nss new file mode 100644 index 0000000..a608ca5 --- /dev/null +++ b/src/_removed/original spells/x0_s0_earthquake.nss @@ -0,0 +1,166 @@ +//:://///////////////////////////////////////////// +//:: Earthquake +//:: X0_S0_Earthquake +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* +// Ground shakes. 1d6 damage, max 10d6 +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 22 2002 +//::////////////////////////////////////////////// +//:: Last Updated By: Andrew Nobbs May 01, 2003 + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oPC = GetFirstPC(); + object oCaster = OBJECT_SELF; + int nCasterLvl = GetCasterLevel(oCaster); + int nMetaMagic = GetMetaMagicFeat(); + int nDamage; + float fDelay; + float nSize = RADIUS_SIZE_COLOSSAL; + effect eExplode = EffectVisualEffect(VFX_FNF_LOS_NORMAL_30); + effect eVis = EffectVisualEffect(VFX_IMP_HEAD_NATURE); + effect eDam; + effect eShake = EffectVisualEffect(356); + //Get the spell target location as opposed to the spell target. + location lTarget = GetSpellTargetLocation(); + //Limit Caster level for the purposes of damage + if (nCasterLvl > 10) + { + nCasterLvl = 10; + } + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eShake, OBJECT_SELF, RoundsToSeconds(6)); + + //Apply epicenter explosion on caster + //ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, GetLocation(OBJECT_SELF)); + + + //Declare the spell shape, size and the location. Capture the first target object in the shape. + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, nSize, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_EARTHQUAKE)); + //Get the distance between the explosion and the target to calculate delay + fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oTarget))/20; +// Earthquake does not allow spell resistance +// if (!MyResistSpell(OBJECT_SELF, oTarget, fDelay)) + { + + nDamage = MaximizeOrEmpower(6, nCasterLvl, GetMetaMagicFeat()); + //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. (Don't bother for caster) + if (oTarget != oCaster) + { + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_ALL); + } + //Set the damage effect + eDam = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING); + // * caster can't be affected by the spell + if( (nDamage > 0) && (oTarget != oCaster)) + { + + // Apply effects to the currently selected target. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + //This visual effect is applied to the target object not the location as above. This visual effect + //represents the flame that erupts on the target not on the ground. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + } + //Select the next target within the spell shape. + oTarget = GetNextObjectInShape(SHAPE_SPHERE, nSize, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Earthquake' has caused a cave-in!", oPC)); + } +} + + + + + diff --git a/src/_removed/original spells/x0_s0_elecjolt.nss b/src/_removed/original spells/x0_s0_elecjolt.nss new file mode 100644 index 0000000..331e26c --- /dev/null +++ b/src/_removed/original spells/x0_s0_elecjolt.nss @@ -0,0 +1,48 @@ +//:://///////////////////////////////////////////// +//:: Electric Jolt +//:: [x0_s0_ElecJolt.nss] +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* +1d3 points of electrical damage to one target. +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 17 2002 +//::////////////////////////////////////////////// + +#include "X0_I0_SPELLS" + +void main() +{ + //Declare major variables + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + object oCaster = OBJECT_SELF; + object oTarget = GetSpellTargetObject(); + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + + + effect eVis = EffectVisualEffect(VFX_IMP_LIGHTNING_S); + if(!GetIsReactionTypeFriendly(oTarget)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_ELECTRIC_JOLT)); + //Make SR Check + if(!MyResistSpell(OBJECT_SELF, oTarget)) + { + //Set damage effect + effect eBad = EffectDamage(MaximizeOrEmpower(3, 1, GetMetaMagicFeat()), DAMAGE_TYPE_ELECTRICAL); + //Apply the VFX impact and damage effect (reflected upon PC) + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oCaster); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eBad, oCaster); + FloatingTextStringOnCreature("The spell 'Electric Jolt' is reflected underwater!", oPC); + } + //Apply the VFX impact and damage effect + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eBad, oTarget); + } + } +} diff --git a/src/_removed/original spells/x0_s0_firebrand.nss b/src/_removed/original spells/x0_s0_firebrand.nss new file mode 100644 index 0000000..18659af --- /dev/null +++ b/src/_removed/original spells/x0_s0_firebrand.nss @@ -0,0 +1,42 @@ +//:://///////////////////////////////////////////// +//:: Firebrand +//:: x0_x0_Firebrand +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* +// * Fires a flame arrow to every target in a +// * colossal area +// * Each target explodes into a small fireball for +// * 1d6 damage / level (max = 15 levels) +// * Only nLevel targets can be affected +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 29 2002 +//::////////////////////////////////////////////// +//:: Last Updated By: + +#include "X0_I0_SPELLS" +void main() +{ + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Firebrand' will not work underwater!", oPC); + return; + } +// + int nDamage = GetCasterLevel(OBJECT_SELF); + if (nDamage > 15) + nDamage = 15; + //Normal spell effects. + if (nInt != 1) + { + DoMissileStorm(nDamage, 15, SPELL_FIREBRAND, VFX_IMP_MIRV_FLAME, VFX_IMP_FLAME_M, DAMAGE_TYPE_FIRE, TRUE); + } +} diff --git a/src/_removed/original spells/x0_s0_flare.nss b/src/_removed/original spells/x0_s0_flare.nss new file mode 100644 index 0000000..c4aa3aa --- /dev/null +++ b/src/_removed/original spells/x0_s0_flare.nss @@ -0,0 +1,56 @@ +//:://///////////////////////////////////////////// +//:: Flare +//:: [X0_S0_Flare.nss] +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* + Creature hit by ray loses 1 to attack rolls. + + DURATION: 10 rounds. +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 17 2002 +//::////////////////////////////////////////////// + +#include "NW_I0_SPELLS" +void main() +{ //Declare major variables + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + object oTarget = GetSpellTargetObject(); + int nCasterLevel = GetCasterLevel(OBJECT_SELF); + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_S); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Flare' will not work underwater!", oPC); + return; + } + //Normal spell effects. + if (nInt != 1) + { + if(!GetIsReactionTypeFriendly(oTarget)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, 416)); + + // * Apply the hit effect so player knows something happened + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + + + //Make SR Check + if ((!MyResistSpell(OBJECT_SELF, oTarget)) && (MySavingThrow(SAVING_THROW_FORT, oTarget, GetSpellSaveDC()) == FALSE) ) + { + //Set damage effect + effect eBad = EffectAttackDecrease(1); + //Apply the VFX impact and damage effect + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBad, oTarget, RoundsToSeconds(10)); + } + } + } +} + diff --git a/src/_removed/original spells/x0_s0_gustwind.nss b/src/_removed/original spells/x0_s0_gustwind.nss new file mode 100644 index 0000000..106b343 --- /dev/null +++ b/src/_removed/original spells/x0_s0_gustwind.nss @@ -0,0 +1,105 @@ +//:://///////////////////////////////////////////// +//:: Gust of Wind +//:: [x0_s0_gustwind.nss] +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* + This spell creates a gust of wind in all directions + around the target. All targets in a medium area will be + affected: + - Target must make a For save vs. spell DC or be + knocked down for 3 rounds + - plays a wind sound + - if an area of effect object is within the area + it is dispelled +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: September 7, 2002 +//::////////////////////////////////////////////// + +#include "X0_I0_SPELLS" +void main() +{ + //Declare major variables + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + object oCaster = OBJECT_SELF; + int nCasterLvl = GetCasterLevel(oCaster); + int nMetaMagic = GetMetaMagicFeat(); + int nDamage; + float fDelay; + effect eExplode = EffectVisualEffect(VFX_FNF_LOS_NORMAL_20); + effect eVis = EffectVisualEffect(VFX_IMP_PULSE_WIND); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Gust of Wind' will not work underwater!", oPC); + return; + } + //Normal spell effects. + if (nInt != 1) + { + // effect eDam; + //Get the spell target location as opposed to the spell target. + location lTarget = GetSpellTargetLocation(); + + //Apply the fireball explosion at the location captured above. + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, lTarget); + + + //Declare the spell shape, size and the location. Capture the first target object in the shape. + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE | OBJECT_TYPE_AREA_OF_EFFECT); + + + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget)) + { + if (GetObjectType(oTarget) == OBJECT_TYPE_AREA_OF_EFFECT) + { + DestroyObject(oTarget); + } + else + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + //Get the distance between the explosion and the target to calculate delay + fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oTarget))/20; + + // * unlocked doors will reverse their open state + if (GetObjectType(oTarget) == OBJECT_TYPE_DOOR) + { + if (GetLocked(oTarget) == FALSE) + { + if (GetIsOpen(oTarget) == FALSE) + { + AssignCommand(oTarget, ActionOpenDoor(oTarget)); + } + else + AssignCommand(oTarget, ActionCloseDoor(oTarget)); + } + } + if(!MyResistSpell(OBJECT_SELF, oTarget) && !/*Fort Save*/ MySavingThrow(SAVING_THROW_FORT, oTarget, GetSpellSaveDC())) + { + + effect eKnockdown = EffectKnockdown(); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eKnockdown, oTarget, RoundsToSeconds(3)); + // Apply effects to the currently selected target. + // DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + //This visual effect is applied to the target object not the location as above. This visual effect + //represents the flame that erupts on the target not on the ground. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + + } + } + } + //Select the next target within the spell shape. + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE |OBJECT_TYPE_AREA_OF_EFFECT); + } + } +} + diff --git a/src/_removed/original spells/x0_s0_inferno.nss b/src/_removed/original spells/x0_s0_inferno.nss new file mode 100644 index 0000000..dc18684 --- /dev/null +++ b/src/_removed/original spells/x0_s0_inferno.nss @@ -0,0 +1,110 @@ +//:://///////////////////////////////////////////// +//:: Inferno +//:: x0_s0_inferno.nss +//:: Copyright (c) 2000 Bioware Corp. +//::////////////////////////////////////////////// +/* + Converted Melf's Acid Arrow script. + Does 2d6 fire per round + + Duration: 1 round per level +*/ +///////////////////////////////////////////////////////// +//::////////////////////////////////////////////// +//:: Created By: Aidan Scanlan +//:: Created On: 01/09/01 +//::////////////////////////////////////////////// +//:: Update Pass By: Preston W, On: Aug 2, 2001 + +#include "X0_I0_SPELLS" + +void RunImpact(int nSecondsRemaining, object oTarget); +void DoDamage(object oTarget); + +void main() +{ + //Declare major variables + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Inferno' will not work underwater!", oPC); + return; + } +// + object oTarget = GetSpellTargetObject(); + int nMetaMagic = GetMetaMagicFeat(); + int nCount; + effect eArrow; + int nDuration = GetCasterLevel(OBJECT_SELF) - 1;// (-1 because we are delaying the first impact by 1 round) + + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration * 2; + } + + + //figure out projectile timing + float fDist = GetDistanceToObject(oTarget); + float fDelay = (fDist/25.0);//(3.0 * log(fDist) + 2.0); + //Check that there is at least one payload damage + + eArrow = EffectVisualEffect(VFX_FNF_FIREBALL); + + if (nDuration < 1) + { + nDuration = 1; + } + //Normal spell effects. + if (nInt != 1) + { + if(!GetIsReactionTypeFriendly(oTarget)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, 446)); + //Make an SR check + if(!MyResistSpell(OBJECT_SELF, oTarget, fDelay)) + { + DoDamage(oTarget); + //Apply the bonus damage + nDuration = nDuration * 6; + DelayCommand(6.0, RunImpact(nDuration, oTarget)); + } + } + ApplyEffectToObject(DURATION_TYPE_INSTANT, eArrow, oTarget); + } +} +void DoDamage(object oTarget) +{ + int nMetaMagic = GetMetaMagicFeat(); + effect eDam = EffectDamage(MaximizeOrEmpower(6,2,nMetaMagic), DAMAGE_TYPE_FIRE); + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_S); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); +} + + +void RunImpact(int nSecondsRemaining, object oTarget) +{ + if (GetIsDead(oTarget) == FALSE) + { + if (nSecondsRemaining % 6 == 0) + { + DoDamage(oTarget); + } + --nSecondsRemaining; + if (nSecondsRemaining > 0) + { + DelayCommand(1.0f,RunImpact(nSecondsRemaining,oTarget)); + } + } + // Note: if the target is dead during one of these second-long heartbeats, + // the DelayCommand doesn't get run again, and the whole package goes away. + // Do NOT attempt to put more than two parameters on the delay command. They + // may all end up on the stack, and that's all bad. 60 x 2 = 120. +} + diff --git a/src/_removed/original spells/x0_s0_ironhorn.nss b/src/_removed/original spells/x0_s0_ironhorn.nss new file mode 100644 index 0000000..325b0e7 --- /dev/null +++ b/src/_removed/original spells/x0_s0_ironhorn.nss @@ -0,0 +1,168 @@ +//:://///////////////////////////////////////////// +//:: Balagarn's Iron Horn +//:: +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* +// Create a virbration that shakes creatures off their feet. +// Make a strength check as if caster has strength 20 +// against all enemies in area +// Changes it so its not a cone but a radius. +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 22 2002 +//::////////////////////////////////////////////// +//:: Last Updated By: Andrew Nobbs May 01, 2003 + +#include "X0_I0_SPELLS" + +#include "x2_inc_spellhook" + +void main() +{ + object oPC = GetFirstPC(); + object oCaster = OBJECT_SELF; + int nInt=GetLocalInt(oPC, "Underwater"); +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + int nCasterLvl = GetCasterLevel(oCaster); + int nMetaMagic = GetMetaMagicFeat(); + float fDelay; + float nSize = RADIUS_SIZE_COLOSSAL; + effect eExplode = EffectVisualEffect(VFX_FNF_HOWL_WAR_CRY); + effect eVis = EffectVisualEffect(VFX_IMP_HEAD_NATURE); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_BUMP); + //Get the spell target location as opposed to the spell target. + location lTarget = GetSpellTargetLocation(); + //Limit Caster level for the purposes of damage + if (nCasterLvl > 20) + { + nCasterLvl = 20; + } + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eShake, OBJECT_SELF, RoundsToSeconds(d3())); + //Apply epicenter explosion on caster + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, GetLocation(OBJECT_SELF)); + //Declare the spell shape, size and the location. Capture the first target object in the shape. + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, nSize, lTarget, TRUE, OBJECT_TYPE_CREATURE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget)) + { + // * spell should not affect the caster + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF) && (oTarget != oCaster)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, 436)); + //Get the distance between the explosion and the target to calculate delay + fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oTarget))/20; + if (!MyResistSpell(OBJECT_SELF, oTarget, fDelay)) + { + effect eTrip = EffectKnockdown(); + // * DO a strength check vs. Strength 20 + if (d20() + GetAbilityScore(oTarget, ABILITY_STRENGTH) <= 20 + d20() ) + { + //Apply the VFX impact and damage effect (reflected upon PC) + if (nInt == 1) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eTrip, oCaster, 6.0)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oCaster)); + FloatingTextStringOnCreature("The spell 'Balagarn's Iron Horn' is reflected underwater!", oPC); + } + // Apply effects to the currently selected target. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eTrip, oTarget, 6.0)); + //This visual effect is applied to the target object not the location as above. This visual effect + //represents the flame that erupts on the target not on the ground. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + else + FloatingTextStrRefOnCreature(2750, OBJECT_SELF, FALSE); + } + } + //Select the next target within the spell shape. + oTarget = GetNextObjectInShape(SHAPE_SPHERE, nSize, lTarget, TRUE, OBJECT_TYPE_CREATURE); + } +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Balagarn's Iron Horn' has caused a cave-in!", oPC)); + } +} + + + + + + + + diff --git a/src/_removed/original spells/x0_s0_sunburst.nss b/src/_removed/original spells/x0_s0_sunburst.nss new file mode 100644 index 0000000..787915e --- /dev/null +++ b/src/_removed/original spells/x0_s0_sunburst.nss @@ -0,0 +1,223 @@ +//:://///////////////////////////////////////////// +//:: Sunburst +//:: X0_S0_Sunburst +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* +// Brilliant globe of heat +// All creatures in the globe are blinded and +// take 6d6 damage +// Undead creatures take 1d6 damage (max 25d6) +// The blindness is permanent unless cast to remove it +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 23 2002 +//::////////////////////////////////////////////// +//:: Last Updated By: Andrew Nobbs May 14, 2003 +//:: Notes: Changed damage to non-undead to 6d6 +//:: 2003-10-09: GZ Added Subrace check for vampire special case, bugfix + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" + +float nSize = RADIUS_SIZE_COLOSSAL; + + + +void main() +{ + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + object oCaster = OBJECT_SELF; + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Sunburst' will not work underwater!", oPC); + return; + } +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + int nCasterLvl = GetCasterLevel(oCaster); + int nMetaMagic = GetMetaMagicFeat(); + int nDamage = 0; + float fDelay; + effect eExplode = EffectVisualEffect(VFX_IMP_SUNSTRIKE); + effect eVis = EffectVisualEffect(VFX_IMP_HEAD_HOLY); + effect eHitVis = EffectVisualEffect(VFX_IMP_DIVINE_STRIKE_FIRE); + effect eLOS = EffectVisualEffect(VFX_FNF_LOS_HOLY_30); + effect eDam; + //Get the spell target location as opposed to the spell target. + location lTarget = GetSpellTargetLocation(); + //Limit Caster level for the purposes of damage + if (nCasterLvl > 25) + { + nCasterLvl = 25; + } + //Normal spell effects. + if (nInt != 1) + { + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, OBJECT_SELF); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eLOS, GetSpellTargetLocation()); + int bDoNotDoDamage = FALSE; + + + //Declare the spell shape, size and the location. Capture the first target object in the shape. + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, nSize, lTarget, TRUE, OBJECT_TYPE_CREATURE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, OBJECT_SELF)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_SUNBURST)); + //This visual effect is applied to the target object not the location as above. This visual effect + //represents the flame that erupts on the target not on the ground. + ApplyEffectToObject(DURATION_TYPE_INSTANT, eHitVis, oTarget); + + if (!MyResistSpell(OBJECT_SELF, oTarget, fDelay)) + { + if (GetRacialType(oTarget) == RACIAL_TYPE_UNDEAD) + { + //Roll damage for each target + nDamage = MaximizeOrEmpower(6, nCasterLvl, nMetaMagic); + } + else + { + nDamage = MaximizeOrEmpower(6, 6, nMetaMagic); + } + + // * if a vampire then destroy it + if (GetAppearanceType(oTarget) == APPEARANCE_TYPE_VAMPIRE_MALE || GetAppearanceType(oTarget) == APPEARANCE_TYPE_VAMPIRE_FEMALE || GetStringLowerCase(GetSubRace(oTarget)) == "vampire" ) + { + // SpeakString("I vampire"); + // * if reflex saving throw fails no blindness + if (!ReflexSave(oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_SPELL)) + { + effect eDead = EffectDamage(GetCurrentHitPoints(oTarget)); + //ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_FLAME_M), oTarget); + + //Apply epicenter explosion on caster + ApplyEffectToObject(DURATION_TYPE_INSTANT, eExplode, oTarget); + + DelayCommand(0.5, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDead, oTarget)); + bDoNotDoDamage = TRUE; + } + } + if (bDoNotDoDamage == FALSE) + //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_SPELL); + + // * Do damage + if ((nDamage > 0) && (bDoNotDoDamage == FALSE)) + { + //Set the damage effect + eDam = EffectDamage(nDamage, DAMAGE_TYPE_MAGICAL); + + // Apply effects to the currently selected target. + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); + + + + if (GetRacialType(oTarget) != RACIAL_TYPE_UNDEAD) + { + // * if reflex saving throw fails no blindness + if (!ReflexSave(oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_SPELL)) + { + effect eBlindness = EffectBlindness(); + ApplyEffectToObject(DURATION_TYPE_PERMANENT, eBlindness, oTarget); + } + } + + } // nDamage > 0 + } + + //----------------------------------------------------------------- + // GZ: Bugfix, reenable damage for next object + //----------------------------------------------------------------- + bDoNotDoDamage = FALSE; + } + //Select the next target within the spell shape. + oTarget = GetNextObjectInShape(SHAPE_SPHERE, nSize, lTarget, TRUE, OBJECT_TYPE_CREATURE); + } + } +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Sunburst' has caused a cave-in!", oPC)); + } +} + diff --git a/src/_removed/original spells/x2_s0_combust.nss b/src/_removed/original spells/x2_s0_combust.nss new file mode 100644 index 0000000..5261870 --- /dev/null +++ b/src/_removed/original spells/x2_s0_combust.nss @@ -0,0 +1,210 @@ +//:://///////////////////////////////////////////// +//:: Combust +//:: X2_S0_Combust +//:: Copyright (c) 2000 Bioware Corp. +//::////////////////////////////////////////////// +/* + The initial eruption of flame causes 2d6 fire damage +1 + point per caster level(maximum +10) + with no saving throw. + + Further, the creature must make + a Reflex save or catch fire taking a further 1d6 points + of damage. This will continue until the Reflex save is + made. + + There is an undocumented artificial limit of + 10 + casterlevel rounds on this spell to prevent + it from running indefinitly when used against + fire resistant creatures with bad saving throws + +*/ +//::////////////////////////////////////////////// +// Created: 2003/09/05 Georg Zoeller +//::////////////////////////////////////////////// + +#include "x2_I0_SPELLS" +#include "x2_inc_toollib" +#include "x2_inc_spellhook" + +void RunCombustImpact(object oTarget, object oCaster, int nLevel, int nMetaMagic); + +void main() +{ + object oPC = GetFirstPC(); + object oCaster = OBJECT_SELF; + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Spell will fail if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Combust' will not work underwater!", oPC); + return; + } + object oTarget = GetSpellTargetObject(); + + //-------------------------------------------------------------------------- + // Spellcast Hook Code + // Added 2003-06-20 by Georg + // If you want to make changes to all spells, check x2_inc_spellhook.nss to + // find out more + //-------------------------------------------------------------------------- + if (!X2PreSpellCastCode()) + { + return; + } + // End of Spell Cast Hook + + //-------------------------------------------------------------------------- + // Calculate the save DC + //-------------------------------------------------------------------------- + int nDC = GetSpellSaveDC(); + int nLevel = GetCasterLevel(OBJECT_SELF); + + + //-------------------------------------------------------------------------- + // Calculate the damage, 2d6 + casterlevel, capped at +10 + //-------------------------------------------------------------------------- + int nDamage = GetCasterLevel(OBJECT_SELF); + if (nDamage > 10) + { + nDamage = 10; + } + int nMetaMagic = GetMetaMagicFeat(); + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage += 12;//Damage is at max + } + else + { + nDamage += d6(2); + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + (nDamage/2);//Damage/Healing is +50% + } + } + + //-------------------------------------------------------------------------- + // Calculate the duration (we need a duration or bad things would happen + // if someone is immune to fire but fails his safe all the time) + //-------------------------------------------------------------------------- + int nDuration = 10 + GetCasterLevel(OBJECT_SELF); + if (nDuration < 1) + { + nDuration = 10; + } + + //-------------------------------------------------------------------------- + // Setup Effects + //-------------------------------------------------------------------------- + effect eDam = EffectDamage(nDamage, DAMAGE_TYPE_FIRE); + effect eDur = EffectVisualEffect(498); + + if(!GetIsReactionTypeFriendly(oTarget)) + { + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + + //----------------------------------------------------------------------- + // Check SR + //----------------------------------------------------------------------- + if(!MyResistSpell(OBJECT_SELF, oTarget)) + { + + //------------------------------------------------------------------- + // Apply VFX + //------------------------------------------------------------------- + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); + TLVFXPillar(VFX_IMP_FLAME_M, GetLocation(oTarget), 5, 0.1f,0.0f, 2.0f); + + //------------------------------------------------------------------ + // This spell no longer stacks. If there is one of that type, + // that's enough + //------------------------------------------------------------------ + if (GetHasSpellEffect(GetSpellId(),oTarget) || GetHasSpellEffect(SPELL_INFERNO,oTarget) ) + { + FloatingTextStrRefOnCreature(100775,OBJECT_SELF,FALSE); + return; + } + + //------------------------------------------------------------------ + // Apply the VFX that is used to track the spells duration + //------------------------------------------------------------------ + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDur, oTarget, RoundsToSeconds(nDuration)); + + //------------------------------------------------------------------ + // Save the spell save DC as a variable for later retrieval + //------------------------------------------------------------------ + SetLocalInt(oTarget,"XP2_L_SPELL_SAVE_DC_" + IntToString (SPELL_COMBUST), nDC); + + //------------------------------------------------------------------ + // Tick damage after 6 seconds again + //------------------------------------------------------------------ + DelayCommand(6.0, RunCombustImpact(oTarget,oCaster,nLevel, nMetaMagic)); + } + } +} + +void RunCombustImpact(object oTarget, object oCaster, int nLevel, int nMetaMagic) +{ + //-------------------------------------------------------------------------- + // Check if the spell has expired (check also removes effects) + //-------------------------------------------------------------------------- + if (GZGetDelayedSpellEffectsExpired(SPELL_COMBUST,oTarget,oCaster)) + { + return; + } + + if (GetIsDead(oTarget) == FALSE) + { + + int nDC = GetLocalInt(oTarget,"XP2_L_SPELL_SAVE_DC_" + IntToString (SPELL_COMBUST)); + + if(!MySavingThrow(SAVING_THROW_REFLEX, oTarget, nDC, SAVING_THROW_TYPE_FIRE)) + { + //------------------------------------------------------------------ + // Calculate the damage, 1d6 + casterlevel, capped at +10 + //------------------------------------------------------------------ + int nDamage = nLevel; + if (nDamage > 10) + { + nDamage = 10; + } + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage += 6; + } + else + { + nDamage += d6(); + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + (nDamage/2); + } + } + + effect eDmg = EffectDamage(nDamage,DAMAGE_TYPE_FIRE); + effect eVFX = EffectVisualEffect(VFX_IMP_FLAME_S); + + ApplyEffectToObject(DURATION_TYPE_INSTANT,eDmg,oTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT,eVFX,oTarget); + + //------------------------------------------------------------------ + // After six seconds (1 round), check damage again + //------------------------------------------------------------------ + DelayCommand(6.0f,RunCombustImpact(oTarget,oCaster, nLevel,nMetaMagic)); + } + else + { + DeleteLocalInt(oTarget,"XP2_L_SPELL_SAVE_DC_" + IntToString (SPELL_COMBUST)); + GZRemoveSpellEffects(SPELL_COMBUST, oTarget); + } + + } + +} + + + + + diff --git a/src/_removed/original spells/x2_s0_elecloop.nss b/src/_removed/original spells/x2_s0_elecloop.nss new file mode 100644 index 0000000..5f3a230 --- /dev/null +++ b/src/_removed/original spells/x2_s0_elecloop.nss @@ -0,0 +1,153 @@ +//:://///////////////////////////////////////////// +//:: Gedlee's Electric Loop +//:: X2_S0_ElecLoop +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + You create a small stroke of lightning that + cycles through all creatures in the area of effect. + The spell deals 1d6 points of damage per 2 caster + levels (maximum 5d6). Those who fail their Reflex + saves must succeed at a Will save or be stunned + for 1 round. + + Spell is standard hostile, so if you use it + in hardcore mode, it will zap yourself! + +*/ +//::////////////////////////////////////////////// +//:: Created By: Georg Zoeller +//:: Created On: Oct 19 2003 +//::////////////////////////////////////////////// + + +#include "x2_I0_SPELLS" +#include "x2_inc_spellhook" + + +void main() +{ + + //-------------------------------------------------------------------------- + // Spellcast Hook Code + // Added 2003-06-20 by Georg + // If you want to make changes to all spells, check x2_inc_spellhook.nss to + // find out more + //-------------------------------------------------------------------------- + if (!X2PreSpellCastCode()) + { + return; + } + // End of Spell Cast Hook + + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + object oCaster = OBJECT_SELF; + location lTarget = GetSpellTargetLocation(); + effect eStrike = EffectVisualEffect(VFX_IMP_LIGHTNING_S); + int nMetaMagic = GetMetaMagicFeat(); + float fDelay; + effect eBeam; + int nDamage; + int nPotential; + effect eDam; + object oLastValid; + effect eStun = EffectLinkEffects(EffectVisualEffect(VFX_IMP_STUN),EffectStunned()); + + //-------------------------------------------------------------------------- + // Calculate Damage Dice. 1d per 2 caster levels, max 5d + //-------------------------------------------------------------------------- + int nNumDice = GetCasterLevel(OBJECT_SELF)/2; + if (nNumDice<1) + { + nNumDice = 1; + } + else if (nNumDice >5) + { + nNumDice = 5; + } + + //-------------------------------------------------------------------------- + // Loop through all targets + //-------------------------------------------------------------------------- + + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_SMALL, lTarget, TRUE, OBJECT_TYPE_CREATURE); + while (GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + + //------------------------------------------------------------------ + // Calculate delay until spell hits current target. If we are the + // first target, the delay is the time until the spell hits us + //------------------------------------------------------------------ + if (GetIsObjectValid(oLastValid)) + { + fDelay += 0.2f; + fDelay += GetDistanceBetweenLocations(GetLocation(oLastValid), GetLocation(oTarget))/20; + } + else + { + fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oTarget))/20; + } + + //------------------------------------------------------------------ + // If there was a previous target, draw a lightning beam between us + // and iterate delay so it appears that the beam is jumping from + // target to target + //------------------------------------------------------------------ + if (GetIsObjectValid(oLastValid)) + { + eBeam = EffectBeam(VFX_BEAM_LIGHTNING, oLastValid, BODY_NODE_CHEST); + DelayCommand(fDelay,ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBeam,oTarget,1.5f)); + } + + if (!MyResistSpell(OBJECT_SELF, oTarget, fDelay)) + { + + nPotential = MaximizeOrEmpower(6, nNumDice, nMetaMagic); + nDamage = GetReflexAdjustedDamage(nPotential, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_ELECTRICITY); + + //-------------------------------------------------------------- + // If we failed the reflex save, we save vs will or are stunned + // for one round + //-------------------------------------------------------------- + if (nPotential == nDamage || (GetHasFeat(FEAT_IMPROVED_EVASION,oTarget) && nDamage == (nPotential/2))) + { + if(!MySavingThrow(SAVING_THROW_WILL, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_MIND_SPELLS, OBJECT_SELF, fDelay)) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eStun,oTarget, RoundsToSeconds(1))); + } + + } + + + if (nDamage >0) + { + eDam = EffectDamage(nDamage, DAMAGE_TYPE_ELECTRICAL); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eStrike, oTarget)); + //Apply the VFX impact and damage effect (reflected upon PC) + if (nInt == 1) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT,eDam,oCaster)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT,eStrike,oCaster)); + FloatingTextStringOnCreature("The spell 'Gedlee's Electric Loop' is reflected underwater!", oPC); + } + } + } + + //------------------------------------------------------------------ + // Store Target to make it appear that the lightning bolt is jumping + // from target to target + //------------------------------------------------------------------ + oLastValid = oTarget; + + } + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_SMALL, lTarget, TRUE, OBJECT_TYPE_CREATURE ); + } + +} + + diff --git a/src/_removed/original spells/x2_s0_grtthdclp.nss b/src/_removed/original spells/x2_s0_grtthdclp.nss new file mode 100644 index 0000000..ddc6a6f --- /dev/null +++ b/src/_removed/original spells/x2_s0_grtthdclp.nss @@ -0,0 +1,173 @@ +//:://///////////////////////////////////////////// +//:: Great Thunderclap +//:: X2_S0_GrtThdclp +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* +// You create a loud noise equivalent to a peal of +// thunder and its acommpanying shock wave. The +// spell has three effects. First, all creatures +// in the area must make Will saves to avoid being +// stunned for 1 round. Second, the creatures must +// make Fortitude saves or be deafened for 1 minute. +// Third, they must make Reflex saves or fall prone. +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: Nov 20, 2002 +//:: Updated On: Oct 20, 2003 - some nice Vfx:) +//::////////////////////////////////////////////// + +#include "NW_I0_SPELLS" +#include "x0_i0_spells" + +#include "x2_inc_spellhook" + +void main() +{ + + /* + Spellcast Hook Code + Added 2003-07-07 by Georg Zoeller + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + + */ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + + // End of Spell Cast Hook + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + object oCaster = OBJECT_SELF; + int nDamage = 0; + int nDC = GetSpellSaveDC(); + float fDelay; + effect eExplode = EffectVisualEffect(VFX_FNF_MYSTICAL_EXPLOSION); + effect eVis = EffectVisualEffect(VFX_IMP_SONIC); + effect eVis2 = EffectVisualEffect(VFX_IMP_BLIND_DEAF_M); + effect eVis3 = EffectVisualEffect(VFX_IMP_STUN); + effect eDeaf = EffectDeaf(); + effect eKnock = EffectKnockdown(); + effect eStun = EffectStunned(); + effect eShake = EffectVisualEffect(356); + + location lTarget = GetSpellTargetLocation(); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, lTarget); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eShake, OBJECT_SELF, 2.0f); + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_GARGANTUAN, lTarget, TRUE, OBJECT_TYPE_CREATURE); + while (GetIsObjectValid(oTarget)) + { + if(spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF) && oTarget != OBJECT_SELF) + { + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + + //Get the distance between the explosion and the target to calculate delay + fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oTarget))/20; + + if(!MySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_SONIC)) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDeaf, oTarget, RoundsToSeconds(10))); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis2, oTarget)); + //Apply the VFX impact and damage effect (reflected upon PC) + if (nInt == 1) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eDeaf,oCaster, RoundsToSeconds(10))); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT,eVis2,oCaster)); + FloatingTextStringOnCreature("The spell 'Great Thunderclap' is reflected underwater!", oPC); + } + } + if(!MySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_SONIC)) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eStun, oTarget, RoundsToSeconds(1))); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + //Apply the VFX impact and damage effect (reflected upon PC) + if (nInt == 1) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eStun,oCaster, RoundsToSeconds(1))); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT,eVis,oCaster)); + FloatingTextStringOnCreature("The spell 'Great Thunderclap' is reflected underwater!", oPC); + } + } + if(!MySavingThrow(SAVING_THROW_REFLEX, oTarget, nDC, SAVING_THROW_TYPE_SONIC)) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eKnock, oTarget, 6.0f)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eVis3, oTarget,4.0f)); + //Apply the VFX impact and damage effect (reflected upon PC) + if (nInt == 1) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eKnock,oCaster, 6.0f)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eVis3,oCaster,4.0f)); + FloatingTextStringOnCreature("The spell 'Great Thunderclap' is reflected underwater!", oPC); + } + } + } + + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_GARGANTUAN, lTarget, TRUE, OBJECT_TYPE_CREATURE); + } +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Great Thunderclap' has caused a cave-in!", oPC)); + } +} + diff --git a/src/_removed/original spells/x2_s0_hellinfern.nss b/src/_removed/original spells/x2_s0_hellinfern.nss new file mode 100644 index 0000000..27d046c --- /dev/null +++ b/src/_removed/original spells/x2_s0_hellinfern.nss @@ -0,0 +1,141 @@ +//:://///////////////////////////////////////////// +//:: Hellish Inferno +//:: x0_s0_inferno.nss +//:: Copyright (c) 2000 Bioware Corp. +//::////////////////////////////////////////////// +/* + NPC only spell for yaron + + like normal inferno but lasts only 5 rounds, + ticks twice per round, adds attack and damage + penalty. + +*/ +//::////////////////////////////////////////////// +// Georg Z, 19-10-2003 +//::////////////////////////////////////////////// + + +#include "X0_I0_SPELLS" +#include "x2_inc_spellhook" +#include "x2_i0_spells" + + +void RunImpact(object oTarget, object oCaster); + +void main() +{ + object oPC = GetFirstPC(); + object oCaster = OBJECT_SELF; + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Spell will fail if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Hellish Inferno' will not work underwater!", oPC); + return; + } + object oTarget = GetSpellTargetObject(); + + //-------------------------------------------------------------------------- + // Spellcast Hook Code + // Added 2003-06-20 by Georg + // If you want to make changes to all spells, check x2_inc_spellhook.nss to + // find out more + //-------------------------------------------------------------------------- + if (!X2PreSpellCastCode()) + { + return; + } + // End of Spell Cast Hook + + //-------------------------------------------------------------------------- + // This spell no longer stacks. If there is one hand, that's enough + //-------------------------------------------------------------------------- + if (GetHasSpellEffect(GetSpellId(),oTarget)) + { + FloatingTextStrRefOnCreature(100775,OBJECT_SELF,FALSE); + return; + } + + //-------------------------------------------------------------------------- + // Calculate the duration + //-------------------------------------------------------------------------- + int nMetaMagic = GetMetaMagicFeat(); + int nDuration = GetCasterLevel(OBJECT_SELF)/2; + + if (nMetaMagic == METAMAGIC_EXTEND) + { + nDuration = nDuration * 2; + } + if (nDuration < 1) + { + nDuration = 1; + } + if (nDuration >6) + { + nDuration= 6; + } + + + //-------------------------------------------------------------------------- + // Flamethrower VFX, thanks to Alex + //-------------------------------------------------------------------------- + effect eRay = EffectBeam(444,OBJECT_SELF,BODY_NODE_CHEST); + + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + + float fDelay = GetDistanceBetween(oTarget, OBJECT_SELF)/13; + + if(!MyResistSpell(OBJECT_SELF, oTarget)) + { + //---------------------------------------------------------------------- + // Engulf the target in flame + //---------------------------------------------------------------------- + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eRay, oTarget, 3.0f); + effect eAttackDec = EffectAttackDecrease(4); + effect eDamageDec = EffectDamageDecrease(4); + effect eLink = EffectLinkEffects(eAttackDec, eDamageDec); + effect eDur = EffectVisualEffect(498); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration)); + DelayCommand(fDelay,ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eDur,oTarget,RoundsToSeconds(nDuration))); + object oSelf = OBJECT_SELF; // because OBJECT_SELF is a function + DelayCommand(fDelay,RunImpact(oTarget, oSelf)); + } + else + { + //---------------------------------------------------------------------- + // Indicate Failure + //---------------------------------------------------------------------- + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eRay, oTarget, 2.0f); + effect eSmoke = EffectVisualEffect(VFX_IMP_REFLEX_SAVE_THROW_USE); + DelayCommand(fDelay+0.3f,ApplyEffectToObject(DURATION_TYPE_INSTANT,eSmoke,oTarget)); + } + +} + + +void RunImpact(object oTarget, object oCaster) +{ + //-------------------------------------------------------------------------- + // Check if the spell has expired (check also removes effects) + //-------------------------------------------------------------------------- + if (GZGetDelayedSpellEffectsExpired(762,oTarget,oCaster)) + { + return; + } + + if (GetIsDead(oTarget) == FALSE) + { + //* GZ: Removed Meta magic, does not work in delayed functions + effect eDam = EffectDamage(d6(2), DAMAGE_TYPE_FIRE); + effect eDam2 = EffectDamage(d6(1), DAMAGE_TYPE_DIVINE); + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_S); + eDam = EffectLinkEffects(eVis,eDam); // flare up + ApplyEffectToObject (DURATION_TYPE_INSTANT,eDam,oTarget); + ApplyEffectToObject (DURATION_TYPE_INSTANT,eDam2,oTarget); + DelayCommand(3.0f,RunImpact(oTarget,oCaster)); + } +} + diff --git a/src/_removed/original spells/x2_s0_horiboom.nss b/src/_removed/original spells/x2_s0_horiboom.nss new file mode 100644 index 0000000..268436b --- /dev/null +++ b/src/_removed/original spells/x2_s0_horiboom.nss @@ -0,0 +1,157 @@ +//:://///////////////////////////////////////////// +//:: Horizikaul's Boom +//:: X2_S0_HoriBoom +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* +// You blast the target with loud and high-pitched +// sounds. The target takes 1d4 points of sonic +// damage per two caster levels (maximum 5d4) and +// must make a Will save or be deafened for 1d4 +// rounds. +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: Nov 22, 2002 +//::////////////////////////////////////////////// +//:: Last Updated By: Andrew Nobbs, 02/06/2003 + +#include "NW_I0_SPELLS" +#include "x0_i0_spells" +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-07-07 by Georg Zoeller + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables ( fDist / (3.0f * log( fDist ) + 2.0f) ) + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + object oCaster = OBJECT_SELF; + object oTarget = GetSpellTargetObject(); + int nCasterLvl = GetCasterLevel(OBJECT_SELF)/2; + int nRounds = d4(1); + int nMetaMagic = GetMetaMagicFeat(); + effect eVis = EffectVisualEffect(VFX_IMP_SONIC); + effect eDeaf = EffectDeaf(); + //Minimum caster level of 1, maximum of 15. + if(nCasterLvl == 0) + { + nCasterLvl = 1; + } + else if (nCasterLvl > 5) + { + nCasterLvl = 5; + } + if(spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + if(!MyResistSpell(OBJECT_SELF, oTarget)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + //Roll damage + int nDam = d4(nCasterLvl); + //Enter Metamagic conditions + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDam = 4 * nCasterLvl; //Damage is at max + } + if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDam = nDam + nDam/2; //Damage/Healing is +50% + } + //Set damage effect + effect eDam = EffectDamage(nDam, DAMAGE_TYPE_SONIC); + //Apply the MIRV and damage effect + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_INSTANT,eDam,oCaster); + ApplyEffectToObject(DURATION_TYPE_INSTANT,eVis,oCaster); + FloatingTextStringOnCreature("The spell 'Horizikaul's Boom' is reflected underwater!", oPC); + } + + if(!MySavingThrow(SAVING_THROW_WILL, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_MIND_SPELLS)) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDeaf, oTarget, RoundsToSeconds(nRounds)); + } + } + } +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Horizikaul's Boom' has caused a cave-in!", oPC)); + } +} diff --git a/src/_removed/original spells/x2_s0_scntsphere.nss b/src/_removed/original spells/x2_s0_scntsphere.nss new file mode 100644 index 0000000..083470c --- /dev/null +++ b/src/_removed/original spells/x2_s0_scntsphere.nss @@ -0,0 +1,112 @@ +//:://///////////////////////////////////////////// +//:: Scintillating Sphere +//:: X2_S0_ScntSphere +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* +// A scintillating sphere is a burst of electricity +// that detonates with a low roar and inflicts 1d6 +// points of damage per caster level (maximum of 10d6) +// to all creatures within the area. Unattended objects +// also take damage. The explosion creates almost no pressure. +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: Nov 25 , 2002 +//::////////////////////////////////////////////// +//:: Last Updated By: Andrew Nobbs, 02/06/2003 + +#include "NW_I0_SPELLS" +#include "x0_i0_spells" +#include "x2_inc_spellhook" + +void main() +{ + +/* + Spellcast Hook Code + Added 2003-07-07 by Georg Zoeller + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + object oCaster = OBJECT_SELF; + int nCasterLvl = GetCasterLevel(oCaster); + int nMetaMagic = GetMetaMagicFeat(); + int nDamage; + float fDelay; + effect eExplode = EffectVisualEffect(459); + effect eVis = EffectVisualEffect(VFX_IMP_LIGHTNING_S); + effect eDam; + //Get the spell target location as opposed to the spell target. + location lTarget = GetSpellTargetLocation(); + //Limit Caster level for the purposes of damage + if (nCasterLvl > 10) + { + nCasterLvl = 10; + } + //Apply the fireball explosion at the location captured above. + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, lTarget); + //Declare the spell shape, size and the location. Capture the first target object in the shape. + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget)) + { + if(spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + //Get the distance between the explosion and the target to calculate delay + fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oTarget))/20; + if (!MyResistSpell(OBJECT_SELF, oTarget, fDelay)) + { + //Roll damage for each target + nDamage = d6(nCasterLvl); + //Resolve metamagic + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nDamage = 6 * nCasterLvl; + } + else if (nMetaMagic == METAMAGIC_EMPOWER) + { + nDamage = nDamage + nDamage / 2; + } + //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. + nDamage = GetReflexAdjustedDamage(nDamage, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_ELECTRICITY); + //Set the damage effect + eDam = EffectDamage(nDamage, DAMAGE_TYPE_ELECTRICAL); + if(nDamage > 0) + { + // Apply effects to the currently selected target. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + //This visual effect is applied to the target object not the location as above. This visual effect + //represents the flame that erupts on the target not on the ground. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + //Apply the VFX impact and damage effect (reflected upon PC) + if (nInt == 1) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT,eDam,oCaster)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT,eVis,oCaster)); + FloatingTextStringOnCreature("The spell 'Scintillating Sphere' is reflected underwater!", oPC); + } + } + } + } + //Select the next target within the spell shape. + oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } +} + diff --git a/src/hakpak/ghost_prc8_top/2da/classes.2da b/src/hakpak/ghost_prc8_top/2da/classes.2da index 0ddeac9..933d128 100644 --- a/src/hakpak/ghost_prc8_top/2da/classes.2da +++ b/src/hakpak/ghost_prc8_top/2da/classes.2da @@ -12,26 +12,26 @@ 8 Rogue 112195 16 17 4898 248 IR_ROGUE 6 CLS_ATK_2 CLS_FEAT_ROG CLS_SAVTHR_ROG CLS_SKILL_ROG CLS_BFEAT_ROG 8 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_ROGUE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ROG 0 1 0 0 -1 8 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 9 Sorcerer 112196 18 19 4899 249 IR_SORCERER 4 CLS_ATK_3 CLS_FEAT_SORC CLS_SAVTHR_SORC CLS_SKILL_SORC CLS_BFEAT_SORC 2 CLS_SPGN_SORC CLS_SPKN_SORC 1 1 10 14 14 10 12 16 CHA 0X00 0X0 0 CLASS_TYPE_SORCERER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SORC 0 1 0 0 -1 9 131 **** 0 1 0 0 0 1 1 CHA Wiz_Sorc 1 1 1 0 0 10 Wizard 112197 20 21 4900 250 IR_WIZARD 4 CLS_ATK_3 CLS_FEAT_WIZ CLS_SAVTHR_WIZ CLS_SKILL_WIZ CLS_BFEAT_WIZ 2 CLS_SPGN_WIZ **** 1 1 10 14 14 12 16 10 INT 0X00 0X0 0 CLASS_TYPE_WIZARD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WIZ 0 1 0 0 -1 10 209 **** 1 1 0 1 1 1 1 INT Wiz_Sorc 1 1 1 0 0 -11 Aberration 112198 525 525 4901 8154 IR_WIZARD 8 CLS_ATK_2 CLS_FEAT_ABER CLS_SAVTHR_WIZ CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 1 0 14 14 11 14 3 5 STR 0X00 0X0 0 CLASS_TYPE_ABERRATION 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ABER 0 0 0 0 -1 73 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +11 Aberration 112198 525 525 4901 8154 IR_WIZARD 8 CLS_ATK_2 CLS_FEAT_ABER CLS_SAVTHR_WIZ CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 1 0 14 14 11 14 3 5 STR 0X00 0X0 0 CLASS_TYPE_ABERRATION 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ABER 0 0 0 0 -1 73 0 **** **** **** **** **** **** **** **** **** Aberration **** **** **** **** **** 12 Animal 112199 526 526 4902 8154 IR_WIZARD 8 CLS_ATK_2 CLS_FEAT_CREA CLS_SAVTHR_WILD CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 0 0 13 17 15 12 2 6 STR 0X00 0X0 0 CLASS_TYPE_ANIMAL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ANI 0 0 0 0 -1 74 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 13 Construct 112200 528 528 4903 8154 IR_WIZARD 10 CLS_ATK_2 CLS_FEAT_CREA CLS_SAVTHR_CONS CLS_SKILL_CREA CLS_BFEAT_BARB 0 **** **** 1 0 21 9 10 11 10 3 STR 0X00 0X0 0 CLASS_TYPE_CONSTRUCT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_CON 0 0 0 0 -1 75 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 14 Humanoid 112201 1763 1764 4904 8154 IR_WIZARD 8 CLS_ATK_2 CLS_FEAT_CREA CLS_SAVTHR_FIGHT CLS_SKILL_CREA CLS_BFEAT_BARB 6 **** **** 1 0 15 10 13 11 8 8 STR 0X00 0X0 0 CLASS_TYPE_HUMANOID 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HUM 0 0 0 0 -1 76 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -15 Monstrous 112202 536 536 4905 8154 IR_WIZARD 8 CLS_ATK_1 CLS_FEAT_MONHUM CLS_SAVTHR_BARD CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 1 0 19 10 15 10 7 8 STR 0X00 0X0 0 CLASS_TYPE_MONSTEROUS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MON 0 0 0 0 -1 77 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +15 Monstrous 112202 536 536 4905 8154 IR_WIZARD 8 CLS_ATK_1 CLS_FEAT_MONHUM CLS_SAVTHR_BARD CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 1 0 19 10 15 10 7 8 STR 0X00 0X0 0 CLASS_TYPE_MONSTEROUS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MON 0 0 0 0 -1 77 0 **** **** **** **** **** **** **** **** **** Monstrous **** **** **** **** **** 16 Elemental 112203 539 539 4906 8154 IR_WIZARD 8 CLS_ATK_2 CLS_FEAT_CREA CLS_SAVTHR_FIGHT CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 1 0 17 8 13 11 4 11 STR 0X00 0X0 0 CLASS_TYPE_ELEMENTAL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ELE 0 0 0 0 -1 78 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -17 Fey 112204 540 540 4907 8154 IR_WIZARD 6 CLS_ATK_3 CLS_FEAT_FEY CLS_SAVTHR_BARD CLS_SKILL_FEY CLS_BFEAT_BARB 6 **** **** 1 0 10 15 11 15 14 18 DEX 0X00 0X0 0 CLASS_TYPE_FEY 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FEY 0 0 0 0 -1 79 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +17 Fey 112204 540 540 4907 8154 IR_WIZARD 6 CLS_ATK_3 CLS_FEAT_FEY CLS_SAVTHR_BARD CLS_SKILL_FEY CLS_BFEAT_BARB 6 **** **** 1 0 10 15 11 15 14 18 DEX 0X00 0X0 0 CLASS_TYPE_FEY 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FEY 0 0 0 0 -1 79 0 **** **** **** **** **** **** **** **** **** Fey **** **** **** **** **** 18 Dragon 112205 529 529 4908 8154 IR_DRGNFIREADPT 12 CLS_ATK_1 CLS_FEAT_DRAG CLS_SAVTHR_MONK CLS_SKILL_DRAGON CLS_BFEAT_BARB 6 **** **** 1 0 13 10 13 10 11 10 STR 0X00 0X0 0 CLASS_TYPE_DRAGON 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DRAG 0 0 0 0 -1 80 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 19 Undead 112206 547 547 4909 8154 IR_WIZARD 12 CLS_ATK_3 CLS_FEAT_CREA CLS_SAVTHR_WIZ CLS_SKILL_CREA CLS_BFEAT_BARB 4 **** **** 1 0 10 12 10 10 10 11 STR 0X00 0X0 0 CLASS_TYPE_UNDEAD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_UNDEAD 0 0 0 0 -1 81 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 20 Commoner 112207 2291 2292 4910 8155 IR_WIZARD 4 CLS_ATK_3 CLS_FEAT_COMM CLS_SAVTHR_CONS CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 1 0 10 10 12 10 10 10 STR 0X00 0X0 0 CLASS_TYPE_COMMONER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 **** 0 0 0 0 -1 82 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 21 Beast 112208 527 527 4911 8154 IR_WIZARD 10 CLS_ATK_2 CLS_FEAT_CREA CLS_SAVTHR_WILD CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 0 0 16 13 16 3 12 8 STR 0X00 0X0 0 CLASS_TYPE_BEAST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BEAST 0 0 0 0 -1 83 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 22 Giant 112209 541 541 4912 8154 IR_WIZARD 8 CLS_ATK_2 CLS_FEAT_GIAN CLS_SAVTHR_FIGHT CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 1 0 25 8 19 10 6 17 STR 0X00 0X0 0 CLASS_TYPE_GIANT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_GIANT 0 0 0 0 -1 84 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 23 MagicBeast 112210 542 542 4913 8154 IR_WIZARD 10 CLS_ATK_1 CLS_FEAT_CREA CLS_SAVTHR_WILD CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 0 0 15 8 15 12 2 10 STR 0X00 0X0 0 CLASS_TYPE_MAGICAL_BEAST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MAGBST 0 0 0 0 -1 85 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -24 Outsider 112211 4812 4812 4914 8154 IR_WIZARD 8 CLS_ATK_1 CLS_FEAT_OUTS CLS_SAVTHR_MONK CLS_SKILL_OUTS CLS_BFEAT_BARB 8 **** **** 1 0 15 10 13 13 10 12 STR 0X00 0X0 0 CLASS_TYPE_OUTSIDER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_OUTS 0 0 0 0 -1 86 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -25 Shapechanger 112212 546 546 4915 8154 IR_WIZARD 8 CLS_ATK_2 CLS_FEAT_SHCHNG CLS_SAVTHR_MONK CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 1 0 15 11 17 10 10 10 STR 0X00 0X0 0 CLASS_TYPE_SHAPECHANGER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHAPE 0 0 0 0 -1 87 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +24 Outsider 112211 4812 4812 4914 8154 IR_WIZARD 8 CLS_ATK_1 CLS_FEAT_OUTS CLS_SAVTHR_MONK CLS_SKILL_OUTS CLS_BFEAT_BARB 8 **** **** 1 0 15 10 13 13 10 12 STR 0X00 0X0 0 CLASS_TYPE_OUTSIDER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_OUTS 0 0 0 0 -1 86 0 **** **** **** **** **** **** **** **** **** Outsider **** **** **** **** **** +25 Shapechanger 112212 546 546 4915 8154 IR_WIZARD 8 CLS_ATK_2 CLS_FEAT_SHCHNG CLS_SAVTHR_MONK CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 1 0 15 11 17 10 10 10 STR 0X00 0X0 0 CLASS_TYPE_SHAPECHANGER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHAPE 0 0 0 0 -1 87 0 **** **** **** **** **** **** **** **** **** Shapechanger **** **** **** **** **** 26 Vermin 112213 548 548 4916 8154 IR_WIZARD 8 CLS_ATK_2 CLS_FEAT_CREA CLS_SAVTHR_FIGHT CLS_SKILL_CREA CLS_BFEAT_BARB 2 **** **** 0 0 11 17 12 10 10 3 STR 0X00 0X0 0 CLASS_TYPE_VERMIN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_VERMIN 0 0 0 0 -1 88 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 27 Shadowdancer 112214 2944 2945 2946 2947 IR_X1_SHADOW 8 CLS_ATK_2 CLS_FEAT_SHADOW CLS_SAVTHR_ROG CLS_SKILL_SHADOW CLS_BFEAT_SHADOW 6 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_SHADOWDANCER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHADOW 40 0 0 0 10 63 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 28 Harper 112215 2956 2957 2958 2959 IR_X1_HARPER 6 CLS_ATK_2 CLS_FEAT_HARPER CLS_SAVTHR_BARD CLS_SKILL_HARPER CLS_BFEAT_HARPER 4 CLS_SPGN_HARPER CLS_SPKN_HARPER 0 1 12 16 14 8 14 12 DEX 0X10 0X2 0 CLASS_TYPE_HARPER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HARPER 5 0 0 0 5 64 130 **** **** **** **** **** **** **** **** **** Harper **** **** **** **** **** 29 Arcane_Archer 112216 9003 9004 9005 9006 IR_ARCHER 8 CLS_ATK_1 CLS_FEAT_ARCHER CLS_SAVTHR_WILD CLS_SKILL_ARCHER CLS_BFEAT_ARCHER 4 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_ARCANE_ARCHER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ARCHER 40 0 0 0 10 65 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -30 Assassin 112217 9007 9008 9009 16790386 IR_ASASIN 6 CLS_ATK_2 CLS_FEAT_ASASIN CLS_SAVTHR_ROG CLS_SKILL_ASASIN CLS_BFEAT_ASASIN 4 CLS_SPGN_ASASIN CLS_SPKN_ASASIN 1 1 12 16 14 8 14 12 DEX 0X09 0X2 0 CLASS_TYPE_ASSASSIN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ASASIN 40 0 0 0 10 66 131 **** **** **** **** **** **** **** **** **** Assassin **** **** **** **** **** +30 Assassin 112217 9007 9008 9009 16790386 IR_ASASIN 6 CLS_ATK_2 CLS_FEAT_ASASIN CLS_SAVTHR_ROG CLS_SKILL_ASASIN CLS_BFEAT_ASASIN 4 CLS_SPGN_ASASIN **** 1 1 12 16 14 8 14 12 DEX 0X09 0X2 0 CLASS_TYPE_ASSASSIN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ASASIN 40 0 0 0 10 66 131 **** 1 1 0 0 1 1 1 INT Assassin 1 1 255 0 0 31 Blackguard 112218 9011 9012 9013 16790387 IR_BLKGRD 10 CLS_ATK_1 CLS_FEAT_BLKGRD CLS_SAVTHR_FIGHT CLS_SKILL_BLKGRD CLS_BFEAT_BLKGRD 2 CLS_SPGN_BLKGRD **** 1 1 12 16 14 8 14 12 CON 0X09 0X2 0 CLASS_TYPE_BLACKGUARD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BLKGRD 40 0 0 0 10 67 0 **** 1 0 0 0 0 0 0 WIS Blackguard 1 1 255 0 0 32 Champion_Torm 112219 9015 9016 9017 9018 IR_DIVCHA 10 CLS_ATK_1 CLS_FEAT_DIVCHA CLS_SAVTHR_WILD CLS_SKILL_DIVCHA CLS_BFEAT_DIVCHA 2 **** **** 0 0 12 16 14 8 14 12 CHA 0X10 0X2 0 CLASS_TYPE_DIVINE_CHAMPION 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DIVCHA 40 0 0 0 10 109 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 33 WeaponMaster 112220 9019 9019 9021 9022 IR_WM 10 CLS_ATK_1 CLS_FEAT_WM CLS_SAVTHR_ROG CLS_SKILL_WM CLS_BFEAT_WM 2 **** **** 1 0 12 16 14 8 14 12 STR 0X00 0X0 0 CLASS_TYPE_WEAPON_MASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WM 40 0 0 0 10 112 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** @@ -40,7 +40,7 @@ 36 Dwarven_Defender 112223 76418 76419 76420 76422 IR_DWDEF 12 CLS_ATK_1 CLS_FEAT_DWDEF CLS_SAVTHR_CLER CLS_SKILL_DWDEF CLS_BFEAT_DWDEF 2 **** **** 1 0 16 8 15 14 10 12 STR 0X05 0X1 0 CLASS_TYPE_DWARVEN_DEFENDER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DWDEF 40 0 0 0 10 89 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 37 Dragon_Disciple 112224 16832127 16832128 16832129 16832130 IR_DRAGOND 6 CLS_ATK_2 CLS_FEAT_DRADIS CLS_SAVTHR_CLER CLS_SKILL_DRADIS CLS_BFEAT_DRADIS 2 **** **** 1 0 14 8 14 16 10 14 STR 0X00 0X0 0 CLASS_TYPE_DRAGON_DISCIPLE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DRADIS 40 0 0 0 10 111 0 cls_stat_dradis **** **** **** **** **** **** **** **** **** **** **** **** **** **** 38 Ooze 112225 84438 84438 84437 8154 IR_CLERIC 10 CLS_ATK_2 CLS_FEAT_CLER CLS_SAVTHR_CLER CLS_SKILL_CLER CLS_BFEAT_CLER 0 **** **** 0 0 14 8 14 16 10 14 STR 0X00 0X0 0 CLASS_TYPE_OOZE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_OOZE 0 0 0 0 -1 75 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -39 Eye_of_Gruumsh 16790665 16824294 16824295 16824296 16824297 IR_GRUUMSH 12 CLS_ATK_1 CLS_FEAT_EOG CLS_SAVTHR_BARB CLS_SKILL_EOG CLS_BFEAT_EOG 2 **** **** 1 0 16 14 14 14 10 8 STR 0X0A 0X3 0 CLASS_TYPE_PRC_EYE_OF_GRUUMSH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_EOG 40 0 0 0 10 17 0 cls_stat_eog **** **** **** **** **** **** **** **** **** **** **** **** **** **** +39 Eye_of_Gruumsh 16790665 16824294 16824295 16824296 16824297 IR_GRUUMSH 12 CLS_ATK_1 CLS_FEAT_EOG CLS_SAVTHR_BARB CLS_SKILL_EOG CLS_BFEAT_EOG 2 **** **** 0 0 16 14 14 14 10 8 STR 0X0A 0X3 0 CLASS_TYPE_PRC_EYE_OF_GRUUMSH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_EOG 40 0 0 0 10 17 0 cls_stat_eog **** **** **** **** **** **** **** **** **** **** **** **** **** **** 40 Shou_Disciple 16790649 16823346 16823347 16823348 16823349 IR_SHOUDISC 10 CLS_ATK_1 CLS_FEAT_SHOU CLS_SAVTHR_WILD CLS_SKILL_SHOU CLS_BFEAT_SHOU 2 **** **** 0 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_SHOU 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHOU 5 0 0 0 5 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 41 Purple_Dragon_Knight 112226 111710 111711 111712 111713 IR_PDK 10 CLS_ATK_1 CLS_FEAT_PDK CLS_SAVTHR_FIGHT CLS_SKILL_PDK CLS_BFEAT_PDK 2 **** **** 0 0 12 16 14 8 14 12 STR 0X14 0X3 0 CLASS_TYPE_PDK 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_PDK 5 0 0 0 5 131 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 42 UrPriest 16790529 16835606 16835607 16835608 16835609 IR_WARLOCK 8 CLS_ATK_2 CLS_FEAT_URPRST CLS_SAVTHR_WIZ CLS_SKILL_URPRST CLS_BFEAT_URPRST 2 CLS_SPGN_BLIGHT **** 1 1 15 9 14 13 10 15 WIS 0X09 0X2 0 CLASS_TYPE_UR_PRIEST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_URPRST 40 0 0 0 10 10 0 **** 1 0 0 0 0 0 0 WIS Cleric 1 1 255 0 0 @@ -65,7 +65,7 @@ 61 Hexblade 16790548 16823462 16823463 16823464 16823465 IR_ELDKNI 10 CLS_ATK_1 CLS_FEAT_HEXBL CLS_SAVTHR_CLER CLS_SKILL_HEXBL CLS_BFEAT_HEXBL 2 CLS_SPGN_HEXBL CLS_SPKN_HEXBL 1 1 14 14 14 10 12 14 CHA 0X08 0X2 0 CLASS_TYPE_HEXBLADE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HEXBL 0 1 0 0 -1 5 131 **** **** **** **** **** **** **** **** **** Hexblade **** **** **** **** **** 62 Duskblade 16790549 16824168 16824169 16824170 16824171 IR_HAVOCMAGE 8 CLS_ATK_1 CLS_FEAT_DUSKBL CLS_SAVTHR_CLER CLS_SKILL_DUSKBL CLS_BFEAT_DUSKBL 2 CLS_SPGN_DUSKBL CLS_SPKN_DUSKBL 1 1 15 12 14 10 15 10 STR 0X00 0X0 0 CLASS_TYPE_DUSKBLADE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DUSKBL 0 1 0 0 -1 5 131 **** **** **** **** **** **** **** **** **** Duskblade **** **** **** **** **** 63 Scout 16790550 16822486 16822513 16822514 16822515 IR_ARCHER 8 CLS_ATK_2 CLS_FEAT_SCOUT CLS_SAVTHR_ROG CLS_SKILL_SCOUT CLS_BFEAT_SCOUT 8 **** **** 1 0 12 16 12 14 12 10 DEX 0X00 0X0 0 CLASS_TYPE_SCOUT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SCOUT 0 1 0 0 -1 7 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -64 Healer 16790551 16822656 16822657 16822658 16822659 IR_CBTMEDIC 8 CLS_ATK_3 CLS_FEAT_HEALER CLS_SAVTHR_CLER CLS_SKILL_HEALER CLS_BFEAT_HEALER 4 CLS_SPGN_HEALER **** 1 1 10 12 12 15 10 16 WIS 0X11 0X2 0 CLASS_TYPE_HEALER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HEALER 0 1 0 0 -1 2 0 **** 1 0 0 0 0 0 0 WIS Healer 1 1 255 0 0 +64 Healer 16790551 16822656 16822657 16822658 16822659 IR_CBTMEDIC 8 CLS_ATK_3 CLS_FEAT_HEALER CLS_SAVTHR_CLER CLS_SKILL_HEALER CLS_BFEAT_HEALER 4 CLS_SPGN_HEALER **** 1 1 10 12 12 15 10 16 WIS 0X11 0X2 0 CLASS_TYPE_HEALER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HEALER 0 1 0 0 -1 895 0 **** 1 0 0 0 0 0 0 WIS Healer 1 1 255 0 0 65 Mage_Killer 16790552 16822219 16822220 16822221 16822222 IR_MAGEKILL 4 CLS_ATK_3 CLS_FEAT_MAGEK CLS_SAVTHR_WIZ CLS_SKILL_MAGEK CLS_BFEAT_MAGEK 2 **** **** 1 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_MAGEKILLER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MAGEK 40 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 66 Harper_Mage 16790553 16822223 16822224 16822225 16822226 IEF_HARPWIZ 4 CLS_ATK_3 CLS_FEAT_HMAGE CLS_SAVTHR_WIZ CLS_SKILL_HMAGE CLS_BFEAT_HMAGE 4 **** **** 0 0 12 16 14 8 14 12 INT 0X10 0X2 0 CLASS_TYPE_HARPERMAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HMAGE 5 0 1 0 5 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 67 Spell_Sword 16790554 16822227 16822228 16822229 16822230 IR_SPELLS 8 CLS_ATK_1 CLS_FEAT_SPELLS CLS_SAVTHR_CLER CLS_SKILL_SPELLS CLS_BFEAT_SPELLS 2 **** **** 1 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_SPELLSWORD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SPELLS 40 0 2 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** @@ -74,13 +74,13 @@ 70 Eldritch_Knight 16790557 16822308 16822309 16822310 16822311 IR_ELDKNI 6 CLS_ATK_1 CLS_FEAT_ELDKNI CLS_SAVTHR_FIGHT CLS_SKILL_ELDKNI CLS_BFEAT_ELDKNI 2 **** **** 1 0 14 13 14 10 14 13 INT 0X00 0X0 0 CLASS_TYPE_ELDRITCH_KNIGHT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ELDKNI 40 0 1 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 71 Elemental_Savant 16790558 16822312 16822313 16822314 16822315 IR_ELEMFIRE 4 CLS_ATK_3 CLS_FEAT_SAVANT CLS_SAVTHR_WIZ CLS_SKILL_SAVANT CLS_BFEAT_SAVANT 2 **** **** 1 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_ELEMENTAL_SAVANT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SAVANT 40 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 72 Factotum 16790559 16823092 16823093 16823094 16823095 IR_BEGUIL 8 CLS_ATK_2 CLS_FEAT_FACTUM CLS_SAVTHR_ROG CLS_SKILL_FACTUM CLS_BFEAT_FACTUM 6 **** **** 1 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_FACTOTUM 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FACTUM 20 1 0 0 -1 8 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -73 CelebrantSharess 16790560 16826321 16826322 16826323 16826324 IR_HEARTW 6 CLS_ATK_3 CLS_FEAT_SHARSS CLS_SAVTHR_WIZ CLS_SKILL_SHARSS CLS_BFEAT_SHARSS 6 CLS_SPGN_SHARSS CLS_SPKN_SHARSS 0 1 12 16 14 8 14 12 CHA 0X13 0X3 0 CLASS_TYPE_CELEBRANT_SHARESS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHARSS 40 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** Celebrant **** **** **** **** **** +73 CelebrantSharess 16790560 16826321 16826322 16826323 16826324 IR_HEARTW 6 CLS_ATK_3 CLS_FEAT_SHARSS CLS_SAVTHR_WIZ CLS_SKILL_SHARSS CLS_BFEAT_SHARSS 6 CLS_SPGN_SHARSS CLS_SPKN_SHARSS 0 1 12 16 14 8 14 12 CHA 0X13 0X3 0 CLASS_TYPE_CELEBRANT_SHARESS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHARSS 40 0 0 0 10 10 0 **** 0 0 0 0 0 1 1 CHA Celebrant **** **** 255 0 **** 74 CultistShatteredPeak 16790561 16789654 16789655 16789656 16789657 IR_SPARCDLST 6 CLS_ATK_2 CLS_FEAT_CULTST CLS_SAVTHR_RANG CLS_SKILL_CULTST CLS_BFEAT_CULTST 6 CLS_SPGN_CULTST **** 0 1 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_CULTIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_CULTST 5 0 0 0 5 64 130 **** 1 1 0 0 1 1 1 INT Cultist 1 1 255 0 0 75 Forsaker 16790562 16847610 16847611 16847612 16847613 IC_LEGDREAD 12 CLS_ATK_1 CLS_FEAT_FORSAK CLS_SAVTHR_CLER CLS_SKILL_FORSAK CLS_BFEAT_FORSAK 2 **** **** 1 0 16 13 16 10 10 9 STR 0X00 0X0 0 CLASS_TYPE_FORSAKER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FORSAK 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 76 Incarnate 16790563 16836706 16836707 16836708 16836709 IR_PSION 6 CLS_ATK_3 CLS_FEAT_INCARN CLS_SAVTHR_CLER CLS_SKILL_INCARN CLS_BFEAT_INCARN 2 **** **** 1 0 10 14 14 12 16 10 INT 0X01 0X3 1 CLASS_TYPE_INCARNATE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_INCARN 0 1 0 0 -1 8 130 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 77 Soulborn 16790564 16836718 16836719 16836720 16836721 IR_SOULKNIFE 10 CLS_ATK_1 CLS_FEAT_SOULBN CLS_SAVTHR_FIGHT CLS_SKILL_SOULBN CLS_BFEAT_SOULBN 2 **** **** 1 0 16 13 16 10 10 9 STR 0X01 0X3 0 CLASS_TYPE_SOULBORN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SOULBN 0 1 0 0 -1 8 130 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 78 Totemist 16790565 16836722 16836723 16836724 16836725 IR_PSYWARRIOR 8 CLS_ATK_2 CLS_FEAT_TOTEM CLS_SAVTHR_RANG CLS_SKILL_TOTEM CLS_BFEAT_TOTEM 4 **** **** 1 0 16 13 16 10 10 9 STR 0X00 0X0 0 CLASS_TYPE_TOTEMIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_TOTEM 0 1 0 0 -1 8 130 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -79 Beguiler 16790566 16789870 16789871 16789872 16789873 IR_BEGUIL 6 CLS_ATK_3 CLS_FEAT_BEGUIL CLS_SAVTHR_WIZ CLS_SKILL_BEGUIL CLS_BFEAT_BEGUIL 6 CLS_SPGN_BEGUIL CLS_SPKN_BEGUIL 1 1 10 14 14 12 16 10 INT 0X00 0X0 0 CLASS_TYPE_BEGUILER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BEGUIL 20 1 0 0 -1 8 130 **** **** **** **** **** **** **** **** **** Beguiler **** **** **** **** **** +79 Beguiler 16790566 16789870 16789871 16789872 16789873 IR_BEGUIL 6 CLS_ATK_3 CLS_FEAT_BEGUIL CLS_SAVTHR_WIZ CLS_SKILL_BEGUIL CLS_BFEAT_BEGUIL 6 CLS_SPGN_BEGUIL CLS_SPKN_BEGUIL 1 1 10 14 14 12 16 10 INT 0X00 0X0 0 CLASS_TYPE_BEGUILER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BEGUIL 20 1 0 0 -1 700 130 **** **** **** **** **** **** **** **** **** Beguiler **** **** **** **** **** 80 Duelist 16790567 16822716 16822717 16822718 16822719 IR_DUEL 10 CLS_ATK_1 CLS_FEAT_DUEL CLS_SAVTHR_ROG CLS_SKILL_DUEL CLS_BFEAT_DUEL 4 **** **** 1 0 14 16 14 8 14 10 DEX 0X00 0X0 0 CLASS_TYPE_DUELIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DUEL 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 81 Hierophant 16790568 16822744 16822745 16822746 16822747 IR_HIERO 8 CLS_ATK_2 CLS_FEAT_HIERO CLS_SAVTHR_CLER CLS_SKILL_HIERO CLS_BFEAT_HIERO 2 **** **** 1 0 14 8 14 16 10 14 WIS 0X00 0X0 0 CLASS_TYPE_HIEROPHANT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HIERO 5 0 0 0 5 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 82 RedAvenger 16790569 16822765 16822766 16822767 16822768 IR_REDAVNG 8 CLS_ATK_2 CLS_FEAT_REDAV CLS_SAVTHR_MONK CLS_SKILL_REDAV CLS_BFEAT_REDAV 4 **** **** 1 0 14 14 14 15 10 10 DEX 0X00 0X0 0 CLASS_TYPE_RED_AVENGER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_REDAV 40 0 0 0 10 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** @@ -97,12 +97,12 @@ 93 SublimeChord 16790580 16829452 16829453 16829454 16829455 IR_X1_HARPER 6 CLS_ATK_3 CLS_FEAT_SCHORD CLS_SAVTHR_WIZ CLS_SKILL_SCHORD CLS_BFEAT_SCHORD 4 CLS_SPGN_SCHORD CLS_SPKN_SCHORD 1 1 10 14 12 10 14 16 CHA 0X00 0X0 0 CLASS_TYPE_SUBLIME_CHORD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SCHORD 40 0 0 0 10 46 131 **** **** **** **** **** **** **** **** **** SublimeCh **** **** **** **** **** 94 Artificer 16790581 16827101 16827102 16827103 16827104 **** 6 CLS_ATK_2 CLS_FEAT_ARTI CLS_SAVTHR_WIZ CLS_SKILL_ARTI CLS_BFEAT_ARTI 4 **** **** 0 0 10 14 12 10 16 14 CHA 0X00 0X0 0 CLASS_TYPE_ARTIFICER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ARTI 0 1 0 0 -1 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 95 Arcane_Duelist 16790582 16823520 16823521 16823522 16823523 IR_SPARCDLST 8 CLS_ATK_3 CLS_FEAT_ADST CLS_SAVTHR_BARD CLS_SKILL_ADST CLS_BFEAT_ADST 4 **** **** 1 0 12 16 14 8 14 12 CHA 0X00 0X0 0 CLASS_TYPE_ARCANE_DUELIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ADST 40 0 0 0 10 **** 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -96 ForceMissileMage 16790583 16836426 16836427 16836428 16836429 IR_HAVOCMAGE 4 CLS_ATK_3 CLS_FEAT_FMM CLS_SAVTHR_ROG CLS_SKILL_FMM CLS_BFEAT_FMM 2 **** **** 1 0 12 14 14 10 12 15 CHA 0X00 0X0 0 CLASS_TYPE_FMM 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FMM 5 0 1 0 10 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +96 ForceMissileMage 16790583 16836426 16836427 16836428 16836429 IR_HAVOCMAGE 4 CLS_ATK_3 CLS_FEAT_FMM CLS_SAVTHR_ROG CLS_SKILL_FMM CLS_BFEAT_FMM 2 **** **** 1 0 12 14 14 10 12 15 INT 0X00 0X0 0 CLASS_TYPE_FMM 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FMM 5 0 1 0 5 31 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 97 WildMage 16790584 16836416 16836417 16836418 16836419 IR_WILDER 4 CLS_ATK_3 CLS_FEAT_WILDMG CLS_SAVTHR_ROG CLS_SKILL_WILDMG CLS_BFEAT_WILDMG 2 **** **** 1 0 12 14 14 10 12 15 CHA 0X04 0X0 0 CLASS_TYPE_WILD_MAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WILDMG 40 0 1 0 10 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 98 Shadowsmith 16790585 16847414 16847415 16847416 16847417 IR_TEMPUS 8 CLS_ATK_1 CLS_FEAT_SHDSMT CLS_SAVTHR_ROG CLS_SKILL_SHDSMT CLS_BFEAT_SHDSMT 6 **** **** 1 0 14 13 14 10 14 13 INT 0x00 0x0 0 CLASS_TYPE_SHADOWSMITH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHDSMT 40 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -99 Abjurant_Champion 16790586 16847652 16847653 16847654 16847655 IR_ELDKNI 10 CLS_ATK_1 CLS_FEAT_ABCHAM CLS_SAVTHR_WIZ CLS_SKILL_ABCHAM CLS_BFEAT_ABCHAM 2 **** **** 1 0 14 13 14 10 14 13 INT 0X00 0X0 0 CLASS_TYPE_ABJURANT_CHAMPION 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ABCHAM 5 0 1 0 5 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +99 Abjurant_Champion 16790586 16847652 16847653 16847654 16847655 IR_ELDKNI 10 CLS_ATK_1 CLS_FEAT_ABCHAM CLS_SAVTHR_WIZ CLS_SKILL_ABCHAM CLS_BFEAT_ABCHAM 2 **** **** 1 0 14 13 14 10 14 13 INT 0X00 0X0 0 CLASS_TYPE_ABJURANT_CHAMPION 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ABCHAM 5 0 1 0 5 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 100 Archmage 16790587 16825000 16825001 16825002 16825003 IR_EPICSPELL 4 CLS_ATK_3 CLS_FEAT_ARCH CLS_SAVTHR_WIZ CLS_SKILL_ARCH CLS_BFEAT_ARCH 2 **** **** 1 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_ARCHMAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ARCH 5 0 2 0 5 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -101 Oozemaster 16790588 16825036 16825037 16825038 16825039 IR_GENSUMMON 8 CLS_ATK_2 CLS_FEAT_OOZE CLS_SAVTHR_FIGHT CLS_SKILL_OOZE CLS_BFEAT_OOZE 4 **** **** 1 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_OOZEMASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_OOZE 40 0 2 2 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +101 Oozemaster 16790588 16825036 16825037 16825038 16825039 IR_GENSUMMON 8 CLS_ATK_2 CLS_FEAT_OOZE CLS_SAVTHR_FIGHT CLS_SKILL_OOZE CLS_BFEAT_OOZE 4 **** **** 1 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_OOZEMASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_OOZEM 40 0 2 2 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 102 Psychic_Rogue 16790589 16835172 16835173 16835174 16835175 IR_PSYWARRIOR 6 CLS_ATK_2 CLS_FEAT_PSYROG CLS_SAVTHR_ROG CLS_SKILL_PSYROG CLS_BFEAT_PSYROG 6 **** **** 1 0 14 12 14 16 10 10 WIS 0X00 0X0 0 CLASS_TYPE_PSYROG 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_PSYROG 20 1 0 0 -1 7 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 103 Spelldancer 16790590 16835157 16835158 16835159 16835160 IR_HAVOCMAGE 6 CLS_ATK_3 CLS_FEAT_SPLDNC CLS_SAVTHR_BARD CLS_SKILL_SPLDNC CLS_BFEAT_SPLDNC 4 **** **** 1 0 12 16 14 8 14 12 INT 0X00 0X0 0 CLASS_TYPE_SPELLDANCER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SPLDNC 5 0 1 0 5 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 104 KnightoftheWeave 16790591 16835149 16835150 16835151 16835152 IR_MAGEKILL 8 CLS_ATK_2 CLS_FEAT_KNGTWV CLS_SAVTHR_DRU CLS_SKILL_KNGTWV CLS_BFEAT_KNGTWV 2 CLS_SPGN_KNGTWV CLS_SPKN_KNGTWV 0 1 12 16 14 8 14 12 INT 0X10 0X2 0 CLASS_TYPE_KNIGHT_WEAVE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_KNGTWV 40 0 0 0 10 10 0 **** **** **** **** **** **** **** **** **** KnightWeave **** **** **** **** **** @@ -113,7 +113,7 @@ 109 Umbral_Disciple 16790596 16837827 16837828 16837829 16837830 IR_ASASIN 6 CLS_ATK_2 CLS_FEAT_UMBRAL CLS_SAVTHR_BARD CLS_SKILL_UMBRAL CLS_BFEAT_UMBRAL 6 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_UMBRAL_DISCIPLE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_UMBRAL 40 0 0 0 10 8 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 110 Alienist 16790597 16789710 16789711 16789712 16789713 IR_ALIEN 4 CLS_ATK_3 CLS_FEAT_ALIEN CLS_SAVTHR_WIZ CLS_SKILL_ALIEN CLS_BFEAT_ALIEN 2 **** **** 1 0 10 14 14 12 16 10 INT 0X00 0X0 0 CLASS_TYPE_ALIENIST 1 1 1 2 2 4 6 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ALIEN 40 0 1 0 10 10 0 cls_stat_alien **** **** **** **** **** **** **** **** **** **** **** **** **** **** 111 BlackBloodCultist 16790598 16823068 16823077 16823078 16823079 IR_WILDWOLF 12 CLS_ATK_2 CLS_FEAT_BBC CLS_SAVTHR_BARB CLS_SKILL_BBC CLS_BFEAT_BBC 4 **** **** 0 0 16 14 14 14 10 8 STR 0X0A 0X3 0 CLASS_TYPE_BLACK_BLOOD_CULTIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BBC 40 0 0 0 10 17 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -112 Warlock 16790599 16827934 16827935 16827936 16827937 IR_WARLOCK 6 CLS_ATK_2 CLS_FEAT_WARLOK CLS_SAVTHR_WIZ CLS_SKILL_WARLOK CLS_BFEAT_WARLOK 2 **** **** 1 0 12 14 14 10 12 15 CHA 0X14 0X3 1 CLASS_TYPE_WARLOCK 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WARLOK 0 1 0 0 -1 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +112 Warlock 16790599 16827934 16827935 16827936 16827937 IR_WARLOCK 6 CLS_ATK_2 CLS_FEAT_WARLOK CLS_SAVTHR_WIZ CLS_SKILL_WARLOK CLS_BFEAT_WARLOK 2 **** **** 1 1 12 14 14 10 12 15 CHA 0X14 0X3 1 CLASS_TYPE_WARLOCK 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WARLOK 0 1 0 0 -1 900 0 **** **** **** **** **** **** **** **** **** Warlock **** **** **** **** **** 113 Fochlucan_Lyrist 16852476 16825142 16825143 16825144 16825145 IR_DRUID 6 CLS_ATK_1 CLS_FEAT_FOCLYR CLS_SAVTHR_BARD CLS_SKILL_FOCLYR CLS_BFEAT_FOCLYR 6 **** **** 1 0 10 12 12 14 12 16 CHA 0X02 0X0 0 CLASS_TYPE_FOCHLUCAN_LYRIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FOCLYR 40 0 1 1 10 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 114 Dragonsong_Lyrist 16790600 16825459 16825460 16825461 16825462 IR_DRSLYR 6 CLS_ATK_2 CLS_FEAT_DRSLYR CLS_SAVTHR_BARD CLS_SKILL_DRSLYR CLS_BFEAT_DRSLYR 4 **** **** 1 0 12 14 14 10 12 15 CHA 0X10 0X2 0 CLASS_TYPE_DRAGONSONG_LYRIST 1 2 3 4 5 6 7 8 9 10 11 12 12 14 15 16 17 18 19 20 CLS_PRES_DSLYR 5 0 2 0 5 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 115 SpinemeldWarrior 16790601 16836998 16836999 16837000 16837001 IR_TEMPEST 10 CLS_ATK_1 CLS_FEAT_SPNMLD CLS_SAVTHR_FIGHT CLS_SKILL_SPNMLD CLS_BFEAT_SPNMLD 4 **** **** 1 0 16 14 14 14 10 8 STR 0X02 0X1 1 CLASS_TYPE_SPINEMELD_WARRIOR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SPNMLD 40 0 0 0 10 17 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** @@ -129,23 +129,23 @@ 125 Soulcaster 16790611 16837012 16837013 16837014 16837015 IR_MYSTIC 4 CLS_ATK_3 CLS_FEAT_SOULC CLS_SAVTHR_WIZ CLS_SKILL_SOULC CLS_BFEAT_SOULC 2 **** **** 1 0 10 11 11 16 16 10 INT 0X00 0X0 0 CLASS_TYPE_SOULCASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SOULC 40 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 126 Sacred_Fist 16790612 16825367 16825368 16825369 16825370 IR_SACREDFIST 8 CLS_ATK_1 CLS_FEAT_SACFIS CLS_SAVTHR_WILD CLS_SKILL_SACFIS CLS_BFEAT_SACFIS 4 **** **** 1 0 14 14 12 16 10 10 WIS 0X00 0X0 0 CLASS_TYPE_SACREDFIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SACFIS 40 0 0 1 10 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 127 Legendary_Dreadnought 16790613 16826086 16826087 16826088 16826089 IC_LEGDREAD 12 CLS_ATK_1 CLS_FEAT_LGDR CLS_SAVTHR_FIGHT CLS_SKILL_LGDR CLS_BFEAT_LGDR 2 **** **** 1 0 16 13 16 10 10 9 STR 0X00 0X0 0 CLASS_TYPE_LEGENDARY_DREADNOUGHT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_LGDR 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -128 Disciple_of_Baalzebul 16790614 16826094 16826095 16826096 16826097 IC_BAALZEBUL 6 CLS_ATK_2 CLS_FEAT_BAAL CLS_SAVTHR_BARD CLS_SKILL_BAAL CLS_BFEAT_BAAL 6 **** **** 1 0 12 14 14 10 12 15 CHA 0X09 0X2 0 CLASS_TYPE_DISC_BAALZEBUL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BAAL 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +128 Disciple_of_Baalzebul 16790614 16826094 16826095 16826096 16826097 IC_BAALZEBUL 6 CLS_ATK_2 CLS_FEAT_BAAL CLS_SAVTHR_BARD CLS_SKILL_BAAL CLS_BFEAT_BAAL 6 **** **** 1 0 12 14 14 10 12 15 CHA 0X09 0X2 0 CLASS_TYPE_DISC_BAALZEBUL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BAAL 40 0 0 0 10 4 0 cls_stat_baal **** **** **** **** **** **** **** **** **** **** **** **** **** **** 129 Mighty_Contender_of_Kord 16790615 16824935 16824936 16824937 16824938 IC_LEGDREAD 10 CLS_ATK_2 CLS_FEAT_KORD CLS_SAVTHR_CLER CLS_SKILL_KORD CLS_BFEAT_KORD 2 **** **** 1 0 14 8 14 16 10 14 WIS 0X00 0X0 0 CLASS_TYPE_MIGHTY_CONTENDER_KORD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_KORD 40 0 0 1 10 4 0 cls_stat_kord **** **** **** **** **** **** **** **** **** **** **** **** **** **** 130 Iaijutsu_Master 16790616 16826114 16826115 16826116 16826117 IC_IAIJUTSU 10 CLS_ATK_1 CLS_FEAT_IAIJ CLS_SAVTHR_ROG CLS_SKILL_IAIJ CLS_BFEAT_IAIJ 4 **** **** 1 0 16 13 16 10 10 9 CHA 0X05 0X1 0 CLASS_TYPE_IAIJUTSU_MASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_IAIJ 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 131 Disciple_of_Dispater 16790617 16826136 16826137 16826138 16826139 IR_BLKGRD 10 CLS_ATK_1 CLS_FEAT_DISP CLS_SAVTHR_MONK CLS_SKILL_DISP CLS_BFEAT_DISP 4 **** **** 1 0 16 13 16 10 10 9 CON 0X09 0X2 0 CLASS_TYPE_DISPATER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DISP 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 132 CW_Samurai 16790618 16826168 16826169 16826170 16826171 IR_SAMURAI 10 CLS_ATK_1 CLS_FEAT_CWSM CLS_SAVTHR_FIGHT CLS_SKILL_SAMUR CLS_BFEAT_CWSM 2 **** **** 0 0 16 13 16 10 10 9 STR 0X05 0X1 0 CLASS_TYPE_CW_SAMURAI 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_CWSM 20 1 0 0 -1 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -133 Ravager 16790619 16826156 16826157 16826158 16826159 IC_RAVA 10 CLS_ATK_1 CLS_FEAT_RAVA CLS_SAVTHR_FIGHT CLS_SKILL_RAVA CLS_BFEAT_RAVA 2 **** **** 1 0 16 13 16 10 10 9 STR 0X0A 0X3 0 CLASS_TYPE_RAVAGER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_RAVA 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -134 Runescarred_Berserker 16790620 16826187 16826188 16826189 16826190 IC_RUNE 10 CLS_ATK_1 CLS_FEAT_RUNE CLS_SAVTHR_FIGHT CLS_SKILL_RUNE CLS_BFEAT_RUNE 4 **** **** 1 0 16 13 16 10 10 9 STR 0X02 0X1 0 CLASS_TYPE_RUNESCARRED 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_RUNE 40 0 0 0 10 4 0 cls_stat_rune **** **** **** **** **** **** **** **** **** **** **** **** **** **** +133 Ravager 16790619 16826156 16826157 16826158 16826159 IC_RAVA 10 CLS_ATK_1 CLS_FEAT_RAVA CLS_SAVTHR_FIGHT CLS_SKILL_RAVA CLS_BFEAT_RAVA 2 **** **** 0 0 16 13 16 10 10 9 STR 0X0A 0X3 0 CLASS_TYPE_RAVAGER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_RAVA 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +134 Runescarred_Berserker 16790620 16826187 16826188 16826189 16826190 IC_RUNE 10 CLS_ATK_1 CLS_FEAT_RUNE CLS_SAVTHR_FIGHT CLS_SKILL_RUNE CLS_BFEAT_RUNE 4 **** **** 0 0 16 13 16 10 10 9 STR 0X02 0X1 0 CLASS_TYPE_RUNESCARRED 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_RUNE 40 0 0 0 10 4 0 cls_stat_rune **** **** **** **** **** **** **** **** **** **** **** **** **** **** 135 Talontar_Blightlord 16790621 16824917 16824918 16824919 16824920 IR_CLERIC 8 CLS_ATK_2 CLS_FEAT_BLTL CLS_SAVTHR_CLER CLS_SKILL_BLTL CLS_BFEAT_BLTL 2 **** **** 0 0 16 13 16 10 10 9 WIS 0X09 0X2 0 CLASS_TYPE_BLIGHTLORD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BLTL 40 0 0 1 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 136 Shadowcaster 16790622 16847394 16847395 16847396 16847397 IR_SHADADEPT 6 CLS_ATK_3 CLS_FEAT_SHDCST CLS_SAVTHR_CLER CLS_SKILL_SHDCST CLS_BFEAT_SHDCST 2 **** **** 1 0 10 10 14 12 16 14 CHA 0x00 0x0 0 CLASS_TYPE_SHADOWCASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHDCST 20 1 0 0 -1 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 137 ChildOfNight 16790623 16847398 16847399 16847400 16847401 IR_X1_SHADOW 6 CLS_ATK_3 CLS_FEAT_CHLDNT CLS_SAVTHR_WIZ CLS_SKILL_CHLDNT CLS_BFEAT_CHLDNT 2 **** **** 1 0 10 10 14 12 16 14 CHA 0x00 0x0 0 CLASS_TYPE_CHILD_OF_NIGHT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_CHLDNT 40 0 0 0 10 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 138 MasterofShadow 16790624 16847402 16847403 16847404 16847405 IR_MYSTIC 8 CLS_ATK_3 CLS_FEAT_MSTRSH CLS_SAVTHR_CLER CLS_SKILL_MSTRSH CLS_BFEAT_MSTRSH 2 **** **** 1 0 12 14 14 10 12 15 CHA 0x00 0x0 0 CLASS_TYPE_MASTER_OF_SHADOW 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MSTRSH 40 0 0 0 10 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 139 Noctumancer 16790625 16847406 16847407 16847408 16847409 IR_NOCTM 4 CLS_ATK_3 CLS_FEAT_NOCTM CLS_SAVTHR_CLER CLS_SKILL_NOCTM CLS_BFEAT_NOCTM 2 **** **** 1 0 12 14 14 10 12 15 CHA 0x00 0x0 **** CLASS_TYPE_NOCTUMANCER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_NOCTM 40 0 1 0 10 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 140 Totem_Rager 16790626 16825977 16825978 16825979 16825980 IR_PSYWARRIOR 10 CLS_ATK_2 CLS_FEAT_TOTRAG CLS_SAVTHR_RANG CLS_SKILL_TOTRAG CLS_BFEAT_TOTRAG 4 **** **** 1 0 16 15 14 10 10 10 CON 0X00 0X0 0 CLASS_TYPE_TOTEM_RAGER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_TOTRAG 40 0 0 0 10 142 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -141 Ninja_CA 16790627 16832316 16832317 16832318 16832319 IR_NINJCA 6 CLS_ATK_2 CLS_FEAT_NINJCA CLS_SAVTHR_ROG CLS_SKILL_NINJCA CLS_BFEAT_NINJCA 6 **** **** 0 0 12 16 12 14 14 8 DEX 0X00 0X0 0 CLASS_TYPE_NINJA 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_NINJCA 40 1 0 0 -1 7 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +141 Ninja_CA 16790627 16832316 16832317 16832318 16832319 IR_NINJCA 6 CLS_ATK_2 CLS_FEAT_NINJCA CLS_SAVTHR_ROG CLS_SKILL_NINJCA CLS_BFEAT_NINJCA 6 **** **** 0 0 12 16 12 14 14 8 DEX 0X00 0X0 0 CLASS_TYPE_NINJA 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_NINJCA 0 1 0 0 -1 7 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 142 Shadowblade 16790628 16847410 16847411 16847412 16847413 IR_SHADOWBLADE 8 CLS_ATK_2 CLS_FEAT_SHDBLD CLS_SAVTHR_FIGHT CLS_SKILL_SHDBLD CLS_BFEAT_SHDBLD 2 **** **** 1 0 14 15 14 12 12 10 DEX 0X00 0X0 0 CLASS_TYPE_SHADOWBLADE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHDBLD 40 0 0 0 10 8 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -143 DragonShaman 16790629 16832703 16832704 16832705 16832706 IR_DRAGSHMN 10 CLS_ATK_2 CLS_FEAT_DRGSHM CLS_SAVTHR_CLER CLS_SKILL_DRGSHM CLS_BFEAT_DRGSHM 2 **** **** 1 0 12 14 16 10 14 10 CON 0X00 0X0 0 CLASS_TYPE_DRAGON_SHAMAN 1 1 3 4 5 6 7 8 9 10 11 12 12 14 15 16 17 18 19 20 CLS_PRES_DRGSHM 40 1 0 0 -1 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -144 Dragonfire_Adept 16790630 16832914 16832915 16832916 16832917 IR_DRGNFIREADPT 8 CLS_ATK_3 CLS_FEAT_DFA CLS_SAVTHR_CLER CLS_SKILL_DFA CLS_BFEAT_DFA 4 **** **** 1 0 10 14 16 12 10 14 CON 0X00 0X0 0 CLASS_TYPE_DRAGONFIRE_ADEPT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DFA 40 1 0 0 -1 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +143 DragonShaman 16790629 16832703 16832704 16832705 16832706 IR_DRAGSHMN 10 CLS_ATK_2 CLS_FEAT_DRGSHM CLS_SAVTHR_CLER CLS_SKILL_DRGSHM CLS_BFEAT_DRGSHM 2 **** **** 1 0 12 14 16 10 14 10 CON 0X00 0X0 0 CLASS_TYPE_DRAGON_SHAMAN 1 1 3 4 5 6 7 8 9 10 11 12 12 14 15 16 17 18 19 20 CLS_PRES_DRGSHM 40 1 0 0 -1 705 0 cls_stat_drgshm **** **** **** **** **** **** **** **** **** **** **** **** **** **** +144 Dragonfire_Adept 16790630 16832914 16832915 16832916 16832917 IR_DRGNFIREADPT 8 CLS_ATK_3 CLS_FEAT_DFA CLS_SAVTHR_CLER CLS_SKILL_DFA CLS_BFEAT_DFA 4 **** **** 1 1 10 14 16 12 10 14 CON 0X00 0X0 0 CLASS_TYPE_DRAGONFIRE_ADEPT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DFA 40 1 0 0 -1 1 0 **** **** **** **** **** **** **** **** **** Dragonfire **** **** **** **** **** 145 Psion 16790631 16823566 16823567 16823568 16823569 IR_PSION 4 CLS_ATK_3 CLS_FEAT_PSION CLS_SAVTHR_WIZ CLS_SKILL_PSION CLS_BFEAT_PSION 2 **** **** 1 0 10 14 14 12 16 10 INT 0X00 0X0 0 CLASS_TYPE_PSION 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_PSION 0 1 0 0 -1 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 146 Psychic_Warrior 16790632 16823570 16823571 16823572 16823573 IR_PSYWARRIOR 8 CLS_ATK_2 CLS_FEAT_PSYWAR CLS_SAVTHR_FIGHT CLS_SKILL_PSYWAR CLS_BFEAT_PSYWAR 2 **** **** 1 0 14 12 14 16 10 10 WIS 0X00 0X0 0 CLASS_TYPE_PSYWAR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_PSYWAR 0 1 0 0 -1 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 147 Soulknife 16790633 16823574 16823575 16823576 16823577 IR_SOULKNIFE 10 CLS_ATK_2 CLS_FEAT_SOULKN CLS_SAVTHR_BARD CLS_SKILL_SOULKN CLS_BFEAT_SOULKN 4 **** **** 1 0 16 15 14 10 10 10 STR 0X00 0X0 0 CLASS_TYPE_SOULKNIFE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SOULKN 0 1 0 0 -1 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** @@ -181,14 +181,14 @@ 177 Frenzied_Berserker 16790662 16824216 16824217 16824218 16824219 IR_FREBZK 12 CLS_ATK_1 CLS_FEAT_FREBZK CLS_SAVTHR_BARB CLS_SKILL_FREBZK CLS_BFEAT_FREBZK 2 **** **** 1 0 16 14 14 14 10 8 STR 0X02 0X1 0 CLASS_TYPE_FRE_BERSERKER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FREBZK 40 0 0 0 10 17 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 178 Tempest 16790663 16824242 16824243 16824244 16824245 IR_TEMPEST 10 CLS_ATK_1 CLS_FEAT_TEMPST CLS_SAVTHR_BARB CLS_SKILL_TEMPST CLS_BFEAT_TEMPST 2 **** **** 1 0 10 16 12 10 16 10 DEX 0X00 0X0 0 CLASS_TYPE_TEMPEST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_TEMPST 40 0 0 0 10 7 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 179 Foe_Hunter 16790664 16824256 16824257 16824258 16824259 IR_FH 10 CLS_ATK_1 CLS_FEAT_FH CLS_SAVTHR_WILD CLS_SKILL_FH CLS_BFEAT_FH 2 **** **** 1 0 10 16 12 10 16 10 DEX 0X00 0X0 0 CLASS_TYPE_FOE_HUNTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FH 40 0 0 0 10 58 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -180 ***Eye_of_Gruumsh*** 16790665 16824294 16824295 16824296 16824297 IR_GRUUMSH 12 CLS_ATK_1 CLS_FEAT_EOG CLS_SAVTHR_BARB CLS_SKILL_EOG CLS_BFEAT_EOG 2 **** **** 0 0 16 14 14 14 10 8 STR 0X0A 0X3 0 CLASS_TYPE_PRC_EYE_OF_GRUUMSH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_EOG 40 0 0 0 10 17 0 cls_stat_eog **** **** **** **** **** **** **** **** **** **** **** **** **** **** +180 Verdant_Lord 16855246 16855247 16855248 16855249 16855250 IR_DRUID 8 CLS_ATK_1 CLS_FEAT_VLORD CLS_SAVTHR_DRU CLS_SKILL_VLORD CLS_BFEAT_VLORD 4 **** **** 1 0 14 13 13 16 10 10 WIS 0X10 0X2 0 CLASS_VERDANT_LORD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_VLORD 40 0 0 1 10 3 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 181 Orc_Warlord 16790666 16824312 16824313 16824314 16824315 IR_ORCWAR 12 CLS_ATK_1 CLS_FEAT_ORCWAR CLS_SAVTHR_MONK CLS_SKILL_ORCWAR CLS_BFEAT_ORCWAR 2 **** **** 1 0 16 14 14 14 10 8 STR 0X08 0X2 0 CLASS_TYPE_ORC_WARLORD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ORCWAR 5 0 0 0 5 17 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 182 Thrall_of_Grazzt 16790667 16824516 16824517 16824518 16824519 IR_TOG 6 CLS_ATK_3 CLS_FEAT_TOG CLS_SAVTHR_WIZ CLS_SKILL_TOG CLS_BFEAT_TOG 4 **** **** 1 0 12 16 14 8 14 12 INT 0X09 0X2 0 CLASS_TYPE_THRALL_OF_GRAZZT_A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_TOG_A 40 0 2 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 183 Necrocarnate 16790668 16838080 16838081 16838082 16838083 ir_truenecro 6 CLS_ATK_3 CLS_FEAT_NECRNM CLS_SAVTHR_WIZ CLS_SKILL_NECRNM CLS_BFEAT_BLANK 2 **** **** 1 0 12 16 14 8 14 12 INT 0X09 0X2 0 CLASS_TYPE_NECROCARNATE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_NECRNM 13 0 0 0 13 13 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 184 Eldritch_Disciple 16790669 16790013 16790014 16790015 16790016 IR_EDISC 8 CLS_ATK_2 CLS_FEAT_EDISC CLS_SAVTHR_CLER CLS_SKILL_EDISC CLS_BFEAT_EDISC 2 **** **** 1 0 14 8 14 16 10 14 WIS 0X00 0X0 0 CLASS_TYPE_ELDRITCH_DISCIPLE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_EDISC 40 0 0 1 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 185 Eldritch_Theurge 16790670 16790017 16790018 16790019 16790020 IR_ETHEUR 4 CLS_ATK_2 CLS_FEAT_ETHEUR CLS_SAVTHR_WIZ CLS_SKILL_ETHEUR CLS_BFEAT_ETHEUR 2 **** **** 1 0 10 14 14 12 16 10 INT 0X00 0X0 0 CLASS_TYPE_ELDRITCH_THEURGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ETHEUR 40 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 186 Ghost_Faced_Killer 16790671 16832352 16832353 16832354 16832355 IR_GFKILL_PRC 8 CLS_ATK_1 CLS_FEAT_GFKILL CLS_SAVTHR_FIGHT CLS_SKILL_GFKILL CLS_BFEAT_GFKILL 4 **** **** 1 0 16 13 16 10 10 9 STR 0X09 0X2 0 CLASS_TYPE_GHOST_FACED_KILLER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_GFKILL 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -187 DreadNecromancer 16790672 16847586 16847587 16847588 16847589 IR_PALEMA 6 CLS_ATK_3 CLS_FEAT_DNECRO CLS_SAVTHR_WIZ CLS_SKILL_DNECRO CLS_BFEAT_DNECRO 2 CLS_SPGN_DNECRO CLS_SPKN_DNECRO 1 1 10 14 12 10 14 16 CHA 0X08 0X2 0 CLASS_TYPE_DREAD_NECROMANCER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DNECRO 0 1 1 0 -1 10 130 **** **** **** **** **** **** **** **** **** DreadNecro **** **** **** **** **** +187 DreadNecromancer 16790672 16847586 16847587 16847588 16847589 IR_PALEMA 6 CLS_ATK_3 CLS_FEAT_DNECRO CLS_SAVTHR_WIZ CLS_SKILL_DNECRO CLS_BFEAT_DNECRO 2 CLS_SPGN_DNECRO CLS_SPKN_DNECRO 1 1 10 14 12 10 14 16 CHA 0X08 0X2 0 CLASS_TYPE_DREAD_NECROMANCER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DNECRO 0 1 0 0 -1 10 130 **** **** **** **** **** **** 1 **** **** DreadNecro **** **** **** **** **** 188 UltimateMagus **** 16790350 16790351 16790352 16790353 IR_EPICSPELL 4 CLS_ATK_3 CLS_FEAT_UM CLS_SAVTHR_WIZ CLS_SKILL_UM CLS_BFEAT_UM 2 **** **** 0 0 10 11 11 16 16 10 INT 0X00 0X0 0 CLASS_TYPE_MYSTIC_THEURGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_UM 40 0 2 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 189 ForestMaster 16790673 16793736 16793737 16793738 16793739 IR_DRUID 8 CLS_ATK_2 CLS_FEAT_FORMAS CLS_SAVTHR_DRU CLS_SKILL_FORMAS CLS_BFEAT_FORMAS 2 **** **** 0 0 14 13 13 16 10 10 WIS 0X00 0X0 0 CLASS_TYPE_FORESTMASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_FORMAS 40 0 0 1 10 3 0 cls_stat_formas **** **** **** **** **** **** **** **** **** **** **** **** **** **** 190 Archivist 16790674 16789866 16789867 16789868 16789869 IR_ARCHIVIST 6 CLS_ATK_3 CLS_FEAT_ARCHV CLS_SAVTHR_CLER CLS_SKILL_ARCHV CLS_BFEAT_ARCHV 4 CLS_SPGN_ARCHV **** 1 1 10 14 14 12 16 10 INT 0X00 0X0 0 CLASS_TYPE_ARCHIVIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ARCHV 0 1 0 0 -1 10 65 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** @@ -198,9 +198,9 @@ 194 RubyKnightVindicator 16790678 16827167 16827168 16827169 16827170 IR_HEIRONEOUS 8 CLS_ATK_1 CLS_FEAT_RBYKNT CLS_SAVTHR_WIZ CLS_SKILL_RBYKNT CLS_BFEAT_RBYKNT 4 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_RUBY_VINDICATOR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_RBYKNT 40 0 0 1 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 195 MasterOfNine 16790679 16847557 16847558 16847559 16847560 IR_PSYWARRIOR 8 CLS_ATK_2 CLS_FEAT_MONINE CLS_SAVTHR_WIZ CLS_SKILL_MONINE CLS_BFEAT_MONINE 6 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_MASTER_OF_NINE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MONINE 5 0 0 0 5 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 196 EternalBlade 16790680 16834750 16834751 16834752 16834753 IR_FH 10 CLS_ATK_1 CLS_FEAT_ETBL CLS_SAVTHR_FIGHT CLS_SKILL_ETBL CLS_BFEAT_ETBL 2 **** **** 1 0 16 13 16 10 10 9 STR 0X00 0X0 0 CLASS_TYPE_ETERNAL_BLADE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ETBL 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -197 ShadowSunNinja 16790681 16834778 16834779 16834780 16834781 IR_SHADADEPT 8 CLS_ATK_2 CLS_FEAT_SSN CLS_SAVTHR_MONK CLS_SKILL_SSN CLS_BFEAT_SSN 4 **** **** 0 0 16 13 16 10 10 9 STR 0X11 0X2 0 CLASS_TYPE_SHADOW_SUN_NINJA 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SSN 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +197 ShadowSunNinja 16790681 16834778 16834779 16834780 16834781 IR_SHADADEPT 8 CLS_ATK_2 CLS_FEAT_SSN CLS_SAVTHR_MONK CLS_SKILL_SSN CLS_BFEAT_SSN 4 **** **** 1 0 16 13 16 10 10 9 STR 0X11 0X2 0 CLASS_TYPE_SHADOW_SUN_NINJA 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SSN 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 198 WitchbornBinder 16790682 16838144 16838145 16838146 16838147 IR_WITCH 6 CLS_ATK_2 CLS_FEAT_WCHBRN CLS_SAVTHR_WIZ CLS_SKILL_WCHBRN CLS_BFEAT_WCHBRN 4 **** **** 1 0 10 14 14 10 12 16 CHA 0X00 0X0 0 CLASS_TYPE_WITCHBORN_BINDER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WCHBRN 40 0 0 0 10 6 2 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -199 Baelnorn 16790683 16829216 16829217 16829218 16829219 IR_BAELNORN 4 CLS_ATK_4 CLS_FEAT_BAELN CLS_SAVTHR_LICH CLS_SKILL_WIZ CLS_BFEAT_LICH 2 **** **** 1 0 13 13 13 13 13 13 CHA 0X11 0X2 0 CLASS_TYPE_BAELNORN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BAELN 4 0 0 0 4 10 0 cls_stat_baeln **** **** **** **** **** **** **** **** **** **** **** **** **** **** +199 Lion_of_Talisid 16855216 16855217 16855218 16855219 16855220 IR_LIONTALISID 8 CLS_ATK_2 CLS_FEAT_LOT CLS_SAVTHR_DRU CLS_SKILL_LOT CLS_BFEAT_LOT 4 **** **** 1 0 14 13 13 16 10 10 WIS 0X16 0X3 0 CLASS_TYPE_LION_OF_TALISID 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_LOT 40 0 0 1 10 3 0 **** **** **** **** **** **** **** **** **** **** **** **** 1 **** **** 200 Disciple_of_Meph 16790684 16823016 16823017 16823018 16823019 IR_DISCMEPH 8 CLS_ATK_1 CLS_FEAT_MEPH CLS_SAVTHR_MONK CLS_SKILL_MEPH CLS_BFEAT_MEPH 4 **** **** 1 0 12 16 14 8 14 12 CHA 0X09 0X2 0 CLASS_TYPE_DISCIPLE_OF_MEPH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_MEPH 40 0 0 0 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 201 Soul_Eater 16790685 16832116 16832117 16832118 16832119 IR_SOULEATER 8 CLS_ATK_1 CLS_FEAT_SLEAT CLS_SAVTHR_MONK CLS_SKILL_SLEAT CLS_BFEAT_SLEAT 4 **** **** 1 0 14 16 10 12 14 10 INT 0X09 0X2 0 CLASS_TYPE_SOUL_EATER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SLEAT 40 0 0 0 10 1 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 202 Henshin_Mystic 16790686 16825076 16825078 16825079 16825080 IR_HNSHN 8 CLS_ATK_2 CLS_FEAT_HNSHN CLS_SAVTHR_MONK CLS_SKILL_HNSHN CLS_BFEAT_HNSHN 4 **** **** 1 0 14 14 14 15 10 10 WIS 0X05 0X1 0 CLASS_TYPE_HENSHIN_MYSTIC 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_HNSHN 40 0 0 0 10 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** @@ -208,7 +208,7 @@ 204 Enlightened_Fist 16790688 16829416 16829417 16829418 16829419 IR_SACREDFIST 8 CLS_ATK_2 CLS_FEAT_ENLFIS CLS_SAVTHR_BARD CLS_SKILL_ENLFIS CLS_BFEAT_ENLFIS 4 **** **** 1 0 10 14 12 14 16 10 DEX 0X00 0X0 0 CLASS_TYPE_ENLIGHTENEDFIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ENLFIS 40 0 1 0 10 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 205 Morninglord 16790689 16789624 16789625 16789626 16789627 IR_MORNING 8 CLS_ATK_2 CLS_FEAT_ML CLS_SAVTHR_CLER CLS_SKILL_ML CLS_BFEAT_ML 2 **** **** 0 0 14 8 14 16 10 14 CHA 0X11 0X2 0 CLASS_TYPE_MORNINGLORD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_ML 40 0 0 1 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 206 IncarnumBlade 16790690 16838136 16838137 16838138 16838139 IR_CRUSADER 10 CLS_ATK_1 CLS_FEAT_IBLADE CLS_SAVTHR_FIGHT CLS_SKILL_IBLADE CLS_BFEAT_BLANK 2 **** **** 1 0 16 14 14 14 10 8 STR 0X01 0X3 0 CLASS_TYPE_INCARNUM_BLADE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_IBLADE 5 0 0 0 5 17 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -207 OAShaman 16790691 16827659 16827660 16827661 16827662 IR_CLERIC 6 CLS_ATK_2 CLS_FEAT_SHAMAN CLS_SAVTHR_WIZ CLS_SKILL_SHAMAN CLS_BFEAT_SHAMAN 4 CLS_SPGN_SHAMAN **** 1 1 10 13 12 16 13 12 WIS 0X00 0X0 0 CLASS_TYPE_SHAMAN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHAMAN 0 1 0 0 -1 2 0 **** 1 0 1 0 0 0 0 WIS Shaman 1 1 1 0 0 +207 OAShaman 16790691 16827659 16827660 16827661 16827662 IR_CLERIC 6 CLS_ATK_2 CLS_FEAT_SHAMAN CLS_SAVTHR_WIZ CLS_SKILL_SHAMAN CLS_BFEAT_SHAMAN 4 CLS_SPGN_SHAMAN **** 0 1 10 13 12 16 13 12 WIS 0X00 0X0 0 CLASS_TYPE_SHAMAN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHAMAN 0 1 0 0 -1 2 0 **** 1 0 1 0 0 0 0 WIS Shaman 1 1 1 0 0 208 Pyrokineticist 16790692 16827043 16827044 16827045 16827046 IR_BFZ 8 CLS_ATK_2 CLS_FEAT_PYRO CLS_SAVTHR_WILD CLS_SKILL_PYRO CLS_BFEAT_PYRO 2 **** **** 1 0 10 14 14 10 12 16 CHA 0X03 0X1 0 CLASS_TYPE_PYROKINETICIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_PYRO 40 0 0 0 10 9 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 209 Shadowmind 16790693 16829364 16829365 16829366 16829367 IR_TFSHAD 6 CLS_ATK_2 CLS_FEAT_SDMIND CLS_SAVTHR_BARD CLS_SKILL_SDMIND CLS_BFEAT_SDMIND 4 **** **** 1 0 10 11 11 16 16 10 INT 0X00 0X0 0 CLASS_TYPE_SHADOWMIND 1 1 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SDMIND 40 0 0 0 10 8 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 210 Psychic_Thurge 16790694 16823908 16823909 16823910 16823911 IR_PSYCHIC 4 CLS_ATK_3 CLS_FEAT_PSYCH CLS_SAVTHR_WIZ CLS_SKILL_PSYCH CLS_BFEAT_PSYCH 2 **** **** 1 0 10 11 11 16 16 10 INT 0X00 0X0 0 CLASS_TYPE_PSYCHIC_THEURGE 1 1 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_PSYCH 40 0 0 1 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** @@ -235,9 +235,9 @@ 231 BrimstoneSpeaker 16790715 16827554 16827555 16827556 16827557 IR_BRIMSTONE 8 CLS_ATK_2 CLS_FEAT_BRIMST CLS_SAVTHR_CLER CLS_SKILL_BRIMST CLS_BFEAT_BRIMST 2 **** **** 1 0 12 16 14 8 14 12 WIS 0X11 0X2 0 CLASS_TYPE_BRIMSTONE_SPEAKER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BRIMST 40 0 0 2 10 2 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 232 Shugenja **** 16825142 16825143 16825144 16825145 IR_HNSHN 6 CLS_ATK_3 CLS_FEAT_SHUGEN CLS_SAVTHR_WIZ CLS_SKILL_SHUGEN CLS_BFEAT_SHUGEN 4 **** **** 0 0 10 14 14 10 12 16 CHA 0X00 0X0 0 CLASS_TYPE_SHUGENJA 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHUGEN 0 1 0 0 -1 0 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 233 Sohei 16790716 16827429 16827430 16827431 16827432 IR_FIGHTER 10 CLS_ATK_2 CLS_FEAT_SOHEI CLS_SAVTHR_CLER CLS_SKILL_SOHEI CLS_BFEAT_SOHEI 2 CLS_SPGN_SOHEI **** 1 1 16 10 13 14 13 10 STR 0X05 0X1 0 CLASS_TYPE_SOHEI 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SOHEI 0 1 0 0 -1 6 0 **** 1 0 0 0 0 0 0 WIS Sohei 1 4 255 0 0 -234 Crusader 16790717 16829702 16829703 16829704 16829705 IR_CRUSADER 10 CLS_ATK_1 CLS_FEAT_CRUSDR CLS_SAVTHR_FIGHT CLS_SKILL_CRUSDR CLS_BFEAT_CRUSDR 4 **** **** 1 0 16 14 14 10 12 10 STR 0X1E 0X3 1 CLASS_TYPE_CRUSADER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_CRUSDR 40 1 0 0 -1 6 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -235 Swordsage 16790718 16829706 16829707 16829708 16829709 IR_MONK 8 CLS_ATK_2 CLS_FEAT_SWDSGE CLS_SAVTHR_BARD CLS_SKILL_SWDSGE CLS_BFEAT_SWDSGE 6 **** **** 1 0 16 14 14 10 12 10 STR 0X00 0X0 0 CLASS_TYPE_SWORDSAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SWDSGE 40 1 0 0 -1 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** -236 Warblade 16790719 16829710 16829711 16829712 16829713 IR_FIGHTER 12 CLS_ATK_1 CLS_FEAT_WARBLD CLS_SAVTHR_FIGHT CLS_SKILL_WARBLD CLS_BFEAT_WARBLD 4 **** **** 1 0 16 14 14 10 12 10 STR 0X00 0X0 0 CLASS_TYPE_WARBLADE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WARBLD 40 1 0 0 -1 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +234 Crusader 16790717 16829702 16829703 16829704 16829705 IR_CRUSADER 10 CLS_ATK_1 CLS_FEAT_CRUSDR CLS_SAVTHR_FIGHT CLS_SKILL_CRUSDR CLS_BFEAT_CRUSDR 4 **** **** 1 0 16 14 14 10 12 10 STR 0X1E 0X3 1 CLASS_TYPE_CRUSADER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_CRUSDR 0 1 0 0 -1 6 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +235 Swordsage 16790718 16829706 16829707 16829708 16829709 IR_MONK 8 CLS_ATK_2 CLS_FEAT_SWDSGE CLS_SAVTHR_BARD CLS_SKILL_SWDSGE CLS_BFEAT_SWDSGE 6 **** **** 1 0 16 14 14 10 12 10 STR 0X00 0X0 0 CLASS_TYPE_SWORDSAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SWDSGE 0 1 0 0 -1 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +236 Warblade 16790719 16829710 16829711 16829712 16829713 IR_FIGHTER 12 CLS_ATK_1 CLS_FEAT_WARBLD CLS_SAVTHR_FIGHT CLS_SKILL_WARBLD CLS_BFEAT_WARBLD 4 **** **** 1 0 16 14 14 10 12 10 STR 0X00 0X0 0 CLASS_TYPE_WARBLADE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WARBLD 0 1 0 0 -1 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 237 Warmage 16790720 16827604 16827605 16827606 16827607 IR_HAVOCMAGE 6 CLS_ATK_3 CLS_FEAT_WRMAGE CLS_SAVTHR_WIZ CLS_SKILL_WRMAGE CLS_BFEAT_WRMAGE 2 CLS_SPGN_WRMAGE CLS_SPKN_WRMAGE 1 1 10 14 12 10 14 16 INT 0X00 0X0 0 CLASS_TYPE_WARMAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_WRMAGE 0 1 0 0 -1 10 130 **** **** **** **** **** **** **** **** **** Warmage **** **** **** **** **** 238 Knight 16790721 16827632 16827633 16827634 16827635 IR_PALADIN 12 CLS_ATK_1 CLS_FEAT_KNIGHT CLS_SAVTHR_WIZ CLS_SKILL_KNIGHT CLS_BFEAT_KNIGHT 2 **** **** 1 0 16 10 16 10 10 12 STR 0X05 0X1 0 CLASS_TYPE_KNIGHT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_KNIGHT 20 1 0 0 -1 6 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 239 FistOfDalQuor 16790722 16827033 16827034 16827035 16827036 IR_SHOUDISC 10 CLS_ATK_2 CLS_FEAT_DALQUR CLS_SAVTHR_CLER CLS_SKILL_DALQUR CLS_BFEAT_DALQUR 2 **** **** 0 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_FIST_DAL_QUOR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DALQUR 5 0 0 0 5 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** diff --git a/src/hakpak/ghost_prc8_top/2da/racialtypes.2da b/src/hakpak/ghost_prc8_top/2da/racialtypes.2da index 3cb7c0e..d6f7bb2 100644 --- a/src/hakpak/ghost_prc8_top/2da/racialtypes.2da +++ b/src/hakpak/ghost_prc8_top/2da/racialtypes.2da @@ -53,7 +53,7 @@ 49 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 4 30 3 1 **** **** 50 Drider Dr 3063 3063 16833081 108146 16833083 **** 406 4 4 4 6 6 6 30 9 RACE_FEAT_DRIDER 16833082 1 RACIAL_TYPE_DRIDER 110 9 1 drow **** **** **** 4 30 3 1 INT 268 51 Wemic Wm 16826957 16826958 16826958 16826959 16826960 **** 467 8 2 0 -2 0 2 40 0 RACE_FEAT_WEMIC 16826961 1 RACIAL_TYPE_WEMIC 6 0 1 wemic **** **** **** 4 30 3 1 INT 274 -52 Plant Pl 16833077 16833077 16833078 16833079 16833080 **** 51 0 -2 0 0 0 2 0 **** **** 0 0 RACIAL_TYPE_PLANT 4 15 0.95 plant **** **** **** 4 30 3 1 INT 2355 +52 Plant Pl 16833077 16833077 16833078 16833079 16833080 **** 51 0 0 0 0 0 0 0 **** **** 0 0 RACIAL_TYPE_PLANT 4 15 0.95 plant **** **** **** 4 30 3 1 INT 2355 53 Brownie Bw 16826962 16826962 16826963 16826964 16826965 **** 55 -6 10 2 2 2 2 30 8 RACE_FEAT_BROWNI 8160 1 RACIAL_TYPE_BROWNIE 20 8 1 brownie **** **** **** 4 30 3 1 INT 278 54 Krinth Kr 16833149 16833149 16833150 16833149 16833151 **** 5 0 0 0 -2 0 2 30 4 RACE_FEAT_KRINTH 16833149 1 RACIAL_TYPE_KRINTH 20 4 1 krinth **** **** **** 4 30 3 1 INT 267 55 Goliath Go 16833166 16833166 16833167 16833170 16833171 **** 5 4 -2 0 0 0 2 30 0 RACE_FEAT_GOL 16833166 1 RACIAL_TYPE_GOLIATH 20 0 1 goliath **** **** **** 4 30 3 1 INT 274 @@ -78,7 +78,7 @@ 74 Muckdweller Mr 16836018 16836018 16836019 16836020 16836021 **** 206 -6 6 0 -2 -2 0 20 8 RACE_FEAT_MUCKD 8163 1 RACIAL_TYPE_MUCKDWELLER 15 8 1 muckdweller **** **** **** 4 30 3 1 INT 276 75 Aranea Ae 16836006 16836006 16836007 16836008 16836009 **** 158 0 4 4 4 2 4 50 9 RACE_FEAT_ARANEA 8163 1 RACIAL_TYPE_ARANEA 15 9 1 aranea **** **** **** 4 30 3 1 INT 284 76 Chitine Ch 16832294 16832294 16832295 16832296 16832297 **** 2 **** 2 2 -4 **** 2 30 8 RACE_FEAT_CHIT 16832294 1 RACIAL_TYPE_CHITINE 15 8 1 chitine **** **** **** 4 30 3 1 INT 274 -77 SpiretopDragon Sd 16835965 16835966 16835967 16835968 16835969 **** 375 -4 8 -4 -2 0 2 60 8 RACE_FEAT_SPDRAG 16835970 1 RACIAL_TYPE_SPIRETOPDRAGON 25 8 1 dragon **** **** **** 4 30 3 1 INT 272 +77 SpiretopDragon Sd 16835965 16835966 16835967 16835968 16835969 **** 375 -4 8 -4 -2 0 2 60 8 RACE_FEAT_SPDRAG 16835970 0 RACIAL_TYPE_SPIRETOPDRAGON 25 8 1 dragon **** **** **** 4 30 3 1 INT 272 78 Jaebrin Ja 16852286 16852286 16852287 16852288 16852289 **** 6 -2 0 0 2 0 0 30 79 RACE_FEAT_JAEBRN 8163 1 RACIAL_TYPE_JAEBRIN 15 79 1 fey human **** **** 4 30 3 1 INT 278 79 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 80 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_burnhand.ncs b/src/hakpak/ghost_prc8_top/nss/nw_s0_burnhand.ncs new file mode 100644 index 0000000000000000000000000000000000000000..2da9e7014386c8704c9ca9c5ad7ee2f7159d2cde GIT binary patch literal 229310 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 0) + { + effect eFire = PRCEffectDamage(oTarget, nDamage, EleDmg); + + // Apply effects to the currently selected target. + DelayCommand(fDist, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + DelayCommand(fDist, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eFire, oTarget)); + PRCBonusDamage(oTarget); + } + } + } + //Select the next target within the spell shape. + oTarget = MyNextObjectInShape(SHAPE_SPELLCONE, 10.0, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } + PRCSetSchool(); +} diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_calllghtn.ncs b/src/hakpak/ghost_prc8_top/nss/nw_s0_calllghtn.ncs new file mode 100644 index 0000000000000000000000000000000000000000..693c8e56b5448efdb784af3d4d571ee51223913f GIT binary patch literal 232901 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

k&* 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 N0I3~obU=UT{{xx~6(j%v literal 0 HcmV?d00001 diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_calllghtn.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_calllghtn.nss new file mode 100644 index 0000000..dade449 --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_calllghtn.nss @@ -0,0 +1,190 @@ +//:://///////////////////////////////////////////// +//:: Call Lightning +//:: NW_S0_CallLghtn.nss +//:: Copyright (c) 2001 Bioware Corp. +//:://///////////////////////////////////////////// +/* +Evocation [Electricity] +Level: Drd 3 +Components: V, S +Casting Time: 1 round +Range: Medium (100 ft. + 10 ft./level) +Effect: One or more 30-ft.-long vertical lines of lightning +Duration: 1 min./level +Saving Throw: Reflex half +Spell Resistance: Yes + +Immediately upon completion of the spell, and once +per round thereafter, you may call down a 5-foot-wide, +30-foot-long, vertical bolt of lightning that deals +3d6 points of electricity damage. The bolt of lightning +flashes down in a vertical stroke at whatever target +point you choose within the spell’s range (measured +from your position at the time). Any creature in the +target square or in the path of the bolt is affected. + +You need not call a bolt of lightning immediately; +other actions, even spellcasting, can be performed. +However, each round after the first you may use a +standard action (concentrating on the spell) to call +a bolt. You may call a total number of bolts equal to +your caster level (maximum 10 bolts). + +If you are outdoors and in a stormy area—a rain shower, +clouds and wind, hot and cloudy conditions, or even a +tornado (including a whirlwind formed by a djinni or an +air elemental of at least Large size)—each bolt deals +3d10 points of electricity damage instead of 3d6. + +This spell functions indoors or underground but not +underwater. + +*/ +//::////////////////////////////////////////////// +//:: Notes: totally not like PnP version, +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: May 22, 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 20, 2001 +//:: modified by mr_bumpkin Dec 4, 2003 + +#include "prc_inc_spells" +#include "prc_add_spell_dc" + +void main() +{ + if (!X2PreSpellCastCode()) return; + + PRCSetSchool(SPELL_SCHOOL_EVOCATION); + + //Declare major variables + object oCaster = OBJECT_SELF; + int nInt = GetLocalInt(oCaster, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + int nDamage; + int nCasterLvl = PRCGetCasterLevel(oCaster); + int nPenetr = nCasterLvl + SPGetPenetr(); + int nMetaMagic = PRCGetMetaMagicFeat(); + int nDice = PRCMin(10, nCasterLvl); + int EleDmg = ChangedElementalDamage(oCaster, DAMAGE_TYPE_ELECTRICAL); + int nSaveType = ChangedSaveType(EleDmg); + + effect eVis = EffectVisualEffect(VFX_IMP_LIGHTNING_M); + effect eDam; + //Get the spell target location as opposed to the spell target. + location lTarget = PRCGetSpellTargetLocation(); + //Limit Caster level for the purposes of damage + if (nCasterLvl > 10) + { + nCasterLvl = 10; + } + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Call Lightning' will not work underwater!", oCaster); + return; + } + //Declare the spell shape, size and the location. Capture the first target object in the shape. + object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget)) + { + if(spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, oCaster)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(oCaster, SPELL_CALL_LIGHTNING)); + //Get the distance between the explosion and the target to calculate delay + float fDelay = PRCGetRandomDelay(0.4, 1.75); + if (!PRCDoResistSpell(oCaster, oTarget, nPenetr, fDelay)) + { + //Roll damage for each target + int nDamage = d6(nDice); + //Resolve metamagic + if(nMetaMagic & METAMAGIC_MAXIMIZE) + nDamage = 6 * nDice; + if(nMetaMagic & METAMAGIC_EMPOWER) + nDamage += nDamage / 2; + + nDamage += SpellDamagePerDice(oCaster, nDice); + //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. + nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, PRCGetSaveDC(oTarget, oCaster), nSaveType); + if(nDamage > 0) + { + //Set the damage effect + effect eDam = PRCEffectDamage(oTarget, nDamage, EleDmg); + + // Apply effects to the currently selected target. + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + PRCBonusDamage(oTarget); + } + } + } + //Select the next target within the spell shape. + oTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } + PRCSetSchool(); + + //Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oCaster, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oCaster, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oCaster, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oCaster, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oCaster, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oCaster, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oCaster, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oCaster)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oCaster)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oCaster)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Call Lightning' has caused a cave-in!", oCaster)); + } +} diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_chlightn.ncs b/src/hakpak/ghost_prc8_top/nss/nw_s0_chlightn.ncs new file mode 100644 index 0000000000000000000000000000000000000000..be660f89908cc16e59bc92ca9fcdb90efb166344 GIT binary patch literal 232126 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

E$Th_JA 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

Z{GtnR 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 literal 0 HcmV?d00001 diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_chlightn.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_chlightn.nss new file mode 100644 index 0000000..60e4e94 --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_chlightn.nss @@ -0,0 +1,277 @@ +//:://///////////////////////////////////////////// +//:: Chain Lightning +//:: NW_S0_ChLightn +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + The primary target is struck with 1d6 per caster, + 1/2 with a reflex save. 1 secondary target per + level is struck for 1d6 / 2 caster levels. No + repeat targets can be chosen. +*/ +//::////////////////////////////////////////////// +//:: Created By: Brennon Holmes +//:: Created On: March 8, 2001 +//::////////////////////////////////////////////// +//:: Last Updated By: Preston Watamaniuk, On: April 26, 2001 +//:: Update Pass By: Preston W, On: July 26, 2001 + +/* +bugfix by Kovi 2002.07.28 +- successful saving throw and (improved) evasion was ignored for + secondary targets, +- all secondary targets suffered exactly the same damage +2002.08.25 +- primary target was not effected +*/ + + +//:: modified by mr_bumpkin Dec 4, 2003 +#include "prc_inc_spells" +#include "prc_add_spell_dc" + + + + +void main() +{ +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_EVOCATION); +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + int CasterLvl = PRCGetCasterLevel(OBJECT_SELF); + int nCasterLevel = CasterLvl; + object oPC = GetFirstPC(); + object oCaster = OBJECT_SELF; + int nDoOnce = 0; + //Limit caster level + // June 2/04 - Bugfix: Cap the level BEFORE the damage calculation, not after. Doh. + if (nCasterLevel > 20) + { + nCasterLevel = 20; + } + int nInt=GetLocalInt(oPC, "Underwater"); + int nDamage = d6(nCasterLevel); + int nDamStrike; + int nNumAffected = 0; + int nMetaMagic = PRCGetMetaMagicFeat(); + //Declare lightning effect connected the casters hands + effect eLightning = EffectBeam(VFX_BEAM_LIGHTNING, OBJECT_SELF, BODY_NODE_HAND);; + effect eVis = EffectVisualEffect(VFX_IMP_LIGHTNING_S); + effect eDamage; + object oFirstTarget = PRCGetSpellTargetObject(); + object oHolder; + object oTarget; + location lSpellLocation; + + //Enter Metamagic conditions + if ((nMetaMagic & METAMAGIC_MAXIMIZE)) + { + nDamage = 6 * nCasterLevel;//Damage is at max + } + if ((nMetaMagic & METAMAGIC_EMPOWER)) + { + nDamage = nDamage + (nDamage/2); //Damage/is +50% + } + nDamage += SpellDamagePerDice(OBJECT_SELF, nCasterLevel); + + CasterLvl +=SPGetPenetr(); + + int EleDmg = ChangedElementalDamage(OBJECT_SELF, DAMAGE_TYPE_ELECTRICAL); + + //Damage the initial target + if (spellsIsTarget(oFirstTarget, SPELL_TARGET_SELECTIVEHOSTILE, OBJECT_SELF)) + { + //Fire cast spell at event for the specified target + SignalEvent(oFirstTarget, EventSpellCastAt(OBJECT_SELF, SPELL_CHAIN_LIGHTNING)); + //Make an SR Check + if (!PRCDoResistSpell(OBJECT_SELF, oFirstTarget,CasterLvl)) + { + int nDC = PRCGetSaveDC(oTarget,OBJECT_SELF); + //Adjust damage via Reflex Save or Evasion or Improved Evasion + nDamStrike = PRCGetReflexAdjustedDamage(nDamage, oFirstTarget, nDC, SAVING_THROW_TYPE_ELECTRICITY); + //Set the damage effect for the first target + eDamage = PRCEffectDamage(oTarget, nDamStrike, EleDmg); + //Apply damage to the first target and the VFX impact. + if(nDamStrike > 0) + { + SPApplyEffectToObject(DURATION_TYPE_INSTANT,eDamage,oFirstTarget); + PRCBonusDamage(oFirstTarget); + SPApplyEffectToObject(DURATION_TYPE_INSTANT,eVis,oFirstTarget); + } + } + } + //Apply the lightning stream effect to the first target, connecting it with the caster + SPApplyEffectToObject(DURATION_TYPE_TEMPORARY,eLightning,oFirstTarget,0.5,FALSE); + + + //Reinitialize the lightning effect so that it travels from the first target to the next target + eLightning = EffectBeam(VFX_BEAM_LIGHTNING, oFirstTarget, BODY_NODE_CHEST); + + + float fDelay = 0.2; + int nCnt = 0; + + + // * + // * Secondary Targets + // * + + + //Get the first target in the spell shape + oTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(oFirstTarget), TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + while (GetIsObjectValid(oTarget) && nCnt < nCasterLevel) + { + //Make sure the caster's faction is not hit and the first target is not hit + if (oTarget != oFirstTarget && spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, OBJECT_SELF) && oTarget != OBJECT_SELF) + { + //Connect the new lightning stream to the older target and the new target + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY,eLightning,oTarget,0.5,FALSE)); + + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_CHAIN_LIGHTNING)); + //Do an SR check + if (!PRCDoResistSpell(OBJECT_SELF, oTarget,CasterLvl, fDelay)) + { + int nDC = PRCGetSaveDC(oTarget,OBJECT_SELF); + nDamage = d6(nCasterLevel) ; + + if ((nMetaMagic & METAMAGIC_MAXIMIZE)) + { + nDamage = 6 * nCasterLevel;//Damage is at max + } + if ((nMetaMagic & METAMAGIC_EMPOWER)) + { + nDamage = nDamage + (nDamage/2); //Damage/is +50% + } + nDamage += SpellDamagePerDice(OBJECT_SELF, nCasterLevel); + //Adjust damage via Reflex Save or Evasion or Improved Evasion + nDamStrike = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC, SAVING_THROW_TYPE_ELECTRICITY); + //Apply the damage and VFX impact to the current target + eDamage = PRCEffectDamage(oTarget, nDamStrike /2, EleDmg); + if(nDamStrike > 0) //age > 0) + { + //Apply the VFX impact and damage effect (reflected upon PC) + if ((nInt == 1)&&(nDoOnce != 1)) + { + ApplyEffectToObject(DURATION_TYPE_INSTANT,eDamage,oCaster); + ApplyEffectToObject(DURATION_TYPE_INSTANT,eVis,oCaster); + FloatingTextStringOnCreature("The spell 'Chain Lightning' is reflected underwater!", oPC); + nDoOnce = 1; + } + + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT,eDamage,oTarget)); + PRCBonusDamage(oTarget); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT,eVis,oTarget)); + } + } + oHolder = oTarget; + + //change the currect holder of the lightning stream to the current target + if (GetObjectType(oTarget) == OBJECT_TYPE_CREATURE) + { + eLightning = EffectBeam(VFX_BEAM_LIGHTNING, oHolder, BODY_NODE_CHEST); + } + else + { + // * April 2003 trying to make sure beams originate correctly + effect eNewLightning = EffectBeam(VFX_BEAM_LIGHTNING, oHolder, BODY_NODE_CHEST); + if(GetIsEffectValid(eNewLightning)) + { + eLightning = eNewLightning; + } + } + + fDelay = fDelay + 0.1f; + } + //Count the number of targets that have been hit. + if(GetObjectType(oTarget) == OBJECT_TYPE_CREATURE) + { + nCnt++; + } + + // April 2003: Setting the new origin for the beam + // oFirstTarget = oTarget; + + //Get the next target in the shape. + oTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(oFirstTarget), TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } + +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Chain Lightning' has caused a cave-in!", oPC)); + } + + } diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_conecold.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_conecold.nss new file mode 100644 index 0000000..6b3aa3e --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_conecold.nss @@ -0,0 +1,137 @@ +//:://///////////////////////////////////////////// +//:: Cone of Cold +//:: NW_S0_ConeCold +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* +// Cone of cold creates an area of extreme cold, +// originating at your hand and extending outward +// in a cone. It drains heat, causing 1d6 points of +// cold damage per caster level (maximum 15d6). +*/ +//::////////////////////////////////////////////// +//:: Created By: Noel Borstad +//:: Created On: 10/18/02000 +//::////////////////////////////////////////////// +//:: Last Updated By: Aidan Scanlan On: April 11, 2001 +//:: Update Pass By: Preston W, On: July 25, 2001 + + +//:: modified by mr_bumpkin Dec 4, 2003 +#include "prc_inc_spells" +#include "prc_add_spell_dc" + +float SpellDelay (object oTarget, int nShape); + + + + +void main() +{ +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_EVOCATION); + + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + int CasterLvl = PRCGetCasterLevel(OBJECT_SELF); + + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + object oCaster = OBJECT_SELF; + + int nCasterLevel = CasterLvl; + int nMetaMagic = PRCGetMetaMagicFeat(); + int nDamage; + float fDelay; + location lTargetLocation = PRCGetSpellTargetLocation(); + object oTarget; + //Limit Caster level for the purposes of damage. + if (nCasterLevel > 15) + { + nCasterLevel = 15; + } + + CasterLvl +=SPGetPenetr(); + + int EleDmg = ChangedElementalDamage(OBJECT_SELF, DAMAGE_TYPE_COLD); + + //Declare the spell shape, size and the location. Capture the first target object in the shape. + oTarget = MyFirstObjectInShape(SHAPE_SPELLCONE, 11.0, lTargetLocation, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while(GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + // March 2003. Removed this as part of the reputation pass + // if((PRCGetSpellId() == 340 && !GetIsFriend(oTarget)) || PRCGetSpellId() == 25) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_CONE_OF_COLD)); + //Get the distance between the target and caster to delay the application of effects + fDelay = GetDistanceBetween(OBJECT_SELF, oTarget)/20.0; + //Make SR check, and appropriate saving throw(s). + if(!PRCDoResistSpell(OBJECT_SELF, oTarget,CasterLvl, fDelay) && (oTarget != OBJECT_SELF)) + { + int nDC = PRCGetSaveDC(oTarget,OBJECT_SELF); + //Detemine damage + nDamage = d6(nCasterLevel); + //Enter Metamagic conditions + if ((nMetaMagic & METAMAGIC_MAXIMIZE)) + { + nDamage = 6 * nCasterLevel;//Damage is at max + } + if ((nMetaMagic & METAMAGIC_EMPOWER)) + { + nDamage = nDamage + (nDamage/2); //Damage/Healing is +50% + } + nDamage += SpellDamagePerDice(OBJECT_SELF, nCasterLevel); + //Adjust damage according to Reflex Save, Evasion or Improved Evasion + nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC, SAVING_THROW_TYPE_COLD); + + // Apply effects to the currently selected target. + effect eCold = PRCEffectDamage(oTarget, nDamage, EleDmg); + effect eVis = EffectVisualEffect(VFX_IMP_FROST_L); + if(nDamage > 0) + { + //Apply the VFX impact and damage effect (reflected upon PC) + if (nInt == 1) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oCaster)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eCold, oCaster)); + FloatingTextStringOnCreature("The spell 'Cone of Cold' is reflected underwater!", oPC); + } + + //Apply delayed effects + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eCold, oTarget)); + PRCBonusDamage(oTarget); + } + } + } + } + //Select the next target within the spell shape. + oTarget = MyNextObjectInShape(SHAPE_SPELLCONE, 11.0, lTargetLocation, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } + + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Getting rid of the local integer storing the spellschool name +} + diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_delfirebal.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_delfirebal.nss new file mode 100644 index 0000000..2218297 --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_delfirebal.nss @@ -0,0 +1,123 @@ +//:://///////////////////////////////////////////// +//:: Delayed Blast Fireball +//:: NW_S0_DelFirebal.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + The caster creates a trapped area which detects + the entrance of enemy creatures into 3 m area + around the spell location. When tripped it + causes a fiery explosion that does 1d6 per + caster level up to a max of 20d6 damage. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: July 27, 2001 +//::////////////////////////////////////////////// +//:: modified by mr_bumpkin Dec 4, 2003 +#include "prc_inc_spells" +#include "prc_add_spell_dc" + +void main() +{ + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Delayed Blast Fireball' will not work underwater!", oPC); + return; + } + + if(!X2PreSpellCastCode()) return; + + PRCSetSchool(SPELL_SCHOOL_EVOCATION); + + //Declare major variables including Area of Effect Object + effect eAOE = EffectAreaOfEffect(AOE_PER_DELAY_BLAST_FIREBALL); + location lTarget = PRCGetSpellTargetLocation(); + int CasterLvl = PRCGetCasterLevel(); + int nDuration = CasterLvl / 2; + //Make sure the duration is at least one round + if(nDuration == 0) + nDuration = 1; + + int nMetaMagic = PRCGetMetaMagicFeat(); + //Check Extend metamagic feat. + if (nMetaMagic & METAMAGIC_EXTEND) + { + nDuration = nDuration *2;//Duration is +100% + } + //Create an instance of the AOE Object using the Apply Effect function + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eAOE, lTarget, RoundsToSeconds(nDuration)); + //Set up variables for cave-in + object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); + object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); + object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); + object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); + object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); + object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); + object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); + object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); + object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); + object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); + object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); + object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); + object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); + object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); + int nDL=GetLocalInt(oPC, "nDungeonLevel"); + if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Delayed Blast Fireball' has caused a cave-in!", oPC)); + } + object oAoE = GetAreaOfEffectObject(lTarget, "VFX_PER_DELAY_BLAST_FIREBALL"); + SetAllAoEInts(SPELL_DELAYED_BLAST_FIREBALL, oAoE, PRCGetSpellSaveDC(SPELL_DELAYED_BLAST_FIREBALL, SPELL_SCHOOL_EVOCATION), 0, CasterLvl); + SetLocalInt(oAoE, "DelayedBlastFireballDamage", ChangedElementalDamage(OBJECT_SELF, DAMAGE_TYPE_FIRE)); + + PRCSetSchool(); +} + + diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_eleswarm.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_eleswarm.nss new file mode 100644 index 0000000..5519a96 --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_eleswarm.nss @@ -0,0 +1,203 @@ +//:://///////////////////////////////////////////// +//:: Elemental Swarm +//:: NW_S0_EleSwarm.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + This spell creates a conduit from the caster + to the elemental planes. The first elemental + summoned is a 24 HD Air elemental. Whenever an + elemental dies it is replaced by the next + elemental in the chain Air, Earth, Water, Fire +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 12, 2001 +//::////////////////////////////////////////////// +//:: Update Pass By: Preston W, On: July 30, 2001 +//:: modified by mr_bumpkin Dec 4, 2003 + +#include "prc_inc_spells" + +void main() +{ + if(!X2PreSpellCastCode()) return; + + PRCSetSchool(SPELL_SCHOOL_CONJURATION); + + //Declare major variables + object oCaster = OBJECT_SELF; + int CasterLvl = PRCGetCasterLevel(oCaster); + int nMetaMagic = PRCGetMetaMagicFeat(); + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + + if(GetPRCSwitch(PRC_PNP_ELEMENTAL_SWARM) + && GetPRCSwitch(PRC_MULTISUMMON)) + { + float fDuration = IntToFloat(60*10*CasterLvl); + float fDelay = 600.0; + if(GetPRCSwitch(PRC_SUMMON_ROUND_PER_LEVEL)) + { + fDuration = RoundsToSeconds(CasterLvl); + fDelay = RoundsToSeconds(1); + } + //Check for metamagic duration + if ((nMetaMagic & METAMAGIC_EXTEND)) + fDuration = fDuration * 2.0; //Duration is +100% + MultisummonPreSummon(); + int i; + int nVFX = VFX_FNF_SUMMON_MONSTER_3; + string sResRef; + int nElement = Random(4); + + //Spell changes if caster is underwater. + if (nInt == 1) + { + switch(nElement) + { + case 0: + sResRef = "NW_S_AIRHUGE"; + break; + case 1: + sResRef = "NW_S_WATERHUGE"; + break; + case 2: + sResRef = "NW_S_FIREHUGE"; + break; + case 3: + sResRef = "NW_S_EARTHHUGE"; + break; + } + } + else + { + switch(nElement) + { + case 0: + sResRef = "NW_S_WATERHUGE"; + break; + case 1: + sResRef = "NW_S_WATERHUGE"; + break; + case 2: + sResRef = "NW_S_WATERHUGE"; + break; + case 3: + sResRef = "NW_S_WATERHUGE"; + break; + } + } + effect eSummon = EffectSummonCreature(sResRef, nVFX); + int nHugeElementals = d4(2); + for(i=0; i 0) + { + //Set the damage effect + eDam = PRCEffectDamage(oTarget, nDamage, EleDmg); + // Apply effects to the currently selected target. + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + PRCBonusDamage(oTarget); + //This visual effect is applied to the target object not the location as above. This visual effect + //represents the flame that erupts on the target not on the ground. + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + } + //Select the next target within the spell shape. + oTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } + + PRCSetSchool(); + +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Fireball' has caused a cave-in!", oPC)); + } + +} + diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_firestrm.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_firestrm.nss new file mode 100644 index 0000000..409a193 --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_firestrm.nss @@ -0,0 +1,170 @@ +//:://///////////////////////////////////////////// +//:: Fire Storm +//:: NW_S0_FireStm +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Creates a zone of destruction around the caster + within which all living creatures are pummeled + with fire. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 11, 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 21, 2001 + +//:: modified by mr_bumpkin Dec 4, 2003 for PRC stuff +#include "prc_inc_spells" +#include "prc_add_spell_dc" + +void main() +{ + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Fire Storm' will not work underwater!", oPC); + return; + } + + if(!X2PreSpellCastCode()) return; + + PRCSetSchool(SPELL_SCHOOL_EVOCATION); + + //Declare major variables + location lTarget = GetLocation(oCaster); + int nMetaMagic = PRCGetMetaMagicFeat(); + int nDamage; + int nDamage2; + + int CasterLvl = PRCGetCasterLevel(OBJECT_SELF); + + + int EleDmg = ChangedElementalDamage(OBJECT_SELF, DAMAGE_TYPE_FIRE); + + + int nCasterLevel = CasterLvl; + if(nCasterLevel > 20) + { + nCasterLevel = 20; //bugfix, was == 20 + } + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_M); + effect eFireStorm = EffectVisualEffect(VFX_FNF_FIRESTORM); + float fDelay; + CasterLvl +=SPGetPenetr(); + + //Apply Fire and Forget Visual in the area; + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eFireStorm, lTarget); + //Declare the spell shape, size and the location. Capture the first target object in the shape. + object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lTarget, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while(GetIsObjectValid(oTarget)) + { + //This spell smites everyone who is more than 2 meters away from the caster. + //if (GetDistanceBetween(oTarget, OBJECT_SELF) > 2.0) + //{ + if (spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, OBJECT_SELF) && oTarget != OBJECT_SELF) + { + fDelay = PRCGetRandomDelay(1.5, 2.5); + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_FIRE_STORM)); + //Make SR check, and appropriate saving throw(s). + if (!PRCDoResistSpell(OBJECT_SELF, oTarget,CasterLvl, fDelay)) + { + //Roll Damage + nDamage = d6(nCasterLevel); + //Enter Metamagic conditions + if(nMetaMagic & METAMAGIC_MAXIMIZE) + nDamage = 6 * nCasterLevel;//Damage is at max + if(nMetaMagic & METAMAGIC_EMPOWER) + nDamage = nDamage + (nDamage/2);//Damage/Healing is +50% + int nDC = PRCGetSaveDC(oTarget,OBJECT_SELF); + //Save versus both holy and fire damage + nDamage += SpellDamagePerDice(OBJECT_SELF, nCasterLevel); + nDamage2 = PRCGetReflexAdjustedDamage(nDamage/2, oTarget, (nDC), SAVING_THROW_TYPE_DIVINE); + nDamage = PRCGetReflexAdjustedDamage(nDamage/2, oTarget, (nDC), SAVING_THROW_TYPE_FIRE); + if(nDamage) + { + // Apply effects to the currently selected target. For this spell we have used + //both Divine and Fire damage. + effect eDivine = PRCEffectDamage(oTarget, nDamage2, DAMAGE_TYPE_DIVINE); + effect eFire = PRCEffectDamage(oTarget, nDamage, EleDmg); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eFire, oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDivine, oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + //} + } + //Select the next target within the spell shape. + oTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lTarget, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } + + PRCSetSchool(); + +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Fire Storm' has caused a cave-in!", oPC)); + } +} \ No newline at end of file diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_flmarrow.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_flmarrow.nss new file mode 100644 index 0000000..63fa7cc --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_flmarrow.nss @@ -0,0 +1,110 @@ +//:://///////////////////////////////////////////// +//:: Flame Arrow +//:: NW_S0_FlmArrow +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Fires a stream of fiery arrows at the selected + target that do 4d6 damage per arrow. 1 Arrow + per 4 levels is created. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Sept 20, 2001 +//:: Updated By: Georg Zoeller, Aug 18 2003: Uncapped +//::////////////////////////////////////////////// +//:: modified by mr_bumpkin Dec 4, 2003 for PRC stuff + +#include "prc_inc_sp_tch" +#include "prc_inc_spells" +#include "prc_add_spell_dc" + +void main() +{ + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Flame Arrow' will not work underwater!", oPC); + return; + } + + if (!X2PreSpellCastCode()) return; + + PRCSetSchool(SPELL_SCHOOL_CONJURATION); + + //Declare major variables + object oTarget = PRCGetSpellTargetObject(); + int nCasterLvl = PRCGetCasterLevel(oCaster); + int nDC = PRCGetSaveDC(oTarget, oCaster); + int nPenetr = nCasterLvl + SPGetPenetr(); + int EleDmg = ChangedElementalDamage(oCaster, DAMAGE_TYPE_FIRE); + int nSaveType = ChangedSaveType(EleDmg); + int nMetaMagic = PRCGetMetaMagicFeat(); + float fDist = GetDistanceBetween(oCaster, oTarget); + float fDelay = fDist/(3.0 * log(fDist) + 2.0); + + int nDamage; + int nCnt; + effect eMissile = EffectVisualEffect(VFX_IMP_MIRV_FLAME); + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_S); + + //Limit missiles to five + int nMissiles = nCasterLvl / 4; + if(nMissiles == 0) + nMissiles = 1; + /* Uncapped because PHB doesn't list any cap and we now got epic levels + else if (nMissiles > 5) + nMissiles = 5;*/ + + if(!GetIsReactionTypeFriendly(oTarget)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(oCaster, SPELL_FLAME_ARROW)); + //Apply a single damage hit for each missile instead of as a single mass + //Make SR Check + if(!PRCDoResistSpell(oCaster, oTarget, nPenetr, fDelay)) + { + int iAttackRoll = 0; + for(nCnt = 1; nCnt <= nMissiles; nCnt++) + { + // causes them each to make a ranged touch attack + iAttackRoll = PRCDoRangedTouchAttack(oTarget); + if(iAttackRoll > 0) + { + //Roll damage + nDamage = d6(4); + //Enter Metamagic conditions + if(nMetaMagic & METAMAGIC_MAXIMIZE) + nDamage = 24;//Damage is at max + if(nMetaMagic & METAMAGIC_EMPOWER) + nDamage = nDamage + (nDamage/2); //Damage/Healing is +50% + nDamage += SpellDamagePerDice(oCaster, 4); + nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC, nSaveType); + + // only add sneak attack damage and bonus damage to first projectile + if(nCnt == 1) + { + nDamage += SpellSneakAttackDamage(oCaster, oTarget); + PRCBonusDamage(oTarget); + } + + //Set damage effect + effect eDam = PRCEffectDamage(oTarget, nDamage, EleDmg); + //Apply the MIRV and damage effect + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eMissile, oTarget); + } + } + } + else + // * May 2003: Make it so the arrow always appears, even if resisted + ApplyEffectToObject(DURATION_TYPE_INSTANT, eMissile, oTarget); + } + PRCSetSchool(); +} \ No newline at end of file diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_flmlash.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_flmlash.nss new file mode 100644 index 0000000..71c4292 --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_flmlash.nss @@ -0,0 +1,114 @@ +//:://///////////////////////////////////////////// +//:: Flame Lash +//:: NW_S0_FlmLash.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Creates a whip of fire that targets a single + individual +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Nov 21, 2001 +//::////////////////////////////////////////////// + +//:: modified by mr_bumpkin Dec 4, 2003 for PRC stuff +#include "prc_inc_spells" +#include "prc_add_spell_dc" + + + + +void main() +{ + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Flame Lash' will not work underwater!", oPC); + return; + } + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_EVOCATION); +/* + Spellcast Hook Code + Added 2003-06-23 by GeorgZ + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oTarget = PRCGetSpellTargetObject(); + + int CasterLvl = PRCGetCasterLevel(OBJECT_SELF); + + + int nDC = PRCGetSaveDC(oTarget,OBJECT_SELF); + int EleDmg = ChangedElementalDamage(OBJECT_SELF, DAMAGE_TYPE_FIRE); + + int nCasterLevel = CasterLvl; + int nMetaMagic = PRCGetMetaMagicFeat(); + if(nCasterLevel > 3) + { + nCasterLevel = (nCasterLevel-3)/3; + } + else + { + nCasterLevel = 0; + } + int nDamage = d6(2 + nCasterLevel); + + //Enter Metamagic conditions + if ((nMetaMagic & METAMAGIC_MAXIMIZE)) + { + nDamage = 6 * (2 + nCasterLevel);//Damage is at max + } + if ((nMetaMagic & METAMAGIC_EMPOWER)) + { + nDamage = nDamage + (nDamage/2); //Damage/Healing is +50% + } + nDamage += SpellDamagePerDice(OBJECT_SELF, 2 + nCasterLevel); + CasterLvl +=SPGetPenetr(); + + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_S); + effect eRay = EffectBeam(VFX_BEAM_FIRE_LASH, OBJECT_SELF, BODY_NODE_HAND); + SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eRay, oTarget, 1.7,FALSE); + + if(!GetIsReactionTypeFriendly(oTarget)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_FLAME_LASH)); + if (!PRCDoResistSpell(OBJECT_SELF, oTarget,CasterLvl, 1.0)) + { + //nDamage += ApplySpellBetrayalStrikeDamage(oTarget, OBJECT_SELF); + nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, (nDC), SAVING_THROW_TYPE_FIRE); + effect eDam = PRCEffectDamage(oTarget, nDamage, EleDmg); + if(nDamage > 0) + { + //Apply the VFX impact and effects + DelayCommand(1.0, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + DelayCommand(1.0, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + } + } + } + + + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Getting rid of the local integer storing the spellschool name +} diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_flmstrike.ncs b/src/hakpak/ghost_prc8_top/nss/nw_s0_flmstrike.ncs new file mode 100644 index 0000000000000000000000000000000000000000..c741aa419ac6d9d166f4cb2f686306078e000149 GIT binary patch literal 229572 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�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≀mbfA%q5Y#WI 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 literal 0 HcmV?d00001 diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_flmstrike.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_flmstrike.nss new file mode 100644 index 0000000..2daf428 --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_flmstrike.nss @@ -0,0 +1,108 @@ +//:://///////////////////////////////////////////// +//:: Flame Strike +//:: NW_S0_FlmStrike +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* +// A flame strike is a vertical column of divine fire +// roaring downward. The spell deals 1d6 points of +// damage per level, to a maximum of 15d6. Half the +// damage is fire damage, but the rest of the damage +// results directly from divine power and is therefore +// not subject to protection from elements (fire), +// fire shield (chill shield), etc. +*/ +//::////////////////////////////////////////////// +//:: Created By: Noel Borstad +//:: Created On: Oct 19, 2000 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 20, 2001 +//:: Update Pass By: Preston W, On: Aug 1, 2001 +//:: modified by mr_bumpkin Dec 4, 2003 for PRC stuff +#include "prc_inc_spells" +#include "prc_add_spell_dc" + +void main() +{ + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Flame Strike' will not work underwater!", oPC); + return; + } + + if(!X2PreSpellCastCode()) return; + + PRCSetSchool(SPELL_SCHOOL_EVOCATION); + + //Declare major variables + + location lTarget = PRCGetSpellTargetLocation(); + int nCasterLvl = PRCGetCasterLevel(oCaster); + int nPenetr = nCasterLvl + SPGetPenetr(); + int nMetaMagic = PRCGetMetaMagicFeat(); + int EleDmg = ChangedElementalDamage(oCaster, DAMAGE_TYPE_FIRE); + int nSaveType = ChangedSaveType(EleDmg); + int nDice = PRCMin(15, nCasterLvl); + + int nDamage, nDamage2; + effect eStrike = EffectVisualEffect(VFX_IMP_DIVINE_STRIKE_FIRE); + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_S); + effect eHoly, eFire; + + //Apply the location impact visual to the caster location instead of caster target creature. + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eStrike, lTarget); + + //Declare the spell shape, size and the location. Capture the first target object in the shape. + object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, lTarget, FALSE, OBJECT_TYPE_CREATURE|OBJECT_TYPE_PLACEABLE|OBJECT_TYPE_DOOR); + //Cycle through the targets within the spell shape until an invalid object is captured. + while(GetIsObjectValid(oTarget)) + { + if(spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, oCaster)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(oCaster, SPELL_FLAME_STRIKE)); + + //Make SR check, and appropriate saving throw(s). + if(!PRCDoResistSpell(oCaster, oTarget, nPenetr, 0.6)) + { + nDamage = d6(nDice); + if(nMetaMagic & METAMAGIC_MAXIMIZE) + nDamage = 6 * nDice; + if(nMetaMagic & METAMAGIC_EMPOWER) + nDamage = nDamage + (nDamage/2); + nDamage += SpellDamagePerDice(oCaster, nDice); + //Adjust the damage based on Reflex Save, Evasion and Improved Evasion + int nDC = PRCGetSaveDC(oTarget, oCaster); + nDamage2 = PRCGetReflexAdjustedDamage(nDamage/2, oTarget, nDC, nSaveType); + + //Make a faction check so that only enemies receieve the full brunt of the damage. + if(!GetIsFriend(oTarget)) + { + nDamage = PRCGetReflexAdjustedDamage(nDamage/2, oTarget, nDC, SAVING_THROW_TYPE_DIVINE); + if(nDamage) + { + eHoly = PRCEffectDamage(oTarget, nDamage, DAMAGE_TYPE_DIVINE); + DelayCommand(0.6, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eHoly, oTarget)); + } + } + // Apply effects to the currently selected target. + if(nDamage2) + { + eFire = PRCEffectDamage(oTarget, nDamage2, EleDmg); + DelayCommand(0.6, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eFire, oTarget)); + DelayCommand(0.6, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + } + //Select the next target within the spell shape. + oTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, lTarget, FALSE, OBJECT_TYPE_CREATURE|OBJECT_TYPE_PLACEABLE|OBJECT_TYPE_DOOR); + } + + PRCSetSchool(); +} \ No newline at end of file diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_icestorm.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_icestorm.nss new file mode 100644 index 0000000..756a41f --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_icestorm.nss @@ -0,0 +1,198 @@ +//:://///////////////////////////////////////////// +//:: Ice Storm +//:: NW_S0_IceStorm +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Everyone in the area takes 3d6 Bludgeoning + and 2d6 Cold damage. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Sept 12, 2001 +//::////////////////////////////////////////////// + +//:: modified by mr_bumpkin Dec 4, 2003 for PRC stuff +#include "prc_inc_spells" +#include "prc_add_spell_dc" + + + + +void main() +{ + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_EVOCATION); +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oCaster = OBJECT_SELF; + int CasterLvl = PRCGetCasterLevel(OBJECT_SELF); + + + int EleDmg = ChangedElementalDamage(OBJECT_SELF, DAMAGE_TYPE_COLD); + + int nCasterLvl = CasterLvl; + int nMetaMagic = PRCGetMetaMagicFeat(); + int nDamage, nDamage2, nDamage3; + int nVariable = nCasterLvl/3; + float fDelay; + effect eExplode = EffectVisualEffect(VFX_FNF_ICESTORM); //USE THE ICESTORM FNF + effect eVis = EffectVisualEffect(VFX_IMP_FROST_S); + effect eDam,eDam2, eDam3; + // These last for one round. Added as they are in the 3.5 PHB + effect eLink = EffectLinkEffects(EffectSkillDecrease(SKILL_LISTEN, 4), EffectMovementSpeedDecrease(50)); + //Get the spell target location as opposed to the spell target. + location lTarget = PRCGetSpellTargetLocation(); + CasterLvl +=SPGetPenetr(); + + //Apply the ice storm VFX at the location captured above. + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, lTarget); + //Declare the spell shape, size and the location. Capture the first target object in the shape. + object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + fDelay = PRCGetRandomDelay(0.75, 2.25); + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_ICE_STORM)); + if (!PRCDoResistSpell(OBJECT_SELF, oTarget,CasterLvl, fDelay)) + { + //Roll damage for each target + nDamage = d6(3); + nDamage2 = d6(2); + nDamage3 = d6(nVariable); + //Resolve metamagic + if ((nMetaMagic & METAMAGIC_MAXIMIZE)) + { + nDamage = 18; + nDamage2 = 12; + nDamage3 = 6 * nVariable; + } + if ((nMetaMagic & METAMAGIC_EMPOWER)) + { + nDamage = nDamage + (nDamage / 2); + nDamage2 = nDamage2 + (nDamage2 / 2); + nDamage3 = nDamage3 + (nDamage3 / 2); + } + nDamage2 = nDamage2 + nDamage3; + nDamage += SpellDamagePerDice(oCaster, 3); + nDamage2 += SpellDamagePerDice(oCaster, 2+nVariable); + //Set the damage effect + eDam = PRCEffectDamage(oTarget, nDamage, DAMAGE_TYPE_BLUDGEONING); + eDam2 = PRCEffectDamage(oTarget, nDamage2, EleDmg); + + //Apply the VFX impact and damage effect (reflected upon PC) + if (nInt == 1) + { + //Apply the ice storm VFX at the location captured above. + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, GetLocation(oCaster)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oCaster)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam2, oCaster)); + //This visual effect is applied to the target object not the location as above. This visual effect + //represents the impact that erupts on the target not on the ground. + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oCaster)); + FloatingTextStringOnCreature("The spell 'Ice Storm' is reflected underwater!", oPC); + } + + // Apply effects to the currently selected target. + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + PRCBonusDamage(oTarget); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam2, oTarget)); + //This visual effect is applied to the target object not the location as above. This visual effect + //represents the impact that erupts on the target not on the ground. + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, 6.0,TRUE,-1,CasterLvl); + } + } + //Select the next target within the spell shape. + oTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } + + + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Getting rid of the local integer storing the spellschool name + +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Ice Storm' has caused a cave-in!", oPC)); + } +} + diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_implosion.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_implosion.nss new file mode 100644 index 0000000..3503ef6 --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_implosion.nss @@ -0,0 +1,152 @@ +//:://///////////////////////////////////////////// +//:: Implosion +//:: NW_S0_Implosion.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + All persons within a 5ft radius of the spell must + save at +3 DC or die. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 13, 2001 +//::////////////////////////////////////////////// + +//:: modified by mr_bumpkin Dec 4, 2003 for PRC stuff +#include "prc_inc_spells" +#include "prc_add_spell_dc" + + + + +void main() +{ +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_EVOCATION); + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oPC = GetFirstPC(); + object oTarget; + effect eDeath = EffectDeath(TRUE); + if(!GetPRCSwitch(PRC_165_DEATH_IMMUNITY)) + eDeath = SupernaturalEffect(eDeath); + effect eImplode= EffectVisualEffect(VFX_FNF_IMPLOSION); + float fDelay; + + int CasterLvl = PRCGetCasterLevel(OBJECT_SELF); + + CasterLvl +=SPGetPenetr(); + + //Apply the implose effect + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImplode, PRCGetSpellTargetLocation()); + //Get the first target in the shape + oTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, PRCGetSpellTargetLocation()); + while (GetIsObjectValid(oTarget)) + { + if (oTarget != OBJECT_SELF + && spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_IMPLOSION)); + fDelay = PRCGetRandomDelay(0.4, 1.2); + //Make SR check + if (!PRCDoResistSpell(OBJECT_SELF, oTarget,CasterLvl, fDelay) && !GetIsIncorporeal(oTarget)) + { + int nDC = PRCGetSaveDC(oTarget,OBJECT_SELF); + //Make Reflex save + if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_SPELL, OBJECT_SELF, fDelay)) + { + DeathlessFrenzyCheck(oTarget); + + //Apply death effect and the VFX impact + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDeath, oTarget)); + } + } + } + //Get next target in the shape + oTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, PRCGetSpellTargetLocation()); + } + + + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Getting rid of the local integer storing the spellschool name +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Implosion' has caused a cave-in!", oPC)); + } +} + diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_inccloud.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_inccloud.nss new file mode 100644 index 0000000..340edab --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_inccloud.nss @@ -0,0 +1,65 @@ +//:://///////////////////////////////////////////// +//:: Incendiary Cloud +//:: NW_S0_IncCloud.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Person within the AoE take 4d6 fire damage + per round. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: May 17, 2001 +//::////////////////////////////////////////////// + +//:: modified by mr_bumpkin Dec 4, 2003 for PRC stuff +#include "prc_inc_spells" +#include "prc_add_spell_dc" + +void main() +{ + if(!X2PreSpellCastCode()) return; + + PRCSetSchool(SPELL_SCHOOL_EVOCATION); + + //Declare major variables, including the Area of Effect object. + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Capture the spell target location so that the AoE object can be created. + + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Incendiary Cloud' will not work underwater!", oPC); + return; + } + + effect eAOE = EffectAreaOfEffect(AOE_PER_FOGFIRE); + //Capture the spell target location so that the AoE object can be created. + location lTarget = PRCGetSpellTargetLocation(); + int CasterLvl = PRCGetCasterLevel(); + int nDuration = CasterLvl; + effect eImpact = EffectVisualEffect(260); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpact, lTarget); + if(nDuration < 1) + { + nDuration = 1; + } + int nMetaMagic = PRCGetMetaMagicFeat(); + //Check for metamagic extend + if (CheckMetaMagic(nMetaMagic, METAMAGIC_EXTEND)) + { + nDuration = nDuration *2; //Duration is +100% + } + //Create the object at the location so that the objects scripts will start working. + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eAOE, lTarget, RoundsToSeconds(nDuration)); + + object oAoE = GetAreaOfEffectObject(lTarget, "VFX_PER_FOGFIRE"); + SetAllAoEInts(SPELL_INCENDIARY_CLOUD, oAoE, PRCGetSpellSaveDC(SPELL_INCENDIARY_CLOUD, SPELL_SCHOOL_EVOCATION), 0, CasterLvl); + SetLocalInt(oAoE, "IC_Damage", ChangedElementalDamage(OBJECT_SELF, DAMAGE_TYPE_FIRE)); + + PRCSetSchool(); +} \ No newline at end of file diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_incclouda.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_incclouda.nss new file mode 100644 index 0000000..b622fca --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_incclouda.nss @@ -0,0 +1,85 @@ +//:://///////////////////////////////////////////// +//:: Incendiary Cloud +//:: NW_S0_IncCloud.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Person within the AoE take 4d6 fire damage + per round. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: May 17, 2001 +//::////////////////////////////////////////////// +//:: March 2003: Removed movement speed penalty + +//:: modified by mr_bumpkin Dec 4, 2003 for PRC stuff +#include "prc_inc_spells" +#include "prc_add_spell_dc" + + + +void main() +{ +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_EVOCATION); + + //Declare major variables + int nMetaMagic = PRCGetMetaMagicFeat(); + int nDamage; + effect eDam; + object oTarget; + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Declare and assign personal impact visual effect. + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_S); + // effect eSpeed = EffectMovementSpeedDecrease(50); + effect eVis2 = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); + effect eLink = eVis2; //EffectLinkEffects(eSpeed, eVis2); + float fDelay; + //Capture the first target object in the shape. + oTarget = GetEnteringObject(); + + int nPenetr = SPGetPenetrAOE(GetAreaOfEffectCreator()); + + + //Declare the spell shape, size and the location. + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, GetAreaOfEffectCreator())) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_INCENDIARY_CLOUD)); + //Make SR check, and appropriate saving throw(s). + if(!PRCDoResistSpell(GetAreaOfEffectCreator(), oTarget,nPenetr, fDelay)) + { + fDelay = PRCGetRandomDelay(0.5, 2.0); + //Roll damage. + nDamage = d6(4); + //Enter Metamagic conditions + if ((nMetaMagic & METAMAGIC_MAXIMIZE)) + { + nDamage = 24;//Damage is at max + } + if ((nMetaMagic & METAMAGIC_EMPOWER)) + { + nDamage = nDamage + (nDamage/2); //Damage/Healing is +50% + } + nDamage += SpellDamagePerDice(GetAreaOfEffectCreator(), 4); + //Adjust damage for Reflex Save, Evasion and Improved Evasion + nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, PRCGetSaveDC(oTarget, GetAreaOfEffectCreator(), SPELL_INCENDIARY_CLOUD), SAVING_THROW_TYPE_FIRE, GetAreaOfEffectCreator()); + // Apply effects to the currently selected target. + eDam = PRCEffectDamage(oTarget, nDamage, GetLocalInt(OBJECT_SELF, "IC_Damage")); + if(nDamage > 0) + { + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + PRCBonusDamage(oTarget); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + // SPApplyEffectToObject(DURATION_TYPE_PERMANENT, eSpeed, oTarget); + } + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Getting rid of the local integer storing the spellschool name +} diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_inccloudb.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_inccloudb.nss new file mode 100644 index 0000000..cbd670d --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_inccloudb.nss @@ -0,0 +1,71 @@ +//:://///////////////////////////////////////////// +//:: Incendiary Cloud: On Exit +//:: NW_S0_IncCloudB.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + All creatures within the AoE take 2d6 acid damage + per round and upon entering if they fail a Fort Save + their movement is halved. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: May 17, 2001 +//::////////////////////////////////////////////// +//:: Update Pass By: Preston W, On: July 20, 2001 + +//:: modified by mr_bumpkin Dec 4, 2003 for PRC stuff +#include "prc_inc_spells" + + + +void main() +{ +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_EVOCATION); + + //Declare major variables + //Get the object that is exiting the AOE + object oTarget = GetExitingObject(); + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + int bValid = FALSE; + effect eAOE; + + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Incendiary Cloud' will not work underwater!", oPC); + return; + } + + if(GetHasSpellEffect(SPELL_INCENDIARY_CLOUD, oTarget)) + { + //Search through the valid effects on the target. + eAOE = GetFirstEffect(oTarget); + while (GetIsEffectValid(eAOE) && bValid == FALSE) + { + if (GetEffectCreator(eAOE) == GetAreaOfEffectCreator()) + { + if(GetEffectType(eAOE) == EFFECT_TYPE_MOVEMENT_SPEED_DECREASE) + { + //If the effect was created by the Acid_Fog then remove it + if(GetEffectSpellId(eAOE) == SPELL_INCENDIARY_CLOUD) + { + RemoveEffect(oTarget, eAOE); + bValid = TRUE; + } + } + } + //Get next effect on the target + eAOE = GetNextEffect(oTarget); + } + } + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Getting rid of the local integer storing the spellschool name +} + diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_inccloudc.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_inccloudc.nss new file mode 100644 index 0000000..61d89ea --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_inccloudc.nss @@ -0,0 +1,111 @@ +//:://///////////////////////////////////////////// +//:: Incendiary Cloud +//:: NW_S0_IncCloudC.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Objects within the AoE take 4d6 fire damage + per round. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: May 17, 2001 +//::////////////////////////////////////////////// +//:: Updated By: GeorgZ 2003-08-21: Now affects doors and placeables as well + + +//:: modified by mr_bumpkin Dec 4, 2003 for PRC stuff +#include "prc_inc_spells" +#include "prc_add_spell_dc" + + + +void main() +{ +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_EVOCATION); + + //Declare major variables + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + int nMetaMagic = PRCGetMetaMagicFeat(); + int nDamage; + effect eDam; + object oTarget; + //Declare and assign personal impact visual effect. + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_S); + float fDelay; + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Incendiary Cloud' will not work underwater!", oPC); + return; + } + //Capture the first target object in the shape. + + //-------------------------------------------------------------------------- + // GZ 2003-Oct-15 + // When the caster is no longer there, all functions calling + // GetAreaOfEffectCreator will fail. Its better to remove the barrier then + //-------------------------------------------------------------------------- + object aoeCreator = GetAreaOfEffectCreator(); + if (!GetIsObjectValid(aoeCreator)) + { + DestroyObject(OBJECT_SELF); + return; + } + + int CasterLvl = PRCGetCasterLevel(aoeCreator); + + int nPenetr = SPGetPenetrAOE(aoeCreator,CasterLvl); + + int EleDmg = GetLocalInt(OBJECT_SELF, "IC_Damage"); + + + oTarget = GetFirstInPersistentObject(OBJECT_SELF,OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + //Declare the spell shape, size and the location. + while(GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, aoeCreator)) + { + fDelay = PRCGetRandomDelay(0.5, 2.0); + //Make SR check, and appropriate saving throw(s). + if(!PRCDoResistSpell(aoeCreator, oTarget,nPenetr, fDelay)) + { + SignalEvent(oTarget, EventSpellCastAt(aoeCreator, SPELL_INCENDIARY_CLOUD)); + //Roll damage. + nDamage = d6(4); + //Enter Metamagic conditions + if ((nMetaMagic & METAMAGIC_MAXIMIZE)) + { + nDamage = 24;//Damage is at max + } + if ((nMetaMagic & METAMAGIC_EMPOWER)) + { + nDamage = nDamage + (nDamage/2); //Damage/Healing is +50% + } + nDamage += SpellDamagePerDice(aoeCreator, 4); + int nDC = PRCGetSaveDC(oTarget,aoeCreator); + //Adjust damage for Reflex Save, Evasion and Improved Evasion + nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC,SAVING_THROW_TYPE_FIRE, aoeCreator); + // Apply effects to the currently selected target. + eDam = PRCEffectDamage(oTarget, nDamage, EleDmg); + if(nDamage > 0) + { + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + PRCBonusDamage(oTarget); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + } + //Select the next target within the spell shape. + oTarget = GetNextInPersistentObject(OBJECT_SELF,OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } + + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Getting rid of the local integer storing the spellschool name +} diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_lghtnbolt.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_lghtnbolt.nss new file mode 100644 index 0000000..8ae9123 --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_lghtnbolt.nss @@ -0,0 +1,142 @@ +//:://///////////////////////////////////////////// +//:: Lightning Bolt +//:: NW_S0_LightnBolt +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Does 1d6 per level in a 5ft tube for 30m +*/ +//::////////////////////////////////////////////// +//:: Created By: Noel Borstad +//:: Created On: March 8, 2001 +//::////////////////////////////////////////////// +//:: Last Updated By: Preston Watamaniuk, On: May 2, 2001 + +//:: modified by mr_bumpkin Dec 4, 2003 for PRC stuff +#include "prc_inc_spells" +#include "prc_add_spell_dc" + + + + +void main() +{ +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_EVOCATION); + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oPC = GetFirstPC(); + object oCaster = OBJECT_SELF; + int nDoOnce = 0; + int nInt=GetLocalInt(oPC, "Underwater"); + int CasterLvl = PRCGetCasterLevel(OBJECT_SELF); + + int EleDmg = ChangedElementalDamage(OBJECT_SELF, DAMAGE_TYPE_ELECTRICAL); + + int nCasterLevel = CasterLvl; + //Limit caster level + if (nCasterLevel > 10) + { + nCasterLevel = 10; + } + int nDamage; + int nMetaMagic = PRCGetMetaMagicFeat(); + //Set the lightning stream to start at the caster's hands + effect eLightning = EffectBeam(VFX_BEAM_LIGHTNING, OBJECT_SELF, BODY_NODE_HAND); + effect eVis = EffectVisualEffect(VFX_IMP_LIGHTNING_S); + effect eDamage; + object oTarget = PRCGetSpellTargetObject(); + location lTarget = GetLocation(oTarget); + object oNextTarget, oTarget2; + float fDelay; + int nCnt = 1; + + CasterLvl +=SPGetPenetr(); + + oTarget2 = GetNearestObject(OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, OBJECT_SELF, nCnt); + while(GetIsObjectValid(oTarget2) && GetDistanceToObject(oTarget2) <= 30.0) + { + //Get first target in the lightning area by passing in the location of first target and the casters vector (position) + oTarget = MyFirstObjectInShape(SHAPE_SPELLCYLINDER, 30.0, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, GetPosition(OBJECT_SELF)); + while (GetIsObjectValid(oTarget)) + { + //Exclude the caster from the damage effects + if (oTarget != OBJECT_SELF && oTarget2 == oTarget) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_LIGHTNING_BOLT)); + //Make an SR check + if (!PRCDoResistSpell(OBJECT_SELF, oTarget,CasterLvl)) + { + int nDC = PRCGetSaveDC(oTarget,OBJECT_SELF); + //Roll damage + nDamage = d6(nCasterLevel); + //Enter Metamagic conditions + if ((nMetaMagic & METAMAGIC_MAXIMIZE)) + { + nDamage = 6 * nCasterLevel;//Damage is at max + } + if ((nMetaMagic & METAMAGIC_EMPOWER)) + { + nDamage = nDamage + (nDamage/2); //Damage/Healing is +50% + } + nDamage += SpellDamagePerDice(OBJECT_SELF, nCasterLevel); + //Adjust damage based on Reflex Save, Evasion and Improved Evasion + nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC,SAVING_THROW_TYPE_ELECTRICITY); + //Set damage effect + eDamage = PRCEffectDamage(oTarget, nDamage, EleDmg); + if(nDamage > 0) + { + fDelay = PRCGetSpellEffectDelay(GetLocation(oTarget), oTarget); + //Apply the VFX impact and damage effect (reflected upon PC) + if ((nInt == 1)&&(nDoOnce != 1)) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT,eDamage,oCaster)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT,eVis,oCaster)); + FloatingTextStringOnCreature("The spell 'Lightning Bolt' is reflected underwater!", oPC); + nDoOnce = 1; + } + //Apply VFX impcat, damage effect and lightning effect + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT,eDamage,oTarget)); + PRCBonusDamage(oTarget); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT,eVis,oTarget)); + } + } + SPApplyEffectToObject(DURATION_TYPE_TEMPORARY,eLightning,oTarget,1.0,FALSE); + //Set the currect target as the holder of the lightning effect + oNextTarget = oTarget; + eLightning = EffectBeam(VFX_BEAM_LIGHTNING, oNextTarget, BODY_NODE_CHEST); + } + } + //Get the next object in the lightning cylinder + oTarget = MyNextObjectInShape(SHAPE_SPELLCYLINDER, 30.0, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, GetPosition(OBJECT_SELF)); + } + nCnt++; + oTarget2 = GetNearestObject(OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, OBJECT_SELF, nCnt); + } + + + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Getting rid of the local integer storing the spellschool name +} + diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_metswarm.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_metswarm.nss new file mode 100644 index 0000000..e34f2e5 --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_metswarm.nss @@ -0,0 +1,123 @@ +//:://///////////////////////////////////////////// +//:: Meteor Swarm +//:: NW_S0_MetSwarm +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Everyone in a 50ft radius around the caster + takes 20d6 fire damage. Those within 6ft of the + caster will take no damage. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: May 24 , 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 22, 2001 + +//:: modified by mr_bumpkin Dec 4, 2003 for PRC stuff +#include "prc_inc_spells" +#include "prc_add_spell_dc" + + + + +void main() +{ +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_EVOCATION); +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + int CasterLvl = PRCGetCasterLevel(OBJECT_SELF); + + CasterLvl +=SPGetPenetr(); + + int EleDmg = ChangedElementalDamage(OBJECT_SELF, DAMAGE_TYPE_FIRE); + + + //Declare major variables + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + int nMetaMagic; + int nDamage; + effect eFire; + effect eMeteor = EffectVisualEffect(VFX_FNF_METEOR_SWARM); + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_M); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Meteor Swarm' will not work underwater!", oPC); + return; + } + //Apply the meteor swarm VFX area impact + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eMeteor, GetLocation(OBJECT_SELF)); + //Get first object in the spell area + float fDelay; + object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(OBJECT_SELF)); + while(GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF) && oTarget != OBJECT_SELF) + { + fDelay = PRCGetRandomDelay(); + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_METEOR_SWARM)); + //Make sure the target is outside the 2m safe zone + if (GetDistanceBetween(oTarget, OBJECT_SELF) > 2.0) + { + //Make SR check + if (!PRCDoResistSpell(OBJECT_SELF, oTarget,CasterLvl, 0.5)) + { + int nDC = PRCGetSaveDC(oTarget,OBJECT_SELF); + //Roll damage + nDamage = d6(20); + + //Enter Metamagic conditions + if ((nMetaMagic & METAMAGIC_MAXIMIZE)) + { + nDamage = 120;//Damage is at max + } + if ((nMetaMagic & METAMAGIC_EMPOWER)) + { + nDamage = nDamage + (nDamage/2); //Damage/Healing is +50% + } + nDamage += SpellDamagePerDice(OBJECT_SELF, 20); + nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, (nDC),SAVING_THROW_TYPE_FIRE); + //Set the damage effect + eFire = PRCEffectDamage(oTarget, nDamage, EleDmg); + if(nDamage > 0) + { + //Apply damage effect and VFX impact. + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eFire, oTarget)); + PRCBonusDamage(oTarget); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + } + } + //Get next target in the spell area + oTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(OBJECT_SELF)); + } + + + + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Getting rid of the local integer storing the spellschool name +} + diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_sndburst.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_sndburst.nss new file mode 100644 index 0000000..2b5a7ed --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_sndburst.nss @@ -0,0 +1,167 @@ +//:://///////////////////////////////////////////// +//:: [Sound Burst] +//:: [NW_S0_SndBurst.nss] +//:: Copyright (c) 2000 Bioware Corp. +//::////////////////////////////////////////////// +/* +Evocation [Sonic] +Level: Brd 2, Clr 2 +Components: V, S, F/DF +Casting Time: 1 standard action +Range: Close (25 ft. + 5 ft./2 levels) +Area: 10-ft.-radius spread +Duration: Instantaneous +Saving Throw: Fortitude partial +Spell Resistance: Yes + +You blast an area with a tremendous cacophony. +Every creature in the area takes 1d8 points of +sonic damage and must succeed on a Fortitude save +to avoid being stunned for 1 round. + +Creatures that cannot hear are not stunned but +are still damaged. + +Arcane Focus +A musical instrument. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Jan 31, 2001 +//::////////////////////////////////////////////// +//:: Last Updated By: Georg Z, Oct. 2003 +//:: modified by mr_bumpkin Dec 4, 2003 + +#include "prc_inc_spells" +#include "prc_add_spell_dc" + +void main() +{ + if(!X2PreSpellCastCode()) return; + + PRCSetSchool(SPELL_SCHOOL_EVOCATION); + + //Declare major variables + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + location lLoc = PRCGetSpellTargetLocation(); + int nCasterLevel = PRCGetCasterLevel(oCaster); + int nPenetr = nCasterLevel + SPGetPenetr(); + int nMetaMagic = PRCGetMetaMagicFeat(); + int EleDmg = ChangedElementalDamage(oCaster, DAMAGE_TYPE_SONIC); + int nSaveType = ChangedSaveType(EleDmg); + + effect eFNF = EffectVisualEffect(VFX_FNF_SOUND_BURST); + effect eVis = EffectVisualEffect(VFX_IMP_SONIC); + + effect eStun = EffectStunned(); + effect eMind = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_NEGATIVE); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); + effect eLink = EffectLinkEffects(eStun, eMind); + eLink = EffectLinkEffects(eLink, eDur); + + //Apply the FNF to the spell location + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eFNF, lLoc); + + //Get the first target in the spell area + object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, lLoc); + while(GetIsObjectValid(oTarget)) + { + if(spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, oCaster)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(oCaster, SPELL_SOUND_BURST)); + //Make a SR check + if(!PRCDoResistSpell(oCaster, oTarget, nPenetr)) + { + // Should not work on creatures already deafened or silenced + if(!PRCGetHasEffect(EFFECT_TYPE_DEAF, oTarget) && !PRCGetHasEffect(EFFECT_TYPE_SILENCE, oTarget)) + { + int nDC = PRCGetSaveDC(oTarget, oCaster); + //Make a Fortitude roll to avoid being stunned + if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, nSaveType)) + SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(2), TRUE, SPELL_SOUND_BURST, nCasterLevel); + } + + //Roll damage + int nDamage = d8(); + //Make meta magic checks + if(nMetaMagic & METAMAGIC_MAXIMIZE) + nDamage = 8; + if(nMetaMagic & METAMAGIC_EMPOWER) + nDamage += nDamage / 2; + + //Set the damage effect + nDamage += SpellDamagePerDice(oCaster, 1); + effect eDam = PRCEffectDamage(oTarget, nDamage, EleDmg); + //Apply the VFX impact and damage effect + DelayCommand(0.01, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + } + } + //Get the next target in the spell area + oTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, lLoc); + } + PRCSetSchool(); + +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Sound Burst' has caused a cave-in!", oPC)); + } +} diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_stormvenc.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_stormvenc.nss new file mode 100644 index 0000000..f96d9ff --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_stormvenc.nss @@ -0,0 +1,115 @@ +//:://///////////////////////////////////////////// +//:: Storm of Vengeance: Heartbeat +//:: NW_S0_StormVenC.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Creates an AOE that decimates the enemies of + the cleric over a 30ft radius around the caster +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Nov 8, 2001 +//::////////////////////////////////////////////// + +//:: modified by mr_bumpkin Dec 4, 2003 +//:: Elemental Damage note: Only made the lightning aspect variable, the acid aspect is always acid. +//:: the Lightning part seemed like the better of the 2 to go with because it accounts for more +//:: of the total damage than the acid does. + +#include "prc_inc_spells" +#include "prc_add_spell_dc" + + + +void main() +{ +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_CONJURATION); + + //Declare major variables + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + + effect eStun = EffectStunned(); + effect eVisAcid = EffectVisualEffect(VFX_IMP_ACID_S); + effect eVisElec = EffectVisualEffect(VFX_IMP_LIGHTNING_M); + effect eVisStun = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DISABLED); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); + effect eLink = EffectLinkEffects(eStun, eVisStun); + eLink = EffectLinkEffects(eLink, eDur); + float fDelay; + + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Storm of Vengeance' will not work underwater!", oPC); + return; + } + + int CasterLvl = PRCGetCasterLevel(GetAreaOfEffectCreator()); + int nPenetr = SPGetPenetrAOE(GetAreaOfEffectCreator(),CasterLvl); + + + + //Get first target in spell area + object oTarget = GetFirstInPersistentObject(OBJECT_SELF,OBJECT_TYPE_CREATURE); + while(GetIsObjectValid(oTarget)) + { + int nDamage = d6(6); + nDamage += SpellDamagePerDice(GetAreaOfEffectCreator(), 6); + effect eElec = PRCEffectDamage(oTarget, nDamage, ChangedElementalDamage(GetAreaOfEffectCreator(), DAMAGE_TYPE_ELECTRICAL)); + + if (spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, GetAreaOfEffectCreator())) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(GetAreaOfEffectCreator(), SPELL_STORM_OF_VENGEANCE)); + //Make an SR Check + fDelay = PRCGetRandomDelay(0.5, 2.0); + if(PRCDoResistSpell(GetAreaOfEffectCreator(), oTarget,nPenetr, fDelay) == 0) + { + int nDC = PRCGetSaveDC(oTarget,GetAreaOfEffectCreator()); + int nAcid = d6(3); + nAcid += SpellDamagePerDice(GetAreaOfEffectCreator(), 3); + // Acid Sheath adds +1 damage per die to acid descriptor spells + if (GetHasDescriptor(SPELL_STORM_OF_VENGEANCE, DESCRIPTOR_ACID) && GetHasSpellEffect(SPELL_MESTILS_ACID_SHEATH, GetAreaOfEffectCreator())) + nAcid += 3; + effect eAcid = PRCEffectDamage(oTarget, nAcid, DAMAGE_TYPE_ACID); + + //Make a saving throw check + // * if the saving throw is made they still suffer acid damage. + // * if they fail the saving throw, they suffer Electrical damage too + if(PRCMySavingThrow(SAVING_THROW_REFLEX, oTarget, (nDC), SAVING_THROW_TYPE_ELECTRICITY, GetAreaOfEffectCreator(), fDelay)) + { + //Apply the VFX impact and effects + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVisAcid, oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eAcid, oTarget)); + if (d2()==1) + { + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVisElec, oTarget)); + } + } + else + { + //Apply the VFX impact and effects + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVisAcid, oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eAcid, oTarget)); + //Apply the VFX impact and effects + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVisElec, oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eElec, oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(2))); + } + } + } + //Get next target in spell area + oTarget = GetNextInPersistentObject(OBJECT_SELF,OBJECT_TYPE_CREATURE); + } + + + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Getting rid of the integer used to hold the spells spell school +} diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_stormveng.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_stormveng.nss new file mode 100644 index 0000000..95db256 --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_stormveng.nss @@ -0,0 +1,113 @@ +//:://///////////////////////////////////////////// +//:: Storm of Vengeance +//:: NW_S0_StormVeng.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Creates an AOE that decimates the enemies of + the cleric over a 30ft radius around the caster +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Nov 8, 2001 +//::////////////////////////////////////////////// +//:: VFX Pass By: Preston W, On: June 25, 2001 + +//:: modified by mr_bumpkin Dec 4, 2003 +#include "prc_inc_spells" +#include "prc_add_spell_dc" + +void main() +{ + if(!X2PreSpellCastCode()) return; + + PRCSetSchool(SPELL_SCHOOL_CONJURATION); + + //Declare major variables + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + location lTarget = PRCGetSpellTargetLocation(); + effect eVis = EffectVisualEffect(VFX_FNF_STORM); + int nAoE = AOE_PER_STORM; + + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Storm of Vengeance' will not work underwater!", oPC); + return; + } + + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, lTarget); + //Create an instance of the AOE Object using the Apply Effect function + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, EffectAreaOfEffect(nAoE), lTarget, RoundsToSeconds(10) + 2.1); + + //Setup Area Of Effect object + object oAoE = GetAreaOfEffectObject(lTarget, "VFX_PER_STORM"); + SetAllAoEInts(SPELL_STORM_OF_VENGEANCE, oAoE, PRCGetSpellSaveDC(SPELL_STORM_OF_VENGEANCE, SPELL_SCHOOL_CONJURATION), 0, PRCGetCasterLevel(oCaster)); + + PRCSetSchool(); + + //Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Storm of Vengeance' has caused a cave-in!", oPC)); + } +} \ No newline at end of file diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_summon.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_summon.nss new file mode 100644 index 0000000..d16edb7 --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_summon.nss @@ -0,0 +1,311 @@ +//:://///////////////////////////////////////////// +//:: Summon Creature Series +//:: NW_S0_Summon +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Carries out the summoning of the appropriate + creature for the Summon Monster Series of spells + 1 to 9 +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Jan 8, 2002 +//::////////////////////////////////////////////// +#include "prc_inc_spells" + +void main() +{ + if(!X2PreSpellCastCode()) return; + + PRCSetSchool(SPELL_SCHOOL_CONJURATION); + + //Declare major variables + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + int bAnimalDomain; + int nMetaMagic = PRCGetMetaMagicFeat(); + int nSwitch = GetPRCSwitch(PRC_SUMMON_ROUND_PER_LEVEL); + float fDuration = nSwitch == 0 ? HoursToSeconds(24) : + RoundsToSeconds(PRCGetCasterLevel(oCaster) * nSwitch); + if(nMetaMagic & METAMAGIC_EXTEND) + fDuration *= 2; + + if (GetPRCSwitch(PRC_BIOWARE_ANIMAL_DOMAIN_POWER)) + bAnimalDomain = GetHasFeat(FEAT_ANIMAL_DOMAIN_POWER, oCaster); + + string sSummon; + int nVFX; + if (nInt == 1) + { + switch(GetSpellId()) + { + case SPELL_SUMMON_CREATURE_I: + sSummon = bAnimalDomain ? "marinebeetle2" : "marinebeetle1"; + nVFX = VFX_FNF_SUMMON_MONSTER_1; + break; + case SPELL_SUMMON_CREATURE_II: + sSummon = bAnimalDomain ? "marinebeetle" : "marinebeetle2"; + nVFX = VFX_FNF_SUMMON_MONSTER_1; + break; + case SPELL_SUMMON_CREATURE_III: + if(bAnimalDomain) + { + sSummon = "giantseaspider"; + nVFX = VFX_FNF_SUMMON_MONSTER_2; + } + else + { + sSummon = "marinebeetle"; + nVFX = VFX_FNF_SUMMON_MONSTER_1; + } + break; + case SPELL_SUMMON_CREATURE_IV: + sSummon = bAnimalDomain ? "giantcrab" : "giantseaspider"; + nVFX = VFX_FNF_SUMMON_MONSTER_2; + break; + case SPELL_SUMMON_CREATURE_V: + sSummon = bAnimalDomain ? "giantcrab" : "giantcrab"; + nVFX = VFX_FNF_SUMMON_MONSTER_2; + break; + case SPELL_SUMMON_CREATURE_VI: + if(bAnimalDomain) + { + nVFX = VFX_FNF_SUMMON_MONSTER_3; + int nRoll = d4(); + sSummon = nRoll == 1 ? "waterhuge" : + nRoll == 2 ? "waterhuge" : + nRoll == 3 ? "waterhuge" : + "waterhuge"; + } + else + { + sSummon = "waterhuge"; + nVFX = VFX_FNF_SUMMON_MONSTER_2; + } + break; + case SPELL_SUMMON_CREATURE_VII_AIR: + sSummon = bAnimalDomain ? "watergreat" : "waterhuge"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_VII_EARTH: + sSummon = bAnimalDomain ? "watergreat" : "waterhuge"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_VII_FIRE: + sSummon = bAnimalDomain ? "watergreat" : "waterhuge"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_VII_WATER: + sSummon = bAnimalDomain ? "watergreat" : "waterhuge"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_VIII_AIR: + sSummon = bAnimalDomain ? "waterelder" : "watergreat"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_VIII_EARTH: + sSummon = bAnimalDomain ? "waterelder" : "watergreat"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_VIII_FIRE: + sSummon = bAnimalDomain ? "waterelder" : "watergreat"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_VIII_WATER: + sSummon = bAnimalDomain ? "waterelder" : "watergreat"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_IX_AIR: + sSummon = "waterelder"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_IX_EARTH: + sSummon = "waterelder"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_IX_FIRE: + sSummon = "waterelder"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_IX_WATER: + sSummon = "waterelder"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_VII: + { + nVFX = VFX_FNF_SUMMON_MONSTER_3; + int nRoll = d4(); + sSummon = nRoll == 1 ? "waterhuge" : + nRoll == 2 ? "waterhuge" : + nRoll == 3 ? "waterhuge" : + "waterhuge"; + } + break; + case SPELL_SUMMON_CREATURE_VIII: + { + nVFX = VFX_FNF_SUMMON_MONSTER_3; + int nRoll = d4(); + sSummon = nRoll == 1 ? "watergreat" : + nRoll == 2 ? "watergreat" : + nRoll == 3 ? "watergreat" : + "watergreat"; + } + break; + case SPELL_SUMMON_CREATURE_IX: + { + nVFX = VFX_FNF_SUMMON_MONSTER_3; + int nRoll = d4(); + sSummon = nRoll == 1 ? "waterelder" : + nRoll == 2 ? "waterelder" : + nRoll == 3 ? "waterelder" : + "waterelder"; + } + break; + } + } + else + { + switch(GetSpellId()) + { + case SPELL_SUMMON_CREATURE_I: + sSummon = bAnimalDomain ? "boardire" : "badgerdire"; + nVFX = VFX_FNF_SUMMON_MONSTER_1; + break; + case SPELL_SUMMON_CREATURE_II: + sSummon = bAnimalDomain ? "wolfdire" : "boardire"; + nVFX = VFX_FNF_SUMMON_MONSTER_1; + break; + case SPELL_SUMMON_CREATURE_III: + if(bAnimalDomain) + { + sSummon = "spiddire"; + nVFX = VFX_FNF_SUMMON_MONSTER_2; + } + else + { + sSummon = "wolfdire"; + nVFX = VFX_FNF_SUMMON_MONSTER_1; + } + break; + case SPELL_SUMMON_CREATURE_IV: + sSummon = bAnimalDomain ? "beardire" : "spiddire"; + nVFX = VFX_FNF_SUMMON_MONSTER_2; + break; + case SPELL_SUMMON_CREATURE_V: + sSummon = bAnimalDomain ? "diretiger" : "beardire"; + nVFX = VFX_FNF_SUMMON_MONSTER_2; + break; + case SPELL_SUMMON_CREATURE_VI: + if(bAnimalDomain) + { + nVFX = VFX_FNF_SUMMON_MONSTER_3; + int nRoll = d4(); + sSummon = nRoll == 1 ? "airhuge" : + nRoll == 2 ? "earthhuge" : + nRoll == 3 ? "firehuge" : + "waterhuge"; + } + else + { + sSummon = "diretiger"; + nVFX = VFX_FNF_SUMMON_MONSTER_2; + } + break; + case SPELL_SUMMON_CREATURE_VII_AIR: + sSummon = bAnimalDomain ? "airgreat" : "airhuge"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_VII_EARTH: + sSummon = bAnimalDomain ? "earthgreat" : "earthhuge"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_VII_FIRE: + sSummon = bAnimalDomain ? "firegreat" : "firehuge"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_VII_WATER: + sSummon = bAnimalDomain ? "watergreat" : "waterhuge"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_VIII_AIR: + sSummon = bAnimalDomain ? "airelder" : "airgreat"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_VIII_EARTH: + sSummon = bAnimalDomain ? "earthelder" : "earthgreat"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_VIII_FIRE: + sSummon = bAnimalDomain ? "fireelder" : "firegreat"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_VIII_WATER: + sSummon = bAnimalDomain ? "waterelder" : "watergreat"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_IX_AIR: + sSummon = "airelder"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_IX_EARTH: + sSummon = "earthelder"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_IX_FIRE: + sSummon = "fireelder"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_IX_WATER: + sSummon = "waterelder"; + nVFX = VFX_FNF_SUMMON_MONSTER_3; + break; + case SPELL_SUMMON_CREATURE_VII: + { + nVFX = VFX_FNF_SUMMON_MONSTER_3; + int nRoll = d4(); + sSummon = nRoll == 1 ? "airhuge" : + nRoll == 2 ? "earthhuge" : + nRoll == 3 ? "firehuge" : + "waterhuge"; + } + break; + case SPELL_SUMMON_CREATURE_VIII: + { + nVFX = VFX_FNF_SUMMON_MONSTER_3; + int nRoll = d4(); + sSummon = nRoll == 1 ? "airgreat" : + nRoll == 2 ? "earthgreat" : + nRoll == 3 ? "firegreat" : + "watergreat"; + } + break; + case SPELL_SUMMON_CREATURE_IX: + { + nVFX = VFX_FNF_SUMMON_MONSTER_3; + int nRoll = d4(); + sSummon = nRoll == 1 ? "airelder" : + nRoll == 2 ? "earthelder" : + nRoll == 3 ? "fireelder" : + "waterelder"; + } + break; + } + } + + if (GetHasFeat(FEAT_SUMMON_ALIEN, oCaster) || GetHasSpellEffect(VESTIGE_ZCERYLL, oCaster)) sSummon = "pseudo"+sSummon; + else sSummon = "nw_s_"+sSummon; + + if (DEBUG) DoDebug("nw_s0_summon: oCaster " +GetName(oCaster)+", GetSpellId " +IntToString(GetSpellId())+", sSummon " +sSummon); + + effect eSummon = EffectSummonCreature(sSummon, nVFX); + + //Apply the VFX impact and summon effect + MultisummonPreSummon(); + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, PRCGetSpellTargetLocation(), fDuration); + + DelayCommand(0.5, AugmentSummonedCreature(sSummon)); + + PRCSetSchool(); +} \ No newline at end of file diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_sunbeam.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_sunbeam.nss new file mode 100644 index 0000000..9285b7c --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_sunbeam.nss @@ -0,0 +1,160 @@ +//:://///////////////////////////////////////////// +//:: Sunbeam +//:: s_Sunbeam.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +//:: All creatures in the beam are struck blind and suffer 4d6 points of damage. (A successful +//:: Reflex save negates the blindness and reduces the damage by half.) Creatures to whom sunlight +//:: is harmful or unnatural suffer double damage. +//:: +//:: Undead creatures caught within the ray are dealt 1d6 points of damage per caster level +//:: (maximum 20d6), or half damage if a Reflex save is successful. In addition, the ray results in +//:: the total destruction of undead creatures specifically affected by sunlight if they fail their saves. +//::////////////////////////////////////////////// +//:: Created By: Keith Soleski +//:: Created On: Feb 22, 2001 +//::////////////////////////////////////////////// +//:: Last Modified By: Keith Soleski, On: March 21, 2001 +//:: VFX Pass By: Preston W, On: June 25, 2001 + +//:: modified by mr_bumpkin Dec 4, 2003 +#include "prc_inc_spells" +#include "prc_add_spell_dc" + + + + +void main() +{ + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Sunbeam' will not work underwater!", oPC); + return; + } + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_EVOCATION); +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + + int nMetaMagic = PRCGetMetaMagicFeat(); + effect eVis = EffectVisualEffect(VFX_IMP_DEATH); + effect eVis2 = EffectVisualEffect(VFX_IMP_SUNSTRIKE); + effect eStrike = EffectVisualEffect(VFX_FNF_SUNBEAM); + effect eDam; + effect eBlind = EffectBlindness(); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); + effect eLink = EffectLinkEffects(eBlind, eDur); + int CasterLvl = PRCGetCasterLevel(OBJECT_SELF); + int nDamage; + int nOrgDam; + int nMax; + float fDelay; + int nBlindLength = 3; + + + int nPenetr = CasterLvl + SPGetPenetr(); + + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eStrike, PRCGetSpellTargetLocation()); + //Get the first target in the spell area + object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, PRCGetSpellTargetLocation()); + while(GetIsObjectValid(oTarget)) + { + + int nCasterLevel= CasterLvl; + //Limit caster level + if (nCasterLevel > 20) + { + nCasterLevel = 20; + } + + // Make a faction check + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + fDelay = PRCGetRandomDelay(1.0, 2.0); + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_SUNBEAM)); + //Make an SR check + if ( ! PRCDoResistSpell(OBJECT_SELF, oTarget,nPenetr, 1.0)) + { + //Check if the target is an undead + if (MyPRCGetRacialType(oTarget) == RACIAL_TYPE_UNDEAD) + { + //Roll damage and save + nDamage = d6(nCasterLevel); + nMax = 6; + } + else + { + //Roll damage and save + nDamage = d6(3); + nOrgDam = nDamage; + nMax = 6; + nCasterLevel = 3; + //Get the adjusted damage due to Reflex Save, Evasion or Improved Evasion + } + + //Do metamagic checks + if ((nMetaMagic & METAMAGIC_MAXIMIZE)) + { + nDamage = nMax * nCasterLevel; + } + if ((nMetaMagic & METAMAGIC_EMPOWER)) + { + nDamage = nDamage + (nDamage/2); + } + + nDamage += SpellDamagePerDice(OBJECT_SELF, nCasterLevel); + int nDC = PRCGetSaveDC(oTarget,OBJECT_SELF); + + //Check that a reflex save was made. + if(PRCMySavingThrow(SAVING_THROW_REFLEX, oTarget, (nDC), SAVING_THROW_TYPE_DIVINE, OBJECT_SELF, 1.0) == 0) + { + DelayCommand(1.0, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nBlindLength),TRUE,-1,CasterLvl)); + } + else + { + nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, 0, SAVING_THROW_TYPE_DIVINE); + } + //Set damage effect + eDam = PRCEffectDamage(oTarget, nDamage, DAMAGE_TYPE_DIVINE); + if(nDamage > 0) + { + //Apply the damage effect and VFX impact + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis2, oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + PRCBonusDamage(oTarget); + } + } + } + //Get the next target in the spell area + oTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, PRCGetSpellTargetLocation()); + } + + + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Getting rid of the integer used to hold the spells spell school +} diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_wailbansh.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_wailbansh.nss new file mode 100644 index 0000000..b8b2837 --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_wailbansh.nss @@ -0,0 +1,173 @@ +//:://///////////////////////////////////////////// +//:: Wail of the Banshee +//:: NW_S0_WailBansh +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + You emit a terrible scream that kills enemy creatures who hear it + The spell affects up to one creature per caster level. Creatures + closest to the point of origin are affected first. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Dec 12, 2000 +//::////////////////////////////////////////////// +//:: Last Updated By: Preston Watamaniuk, On: April 11, 2001 +//:: VFX Pass By: Preston W, On: June 25, 2001 + +//:: modified by mr_bumpkin Dec 4, 2003 +#include "prc_inc_spells" +#include "prc_add_spell_dc" + + + + +void main() +{ + DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_NECROMANCY); +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oPC = GetFirstPC(); + int nCasterLevel = PRCGetCasterLevel(OBJECT_SELF); + + int nToAffect = nCasterLevel; + + object oTarget; + float fTargetDistance; + float fDelay; + location lTarget; + effect eVis = EffectVisualEffect(VFX_IMP_DEATH); + effect eWail = EffectVisualEffect(VFX_FNF_WAIL_O_BANSHEES); + int nCnt = 1; + + nCasterLevel +=SPGetPenetr(); + + //Apply the FNF VFX impact + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eWail, PRCGetSpellTargetLocation()); + //Get the closet target from the spell target location + oTarget = PRCGetSpellTargetObject(); // direct target + if (!GetIsObjectValid(oTarget) || GetObjectType(oTarget) != OBJECT_TYPE_CREATURE) + oTarget = GetNearestObjectToLocation(OBJECT_TYPE_CREATURE, PRCGetSpellTargetLocation(), nCnt); + while (nCnt < nToAffect) + { + lTarget = GetLocation(oTarget); + //Get the distance of the target from the center of the effect + fDelay = PRCGetRandomDelay(3.0, 4.0);// + fTargetDistance = GetDistanceBetweenLocations(PRCGetSpellTargetLocation(), lTarget); + //Check that the current target is valid and closer than 10.0m + if(GetIsObjectValid(oTarget) && fTargetDistance <= 10.0) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, OBJECT_SELF)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_WAIL_OF_THE_BANSHEE)); + //Make SR check + if(!PRCDoResistSpell(OBJECT_SELF, oTarget,nCasterLevel)) //, 0.1)) + { + int nDC = PRCGetSaveDC(oTarget,OBJECT_SELF); + //Make a fortitude save to avoid death + if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, (nDC), SAVING_THROW_TYPE_DEATH)) //, OBJECT_SELF, 3.0)) + { + DeathlessFrenzyCheck(oTarget); + + //Apply the delay VFX impact and death effect + SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + effect eDeath = EffectDeath(); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDeath, oTarget)); // no delay + } + } + } + } + else + { + //Kick out of the loop + nCnt = nToAffect; + } + //Increment the count of creatures targeted + nCnt++; + //Get the next closest target in the spell target location. + oTarget = GetNearestObjectToLocation(OBJECT_TYPE_CREATURE, PRCGetSpellTargetLocation(), nCnt); + } + + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Getting rid of the integer used to hold the spells spell school + +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Wail of the Banshee' has caused a cave-in!", oPC)); + } +} diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_wallfire.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_wallfire.nss new file mode 100644 index 0000000..2356d12 --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_wallfire.nss @@ -0,0 +1,63 @@ +//:://///////////////////////////////////////////// +//:: Wall of Fire +//:: NW_S0_WallFire.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Creates a wall of fire that burns any creature + entering the area around the wall. Those moving + through the AOE are burned for 4d6 fire damage +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: July 17, 2001 +//::////////////////////////////////////////////// + +//:: modified by mr_bumpkin Dec 4, 2003 +#include "prc_inc_spells" +#include "prc_add_spell_dc" + +void main() +{ + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + + if(!X2PreSpellCastCode()) return; + + PRCSetSchool(SPELL_SCHOOL_EVOCATION); + + //Declare Area of Effect object using the appropriate constant + effect eAOE = EffectAreaOfEffect(AOE_PER_WALLFIRE); + //Get the location where the wall is to be placed. + location lTarget = PRCGetSpellTargetLocation(); + int CasterLvl = PRCGetCasterLevel(); + int nDuration = CasterLvl / 2; + if(nDuration == 0) + { + nDuration = 1; + } + int nMetaMagic = PRCGetMetaMagicFeat(); + + //Check fort metamagic + if (CheckMetaMagic(nMetaMagic, METAMAGIC_EXTEND)) + { + nDuration = nDuration *2; //Duration is +100% + } + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Wall of Fire' will not work underwater!", oPC); + return; + } + //Create the Area of Effect Object declared above. + ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eAOE, lTarget, RoundsToSeconds(nDuration)); + + object oAoE = GetAreaOfEffectObject(lTarget, "VFX_PER_WALLFIRE"); + SetAllAoEInts(SPELL_WALL_OF_FIRE, oAoE, PRCGetSpellSaveDC(SPELL_WALL_OF_FIRE, SPELL_SCHOOL_EVOCATION), 0, CasterLvl); + SetLocalInt(oAoE, "Wall_Fire_Damage", ChangedElementalDamage(OBJECT_SELF, DAMAGE_TYPE_FIRE)); + + PRCSetSchool(); +} diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_wallfirea.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_wallfirea.nss new file mode 100644 index 0000000..8e773fb --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_wallfirea.nss @@ -0,0 +1,83 @@ +//:://///////////////////////////////////////////// +//:: Wall of Fire: On Enter +//:: NW_S0_WallFireA.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Person within the AoE take 4d6 fire damage + per round. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: May 17, 2001 +//::////////////////////////////////////////////// + +//:: modified by mr_bumpkin Dec 4, 2003 +#include "prc_inc_spells" +#include "prc_add_spell_dc" + + + +void main() +{ + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_EVOCATION); + + //Declare major variables + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + int nMetaMagic = PRCGetMetaMagicFeat(); + int nDamage; + effect eDam; + object oTarget; + //Declare and assign personal impact visual effect. + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_M); + int nPenetr = SPGetPenetrAOE(GetAreaOfEffectCreator()); + + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Wall of Fire' will not work underwater!", oPC); + return; + } + + //Capture the first target object in the shape. + oTarget = GetEnteringObject(); + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, GetAreaOfEffectCreator())) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_WALL_OF_FIRE)); + //Make SR check, and appropriate saving throw(s). + if(!PRCDoResistSpell(GetAreaOfEffectCreator(), oTarget,nPenetr)) + { + //Roll damage. + nDamage = d6(4); + //Enter Metamagic conditions + if ((nMetaMagic & METAMAGIC_MAXIMIZE)) + { + nDamage = 24;//Damage is at max + } + if ((nMetaMagic & METAMAGIC_EMPOWER)) + { + nDamage = nDamage + (nDamage/2); //Damage/Healing is +50% + } + nDamage += SpellDamagePerDice(GetAreaOfEffectCreator(), 4); + nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, (PRCGetSaveDC(oTarget,GetAreaOfEffectCreator())), SAVING_THROW_TYPE_FIRE); + if(nDamage > 0) + { + // Apply effects to the currently selected target. + eDam = PRCEffectDamage(oTarget, nDamage, GetLocalInt(OBJECT_SELF, "Wall_Fire_Damage")); + SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); + PRCBonusDamage(oTarget); + SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + } + } + } + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Getting rid of the integer used to hold the spells spell school +} diff --git a/src/hakpak/ghost_prc8_top/nss/nw_s0_wallfirec.nss b/src/hakpak/ghost_prc8_top/nss/nw_s0_wallfirec.nss new file mode 100644 index 0000000..d783a70 --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/nw_s0_wallfirec.nss @@ -0,0 +1,111 @@ +//:://///////////////////////////////////////////// +//:: Wall of Fire: Heartbeat +//:: NW_S0_WallFireA.nss +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Person within the AoE take 4d6 fire damage + per round. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: May 17, 2001 +//::////////////////////////////////////////////// + +//:: modified by mr_bumpkin Dec 4, 2003 +#include "prc_inc_spells" +#include "prc_add_spell_dc" + + + +void main() +{ + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_EVOCATION); + + //Declare major variables + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + int nMetaMagic = PRCGetMetaMagicFeat(); + int nDamage; + effect eDam; + object oTarget; + //Declare and assign personal impact visual effect. + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_M); + + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Wall of Fire' will not work underwater!", oPC); + return; + } + + //Capture the first target object in the shape. + + //-------------------------------------------------------------------------- + // GZ 2003-Oct-15 + // When the caster is no longer there, all functions calling + // GetAreaOfEffectCreator will fail. Its better to remove the barrier then + //-------------------------------------------------------------------------- + if (!GetIsObjectValid(GetAreaOfEffectCreator())) + { + DestroyObject(OBJECT_SELF); + return; + } + + int CasterLvl = PRCGetCasterLevel(GetAreaOfEffectCreator()); + + int nPenetr = SPGetPenetrAOE(GetAreaOfEffectCreator(),CasterLvl); + int EleDmg = GetLocalInt(OBJECT_SELF, "Wall_Fire_Damage"); + + oTarget = GetFirstInPersistentObject(OBJECT_SELF,OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + //Declare the spell shape, size and the location. + while(GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, GetAreaOfEffectCreator())) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_WALL_OF_FIRE)); + //Make SR check, and appropriate saving throw(s). + if(!PRCDoResistSpell(GetAreaOfEffectCreator(), oTarget,nPenetr)) + { + //Roll damage. + nDamage = d6(4); + //Enter Metamagic conditions + if ((nMetaMagic & METAMAGIC_MAXIMIZE)) + { + nDamage = 24;//Damage is at max + } + if ((nMetaMagic & METAMAGIC_EMPOWER)) + { + nDamage = nDamage + (nDamage/2); //Damage/Healing is +50% + } + + nDamage += SpellDamagePerDice(GetAreaOfEffectCreator(), 4); + + int nDC = PRCGetSaveDC(oTarget,GetAreaOfEffectCreator()); + + nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, (nDC), SAVING_THROW_TYPE_FIRE); + if(nDamage > 0) + { + // Apply effects to the currently selected target. + eDam = PRCEffectDamage(oTarget, nDamage, EleDmg); + SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); + PRCBonusDamage(oTarget); + SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eVis, oTarget, 1.0,FALSE); + } + } + } + //Select the next target within the spell shape. + oTarget = GetNextInPersistentObject(OBJECT_SELF,OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } + + + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Getting rid of the integer used to hold the spells spell school +} diff --git a/src/hakpak/ghost_prc8_top/nss/x0_s0_bombard.nss b/src/hakpak/ghost_prc8_top/nss/x0_s0_bombard.nss new file mode 100644 index 0000000..9abd1f4 --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/x0_s0_bombard.nss @@ -0,0 +1,192 @@ +//:://///////////////////////////////////////////// +//:: Bombardment +//:: X0_S0_Bombard +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* +// Rocks fall from sky +// 1d8 damage/level to a max of 10d8 +// Reflex save for half +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 22 2002 +//::////////////////////////////////////////////// +//:: Last Updated By: Andrew Nobbs May 01, 2003 + +//:: altered by mr_bumpkin Dec 4, 2003 for prc stuff +#include "prc_inc_spells" + + +#include "prc_add_spell_dc" + +void main() +{ + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + object oCaster = OBJECT_SELF; + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Bombardment' will not work underwater!", oPC); + return; + } + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_CONJURATION); +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + int CasterLvl = PRCGetCasterLevel(OBJECT_SELF); + + int nCasterLvl = CasterLvl; + CasterLvl +=SPGetPenetr(); + + + int nMetaMagic = PRCGetMetaMagicFeat(); + int nDamage; + float fDelay; + effect eExplode = EffectVisualEffect(VFX_FNF_METEOR_SWARM); + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_M); + effect eDam; + //Get the spell target location as opposed to the spell target. + location lTarget = PRCGetSpellTargetLocation(); + //Limit Caster level for the purposes of damage + if (nCasterLvl > 20) + { + nCasterLvl = 20; + } + + //Apply the fireball explosion at the location captured above. + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, lTarget); + //Declare the spell shape, size and the location. Capture the first target object in the shape. + object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget)) + { + if(spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF) == TRUE) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + //Get the distance between the explosion and the target to calculate delay + fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oTarget))/20; + if (!PRCDoResistSpell(OBJECT_SELF, oTarget,CasterLvl, fDelay)) + { + int nSpellDC = (PRCGetSaveDC(oTarget,OBJECT_SELF)) ; + //Roll damage for each target + nDamage = d8(nCasterLvl); + //Resolve metamagic + if ((nMetaMagic & METAMAGIC_MAXIMIZE)) + { + nDamage = 8 * nCasterLvl; + } + if ((nMetaMagic & METAMAGIC_EMPOWER)) + { + nDamage = nDamage + nDamage / 2; + } + nDamage += SpellDamagePerDice(oCaster, nCasterLvl); + //nDamage += ApplySpellBetrayalStrikeDamage(oTarget, OBJECT_SELF, FALSE); + //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. + nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nSpellDC, SAVING_THROW_TYPE_ALL); + //Set the damage effect + eDam = PRCEffectDamage(oTarget, nDamage, DAMAGE_TYPE_BLUDGEONING); + if(nDamage > 0) + { + + // Apply effects to the currently selected target. + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + //This visual effect is applied to the target object not the location as above. This visual effect + //represents the flame that erupts on the target not on the ground. + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + } + //Select the next target within the spell shape. + oTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } + + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Erasing the variable used to store the spell's spell school + +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Bombardment' has caused a cave-in!", oPC)); + } +} + + + diff --git a/src/hakpak/ghost_prc8_top/nss/x0_s0_earthquake.nss b/src/hakpak/ghost_prc8_top/nss/x0_s0_earthquake.nss new file mode 100644 index 0000000..88c4d52 --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/x0_s0_earthquake.nss @@ -0,0 +1,201 @@ +//:://///////////////////////////////////////////// +//:: Earthquake +//:: X0_S0_Earthquake +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* +// Ground shakes. 1d6 damage, max 10d6 +// LOCKINDAL: Changed to alternate: DC 15 or knock down, 25% creatures must make DC 20 or die. +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 22 2002 +//::////////////////////////////////////////////// +//:: Last Updated By: Andrew Nobbs May 01, 2003 +//:: Altered By: Lockindal + +//:: altered by mr_bumpkin Dec 4, 2003 for prc stuff +#include "prc_inc_spells" + +#include "prc_alterations" +#include "prc_add_spell_dc" + +void DoQuake(object oCaster, int nCasterLvl, location lTarget) +{ + PRCSetSchool(SPELL_SCHOOL_EVOCATION); + + //Declare major variables + int nSpectacularDeath = TRUE; + int nDisplayFeedback = TRUE; + int bInside = GetIsAreaInterior(GetArea(oCaster)); + int nProneDC = 15; + int nDamageDC = 15; + int nFissureDC = 20; + int nDamage; + float fDelay; + float fSize = FeetToMeters(80.0f); + float fProneDur = 18.0; + effect eExplode = EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM); + effect eExplode2 = EffectVisualEffect(VFX_FNF_GAS_EXPLOSION_NATURE); + effect eExplode3 = EffectVisualEffect(VFX_IMP_DUST_EXPLOSION); + effect eVis = EffectVisualEffect(VFX_IMP_HEAD_NATURE); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE2); + effect eKnockdown = EffectKnockdown(); + + // Perform screen shake + SPApplyEffectToObject(DURATION_TYPE_INSTANT, eShake, oCaster); + + //Apply epicenter explosion on caster + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, GetLocation(oCaster)); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode2, GetLocation(oCaster)); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode3, GetLocation(oCaster)); + + + //Declare the spell shape, size and the location. Capture the first target object in the shape. + object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, fSize, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while(GetIsObjectValid(oTarget)) + { + // Normal targeting restriction, except also skip affecting the caster + if(oTarget != oCaster && spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, oCaster)) + { + // Let the target's AI know + SignalEvent(oTarget, EventSpellCastAt(oCaster, SPELL_EARTHQUAKE)); + + // First, always knock targets prone, DC 15 to avoid + if(!PRCMySavingThrow(SAVING_THROW_REFLEX, oTarget, nProneDC, SAVING_THROW_TYPE_SPELL, oCaster)) + { + SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eKnockdown, oTarget, fProneDur, FALSE, SPELL_EARTHQUAKE, nCasterLvl, oCaster); + } + + // Indoors, get hit by falling rubble for 8d6, reflex half + if(bInside) + { + nDamage = SpellDamagePerDice(oCaster, 8) + d6(8); + nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDamageDC, SAVING_THROW_TYPE_SPELL, oCaster); + SPApplyEffectToObject(DURATION_TYPE_INSTANT, PRCEffectDamage(oTarget, nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_ENERGY), + oTarget, 0.0f, FALSE, SPELL_EARTHQUAKE, nCasterLvl, oCaster); + } + // Outdoors, 25% chance to fall into a fissure and die + else + { + if(d4() == 4) + { + if(!PRCMySavingThrow(SAVING_THROW_REFLEX, oTarget, nFissureDC, SAVING_THROW_TYPE_SPELL, oCaster)) + { + DeathlessFrenzyCheck(oTarget); + /// @todo Find appropriate VFX to play here + SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDeath(nSpectacularDeath, nDisplayFeedback), + oTarget, 0.0f, FALSE, SPELL_EARTHQUAKE, nCasterLvl, oCaster); + } + } + } + } + + //Select the next target within the spell shape. + oTarget = MyNextObjectInShape(SHAPE_SPHERE, fSize, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } + + PRCSetSchool(); +} + + +void main() +{ +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_EVOCATION); +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + location lTarget = PRCGetSpellTargetLocation(); + int nCasterLvl = PRCGetCasterLevel(oCaster); + int nMetaMagic = PRCGetMetaMagicFeat(); + + // Perform the earthquake + DoQuake(oCaster, nCasterLvl, lTarget); + + // Extended earthquake - apply the effects again next round + if(nMetaMagic & METAMAGIC_EXTEND) + DelayCommand(6.0f, DoQuake(oCaster, nCasterLvl, lTarget)); + +// Erasing the variable used to store the spell's spell school +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); + +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Earthquake' has caused a cave-in!", oPC)); + } +} \ No newline at end of file diff --git a/src/hakpak/ghost_prc8_top/nss/x0_s0_firebrand.nss b/src/hakpak/ghost_prc8_top/nss/x0_s0_firebrand.nss new file mode 100644 index 0000000..e2e65e3 --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/x0_s0_firebrand.nss @@ -0,0 +1,239 @@ +//:://///////////////////////////////////////////// +//:: Firebrand +//:: x0_x0_Firebrand +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* +// * Fires a flame arrow to every target in a +// * colossal area +// * Each target explodes into a small fireball for +// * 1d6 damage / level (max = 15 levels) +// * Only nLevel targets can be affected +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 29 2002 +//::////////////////////////////////////////////// +//:: Last Updated By: + +// +// Altered to give targets reflex saves per pnp. +// + +//:: altered by mr_bumpkin Dec 4, 2003 for prc stuff +#include "prc_inc_spells" + + +#include "prc_add_spell_dc" + +void DoFirebrand(int CasterLvl,int nD6Dice, int nCap, int nSpell, + int nMIRV = VFX_IMP_MIRV, int nVIS = VFX_IMP_MAGBLUE, + int nDAMAGETYPE = DAMAGE_TYPE_MAGICAL, int nONEHIT = FALSE); + +void main() +{ + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Firebrand' will not work underwater!", oPC); + return; + } + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_EVOCATION); +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + int CasterLvl = PRCGetCasterLevel(OBJECT_SELF); + + int nDamage = CasterLvl; + if (nDamage > 15) + nDamage = 15; + + + + // Changed to local function to add reflex save. + DoFirebrand(CasterLvl,nDamage, 15, SPELL_FIREBRAND, VFX_IMP_MIRV_FLAME, VFX_IMP_FLAME_M, ChangedElementalDamage(OBJECT_SELF, DAMAGE_TYPE_FIRE), FALSE); + + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Erasing the variable used to store the spell's spell school + +} + + + +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 31, 2002 +//::////////////////////////////////////////////// +//:: Modified March 14 2003: Removed the option to hurt chests/doors +//:: was potentially causing bugs when no creature targets available. +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 31, 2002 +//::////////////////////////////////////////////// +//:: Modified March 14 2003: Removed the option to hurt chests/doors +//:: was potentially causing bugs when no creature targets available. +void DoFirebrand(int CasterLvl,int nD6Dice, int nCap, int nSpell, int nMIRV = VFX_IMP_MIRV, int nVIS = VFX_IMP_MAGBLUE, int nDAMAGETYPE = DAMAGE_TYPE_MAGICAL, int nONEHIT = FALSE) +{ + object oTarget = OBJECT_INVALID; + int nDamage = 0; + int nMetaMagic = PRCGetMetaMagicFeat(); + int nCnt = 1; + effect eMissile = EffectVisualEffect(nMIRV); + effect eVis = EffectVisualEffect(nVIS); + float fDist = 0.0; + float fDelay = 0.0; + float fDelay2, fTime; + location lTarget = PRCGetSpellTargetLocation(); // missile spread centered around caster + int nMissiles = CasterLvl; + + if (nMissiles > nCap) + { + nMissiles = nCap; + } + + /* New Algorithm + 1. Count # of targets + 2. Determine number of missiles + 3. First target gets a missile and all Excess missiles + 4. Rest of targets (max nMissiles) get one missile + */ + int nEnemies = 0; + int nCasterlvl = CasterLvl +SPGetPenetr(); + + + + oTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_GARGANTUAN, lTarget, TRUE, OBJECT_TYPE_CREATURE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget) ) + { + // * caster cannot be harmed by this spell + if (spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, OBJECT_SELF) && (oTarget != OBJECT_SELF)) + { + // GZ: You can only fire missiles on visible targets + if (GetObjectSeen(oTarget,OBJECT_SELF)) + { + nEnemies++; + } + } + oTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_GARGANTUAN, lTarget, TRUE, OBJECT_TYPE_CREATURE); + } + + if (nEnemies == 0) return; // * Exit if no enemies to hit + int nExtraMissiles = nMissiles / nEnemies; + + // April 2003 + // * if more enemies than missiles, need to make sure that at least + // * one missile will hit each of the enemies + if (nExtraMissiles <= 0) + { + nExtraMissiles = 1; + } + + // by default the Remainder will be 0 (if more than enough enemies for all the missiles) + int nRemainder = 0; + + if (nExtraMissiles >0) + nRemainder = nMissiles % nEnemies; + + if (nEnemies > nMissiles) + nEnemies = nMissiles; + + oTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_GARGANTUAN, lTarget, TRUE, OBJECT_TYPE_CREATURE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget) && nCnt <= nEnemies) + { + // * caster cannot be harmed by this spell + if (spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, OBJECT_SELF) && (oTarget != OBJECT_SELF) && (GetObjectSeen(oTarget,OBJECT_SELF))) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, nSpell)); + + // * recalculate appropriate distances + fDist = GetDistanceBetween(OBJECT_SELF, oTarget); + fDelay = fDist/(3.0 * log(fDist) + 2.0); + + // Firebrand. + // It means that once the target has taken damage this round from the + // spell it won't take subsequent damage + if (nONEHIT == TRUE) + { + nExtraMissiles = 1; + nRemainder = 0; + } + + int i = 0; + //-------------------------------------------------------------- + // GZ: Moved SR check out of loop to have 1 check per target + // not one check per missile, which would rip spell mantels + // apart + //-------------------------------------------------------------- + if (!PRCDoResistSpell(OBJECT_SELF, oTarget,nCasterlvl, fDelay)) + { + int nDC = PRCGetSaveDC(oTarget,OBJECT_SELF); + for (i=1; i <= nExtraMissiles + nRemainder; i++) + { + //Roll damage + int nDam = d6(nD6Dice); + //Enter Metamagic conditions + if ((nMetaMagic & METAMAGIC_MAXIMIZE)) + { + nDam = nD6Dice*6;//Damage is at max + } + if ((nMetaMagic & METAMAGIC_EMPOWER)) + { + nDam = nDam + nDam/2; //Damage/Healing is +50% + } + nDam += SpellDamagePerDice(OBJECT_SELF, nD6Dice); + if(i == 1) //nDam += ApplySpellBetrayalStrikeDamage(oTarget, OBJECT_SELF); + fTime = fDelay; + fDelay2 += 0.1; + fTime += fDelay2; + + // Adjust damage for reflex save / evasion / imp evasion + nDam = PRCGetReflexAdjustedDamage(nDam, oTarget, + nDC, SAVING_THROW_TYPE_FIRE); + + // Always apply missle but only apply impact/damage if we really have damage. + DelayCommand(fDelay2, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eMissile, oTarget)); + if (nDam > 0) + { + //Set damage effect + effect eDam = PRCEffectDamage(oTarget, nDam, nDAMAGETYPE); + //Apply the MIRV and damage effect + DelayCommand(fTime, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eVis, oTarget,0.0f,TRUE,-1,CasterLvl)); + DelayCommand(fTime, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + } + } + } // for + else + { // * apply a dummy visual effect + SPApplyEffectToObject(DURATION_TYPE_INSTANT, eMissile, oTarget); + } + nCnt++;// * increment count of missiles fired + nRemainder = 0; + } + oTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_GARGANTUAN, lTarget, TRUE, OBJECT_TYPE_CREATURE); + } + +} diff --git a/src/hakpak/ghost_prc8_top/nss/x0_s0_gustwind.nss b/src/hakpak/ghost_prc8_top/nss/x0_s0_gustwind.nss new file mode 100644 index 0000000..1addff9 --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/x0_s0_gustwind.nss @@ -0,0 +1,158 @@ +//:://///////////////////////////////////////////// +//:: Gust of Wind +//:: [x0_s0_gustwind.nss] +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* + This spell creates a gust of wind in all directions + around the target. All targets in a medium area will be + affected: + - Target must make a For save vs. spell DC or be + knocked down for 3 rounds + - plays a wind sound + - if an area of effect object is within the area + it is dispelled +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: September 7, 2002 +//::////////////////////////////////////////////// + +//:: altered by mr_bumpkin Dec 4, 2003 for prc stuff +#include "prc_inc_spells" + + +#include "prc_add_spell_dc" + +void main() +{ +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_EVOCATION); +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + string sAOETag; + object oPC = GetFirstPC(); + object oCaster = OBJECT_SELF; + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + + int CasterLvl = PRCGetCasterLevel(OBJECT_SELF); + int nCasterLvl = CasterLvl; + int nMetaMagic = PRCGetMetaMagicFeat(); + int nDamage; + float fDelay; + effect eExplode = EffectVisualEffect(VFX_FNF_LOS_NORMAL_20); + effect eVis = EffectVisualEffect(VFX_IMP_PULSE_WIND); + + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Gust of Wind' will not work underwater!", oPC); + return; + } + + nCasterLvl += SPGetPenetr(); + + + // effect eDam; + //Get the spell target location as opposed to the spell target. + location lTarget = PRCGetSpellTargetLocation(); + + //Apply the fireball explosion at the location captured above. + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, lTarget); + + + //Declare the spell shape, size and the location. Capture the first target object in the shape. + object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE | OBJECT_TYPE_AREA_OF_EFFECT); + + + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget)) + { + if (GetObjectType(oTarget) == OBJECT_TYPE_AREA_OF_EFFECT) + { + // 1.69 change + // Gust of wind should only destroy "cloud/fog like" area of effect spells. + sAOETag = GetTag(oTarget); + if ( sAOETag == "VFX_PER_FOGACID" || + sAOETag == "VFX_PER_FOGKILL" || + sAOETag == "VFX_PER_FOGBEWILDERMENT" || + sAOETag == "VFX_PER_FOGSTINK" || + sAOETag == "VFX_PER_FOGFIRE" || + sAOETag == "VFX_PER_FOGMIND" || + sAOETag == "VFX_PER_CREEPING_DOOM") + { + DestroyObject(oTarget); + } + } + else + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, PRCGetSpellId())); + //Get the distance between the explosion and the target to calculate delay + fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oTarget))/20; + + // * unlocked doors will reverse their open state + if (GetObjectType(oTarget) == OBJECT_TYPE_DOOR) + { + if (GetLocked(oTarget) == FALSE) + { + if (GetIsOpen(oTarget) == FALSE) + { + AssignCommand(oTarget, ActionOpenDoor(oTarget)); + } + else + AssignCommand(oTarget, ActionCloseDoor(oTarget)); + } + } + int nDC = PRCGetSaveDC(oTarget,OBJECT_SELF); + if(!PRCDoResistSpell(OBJECT_SELF, oTarget,nCasterLvl) + && !/*Fort Save*/ PRCMySavingThrow(SAVING_THROW_FORT, oTarget, (nDC))) + { + + effect eKnockdown = EffectKnockdown(); + SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eKnockdown, oTarget, RoundsToSeconds(3),TRUE,-1,CasterLvl); + // Apply effects to the currently selected target. + // DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + //This visual effect is applied to the target object not the location as above. This visual effect + //represents the flame that erupts on the target not on the ground. + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + + } + } + } + //Select the next target within the spell shape. + oTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE |OBJECT_TYPE_AREA_OF_EFFECT); + } + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Erasing the variable used to store the spell's spell school +} + + + + + + + + + diff --git a/src/hakpak/ghost_prc8_top/nss/x0_s0_inferno.nss b/src/hakpak/ghost_prc8_top/nss/x0_s0_inferno.nss new file mode 100644 index 0000000..4f84b2e --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/x0_s0_inferno.nss @@ -0,0 +1,155 @@ +//:://///////////////////////////////////////////// +//:: Inferno +//:: x0_s0_inferno.nss +//:: Copyright (c) 2000 Bioware Corp. +//::////////////////////////////////////////////// +/* + Does 2d6 fire per round + Duration: 1 round per level +*/ +//::////////////////////////////////////////////// +//:: Created By: Aidan Scanlan +//:: Created On: 01/09/01 +//::////////////////////////////////////////////// +//:: Rewritten: Georg Zoeller, 2003-Oct-19 +//:: - VFX update +//:: - Spell no longer stacks with itself +//:: - Spell can now be dispelled +//:: - Spell is now much less cpu expensive + +//:: altered by mr_bumpkin Dec 4, 2003 for prc stuff +#include "prc_inc_spells" +#include "prc_alterations" +#include "prc_add_spell_dc" + +void RunImpact(object oTarget, object oCaster, int nMetamagic,int EleDmg); + +void main() +{ + + DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); + SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_TRANSMUTATION); + + object oCaster = OBJECT_SELF; + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Inferno' will not work underwater!", oPC); + return; + } + + object oTarget = PRCGetSpellTargetObject(); + + //-------------------------------------------------------------------------- + // Spellcast Hook Code + // Added 2003-06-20 by Georg + // If you want to make changes to all spells, check x2_inc_spellhook.nss to + // find out more + //-------------------------------------------------------------------------- + if (!X2PreSpellCastCode()) + { + return; + } + // End of Spell Cast Hook + + //-------------------------------------------------------------------------- + // This spell no longer stacks. If there is one of that type, thats ok + //-------------------------------------------------------------------------- + if (GetHasSpellEffect(GetSpellId(),oTarget) || GetHasSpellEffect(SPELL_COMBUST,oTarget)) + { + FloatingTextStrRefOnCreature(100775,OBJECT_SELF,FALSE); + return; + } + + //-------------------------------------------------------------------------- + // Calculate the duration + //-------------------------------------------------------------------------- + int nMetaMagic = PRCGetMetaMagicFeat(); + int CasterLvl = PRCGetCasterLevel(OBJECT_SELF); + int EleDmg = ChangedElementalDamage(OBJECT_SELF, DAMAGE_TYPE_FIRE); + + int nDuration = CasterLvl ; + int nPenetr = CasterLvl + SPGetPenetr(); + + if ((nMetaMagic & METAMAGIC_EXTEND)) + { + nDuration = nDuration * 2; + } + + if (nDuration < 1) + { + nDuration = 1; + } + + //-------------------------------------------------------------------------- + // Flamethrower VFX, thanks to Alex + //-------------------------------------------------------------------------- + effect eRay = EffectBeam(444,OBJECT_SELF,BODY_NODE_CHEST); + effect eDur = EffectVisualEffect(498); + + + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + + float fDelay = GetDistanceBetween(oTarget, OBJECT_SELF)/13; + + if(!PRCDoResistSpell(OBJECT_SELF, oTarget,nPenetr)) + { + //---------------------------------------------------------------------- + // Engulf the target in flame + //---------------------------------------------------------------------- + SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eRay, oTarget, 3.0f,FALSE); + + + //---------------------------------------------------------------------- + // Apply the VFX that is used to track the spells duration + //---------------------------------------------------------------------- + DelayCommand(fDelay,SPApplyEffectToObject(DURATION_TYPE_TEMPORARY,eDur,oTarget,RoundsToSeconds(nDuration),FALSE)); + object oSelf = OBJECT_SELF; // because OBJECT_SELF is a function + DelayCommand(fDelay+0.1f,RunImpact(oTarget, oSelf,nMetaMagic,EleDmg)); + } + else + { + //---------------------------------------------------------------------- + // Indicate Failure + //---------------------------------------------------------------------- + SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eRay, oTarget, 2.0f,FALSE); + effect eSmoke = EffectVisualEffect(VFX_IMP_REFLEX_SAVE_THROW_USE); + DelayCommand(fDelay+0.3f,SPApplyEffectToObject(DURATION_TYPE_INSTANT,eSmoke,oTarget)); + } + +} + + +void RunImpact(object oTarget, object oCaster, int nMetaMagic,int EleDmg) +{ + //-------------------------------------------------------------------------- + // Check if the spell has expired (check also removes effects) + //-------------------------------------------------------------------------- + if (PRCGetDelayedSpellEffectsExpired(446,oTarget,oCaster)) + { + return; + } + + if (GetIsDead(oTarget) == FALSE) + { + //---------------------------------------------------------------------- + // Calculate Damage + //---------------------------------------------------------------------- + int nDamage = PRCMaximizeOrEmpower(6,2,nMetaMagic); + nDamage += SpellDamagePerDice(oCaster, 2); + //nDamage += ApplySpellBetrayalStrikeDamage(oTarget, OBJECT_SELF, FALSE); + effect eDam = PRCEffectDamage(oTarget, nDamage, EleDmg); + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_S); + eDam = EffectLinkEffects(eVis,eDam); // flare up + SPApplyEffectToObject (DURATION_TYPE_INSTANT,eDam,oTarget); + DelayCommand(6.0f,RunImpact(oTarget,oCaster,nMetaMagic,EleDmg)); + } + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Erasing the variable used to store the spell's spell school +} + diff --git a/src/hakpak/ghost_prc8_top/nss/x0_s0_ironhorn.nss b/src/hakpak/ghost_prc8_top/nss/x0_s0_ironhorn.nss new file mode 100644 index 0000000..172441a --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/x0_s0_ironhorn.nss @@ -0,0 +1,178 @@ +//:://///////////////////////////////////////////// +//:: Balagarn's Iron Horn +//:: +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* +// Create a virbration that shakes creatures off their feet. +// Make a strength check as if caster has strength 20 +// against all enemies in area +// Changes it so its not a cone but a radius. +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 22 2002 +//::////////////////////////////////////////////// +//:: Last Updated By: Andrew Nobbs May 01, 2003 + + +//:: altered by mr_bumpkin Dec 4, 2003 for prc stuff +#include "prc_inc_spells" + +#include "prc_alterations" + +#include "prc_add_spell_dc" + +void main() +{ +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_TRANSMUTATION); +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + object oPC = GetFirstPC(); + object oCaster = OBJECT_SELF; + int nInt=GetLocalInt(oPC, "Underwater"); + int CasterLvl = PRCGetCasterLevel(OBJECT_SELF); + int nCasterLvl = CasterLvl; + int nPenetr = CasterLvl + SPGetPenetr(); + + int nMetaMagic = PRCGetMetaMagicFeat(); + float fDelay; + float nSize = RADIUS_SIZE_COLOSSAL; + effect eExplode = EffectVisualEffect(VFX_FNF_HOWL_WAR_CRY); + effect eVis = EffectVisualEffect(VFX_IMP_HEAD_NATURE); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_BUMP); + //Get the spell target location as opposed to the spell target. + location lTarget = PRCGetSpellTargetLocation(); + //Limit Caster level for the purposes of damage + if (nCasterLvl > 20) + { + nCasterLvl = 20; + } + SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eShake, OBJECT_SELF, RoundsToSeconds(d3()),TRUE,-1,CasterLvl); + //Apply epicenter explosion on caster + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, GetLocation(OBJECT_SELF)); + //Declare the spell shape, size and the location. Capture the first target object in the shape. + object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, nSize, lTarget, TRUE, OBJECT_TYPE_CREATURE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget)) + { + // * spell should not affect the caster + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF) && (oTarget != oCaster)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, 436)); + //Get the distance between the explosion and the target to calculate delay + fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oTarget))/20; + if (!PRCDoResistSpell(OBJECT_SELF, oTarget,nPenetr, fDelay)) + { + effect eTrip = EffectKnockdown(); + // * DO a strength check vs. Strength 20 + if (d20() + GetAbilityScore(oTarget, ABILITY_STRENGTH) <= 20 + d20() ) + { //Apply the VFX impact and damage effect (reflected upon PC) + if (nInt == 1) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eTrip, oCaster, 6.0)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oCaster)); + FloatingTextStringOnCreature("The spell 'Balagarn's Iron Horn' is reflected underwater!", oPC); + } + // Apply effects to the currently selected target. + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eTrip, oTarget, 6.0,TRUE,-1,CasterLvl)); + //This visual effect is applied to the target object not the location as above. This visual effect + //represents the flame that erupts on the target not on the ground. + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + else + FloatingTextStrRefOnCreature(2750, OBJECT_SELF, FALSE); + } + } + //Select the next target within the spell shape. + oTarget = MyNextObjectInShape(SHAPE_SPHERE, nSize, lTarget, TRUE, OBJECT_TYPE_CREATURE); + } + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Erasing the variable used to store the spell's spell school +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Balagarn's Iron Horn' has caused a cave-in!", oPC)); + } +} + + + + + + + diff --git a/src/hakpak/ghost_prc8_top/nss/x0_s0_sunburst.nss b/src/hakpak/ghost_prc8_top/nss/x0_s0_sunburst.nss new file mode 100644 index 0000000..1db1b6f --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/x0_s0_sunburst.nss @@ -0,0 +1,244 @@ +//:://///////////////////////////////////////////// +//:: Sunburst +//:: X0_S0_Sunburst +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* +// Brilliant globe of heat +// All creatures in the globe are blinded and +// take 6d6 damage +// Undead creatures take 1d6 damage (max 25d6) +// The blindness is permanent unless cast to remove it +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 23 2002 +//::////////////////////////////////////////////// +//:: Last Updated By: Andrew Nobbs May 14, 2003 +//:: Notes: Changed damage to non-undead to 6d6 +//:: 2003-10-09: GZ Added Subrace check for vampire special case, bugfix + + +//:: altered by mr_bumpkin Dec 4, 2003 for prc stuff +#include "prc_inc_spells" + + +#include "prc_add_spell_dc" + +float nSize = RADIUS_SIZE_COLOSSAL; + + + +void main() +{ +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_EVOCATION); + + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + object oCaster = OBJECT_SELF; + //Spell fails if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Sunburst' will not work underwater!", oPC); + return; + } + +/* + Spellcast Hook Code + Added 2003-06-20 by Georg + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables + + int CasterLvl = PRCGetCasterLevel(OBJECT_SELF); + + + int nCasterLvl = CasterLvl; + int nMetaMagic = PRCGetMetaMagicFeat(); + int nDamage = 0; + float fDelay; + effect eExplode = EffectVisualEffect(VFX_IMP_SUNSTRIKE); + effect eVis = EffectVisualEffect(VFX_IMP_HEAD_HOLY); + effect eHitVis = EffectVisualEffect(VFX_IMP_DIVINE_STRIKE_FIRE); + effect eLOS = EffectVisualEffect(VFX_FNF_LOS_HOLY_30); + effect eDam; + //Get the spell target location as opposed to the spell target. + location lTarget = PRCGetSpellTargetLocation(); + //Limit Caster level for the purposes of damage + if (nCasterLvl > 25) + { + nCasterLvl = 25; + } + int nPenetr = CasterLvl + SPGetPenetr(); + + SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, OBJECT_SELF); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eLOS, PRCGetSpellTargetLocation()); + int bDoNotDoDamage = FALSE; + + + //Declare the spell shape, size and the location. Capture the first target object in the shape. + object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, nSize, lTarget, TRUE, OBJECT_TYPE_CREATURE); + //Cycle through the targets within the spell shape until an invalid object is captured. + while (GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, OBJECT_SELF)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_SUNBURST)); + //This visual effect is applied to the target object not the location as above. This visual effect + //represents the flame that erupts on the target not on the ground. + SPApplyEffectToObject(DURATION_TYPE_INSTANT, eHitVis, oTarget); + + if (!PRCDoResistSpell(OBJECT_SELF, oTarget,nPenetr, fDelay)) + { + if (MyPRCGetRacialType(oTarget) == RACIAL_TYPE_UNDEAD) + { + //Roll damage for each target + nDamage = PRCMaximizeOrEmpower(6, nCasterLvl, nMetaMagic); + nDamage += SpellDamagePerDice(oCaster, nCasterLvl); + } + else + { + nDamage = PRCMaximizeOrEmpower(6, 6, nMetaMagic); + nDamage += SpellDamagePerDice(oCaster, 6); + } + + //nDamage += ApplySpellBetrayalStrikeDamage(oTarget, OBJECT_SELF, FALSE); + int nDC = PRCGetSaveDC(oTarget,OBJECT_SELF); + + // * if a vampire then destroy it + if (GetAppearanceType(oTarget) == APPEARANCE_TYPE_VAMPIRE_MALE || GetAppearanceType(oTarget) == APPEARANCE_TYPE_VAMPIRE_FEMALE || GetStringLowerCase(GetSubRace(oTarget)) == "vampire" ) + { + // SpeakString("I vampire"); + // * if reflex saving throw fails no blindness + if (!ReflexSave(oTarget, (nDC), SAVING_THROW_TYPE_SPELL)) + { + effect eDead = PRCEffectDamage(oTarget, GetCurrentHitPoints(oTarget)); + //SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_FLAME_M), oTarget); + + //Apply epicenter explosion on caster + SPApplyEffectToObject(DURATION_TYPE_INSTANT, eExplode, oTarget); + + DelayCommand(0.5, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDead, oTarget)); + bDoNotDoDamage = TRUE; + } + } + if (bDoNotDoDamage == FALSE) + //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. + nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, PRCGetSaveDC(oTarget, OBJECT_SELF), SAVING_THROW_TYPE_SPELL); + + // * Do damage + if ((nDamage > 0) && (bDoNotDoDamage == FALSE)) + { + //Set the damage effect + eDam = PRCEffectDamage(oTarget, nDamage, DAMAGE_TYPE_MAGICAL); + + // Apply effects to the currently selected target. + DelayCommand(0.01, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + PRCBonusDamage(oTarget); + + + + // * if reflex saving throw fails apply blindness + if (!ReflexSave(oTarget, PRCGetSaveDC(oTarget, OBJECT_SELF), SAVING_THROW_TYPE_SPELL)) + { + effect eBlindness = EffectBlindness(); + SPApplyEffectToObject(DURATION_TYPE_PERMANENT, eBlindness, oTarget,0.0f,TRUE,-1,CasterLvl); + } + + } // nDamage > 0 + } + + //----------------------------------------------------------------- + // GZ: Bugfix, reenable damage for next object + //----------------------------------------------------------------- + bDoNotDoDamage = FALSE; + } + //Select the next target within the spell shape. + oTarget = MyNextObjectInShape(SHAPE_SPHERE, nSize, lTarget, TRUE, OBJECT_TYPE_CREATURE); + } + + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Erasing the variable used to store the spell's spell school +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Sunburst' has caused a cave-in!", oPC)); + } +} + + + + + diff --git a/src/hakpak/ghost_prc8_top/nss/x2_s0_combust.nss b/src/hakpak/ghost_prc8_top/nss/x2_s0_combust.nss new file mode 100644 index 0000000..674758e --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/x2_s0_combust.nss @@ -0,0 +1,156 @@ +/* + x2_s0_combust + + The initial eruption of flame causes 2d6 fire damage +1 + point per caster level(maximum +10) + with no saving throw. + + Further, the creature must make + a Reflex save or catch fire taking a further 1d6 points + of damage. This will continue until the Reflex save is + made. + + There is an undocumented artificial limit of + 10 + casterlevel rounds on this spell to prevent + it from running indefinitly when used against + fire resistant creatures with bad saving throws + + By: Georg Zoeller + Created: 2003/09/05 + Modified: Jun 30, 2006 +*/ + +#include "prc_sp_func" +#include "x2_inc_toollib" +#include "prc_add_spell_dc" +void RunCombustImpact(object oTarget, object oCaster, int nLevel, int nMetaMagic,int EleDmg) +{ + if (PRCGetDelayedSpellEffectsExpired(SPELL_COMBUST,oTarget,oCaster)) return; + + if (GetIsDead(oTarget) == FALSE) + { + int nDC = GetLocalInt(oTarget,"XP2_L_SPELL_SAVE_DC_" + IntToString (SPELL_COMBUST)); + if(!PRCMySavingThrow(SAVING_THROW_REFLEX, oTarget, nDC, SAVING_THROW_TYPE_FIRE)) + { + int nDamageLimit = nLevel; + if (nDamageLimit > 10) nDamageLimit = 10; + int nDamage = nDamageLimit + d6(); + if ((nMetaMagic & METAMAGIC_MAXIMIZE)) + { + nDamage = nDamageLimit + 6; + } + if ((nMetaMagic & METAMAGIC_EMPOWER)) + { + nDamage = nDamage + (nDamage/2); + } + nDamage += SpellDamagePerDice(oCaster, nDamageLimit); + effect eDmg = PRCEffectDamage(oTarget, nDamage,EleDmg); + effect eVFX = EffectVisualEffect(VFX_IMP_FLAME_S); + + SPApplyEffectToObject(DURATION_TYPE_INSTANT,eDmg,oTarget); + PRCBonusDamage(oTarget); + SPApplyEffectToObject(DURATION_TYPE_INSTANT,eVFX,oTarget); + + DelayCommand(6.0f,RunCombustImpact(oTarget,oCaster, nLevel,nMetaMagic,EleDmg)); + } + else + { + DeleteLocalInt(oTarget,"XP2_L_SPELL_SAVE_DC_" + IntToString (SPELL_COMBUST)); + GZPRCRemoveSpellEffects(SPELL_COMBUST, oTarget); + } + } +} + +//Implements the spell impact, put code here +// if called in many places, return TRUE if +// stored charges should be decreased +// eg. touch attack hits +// +// Variables passed may be changed if necessary +int DoSpell(object oCaster, object oTarget, int nCasterLevel, int nEvent) +{ + int nDC = (PRCGetSaveDC(oTarget,oCaster)); + int EleDmg = ChangedElementalDamage(oCaster, DAMAGE_TYPE_FIRE); + int nDamageLimit = nCasterLevel; + if (nDamageLimit > 10) + { + nDamageLimit = 10; + } + int nDamage = nDamageLimit + d6(2); + int nMetaMagic = PRCGetMetaMagicFeat(); + if ((nMetaMagic & METAMAGIC_MAXIMIZE)) + { + nDamage = nDamageLimit + 12;//Damage is at max + } + if ((nMetaMagic & METAMAGIC_EMPOWER)) + { + nDamage += nDamage / 2;//Damage/Healing is +50% + } + nDamage += SpellDamagePerDice(oCaster, nDamageLimit); + //nDamage += ApplySpellBetrayalStrikeDamage(oTarget, OBJECT_SELF); + int nDuration = 10 + nCasterLevel; + if (nDuration < 1) + { + nDuration = 10; + } + effect eDam = PRCEffectDamage(oTarget, nDamage, EleDmg); + effect eDur = EffectVisualEffect(498); + + if(!GetIsReactionTypeFriendly(oTarget)) + { + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_COMBUST)); + if(!PRCDoResistSpell(OBJECT_SELF, oTarget,nCasterLevel+SPGetPenetr())) + { + SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); + TLVFXPillar(VFX_IMP_FLAME_M, GetLocation(oTarget), 5, 0.1f,0.0f, 2.0f); + if (GetHasSpellEffect(GetSpellId(),oTarget) || GetHasSpellEffect(SPELL_INFERNO,oTarget) ) + { + FloatingTextStrRefOnCreature(100775,oCaster,FALSE); + return TRUE; + } + SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDur, oTarget, RoundsToSeconds(nDuration)); + SetLocalInt(oTarget,"XP2_L_SPELL_SAVE_DC_" + IntToString (SPELL_COMBUST), nDC); + DelayCommand(6.0, RunCombustImpact(oTarget,oCaster,nCasterLevel, nMetaMagic,EleDmg)); + } + } + + return TRUE; //return TRUE if spell charges should be decremented +} + +void main() +{ + object oPC = GetFirstPC(); + object oCaster = OBJECT_SELF; + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Spell will fail if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Combust' will not work underwater!", oPC); + return; + } + int nCasterLevel = PRCGetCasterLevel(oCaster); + PRCSetSchool(GetSpellSchool(PRCGetSpellId())); + if (!X2PreSpellCastCode()) return; + object oTarget = PRCGetSpellTargetObject(); + int nEvent = GetLocalInt(oCaster, PRC_SPELL_EVENT); //use bitwise & to extract flags + if(!nEvent) //normal cast + { + if(GetLocalInt(oCaster, PRC_SPELL_HOLD) && oCaster == oTarget) + { //holding the charge, casting spell on self + SetLocalSpellVariables(oCaster, 1); //change 1 to number of charges + return; + } + DoSpell(oCaster, oTarget, nCasterLevel, nEvent); + } + else + { + if(nEvent & PRC_SPELL_EVENT_ATTACK) + { + if(DoSpell(oCaster, oTarget, nCasterLevel, nEvent)) + DecrementSpellCharges(oCaster); + } + } + PRCSetSchool(); +} \ No newline at end of file diff --git a/src/hakpak/ghost_prc8_top/nss/x2_s0_elecloop.nss b/src/hakpak/ghost_prc8_top/nss/x2_s0_elecloop.nss new file mode 100644 index 0000000..03cc847 --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/x2_s0_elecloop.nss @@ -0,0 +1,174 @@ +//:://///////////////////////////////////////////// +//:: Gedlee's Electric Loop +//:: X2_S0_ElecLoop +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + You create a small stroke of lightning that + cycles through all creatures in the area of effect. + The spell deals 1d6 points of damage per 2 caster + levels (maximum 5d6). Those who fail their Reflex + saves must succeed at a Will save or be stunned + for 1 round. + + Spell is standard hostile, so if you use it + in hardcore mode, it will zap yourself! + +*/ +//::////////////////////////////////////////////// +//:: Created By: Georg Zoeller +//:: Created On: Oct 19 2003 +//::////////////////////////////////////////////// + +//:: modified by mr_bumpkin Dec 4, 2003 for prc stuff +#include "prc_inc_spells" + + + +#include "prc_add_spell_dc" + + +void main() +{ +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_EVOCATION); + + //-------------------------------------------------------------------------- + // Spellcast Hook Code + // Added 2003-06-20 by Georg + // If you want to make changes to all spells, check x2_inc_spellhook.nss to + // find out more + //-------------------------------------------------------------------------- + if (!X2PreSpellCastCode()) + { + return; + } + // End of Spell Cast Hook + + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + object oCaster = OBJECT_SELF; + + location lTarget = PRCGetSpellTargetLocation(); + effect eStrike = EffectVisualEffect(VFX_IMP_LIGHTNING_S); + int nMetaMagic = PRCGetMetaMagicFeat(); + float fDelay; + effect eBeam; + int nDamage; + int nPotential; + effect eDam; + object oLastValid; + effect eStun = EffectLinkEffects(EffectVisualEffect(VFX_IMP_STUN),EffectStunned()); + + //-------------------------------------------------------------------------- + // Calculate Damage Dice. 1d per 2 caster levels, max 5d + //-------------------------------------------------------------------------- + int CasterLvl = PRCGetCasterLevel(OBJECT_SELF); + + + + int EleDmg = ChangedElementalDamage(OBJECT_SELF, DAMAGE_TYPE_ELECTRICAL); + + int nNumDice = CasterLvl/2; + if (nNumDice<1) + { + nNumDice = 1; + } + else if (nNumDice >5) + { + nNumDice = 5; + } + + CasterLvl +=SPGetPenetr(); + + //-------------------------------------------------------------------------- + // Loop through all targets + //-------------------------------------------------------------------------- + + object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_SMALL, lTarget, TRUE, OBJECT_TYPE_CREATURE); + while (GetIsObjectValid(oTarget)) + { + if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, PRCGetSpellId())); + + //------------------------------------------------------------------ + // Calculate delay until spell hits current target. If we are the + // first target, the delay is the time until the spell hits us + //------------------------------------------------------------------ + if (GetIsObjectValid(oLastValid)) + { + fDelay += 0.2f; + fDelay += GetDistanceBetweenLocations(GetLocation(oLastValid), GetLocation(oTarget))/20; + } + else + { + fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oTarget))/20; + } + + //------------------------------------------------------------------ + // If there was a previous target, draw a lightning beam between us + // and iterate delay so it appears that the beam is jumping from + // target to target + //------------------------------------------------------------------ + if (GetIsObjectValid(oLastValid)) + { + eBeam = EffectBeam(VFX_BEAM_LIGHTNING, oLastValid, BODY_NODE_CHEST); + DelayCommand(fDelay,SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBeam,oTarget,1.5f)); + } + + if (!PRCDoResistSpell(OBJECT_SELF, oTarget,CasterLvl, fDelay)) + { + + int nDC = PRCGetSaveDC(oTarget,OBJECT_SELF); + nPotential = PRCMaximizeOrEmpower(6, nNumDice, nMetaMagic); + nPotential += SpellDamagePerDice(OBJECT_SELF, nNumDice); + //nPotential += ApplySpellBetrayalStrikeDamage(oTarget, OBJECT_SELF); + nDamage = PRCGetReflexAdjustedDamage(nPotential, oTarget, (nDC), SAVING_THROW_TYPE_ELECTRICITY); + + //-------------------------------------------------------------- + // If we failed the reflex save, we save vs will or are stunned + // for one round + //-------------------------------------------------------------- + if (nPotential == nDamage || (GetHasFeat(FEAT_IMPROVED_EVASION,oTarget) && nDamage == (nPotential/2))) + { + if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, (nDC), SAVING_THROW_TYPE_MIND_SPELLS, OBJECT_SELF, fDelay)) + { + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY,eStun,oTarget, RoundsToSeconds(1))); + } + + } + + + if (nDamage >0) + { + eDam = PRCEffectDamage(oTarget, nDamage, EleDmg); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); + PRCBonusDamage(oTarget); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eStrike, oTarget)); + //Apply the VFX impact and damage effect (reflected upon PC) + if (nInt == 1) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT,eDam,oCaster)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT,eStrike,oCaster)); + FloatingTextStringOnCreature("The spell 'Gedlee's Electric Loop' is reflected underwater!", oPC); + } + } + } + + //------------------------------------------------------------------ + // Store Target to make it appear that the lightning bolt is jumping + // from target to target + //------------------------------------------------------------------ + oLastValid = oTarget; + + } + oTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_SMALL, lTarget, TRUE, OBJECT_TYPE_CREATURE ); + } + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Erasing the variable used to store the spell's spell school + +} + + diff --git a/src/hakpak/ghost_prc8_top/nss/x2_s0_grtthdclp.nss b/src/hakpak/ghost_prc8_top/nss/x2_s0_grtthdclp.nss new file mode 100644 index 0000000..2a7f71b --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/x2_s0_grtthdclp.nss @@ -0,0 +1,116 @@ +//:://///////////////////////////////////////////// +//:: Great Thunderclap +//:: X2_S0_GrtThdclp +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* +// You create a loud noise equivalent to a peal of +// thunder and its acommpanying shock wave. The +// spell has three effects. First, all creatures +// in the area must make Will saves to avoid being +// stunned for 1 round. Second, the creatures must +// make Fortitude saves or be deafened for 1 minute. +// Third, they must make Reflex saves or fall prone. +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: Nov 20, 2002 +//:: Updated On: Oct 20, 2003 - some nice Vfx:) +//::////////////////////////////////////////////// + +//:: altered by mr_bumpkin Dec 4, 2003 for prc stuff +#include "prc_inc_spells" + + + + +#include "prc_add_spell_dc" + +void main() +{ +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_EVOCATION); + /* + Spellcast Hook Code + Added 2003-07-07 by Georg Zoeller + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + + */ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + + // End of Spell Cast Hook + + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + object oCaster = OBJECT_SELF; + + int nDamage = 0; + + float fDelay; + effect eExplode = EffectVisualEffect(VFX_FNF_MYSTICAL_EXPLOSION); + effect eVis = EffectVisualEffect(VFX_IMP_SONIC); + effect eVis2 = EffectVisualEffect(VFX_IMP_BLIND_DEAF_M); + effect eVis3 = EffectVisualEffect(VFX_IMP_STUN); + effect eDeaf = EffectDeaf(); + effect eKnock = EffectKnockdown(); + effect eStun = EffectStunned(); + effect eShake = EffectVisualEffect(356); + + location lTarget = PRCGetSpellTargetLocation(); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, lTarget); + SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eShake, OBJECT_SELF, 2.0f); + object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_GARGANTUAN, lTarget, TRUE, OBJECT_TYPE_CREATURE); + while (GetIsObjectValid(oTarget)) + { + if(spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF) && oTarget != OBJECT_SELF) + { + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, PRCGetSpellId())); + + //Get the distance between the explosion and the target to calculate delay + fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oTarget))/20; + + int nDC = PRCGetSaveDC(oTarget,OBJECT_SELF); + + //should not work on creatures already deafened + if(!PRCGetHasEffect(EFFECT_TYPE_DEAF, oTarget) && !PRCGetHasEffect(EFFECT_TYPE_SILENCE, oTarget)) + { + if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_SONIC)) + { + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDeaf, oTarget, RoundsToSeconds(10))); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis2, oTarget)); + + //Apply the VFX impact and damage effect (reflected upon PC) + if (nInt == 1) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eDeaf,oCaster, RoundsToSeconds(10))); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT,eVis2,oCaster)); + FloatingTextStringOnCreature("The spell 'Great Thunderclap' is reflected underwater!", oPC); + } + } + if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_SONIC)) + { + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eStun, oTarget, RoundsToSeconds(1))); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + } + } + if(!PRCMySavingThrow(SAVING_THROW_REFLEX, oTarget, nDC, SAVING_THROW_TYPE_SONIC)) + { + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eKnock, oTarget, 6.0f)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eVis3, oTarget,4.0f)); + } + } + + oTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_GARGANTUAN, lTarget, TRUE, OBJECT_TYPE_CREATURE); + } + + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Erasing the variable used to store the spell's spell school +} + diff --git a/src/hakpak/ghost_prc8_top/nss/x2_s0_hellinfern.nss b/src/hakpak/ghost_prc8_top/nss/x2_s0_hellinfern.nss new file mode 100644 index 0000000..1704bd3 --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/x2_s0_hellinfern.nss @@ -0,0 +1,151 @@ +//:://///////////////////////////////////////////// +//:: Hellish Inferno +//:: x0_s0_inferno.nss +//:: Copyright (c) 2000 Bioware Corp. +//::////////////////////////////////////////////// +/* + NPC only spell for yaron + + like normal inferno but lasts only 5 rounds, + ticks twice per round, adds attack and damage + penalty. + +*/ +//::////////////////////////////////////////////// +// Georg Z, 19-10-2003 +//::////////////////////////////////////////////// + +//:: altered by mr_bumpkin Dec 4, 2003 for prc stuff +#include "prc_inc_spells" +#include "prc_alterations" +#include "prc_add_spell_dc" + + +void RunImpact(object oTarget, object oCaster); + +void main() +{ + object oPC = GetFirstPC(); + object oCaster = OBJECT_SELF; + int nInt=GetLocalInt(oPC, "Underwater"); + effect eFail = SupernaturalEffect(EffectSpellFailure()); + //Spell will fail if caster is underwater. + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eFail,oCaster,0.1); + FloatingTextStringOnCreature("The spell 'Hellish Inferno' will not work underwater!", oPC); + return; + } + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_EVOCATION); + + object oTarget = PRCGetSpellTargetObject(); + + //-------------------------------------------------------------------------- + // Spellcast Hook Code + // Added 2003-06-20 by Georg + // If you want to make changes to all spells, check x2_inc_spellhook.nss to + // find out more + //-------------------------------------------------------------------------- + if (!X2PreSpellCastCode()) + { + return; + } + // End of Spell Cast Hook + + //-------------------------------------------------------------------------- + // This spell no longer stacks. If there is one hand, that's enough + //-------------------------------------------------------------------------- + if (GetHasSpellEffect(GetSpellId(),oTarget)) + { + FloatingTextStrRefOnCreature(100775,OBJECT_SELF,FALSE); + return; + } + + //-------------------------------------------------------------------------- + // Calculate the duration + //-------------------------------------------------------------------------- + int nMetaMagic = PRCGetMetaMagicFeat(); + int CasterLvl = PRCGetCasterLevel(OBJECT_SELF); + + int nDuration = CasterLvl/2; + + if (CheckMetaMagic(nMetaMagic, METAMAGIC_EXTEND)) + { + nDuration = nDuration * 2; + } + if (nDuration < 1) + { + nDuration = 1; + } + if (nDuration >6) + { + nDuration= 6; + } + + CasterLvl +=SPGetPenetr(); + + //-------------------------------------------------------------------------- + // Flamethrower VFX, thanks to Alex + //-------------------------------------------------------------------------- + effect eRay = EffectBeam(444,OBJECT_SELF,BODY_NODE_CHEST); + + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId())); + + float fDelay = GetDistanceBetween(oTarget, OBJECT_SELF)/13; + + if(!PRCDoResistSpell(OBJECT_SELF, oTarget,CasterLvl)) + { + //---------------------------------------------------------------------- + // Engulf the target in flame + //---------------------------------------------------------------------- + SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eRay, oTarget, 3.0f); + effect eAttackDec = EffectAttackDecrease(4); + effect eDamageDec = EffectDamageDecrease(4, DAMAGE_TYPE_BLUDGEONING|DAMAGE_TYPE_PIERCING|DAMAGE_TYPE_SLASHING); + effect eLink = EffectLinkEffects(eAttackDec, eDamageDec); + effect eDur = EffectVisualEffect(498); + SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration)); + DelayCommand(fDelay,SPApplyEffectToObject(DURATION_TYPE_TEMPORARY,eDur,oTarget,RoundsToSeconds(nDuration))); + object oSelf = OBJECT_SELF; // because OBJECT_SELF is a function + DelayCommand(fDelay,RunImpact(oTarget, oSelf)); + } + else + { + //---------------------------------------------------------------------- + // Indicate Failure + //---------------------------------------------------------------------- + SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eRay, oTarget, 2.0f); + effect eSmoke = EffectVisualEffect(VFX_IMP_REFLEX_SAVE_THROW_USE); + DelayCommand(fDelay+0.3f,SPApplyEffectToObject(DURATION_TYPE_INSTANT,eSmoke,oTarget)); + } + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Erasing the variable used to store the spell's spell school + +} + + +void RunImpact(object oTarget, object oCaster) +{ + //-------------------------------------------------------------------------- + // Check if the spell has expired (check also removes effects) + //-------------------------------------------------------------------------- + if (PRCGetDelayedSpellEffectsExpired(762,oTarget,oCaster)) + { + return; + } + + if (GetIsDead(oTarget) == FALSE) + { + //* GZ: Removed Meta magic, does not work in delayed functions + effect eDam = PRCEffectDamage(oTarget, d6(2), ChangedElementalDamage(oCaster, DAMAGE_TYPE_FIRE)); + effect eDam2 = PRCEffectDamage(oTarget, d6(1), DAMAGE_TYPE_DIVINE); + effect eVis = EffectVisualEffect(VFX_IMP_FLAME_S); + eDam = EffectLinkEffects(eVis,eDam); // flare up + SPApplyEffectToObject (DURATION_TYPE_INSTANT,eDam,oTarget); + SPApplyEffectToObject (DURATION_TYPE_INSTANT,eDam2,oTarget); + DelayCommand(3.0f,RunImpact(oTarget,oCaster)); + } +} + diff --git a/src/hakpak/ghost_prc8_top/nss/x2_s0_horiboom.nss b/src/hakpak/ghost_prc8_top/nss/x2_s0_horiboom.nss new file mode 100644 index 0000000..46059a5 --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/x2_s0_horiboom.nss @@ -0,0 +1,186 @@ +//:://///////////////////////////////////////////// +//:: Horizikaul's Boom +//:: X2_S0_HoriBoom +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* +// You blast the target with loud and high-pitched +// sounds. The target takes 1d4 points of sonic +// damage per two caster levels (maximum 5d4) and +// must make a Will save or be deafened for 1d4 +// rounds. +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: Nov 22, 2002 +//::////////////////////////////////////////////// +//:: Last Updated By: Andrew Nobbs, 02/06/2003 + + +//:: altered by mr_bumpkin Dec 4, 2003 for prc stuff +#include "prc_inc_spells" + + + +#include "prc_add_spell_dc" + +void main() +{ +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_EVOCATION); +/* + Spellcast Hook Code + Added 2003-07-07 by Georg Zoeller + If you want to make changes to all spells, + check x2_inc_spellhook.nss to find out more + +*/ + + if (!X2PreSpellCastCode()) + { + // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell + return; + } + +// End of Spell Cast Hook + + + //Declare major variables ( fDist / (3.0f * log( fDist ) + 2.0f) ) + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + object oCaster = OBJECT_SELF; + object oTarget = PRCGetSpellTargetObject(); + int CasterLvl = PRCGetCasterLevel(OBJECT_SELF); + + int nCasterLvl = CasterLvl/2; + int nRounds = d4(1); + int nMetaMagic = PRCGetMetaMagicFeat(); + effect eVis = EffectVisualEffect(VFX_IMP_SONIC); + effect eDeaf = EffectDeaf(); + effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); + effect eLink = EffectLinkEffects(eDeaf, eDur); + + //Minimum caster level of 1, maximum of 15. + if(nCasterLvl == 0) + { + nCasterLvl = 1; + } + else if (nCasterLvl > 5) + { + nCasterLvl = 5; + } + + CasterLvl +=SPGetPenetr(); + + if(spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF)) + { + if(!PRCDoResistSpell(OBJECT_SELF, oTarget,CasterLvl)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_HORIZIKAULS_BOOM)); + //Roll damage + int nDam = d4(nCasterLvl); + //Enter Metamagic conditions + if ((nMetaMagic & METAMAGIC_MAXIMIZE)) + { + nDam = 4 * nCasterLvl; //Damage is at max + } + if ((nMetaMagic & METAMAGIC_EMPOWER)) + { + nDam = nDam + nDam/2; //Damage/Healing is +50% + } + if(nMetaMagic & METAMAGIC_EXTEND) + { + nRounds *= 2; + } + nDam += SpellDamagePerDice(OBJECT_SELF, nCasterLvl); + //nDam += ApplySpellBetrayalStrikeDamage(oTarget, OBJECT_SELF, FALSE); + //Set damage effect + effect eDam = PRCEffectDamage(oTarget, nDam, ChangedElementalDamage(OBJECT_SELF, DAMAGE_TYPE_SONIC)); + //Apply the MIRV and damage effect + SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); + PRCBonusDamage(oTarget); + SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + if (nInt == 1) + { + ApplyEffectToObject(DURATION_TYPE_INSTANT,eDam,oCaster); + ApplyEffectToObject(DURATION_TYPE_INSTANT,eVis,oCaster); + FloatingTextStringOnCreature("The spell 'Horizikaul's Boom' is reflected underwater!", oPC); + } + + //Should not work on creatures already deafened or silenced + if(!PRCGetHasEffect(EFFECT_TYPE_DEAF, oTarget) && !PRCGetHasEffect(EFFECT_TYPE_SILENCE, oTarget)) + { + if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, (PRCGetSaveDC(oTarget,OBJECT_SELF)), SAVING_THROW_TYPE_MIND_SPELLS)) + { + SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDeaf, oTarget, RoundsToSeconds(nRounds)); + } + } + } + } + + +DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR"); +// Erasing the variable used to store the spell's spell school + +//Set up variables for cave-in +object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1); +object oHench2 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 2); +object oFamiliar0 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC, 1); +object oFamiliar1 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench1, 1); +object oFamiliar2 = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHench2, 1); +object oSummoned0 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, 1); +object oSummoned1 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench1, 1); +object oSummoned2 = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oHench2, 1); +object oAnimal0 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC, 1); +object oAnimal1 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench1, 1); +object oAnimal2 = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHench2, 1); +object oDominated0 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, 1); +object oDominated1 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench1, 1); +object oDominated2 = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oHench2, 1); +int nDL=GetLocalInt(oPC, "nDungeonLevel"); +if (nDL == 1) + { + int nDam1 = d10(); + int nDam2 = d10(); + int nDamage = (nDam1 + nDam2); + effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_NORMAL); + effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, GetLocation(oPC)); + PlaySound("as_na_rockfallg1"); + //Apply Cave-in Visual Effect + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_STONE_MEDIUM), oDominated2)); + //Apply Cave-in Damage + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oPC)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oHench2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFamiliar2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oSummoned2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oAnimal2)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated0)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated1)); + DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oDominated2)); + //Send Message to PC + DelayCommand(3.0, FloatingTextStringOnCreature("The spell 'Horizikaul's Boom' has caused a cave-in!", oPC)); + } +} diff --git a/src/hakpak/ghost_prc8_top/nss/x2_s0_scntsphere.nss b/src/hakpak/ghost_prc8_top/nss/x2_s0_scntsphere.nss new file mode 100644 index 0000000..8e59dd3 --- /dev/null +++ b/src/hakpak/ghost_prc8_top/nss/x2_s0_scntsphere.nss @@ -0,0 +1,106 @@ +//:://///////////////////////////////////////////// +//:: Scintillating Sphere +//:: X2_S0_ScntSphere +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* +// A scintillating sphere is a burst of electricity +// that detonates with a low roar and inflicts 1d6 +// points of damage per caster level (maximum of 10d6) +// to all creatures within the area. Unattended objects +// also take damage. The explosion creates almost no pressure. +*/ +//::////////////////////////////////////////////// +//:: Created By: Andrew Nobbs +//:: Created On: Nov 25 , 2002 +//::////////////////////////////////////////////// +//:: Last Updated By: Andrew Nobbs, 02/06/2003 +//:: altered by mr_bumpkin Dec 4, 2003 for prc stuff +#include "prc_inc_spells" +#include "prc_add_spell_dc" + +void ApplyDamage(object oTarget, effect eDamage) +{ + effect eVis = EffectVisualEffect(VFX_IMP_LIGHTNING_S); + SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget); + SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); + PRCBonusDamage(oTarget); +} + +void main() +{ + if(!X2PreSpellCastCode()) return; + + PRCSetSchool(SPELL_SCHOOL_EVOCATION); + + //Declare major variables + object oPC = GetFirstPC(); + int nInt=GetLocalInt(oPC, "Underwater"); + object oCaster = OBJECT_SELF; + location lTarget = PRCGetSpellTargetLocation(); + int nCasterLvl = PRCGetCasterLevel(oCaster); + int nPenetr = nCasterLvl + SPGetPenetr(); + int nMetaMagic = PRCGetMetaMagicFeat(); + int EleDmg = ChangedElementalDamage(oCaster, DAMAGE_TYPE_ELECTRICAL); + int nSaveType = ChangedSaveType(EleDmg); + int nDamage; + float fDelay; + effect eDam; + effect eVis = EffectVisualEffect(VFX_IMP_LIGHTNING_S); + + //Limit Caster level for the purposes of damage + if (nCasterLvl > 10) + nCasterLvl = 10; + + //Apply the fireball explosion at the location captured above. + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_ELECTRIC_EXPLOSION), lTarget); + + //Cycle through the targets within the spell shape until an invalid object is captured. + object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + while(GetIsObjectValid(oTarget)) + { + if(spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, oCaster)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(oCaster, SPELL_SCINTILLATING_SPHERE)); + + if (!PRCDoResistSpell(oCaster, oTarget, nPenetr, fDelay)) + { + //Roll damage for each target + nDamage = d6(nCasterLvl); + //Resolve metamagic + if(nMetaMagic & METAMAGIC_MAXIMIZE) + nDamage = 6 * nCasterLvl; + if(nMetaMagic & METAMAGIC_EMPOWER) + nDamage += nDamage / 2; + nDamage += SpellDamagePerDice(oCaster, nCasterLvl); + + + int nDC = PRCGetSaveDC(oTarget, oCaster); + //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. + nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC, nSaveType); + + if(nDamage > 0) + { + + //Get the distance between the explosion and the target to calculate delay + fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oTarget))/20; + //Set the damage effect + eDam = PRCEffectDamage(oTarget, nDamage, EleDmg); + // Apply effects to the currently selected target. + DelayCommand(fDelay, ApplyDamage(oTarget, eDam)); + //Apply the VFX impact and damage effect (reflected upon PC) + if (nInt == 1) + { + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT,eDam,oCaster)); + DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT,eVis,oCaster)); + FloatingTextStringOnCreature("The spell 'Scintillating Sphere' is reflected underwater!", oPC); + } + } + } + } + //Select the next target within the spell shape. + oTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE); + } + PRCSetSchool(); +} \ No newline at end of file diff --git a/src/include/inc_dynconv.nss b/src/include/inc_dynconv.nss index 4603fc4..68aabac 100644 --- a/src/include/inc_dynconv.nss +++ b/src/include/inc_dynconv.nss @@ -12,6 +12,7 @@ //::////////////////////////////////////////////// //::////////////////////////////////////////////// +//PRC8 Token pre-fix = 161838 ////////////////////////////////////////////////// /* Constant definitions */ @@ -21,23 +22,23 @@ 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_TOKEN_HEADER = 16183899; +const int DYNCONV_TOKEN_REPLY_0 = 161838100; +const int DYNCONV_TOKEN_REPLY_1 = 161838101; +const int DYNCONV_TOKEN_REPLY_2 = 161838102; +const int DYNCONV_TOKEN_REPLY_3 = 161838103; +const int DYNCONV_TOKEN_REPLY_4 = 161838104; +const int DYNCONV_TOKEN_REPLY_5 = 161838105; +const int DYNCONV_TOKEN_REPLY_6 = 161838106; +const int DYNCONV_TOKEN_REPLY_7 = 161838107; +const int DYNCONV_TOKEN_REPLY_8 = 161838108; +const int DYNCONV_TOKEN_REPLY_9 = 161838109; +const int DYNCONV_TOKEN_EXIT = 161838110; +const int DYNCONV_TOKEN_WAIT = 161838111; +const int DYNCONV_TOKEN_NEXT = 161838112; +const int DYNCONV_TOKEN_PREV = 161838113; +const int DYNCONV_MIN_TOKEN = 16183899; +const int DYNCONV_MAX_TOKEN = 161838113; const int DYNCONV_STRREF_PLEASE_WAIT = 16824202; // "Please wait" const int DYNCONV_STRREF_PREVIOUS = 16824203; // "Previous" @@ -477,9 +478,28 @@ void _DynConvInternal_ExitedConvo(object oPC, int bAbort) 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)); + + DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_HEADER)); + DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_REPLY_0)); + DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_REPLY_1)); + DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_REPLY_2)); + DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_REPLY_3)); + DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_REPLY_4)); + DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_REPLY_5)); + DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_REPLY_6)); + DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_REPLY_7)); + DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_REPLY_8)); + DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_REPLY_9)); + DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_EXIT)); + DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_WAIT)); + DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_NEXT)); + DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_PREV)); + DeleteLocalString(oPC, GetTokenIDString(DYNCONV_MIN_TOKEN)); + DeleteLocalString(oPC, GetTokenIDString(DYNCONV_MAX_TOKEN)); + + //int i; + //for(i = DYNCONV_MIN_TOKEN; i <= DYNCONV_MAX_TOKEN; i++) + //DeleteLocalString(oPC, GetTokenIDString(i)); } } } diff --git a/src/include/inc_epicspelldef.nss b/src/include/inc_epicspelldef.nss index 78b89b4..613b0f1 100644 --- a/src/include/inc_epicspelldef.nss +++ b/src/include/inc_epicspelldef.nss @@ -47,77 +47,78 @@ const string MES_CONTINGENCIES_YES2 = "The contingencies must expire to allo */ //Primogenitors SpellID constants -const int SPELL_EPIC_A_STONE = 0;//4007; -const int SPELL_EPIC_ACHHEEL = 1;//4000; -const int SPELL_EPIC_AL_MART = 2;//4002; -const int SPELL_EPIC_ALLHOPE = 3;//4001; -const int SPELL_EPIC_ANARCHY = 4;//4003; -const int SPELL_EPIC_ANBLAST = 5;//4004; -const int SPELL_EPIC_ANBLIZZ = 6;//4005; -const int SPELL_EPIC_ARMY_UN = 7;//4006; -const int SPELL_EPIC_BATTLEB = 999;//4008; -const int SPELL_EPIC_CELCOUN = 8;//4009; -const int SPELL_EPIC_CHAMP_V = 9;//4010; -const int SPELL_EPIC_CON_RES =10;//4011; -const int SPELL_EPIC_CON_REU =11;//4012; -const int SPELL_EPIC_DEADEYE =12;//4013; -const int SPELL_EPIC_DIREWIN =13;//4015; -const int SPELL_EPIC_DREAMSC =14;//4017; -const int SPELL_EPIC_DRG_KNI =15;//4016; -const int SPELL_EPIC_DTHMARK =1000;//4014; -const int SPELL_EPIC_DULBLAD =16;//4018; -const int SPELL_EPIC_DWEO_TH =17;//4019; -const int SPELL_EPIC_ENSLAVE =18;//4020; -const int SPELL_EPIC_EP_M_AR =19;//4021; -const int SPELL_EPIC_EP_RPLS =20;//4022; -const int SPELL_EPIC_EP_SP_R =21;//4023; -const int SPELL_EPIC_EP_WARD =22;//4024; -const int SPELL_EPIC_ET_FREE =23;//4025; -const int SPELL_EPIC_FIEND_W =24;//4026; -const int SPELL_EPIC_FLEETNS =25;//4027; -const int SPELL_EPIC_GEMCAGE =26;//4028; -const int SPELL_EPIC_GODSMIT =27;//4029; -const int SPELL_EPIC_GR_RUIN =28;//4030; -const int SPELL_EPIC_GR_SP_RE=29;//4031; -const int SPELL_EPIC_GR_TIME =30;//4032; -const int SPELL_EPIC_HELBALL =31;//4034; -const int SPELL_EPIC_HELSEND =1001;//4033; -const int SPELL_EPIC_HERCALL =32;//4035; -const int SPELL_EPIC_HERCEMP =33;//4036; -const int SPELL_EPIC_IMPENET =34;//4037; -const int SPELL_EPIC_LEECH_F =35;//4038; -const int SPELL_EPIC_LEG_ART =1002;//4039; -const int SPELL_EPIC_LIFE_FT =1003;//4040; -const int SPELL_EPIC_MAGMA_B =36;//4041; -const int SPELL_EPIC_MASSPEN =37;//4042; -const int SPELL_EPIC_MORI = 38;//4043; -const int SPELL_EPIC_MUMDUST =39;//4044; -const int SPELL_EPIC_NAILSKY =40;//4045; -const int SPELL_EPIC_NIGHTSU =1004;//4046; -const int SPELL_EPIC_ORDER_R =41;//4047; -const int SPELL_EPIC_PATHS_B =42;//4048; -const int SPELL_EPIC_PEERPEN =43;//4049; -const int SPELL_EPIC_PESTIL = 44;//4050; -const int SPELL_EPIC_PIOUS_P =45;//4051; -const int SPELL_EPIC_PLANCEL =46;//4052; -const int SPELL_EPIC_PSION_S =47;//4053; -const int SPELL_EPIC_RAINFIR =48;//4054; -const int SPELL_EPIC_RISEN_R =1005;//4055; -const int SPELL_EPIC_RUINN = 49;//4056; //NON_STANDARD -const int SPELL_EPIC_SINGSUN =50;//4057; -const int SPELL_EPIC_SP_WORM =51;//4058; -const int SPELL_EPIC_STORM_M =52;//4059; -const int SPELL_EPIC_SUMABER =53;//4060; -const int SPELL_EPIC_SUP_DIS =54;//4061; -const int SPELL_EPIC_SYMRUST =1006;//4062; -const int SPELL_EPIC_THEWITH =55;//4063; -const int SPELL_EPIC_TOLO_KW =56;//4064; -const int SPELL_EPIC_TRANVIT =57;//4065; -const int SPELL_EPIC_TWINF = 58;//4066; -const int SPELL_EPIC_UNHOLYD =59;//4067; -const int SPELL_EPIC_UNIMPIN =60;//4068; -const int SPELL_EPIC_UNSEENW =61;//4069; -const int SPELL_EPIC_WHIP_SH =62;//4070; +const int SPELL_EPIC_A_STONE = 0;//4007; +const int SPELL_EPIC_ACHHEEL = 1;//4000; +const int SPELL_EPIC_AL_MART = 2;//4002; +const int SPELL_EPIC_ALLHOPE = 3;//4001; +const int SPELL_EPIC_ANARCHY = 4;//4003; +const int SPELL_EPIC_ANBLAST = 5;//4004; +const int SPELL_EPIC_ANBLIZZ = 6;//4005; +const int SPELL_EPIC_ARMY_UN = 7;//4006; +const int SPELL_EPIC_BATTLEB = 999;//4008; +const int SPELL_EPIC_CELCOUN = 8;//4009; +const int SPELL_EPIC_CHAMP_V = 9;//4010; +const int SPELL_EPIC_CON_RES = 10;//4011; +const int SPELL_EPIC_CON_REU = 11;//4012; +const int SPELL_EPIC_DEADEYE = 12;//4013; +const int SPELL_EPIC_DIREWIN = 13;//4015; +const int SPELL_EPIC_DREAMSC = 14;//4017; +const int SPELL_EPIC_DRG_KNI = 15;//4016; +const int SPELL_EPIC_DTHMARK = 1000;//4014; +const int SPELL_EPIC_DULBLAD = 16;//4018; +const int SPELL_EPIC_DWEO_TH = 17;//4019; +const int SPELL_EPIC_ENSLAVE = 18;//4020; +const int SPELL_EPIC_EP_M_AR = 19;//4021; +const int SPELL_EPIC_EP_RPLS = 20;//4022; +const int SPELL_EPIC_EP_SP_R = 21;//4023; +const int SPELL_EPIC_EP_WARD = 22;//4024; +const int SPELL_EPIC_ET_FREE = 23;//4025; +const int SPELL_EPIC_FIEND_W = 24;//4026; +const int SPELL_EPIC_FLEETNS = 25;//4027; +const int SPELL_EPIC_GEMCAGE = 26;//4028; +const int SPELL_EPIC_GODSMIT = 27;//4029; +const int SPELL_EPIC_GR_RUIN = 28;//4030; +const int SPELL_EPIC_GR_SP_RE = 29;//4031; +const int SPELL_EPIC_GR_TIME = 30;//4032; +const int SPELL_EPIC_HELBALL = 31;//4034; +const int SPELL_EPIC_HELSEND = 1001;//4033; +const int SPELL_EPIC_HERCALL = 32;//4035; +const int SPELL_EPIC_HERCEMP = 33;//4036; +const int SPELL_EPIC_IMPENET = 34;//4037; +const int SPELL_EPIC_LEECH_F = 35;//4038; +const int SPELL_EPIC_LEG_ART = 1002;//4039; +const int SPELL_EPIC_LIFE_FT = 1003;//4040; +const int SPELL_EPIC_MAGMA_B = 36;//4041; +const int SPELL_EPIC_MASSPEN = 37;//4042; +const int SPELL_EPIC_MORI = 38;//4043; +const int SPELL_EPIC_MUMDUST = 39;//4044; +const int SPELL_EPIC_NAILSKY = 40;//4045; +const int SPELL_EPIC_NIGHTSU = 1004;//4046; +const int SPELL_EPIC_ORDER_R = 41;//4047; +const int SPELL_EPIC_PATHS_B = 42;//4048; +const int SPELL_EPIC_PEERPEN = 43;//4049; +const int SPELL_EPIC_PESTIL = 44;//4050; +const int SPELL_EPIC_PIOUS_P = 45;//4051; +const int SPELL_EPIC_PLANCEL = 46;//4052; +const int SPELL_EPIC_PSION_S = 47;//4053; +const int SPELL_EPIC_RAINFIR = 48;//4054; +//const int SPELL_EPIC_RISEN_R =1005;//4055; +const int SPELL_EPIC_RISEN_R = 49;//4055; +const int SPELL_EPIC_RUINN = 50;//4056; //NON_STANDARD +const int SPELL_EPIC_SINGSUN = 51;//4057; +const int SPELL_EPIC_SP_WORM = 52;//4058; +const int SPELL_EPIC_STORM_M = 53;//4059; +const int SPELL_EPIC_SUMABER = 54;//4060; +const int SPELL_EPIC_SUP_DIS = 55;//4061; +const int SPELL_EPIC_SYMRUST = 1006;//4062; +const int SPELL_EPIC_THEWITH = 56;//4063; +const int SPELL_EPIC_TOLO_KW = 57;//4064; +const int SPELL_EPIC_TRANVIT = 58;//4065; +const int SPELL_EPIC_TWINF = 59;//4066; +const int SPELL_EPIC_UNHOLYD = 60;//4067; +const int SPELL_EPIC_UNIMPIN = 61;//4068; +const int SPELL_EPIC_UNSEENW = 62;//4069; +const int SPELL_EPIC_WHIP_SH = 63;//4070; /* diff --git a/src/include/inc_epicspellfnc.nss b/src/include/inc_epicspellfnc.nss index 59f4dd6..4537d45 100644 --- a/src/include/inc_epicspellfnc.nss +++ b/src/include/inc_epicspellfnc.nss @@ -26,7 +26,7 @@ int GetSpellFromAbrev(string sAbrev); ////////////////////////////////////////////////// #include "inc_utility" -//#include "inc_epicspelldef" +#include "inc_epicspells" // SEED FUNCTIONS @@ -246,7 +246,7 @@ int GetSpellFromAbrev(string sAbrev) sAbrev = GetStringLowerCase(sAbrev); if(GetStringLeft(sAbrev, 8) == "epic_sp_") sAbrev = GetStringRight(sAbrev, GetStringLength(sAbrev)-8); - if(DEBUG) DoDebug("sAbrew to check vs: " + sAbrev); + if(DEBUG) DoDebug("sAbrev to check vs: " + sAbrev); int i = 0; string sLabel = GetStringLowerCase(Get2DACache("epicspells", "LABEL", i)); while(sLabel != "") diff --git a/src/include/inc_epicspells.nss b/src/include/inc_epicspells.nss index ec3eac9..4682672 100644 --- a/src/include/inc_epicspells.nss +++ b/src/include/inc_epicspells.nss @@ -303,11 +303,18 @@ int GetIsEpicShaman(object oPC) && GetAbilityScore(oPC, ABILITY_WISDOM) > 18; } -int GetIsEpicSorcerer(object oPC) +int GetIsEpicSorcerer(object oPC) +{ + return GetHitDice(oPC) >= 21 + && GetCasterLvl(CLASS_TYPE_SORCERER, oPC) > 17 + && GetAbilityScore(oPC, ABILITY_CHARISMA) > 18; +} + +/* int GetIsEpicSorcerer(object oPC) { return GetPrCAdjustedCasterLevel(CLASS_TYPE_SORCERER, oPC, FALSE) > 17 && GetAbilityScore(oPC, ABILITY_CHARISMA) > 18; -} +} */ int GetIsEpicSublimeChord(object oPC) { diff --git a/src/include/inc_infusion.nss b/src/include/inc_infusion.nss new file mode 100644 index 0000000..e9c7528 --- /dev/null +++ b/src/include/inc_infusion.nss @@ -0,0 +1,481 @@ +//::////////////////////////////////////////////// +//:: ;-. ,-. ,-. ,-. +//:: | ) | ) / ( ) +//:: |-' |-< | ;-: +//:: | | \ \ ( ) +//:: ' ' ' `-' `-' +//:://///////////////////////////////////////////// +//:: +/* + Script: inc_infusion + Author: Jaysyn + Created: 2025-08-11 17:01:26 + + Description: + Contains most functions related to the Create + Infusion feat. + +*/ +//:: +//::////////////////////////////////////////////// +#include "prc_inc_spells" + +int GetMaxDivineSpellLevel(object oCaster, int nClass); +int GetCastSpellCasterLevelFromItem(object oItem, int nSpellID); +int GetIsClassSpell(object oCaster, int nSpellID, int nClass); +int GetHasSpellOnClassList(object oCaster, int nSpellID); +void InfusionSecondSave(object oUser, int nDC); + +/** + * @brief Finds the class index for which the given spell is available to the specified caster. + * + * This function iterates through all possible classes and returns the first class + * index for which the specified spell is on the caster's spell list. + * + * @param oCaster The creature object to check. + * @param nSpellID The spell ID to find the class for. + * + * @return The class index that has the spell on its class spell list for the caster, + * or -1 if no matching class is found. + */ +int FindSpellCastingClass(object oCaster, int nSpellID) +{ + int i = 0; + int nClassFound = -1; + int nClass; + + // Only loop through caster's classes + for (i = 0; i <= 8; i++) + { + nClass = GetClassByPosition(i, oCaster); + if (nClass == CLASS_TYPE_INVALID) continue; + + if (GetIsClassSpell(oCaster, nSpellID, nClass)) + { + nClassFound = nClass; + break; + } + } + + return nClassFound; +} + + +/** + * @brief Performs validation checks to determine if the caster can use a spell infusion from the specified item. + * + * This function verifies that the item is a valid infused herb, checks the caster's relevant class and ability scores, + * confirms the caster is a divine spellcaster with the necessary caster level, and ensures the spell is on the caster's class spell list. + * + * @param oCaster The creature attempting to use the infusion. + * @param oItem The infused herb item containing the spell. + * @param nSpellID The spell ID of the infusion spell being cast. + * + * @return TRUE if all infusion use checks pass and the caster can use the infusion; FALSE otherwise. + */ + int DoInfusionUseChecks(object oCaster, object oItem, int nSpellID) +{ + int bPnPHerbs = GetPRCSwitch(PRC_CREATE_INFUSION_OPTIONAL_HERBS); + + if(GetBaseItemType(oItem) != BASE_ITEM_INFUSED_HERB) + { + FloatingTextStringOnCreature("Not casting from an Infused Herb", oCaster); + return FALSE; + } + + int nItemSpellLvl = GetCastSpellCasterLevelFromItem(oItem, nSpellID); + if (bPnPHerbs && nItemSpellLvl == -1) + { + FloatingTextStringOnCreature("Item has no spellcaster level.", oCaster); + return FALSE; + } + + // **CRITICAL: Find the correct class that actually has the spell on its list** + int nClassCaster = FindSpellCastingClass(oCaster, nSpellID); + + if(DEBUG) DoDebug("nClassCaster is: " + IntToString(nClassCaster) + "."); + + // Check for valid class + if (nClassCaster == -1) + { + FloatingTextStringOnCreature("No valid class found for this spell.", oCaster); + return FALSE; + } + + if(GetMaxDivineSpellLevel(oCaster, nClassCaster) < 1 ) + { + FloatingTextStringOnCreature("You must be a divine spellcaster to activate an infusion.", oCaster); + return FALSE; + } + + // Must have spell on class list - (This will also double-check via the class) + if (!GetHasSpellOnClassList(oCaster, nSpellID)) + { + FloatingTextStringOnCreature("You must have a spell on one of your class spell lists to cast it from an infusion.", oCaster); + return FALSE; + } + + // Must meet ability requirement: Ability score >= 10 + spell level + int nSpellLevel = PRCGetSpellLevelForClass(nSpellID, nClassCaster); + int nClassAbility = GetAbilityScoreForClass(nClassCaster, oCaster); + + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nClassCaster is "+IntToString(nClassCaster)+"."); + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: Class nSpellLevel is "+IntToString(nSpellLevel)+"."); + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nClassAbility is "+IntToString(nClassAbility)+"."); + + if (nClassAbility < 10 + nSpellLevel) + { + FloatingTextStringOnCreature("You must meet ability score requirement to cast spell from infusion.", oCaster); + return FALSE; + } + + // Must have a divine caster level at least equal to infusion's caster level + int nDivineLvl = GetPrCAdjustedCasterLevelByType(TYPE_DIVINE, oCaster); + + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nDivineLvl is "+IntToString(nDivineLvl)+"."); + + if (nDivineLvl < nItemSpellLvl) + { + FloatingTextStringOnCreature("Your divine caster level is too low to cast this spell from an infusion.", oCaster); + return FALSE; + } + + return TRUE; +} + +/* int DoInfusionUseChecks(object oCaster, object oItem, int nSpellID) +{ + int bPnPHerbs = GetPRCSwitch(PRC_CREATE_INFUSION_OPTIONAL_HERBS); + + if(GetBaseItemType(oItem) != BASE_ITEM_INFUSED_HERB) + { + FloatingTextStringOnCreature("Not casting from an Infused Herb", oCaster); + return FALSE; + + } + + int nItemSpellLvl = GetCastSpellCasterLevelFromItem(oItem, nSpellID); + if (bPnPHerbs && nItemSpellLvl == -1) + { + FloatingTextStringOnCreature("Item has no spellcaster level.", oCaster); + return FALSE; + } + + // Find relevant class for the spell + int nClassCaster = FindSpellCastingClass(oCaster, nSpellID); + + if(DEBUG) DoDebug("nClassCaster is: "+IntToString(nClassCaster)+"."); + + if(GetMaxDivineSpellLevel(oCaster, nClassCaster) < 1 ) + { + FloatingTextStringOnCreature("You must be a divine spellcaster to activate an infusion.", oCaster); + return FALSE; + } + + // Must have spell on class list + if (!GetHasSpellOnClassList(oCaster, nSpellID)) + { + FloatingTextStringOnCreature("You must have a spell on one of your class spell lists to cast it from an infusion.", oCaster); + return FALSE; + } + + // Must meet ability requirement: Ability score >= 10 + spell level + int nSpellLevel = PRCGetSpellLevelForClass(nSpellID, nClassCaster); + int nClassAbility = GetAbilityScoreForClass(nClassCaster, oCaster); + + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nClassCaster is "+IntToString(nClassCaster)+"."); + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: Class nSpellLevel is "+IntToString(nSpellLevel)+"."); + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nClassAbility is "+IntToString(nClassAbility)+"."); + + if (nClassAbility < 10 + nSpellLevel) + { + FloatingTextStringOnCreature("You must meet ability score requirement to cast spell from infusion.", oCaster); + return FALSE; + } + + // Must have a divine caster level at least equal to infusion's caster level + int nDivineLvl = GetPrCAdjustedCasterLevelByType(TYPE_DIVINE, oCaster); + + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nDivineLvl is "+IntToString(nDivineLvl)+"."); + + if (nDivineLvl < nItemSpellLvl) + { + FloatingTextStringOnCreature("Your divine caster level is too low to cast this spell from an infusion.", oCaster); + return FALSE; + } + + return TRUE; +} + */ +/** + * @brief Retrieves the maximum divine spell level known by the caster for a given class. + * + * This function checks the caster's local integers named "PRC_DivSpell1" through "PRC_DivSpell9" + * in descending order to determine the highest divine spell level available. + * It returns the highest spell level for which the corresponding local int is false (zero). + * + * @param oCaster The creature whose divine spell levels are being checked. + * @param nClass The class index for which to check the divine spell level (currently unused). + * + * @return The highest divine spell level known by the caster (1 to 9). + */ +int GetMaxDivineSpellLevel(object oCaster, int nClass) +{ + int i = 9; + for (i; i > 0; i--) + { + if(!GetLocalInt(oCaster, "PRC_DivSpell"+IntToString(i))) + return i; + } + return 1; +} + +/** + * @brief Retrieves the spell school of an herb based on its resref by looking it up in the craft_infusion.2da file. + * + * This function searches the "craft_infusion" 2DA for a row matching the herb's resref. + * If found, it returns the corresponding spell school as an integer constant. + * If not found or the SpellSchool column is missing/invalid, it returns -1. + * + * @param oHerb The herb object to check. + * + * @return The spell school constant corresponding to the herb's infusion spell school, + * or -1 if the herb is invalid, not found, or the data is missing. + */ +int GetHerbsSpellSchool(object oHerb) +{ + if (!GetIsObjectValid(oHerb)) return -1; + + string sResref = GetResRef(oHerb); + int nRow = 0; + string sRowResref; + + while (nRow < 200) + { + sRowResref = Get2DACache("craft_infusion", "Resref", nRow); + if (sRowResref == "") break; + if (sRowResref == sResref) + { + string sHerbSpellSchool = Get2DAString("craft_infusion", "SpellSchool", nRow); + + if (sHerbSpellSchool == "A") return SPELL_SCHOOL_ABJURATION; + else if (sHerbSpellSchool == "C") return SPELL_SCHOOL_CONJURATION; + else if (sHerbSpellSchool == "D") return SPELL_SCHOOL_DIVINATION; + else if (sHerbSpellSchool == "E") return SPELL_SCHOOL_ENCHANTMENT; + else if (sHerbSpellSchool == "V") return SPELL_SCHOOL_EVOCATION; + else if (sHerbSpellSchool == "I") return SPELL_SCHOOL_ILLUSION; + else if (sHerbSpellSchool == "N") return SPELL_SCHOOL_NECROMANCY; + else if (sHerbSpellSchool == "T") return SPELL_SCHOOL_TRANSMUTATION; + else return SPELL_SCHOOL_GENERAL; + + return -1; + } + nRow++; + } + return -1; // Not found +} + +/** + * @brief Retrieves the infusion spell level of an herb by matching its resref in the craft_infusion.2da file. + * + * This function searches the "craft_infusion" 2DA for a row matching the herb's resref. + * If found, it returns the spell level from the SpellLevel column as an integer. + * If not found or the column is missing, it returns -1. + * + * @param oHerb The herb object whose infusion spell level is to be retrieved. + * + * @return The spell level as an integer if found, or -1 if the herb is invalid, not found, or the column is missing. + */ +int GetHerbsInfusionSpellLevel(object oHerb) +{ + if (!GetIsObjectValid(oHerb)) return -1; + + string sResref = GetResRef(oHerb); + int nRow = 0; + string sRowResref; + + // Brute-force loop — adjust limit if your 2DA has more than 500 rows + while (nRow < 200) + { + sRowResref = Get2DACache("craft_infusion", "Resref", nRow); + if (sRowResref == "") break; // End of valid rows + if (sRowResref == sResref) + { + string sSpellLevelStr = Get2DAString("craft_infusion", "SpellLevel", nRow); + return StringToInt(sSpellLevelStr); + } + nRow++; + } + return -1; // Not found +} + +/** + * @brief Retrieves the caster level of a specific cast-spell item property from an item. + * + * This function iterates through the item properties of the given item, searching for an + * ITEM_PROPERTY_CAST_SPELL_CASTER_LEVEL property that matches the specified spell ID. + * If found, it returns the caster level value stored in the item property. + * + * @param oItem The item object to check. + * @param nSpellID The spell ID to match against the item property. + * + * @return The caster level associated with the matching cast-spell item property, + * or -1 if no matching property is found. + */ +int GetCastSpellCasterLevelFromItem(object oItem, int nSpellID) +{ + int nFoundCL = -1; + + itemproperty ip = GetFirstItemProperty(oItem); + while (GetIsItemPropertyValid(ip)) + { + int nType = GetItemPropertyType(ip); + + // First preference: PRC's CASTER_LEVEL itemprop + if (nType == ITEM_PROPERTY_CAST_SPELL_CASTER_LEVEL) + { + int nSubType = GetItemPropertySubType(ip); + string sSpellIDStr = Get2DAString("iprp_spells", "SpellIndex", nSubType); + int nSubSpellID = StringToInt(sSpellIDStr); + + if (nSubSpellID == nSpellID) + { + return GetItemPropertyCostTableValue(ip); // Found exact CL + } + } + + // Fallback: vanilla CAST_SPELL property + if (nType == ITEM_PROPERTY_CAST_SPELL && nFoundCL == -1) + { + int nSubType = GetItemPropertySubType(ip); + string sSpellIDStr = Get2DAString("iprp_spells", "SpellIndex", nSubType); + int nSubSpellID = StringToInt(sSpellIDStr); + + if (nSubSpellID == nSpellID) + { + // Vanilla uses CostTableValue for *number of uses*, not CL, + // so we’ll assume default caster level = spell level * 2 - 1 + int nSpellLevel = StringToInt(Get2DAString("spells", "Innate", nSubSpellID)); + nFoundCL = nSpellLevel * 2 - 1; // default NWN caster level rule + } + } + + ip = GetNextItemProperty(oItem); + } + + return nFoundCL; // -1 if not found +} + + +/** + * @brief Checks if a given spell ID is present on the specified class's spell list for the caster. + * + * This function determines the spell level of the spell for the given class using PRCGetSpellLevelForClass. + * If the spell level is -1, the spell is not on the class's spell list. + * Otherwise, the spell is considered to be on the class spell list. + * + * @param oCaster The creature object casting or querying the spell. + * @param nSpellID The spell ID to check. + * @param nClass The class index to check the spell list against. + * + * @return TRUE if the spell is on the class's spell list; FALSE otherwise. + */ +int GetIsClassSpell(object oCaster, int nSpellID, int nClass) +{ + if(DEBUG) DoDebug("inc_infusion >> GetIsClassSpell: nSpellID is: "+IntToString(nSpellID)+"."); + if(DEBUG) DoDebug("inc_infusion >> GetIsClassSpell: nClass is: "+IntToString(nClass)+"."); + + int nSpellLevel = PRCGetSpellLevelForClass(nSpellID, nClass); + if (nSpellLevel == -1) + { + if(DEBUG) DoDebug("inc_infusion >> GetIsClassSpell: SpellLevel is "+IntToString(nSpellLevel)+"."); + if(DEBUG) DoDebug("inc_infusion >> GetIsClassSpell: Spell "+IntToString(nSpellID)+" is not in spelllist of "+IntToString(nClass)+"."); + return FALSE; + } + return TRUE; +} + +/** + * @brief Checks if the caster has the specified spell on any of their class spell lists. + * + * This function iterates through all classes the caster has (up to position 8), + * and returns TRUE if the spell is found on any class's spell list. + * + * @param oCaster The creature object to check. + * @param nSpellID The spell ID to search for. + * + * @return TRUE if the spell is present on at least one of the caster's class spell lists; + * FALSE otherwise. + */ +int GetHasSpellOnClassList(object oCaster, int nSpellID) +{ + int i; + for (i = 0; i <= 8; i++) + { + int nClass = GetClassByPosition(i, oCaster); + if (nClass == CLASS_TYPE_INVALID) continue; + + if (GetIsClassSpell(oCaster, nSpellID, nClass)) + { + if(DEBUG) DoDebug("inc_infusion >> GetHasSpellOnClassList: Class spell found."); + return TRUE; + } + } + if(DEBUG) DoDebug("inc_infusion >> GetHasSpellOnClassList: Class spell not found."); + return FALSE; +} + +/** + * @brief Applies a poison nausea effect to the user when infusion use fails. + * + * This function performs an immediate Fortitude saving throw against poison DC based on infusion caster level. + * If the user fails and is not immune to poison, an infusion nausea effect is applied, replacing any existing one. + * A second saving throw is scheduled after 1 minute to attempt to remove the effect. + * + * @param oUser The creature who used the infusion and may be poisoned. + * @param nInfusionCL The caster level of the infusion used, affecting the DC of the saving throw. + */ +void ApplyInfusionPoison(object oUser, int nInfusionCL) +{ + int nDC = 10 + (nInfusionCL / 2); + int bImmune = GetIsImmune(oUser, IMMUNITY_TYPE_POISON); + + // First save immediately + if (!bImmune && !PRCMySavingThrow(SAVING_THROW_FORT, oUser, nDC, SAVING_THROW_TYPE_POISON)) + { + // Remove existing infusion poison nausea effect before applying new + effect eOld = GetFirstEffect(oUser); + while (GetIsEffectValid(eOld)) + { + if (GetEffectTag(eOld) == "INFUSION_POISON_TAG") + { + RemoveEffect(oUser, eOld); + break; // Assuming only one effect with this tag + } + eOld = GetNextEffect(oUser); + } + + effect eNausea = EffectNausea(oUser, 60.0f); + + TagEffect(eNausea, "INFUSION_POISON_TAG"); + FloatingTextStringOnCreature("The infusion has made you nauseous.", oUser); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eNausea, oUser, RoundsToSeconds(10)); + } + + // Second save 1 minute later + if (!bImmune) + { + DelayCommand(60.0, InfusionSecondSave(oUser, nDC)); + } +} + +void InfusionSecondSave(object oUser, int nDC) +{ + if (!PRCMySavingThrow(SAVING_THROW_FORT, oUser, nDC, SAVING_THROW_TYPE_POISON)) + { + FloatingTextStringOnCreature("The infusion has made you nauseous.", oUser); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectNausea(oUser, 60.0f), oUser, RoundsToSeconds(10)); + } +} + +//:: void main (){} \ No newline at end of file diff --git a/src/include/inc_item_props.nss b/src/include/inc_item_props.nss index b1edfc2..b912fad 100644 --- a/src/include/inc_item_props.nss +++ b/src/include/inc_item_props.nss @@ -1643,7 +1643,60 @@ int GetIsMagicItem(object oItem) int FeatToIprop(int nFeat) { switch(nFeat) - {//: Weapon Focus + { + //:: Weapon Proficiencies + case FEAT_WEAPON_PROFICIENCY_SHORTSWORD: return IP_CONST_FEAT_WEAPON_PROFICIENCY_SHORTSWORD; + case FEAT_WEAPON_PROFICIENCY_LONGSWORD: return IP_CONST_FEAT_WEAPON_PROFICIENCY_LONGSWORD; + case FEAT_WEAPON_PROFICIENCY_BATTLEAXE: return IP_CONST_FEAT_WEAPON_PROFICIENCY_BATTLEAXE; + case FEAT_WEAPON_PROFICIENCY_BASTARD_SWORD: return IP_CONST_FEAT_WEAPON_PROFICIENCY_BASTARD_SWORD; + case FEAT_WEAPON_PROFICIENCY_LIGHT_FLAIL: return IP_CONST_FEAT_WEAPON_PROFICIENCY_LIGHT_FLAIL; + case FEAT_WEAPON_PROFICIENCY_WARHAMMER: return IP_CONST_FEAT_WEAPON_PROFICIENCY_WARHAMMER; + case FEAT_WEAPON_PROFICIENCY_LONGBOW: return IP_CONST_FEAT_WEAPON_PROFICIENCY_LONGBOW; + case FEAT_WEAPON_PROFICIENCY_LIGHT_MACE: return IP_CONST_FEAT_WEAPON_PROFICIENCY_LIGHT_MACE; + case FEAT_WEAPON_PROFICIENCY_HALBERD: return IP_CONST_FEAT_WEAPON_PROFICIENCY_HALBERD; + case FEAT_WEAPON_PROFICIENCY_SHORTBOW: return IP_CONST_FEAT_WEAPON_PROFICIENCY_SHORTBOW; + case FEAT_WEAPON_PROFICIENCY_TWO_BLADED_SWORD: return IP_CONST_FEAT_WEAPON_PROFICIENCY_TWO_BLADED_SWORD; + case FEAT_WEAPON_PROFICIENCY_GREATSWORD: return IP_CONST_FEAT_WEAPON_PROFICIENCY_GREATSWORD; + case FEAT_WEAPON_PROFICIENCY_GREATAXE: return IP_CONST_FEAT_WEAPON_PROFICIENCY_GREATAXE; + case FEAT_WEAPON_PROFICIENCY_DART: return IP_CONST_FEAT_WEAPON_PROFICIENCY_DART; + case FEAT_WEAPON_PROFICIENCY_DIRE_MACE: return IP_CONST_FEAT_WEAPON_PROFICIENCY_DIRE_MACE; + case FEAT_WEAPON_PROFICIENCY_DOUBLE_AXE: return IP_CONST_FEAT_WEAPON_PROFICIENCY_DOUBLE_AXE; + case FEAT_WEAPON_PROFICIENCY_HEAVY_FLAIL: return IP_CONST_FEAT_WEAPON_PROFICIENCY_HEAVY_FLAIL; + case FEAT_WEAPON_PROFICIENCY_LIGHT_HAMMER: return IP_CONST_FEAT_WEAPON_PROFICIENCY_LIGHT_HAMMER; + case FEAT_WEAPON_PROFICIENCY_HANDAXE: return IP_CONST_FEAT_WEAPON_PROFICIENCY_HANDAXE; + case FEAT_WEAPON_PROFICIENCY_KAMA: return IP_CONST_FEAT_WEAPON_PROFICIENCY_KAMA; + case FEAT_WEAPON_PROFICIENCY_KATANA: return IP_CONST_FEAT_WEAPON_PROFICIENCY_KATANA; + case FEAT_WEAPON_PROFICIENCY_KUKRI: return IP_CONST_FEAT_WEAPON_PROFICIENCY_KUKRI; + case FEAT_WEAPON_PROFICIENCY_MORNINGSTAR: return IP_CONST_FEAT_WEAPON_PROFICIENCY_MORNINGSTAR; + case FEAT_WEAPON_PROFICIENCY_RAPIER: return IP_CONST_FEAT_WEAPON_PROFICIENCY_RAPIER; + case FEAT_WEAPON_PROFICIENCY_SCIMITAR: return IP_CONST_FEAT_WEAPON_PROFICIENCY_SCIMITAR; + case FEAT_WEAPON_PROFICIENCY_SCYTHE: return IP_CONST_FEAT_WEAPON_PROFICIENCY_SCYTHE; + case FEAT_WEAPON_PROFICIENCY_SHORTSPEAR: return IP_CONST_FEAT_WEAPON_PROFICIENCY_SHORTSPEAR; + case FEAT_WEAPON_PROFICIENCY_SHURIKEN: return IP_CONST_FEAT_WEAPON_PROFICIENCY_SHURIKEN; + case FEAT_WEAPON_PROFICIENCY_SICKLE: return IP_CONST_FEAT_WEAPON_PROFICIENCY_SICKLE; + case FEAT_WEAPON_PROFICIENCY_SLING: return IP_CONST_FEAT_WEAPON_PROFICIENCY_SLING; + case FEAT_WEAPON_PROFICIENCY_THROWING_AXE: return IP_CONST_FEAT_WEAPON_PROFICIENCY_THROWING_AXE; + case FEAT_WEAPON_PROFICIENCY_TRIDENT: return IP_CONST_FEAT_WEAPON_PROFICIENCY_TRIDENT; + case FEAT_WEAPON_PROFICIENCY_DWARVEN_WARAXE: return IP_CONST_FEAT_WEAPON_PROFICIENCY_DWARVEN_WARAXE; + case FEAT_WEAPON_PROFICIENCY_WHIP: return IP_CONST_FEAT_WEAPON_PROFICIENCY_WHIP; + case FEAT_WEAPON_PROFICIENCY_ELVEN_LIGHTBLADE: return IP_CONST_FEAT_WEAPON_PROFICIENCY_ELVEN_LIGHTBLADE; + case FEAT_WEAPON_PROFICIENCY_ELVEN_THINBLADE: return IP_CONST_FEAT_WEAPON_PROFICIENCY_ELVEN_THINBLADE; + case FEAT_WEAPON_PROFICIENCY_ELVEN_COURTBLADE: return IP_CONST_FEAT_WEAPON_PROFICIENCY_ELVEN_COURTBLADE; + case FEAT_WEAPON_PROFICIENCY_LIGHT_LANCE: return IP_CONST_FEAT_WEAPON_PROFICIENCY_LIGHT_LANCE; + case FEAT_WEAPON_PROFICIENCY_HEAVY_PICK: return IP_CONST_FEAT_WEAPON_PROFICIENCY_HEAVY_PICK; + case FEAT_WEAPON_PROFICIENCY_LIGHT_PICK: return IP_CONST_FEAT_WEAPON_PROFICIENCY_LIGHT_PICK; + case FEAT_WEAPON_PROFICIENCY_SAI: return IP_CONST_FEAT_WEAPON_PROFICIENCY_SAI; + case FEAT_WEAPON_PROFICIENCY_NUNCHAKU: return IP_CONST_FEAT_WEAPON_PROFICIENCY_NUNCHAKU; + case FEAT_WEAPON_PROFICIENCY_FALCHION: return IP_CONST_FEAT_WEAPON_PROFICIENCY_FALCHION; + case FEAT_WEAPON_PROFICIENCY_SAP: return IP_CONST_FEAT_WEAPON_PROFICIENCY_SAP; + case FEAT_WEAPON_PROFICIENCY_KATAR: return IP_CONST_FEAT_WEAPON_PROFICIENCY_KATAR; + case FEAT_WEAPON_PROFICIENCY_HEAVY_MACE: return IP_CONST_FEAT_WEAPON_PROFICIENCY_HEAVY_MACE; + case FEAT_WEAPON_PROFICIENCY_MAUL: return IP_CONST_FEAT_WEAPON_PROFICIENCY_MAUL; + case FEAT_WEAPON_PROFICIENCY_DOUBLE_SCIMITAR: return IP_CONST_FEAT_WEAPON_PROFICIENCY_DOUBLE_SCIMITAR; + case FEAT_WEAPON_PROFICIENCY_GOAD: return IP_CONST_FEAT_WEAPON_PROFICIENCY_GOAD; + case FEAT_WEAPON_PROFICIENCY_EAGLE_CLAW: return IP_CONST_FEAT_WEAPON_PROFICIENCY_EAGLE_CLAW; + + //: Weapon Focus case FEAT_WEAPON_FOCUS_BASTARD_SWORD: return IP_CONST_FEAT_WEAPON_FOCUS_BASTARD_SWORD; case FEAT_WEAPON_FOCUS_BATTLE_AXE: return IP_CONST_FEAT_WEAPON_FOCUS_BATTLE_AXE; case FEAT_WEAPON_FOCUS_CLUB: return IP_CONST_FEAT_WEAPON_FOCUS_CLUB; diff --git a/src/include/inc_lookups.nss b/src/include/inc_lookups.nss index e5a5124..fa68b5c 100644 --- a/src/include/inc_lookups.nss +++ b/src/include/inc_lookups.nss @@ -242,25 +242,27 @@ void SetupLookupStage(object oMod, int n) case 11: SetLkupStage(n, oMod, CLASS_TYPE_DRAGON_SHAMAN, "cls_inv_drgshm"); break; case 12: SetLkupStage(n, oMod, CLASS_TYPE_WARLOCK, "cls_inv_warlok"); break; case 13: SetLkupStage(n, oMod, CLASS_TYPE_ARCHIVIST, "cls_spell_archv"); break; - case 14: SetLkupStage(n, oMod, CLASS_TYPE_ASSASSIN, "cls_spell_asasin"); break; - case 15: SetLkupStage(n, oMod, CLASS_TYPE_BARD, "cls_spell_bard"); break; - case 16: SetLkupStage(n, oMod, CLASS_TYPE_BEGUILER, "cls_spell_beguil"); break; - case 17: SetLkupStage(n, oMod, CLASS_TYPE_DREAD_NECROMANCER, "cls_spell_dnecro"); break; - case 18: SetLkupStage(n, oMod, CLASS_TYPE_DUSKBLADE, "cls_spell_duskbl"); break; - case 19: SetLkupStage(n, oMod, CLASS_TYPE_FAVOURED_SOUL, "cls_spell_favsol"); break; - case 20: SetLkupStage(n, oMod, CLASS_TYPE_HARPER, "cls_spell_harper"); break; - case 21: SetLkupStage(n, oMod, CLASS_TYPE_HEXBLADE, "cls_spell_hexbl"); break; - case 22: SetLkupStage(n, oMod, CLASS_TYPE_JUSTICEWW, "cls_spell_justww"); break; - case 23: SetLkupStage(n, oMod, CLASS_TYPE_SORCERER, "cls_spell_sorc"); break; - case 24: SetLkupStage(n, oMod, CLASS_TYPE_SUBLIME_CHORD, "cls_spell_schord"); break; - case 25: SetLkupStage(n, oMod, CLASS_TYPE_SUEL_ARCHANAMACH, "cls_spell_suel"); break; - case 26: SetLkupStage(n, oMod, CLASS_TYPE_VIGILANT, "cls_spell_vigil"); break; - case 27: SetLkupStage(n, oMod, CLASS_TYPE_WARMAGE, "cls_spell_wrmage"); break; - case 28: SetLkupStage(n, oMod, CLASS_TYPE_KNIGHT_WEAVE, "cls_spell_kngtwv"); break; - case 29: SetLkupStage(n, oMod, CLASS_TYPE_PSYCHIC_ROGUE, "cls_psipw_psyrog"); break; - case 30: SetLkupStage(n, oMod, CLASS_TYPE_SHADOWCASTER, "cls_myst_shdcst"); break; - case 31: SetLkupStage(n, oMod, CLASS_TYPE_SHADOWSMITH, "cls_myst_shdsmt"); break; - case 32: SetLkupStage(n, oMod, CLASS_TYPE_CELEBRANT_SHARESS, "cls_spell_sharss"); break; + case 14: SetLkupStage(n, oMod, CLASS_TYPE_BARD, "cls_spell_bard"); break; + case 15: SetLkupStage(n, oMod, CLASS_TYPE_BEGUILER, "cls_spell_beguil"); break; + case 16: SetLkupStage(n, oMod, CLASS_TYPE_DREAD_NECROMANCER, "cls_spell_dnecro"); break; + case 17: SetLkupStage(n, oMod, CLASS_TYPE_DUSKBLADE, "cls_spell_duskbl"); break; + case 18: SetLkupStage(n, oMod, CLASS_TYPE_FAVOURED_SOUL, "cls_spell_favsol"); break; + case 19: SetLkupStage(n, oMod, CLASS_TYPE_HARPER, "cls_spell_harper"); break; + case 20: SetLkupStage(n, oMod, CLASS_TYPE_HEXBLADE, "cls_spell_hexbl"); break; + case 21: SetLkupStage(n, oMod, CLASS_TYPE_JUSTICEWW, "cls_spell_justww"); break; + case 22: SetLkupStage(n, oMod, CLASS_TYPE_SORCERER, "cls_spell_sorc"); break; + case 23: SetLkupStage(n, oMod, CLASS_TYPE_SUBLIME_CHORD, "cls_spell_schord"); break; + case 24: SetLkupStage(n, oMod, CLASS_TYPE_SUEL_ARCHANAMACH, "cls_spell_suel"); break; + case 25: SetLkupStage(n, oMod, CLASS_TYPE_VIGILANT, "cls_spell_vigil"); break; + case 26: SetLkupStage(n, oMod, CLASS_TYPE_WARMAGE, "cls_spell_wrmage"); break; + case 27: SetLkupStage(n, oMod, CLASS_TYPE_KNIGHT_WEAVE, "cls_spell_kngtwv"); break; + case 28: SetLkupStage(n, oMod, CLASS_TYPE_PSYCHIC_ROGUE, "cls_psipw_psyrog"); break; + case 29: SetLkupStage(n, oMod, CLASS_TYPE_SHADOWCASTER, "cls_myst_shdcst"); break; + case 30: SetLkupStage(n, oMod, CLASS_TYPE_SHADOWSMITH, "cls_myst_shdsmt"); break; + case 31: SetLkupStage(n, oMod, CLASS_TYPE_CELEBRANT_SHARESS, "cls_spell_sharss"); break; + + //:: These were all moved to the Bioware spellbooks -Jaysyn + //case 14: SetLkupStage(n, oMod, CLASS_TYPE_ASSASSIN, "cls_spell_asasin"); break; //case 46: SetLkupStage(n, oMod, CLASS_TYPE_CULTIST_SHATTERED_PEAK, "cls_spell_cultst"); break; //case 40: SetLkupStage(n, oMod, CLASS_TYPE_NENTYAR_HUNTER, "cls_spell_hunter"); break; //case 28: SetLkupStage(n, oMod, CLASS_TYPE_SHADOWLORD, "cls_spell_tfshad"); break; @@ -528,7 +530,7 @@ int SpellToSpellbookID(int nSpell) int nOutSpellID = GetLocalInt(oWP, /*"PRC_GetRowFromSpellID_" + */IntToString(nSpell)); if(nOutSpellID == 0) nOutSpellID = -1; - //if(DEBUG) DoDebug("SpellToSpellbookID(" + IntToString(nSpell) + ", " + sFile + ") = " + IntToString(nOutSpellID)); + if(DEBUG) DoDebug("inc_lookup >> SpellToSpellbookID: (nSpell: " + IntToString(nSpell) + ") = nOutSpellID: " + IntToString(nOutSpellID)); return nOutSpellID; } diff --git a/src/include/inc_newspellbook.nss b/src/include/inc_newspellbook.nss index 909b93d..5a06b4d 100644 --- a/src/include/inc_newspellbook.nss +++ b/src/include/inc_newspellbook.nss @@ -8,7 +8,7 @@ Make cls_spcr_*.2da Make blank cls_spell_*.2da Add cls_spgn_*.2da to classes.2da Add class entry in prc_classes.2da -Add the spellbook feat (#1999) to cls_feat_*.2da at the appropriate level +Add the spellbook feat (#1999) to cls_feat_*.2da at the appropriate level (not needed for NWN:EE) Add class to PRCGetSpellSaveDC() in prc_add_spell_dc Add class to GetSpellbookTypeForClass() below Add class to GetAbilityScoreForClass() below @@ -20,6 +20,8 @@ Add class to GetCasterLvl() in prc_inc_spells Add Practiced Spellcaster feat to feat.2da and to PracticedSpellcasting() in prc_inc_castlvl Run the assemble_spellbooks.bat file Make the prc_* scripts in newspellbook. The filenames can be found under the spell entries for the class in spells.2da. +Update the fileends for all relevant files in inc_switch_setup +Delete prc_data in the \database\ folder before testing new spells. Spont: Make cls_spgn_*.2da @@ -41,6 +43,8 @@ Add class to prc_amagsys_gain if(CheckMissingSpells(oPC, CLASS_TYPE_SORCERER, Mi Add class to ExecuteScript("prc_amagsys_gain", oPC) list in EvalPRCFeats in prc_inc_function Run the assemble_spellbooks.bat file Make the prc_* scripts in newspellbook +Update the fileends for all relevant files in inc_switch_setup +Delete prc_data in the \database\ folder before testing new spells. prc_classes.2da entry: Label - name for the class @@ -104,11 +108,10 @@ void ProcessPreparedSpellLevel(object oPC, int nClass, int nSpellLevel, int nLev //#include "prc_effect_inc" //access via prc_inc_core //#include "inc_lookups" //access via prc_inc_core #include "prc_inc_core" -#include "inc_sp_gain_mem" //providing child access to prc_inc_core - //Must load in this order. +#include "inc_sp_gain_mem" //#include "prc_inc_castlvl" //access via prc_inc_core //#include "prc_inc_descrptr" //access via prc_inc_core - +#include "inc_item_props" ////////////////////////////////////////////////// /* Function definitions */ @@ -119,6 +122,7 @@ int GetSpellbookTypeForClass(int nClass) switch(nClass) { case CLASS_TYPE_ARCHIVIST: + case CLASS_TYPE_ASSASSIN: case CLASS_TYPE_BLACKGUARD: case CLASS_TYPE_BLIGHTER: case CLASS_TYPE_CLERIC: @@ -141,7 +145,6 @@ int GetSpellbookTypeForClass(int nClass) case CLASS_TYPE_VIGILANT: case CLASS_TYPE_WIZARD: return SPELLBOOK_TYPE_PREPARED; - case CLASS_TYPE_ASSASSIN: case CLASS_TYPE_BARD: case CLASS_TYPE_BEGUILER: case CLASS_TYPE_CELEBRANT_SHARESS: @@ -559,7 +562,7 @@ int bKnowsAllClassSpells(int nClass) { //case CLASS_TYPE_WIZARD: case CLASS_TYPE_ARCHIVIST: - case CLASS_TYPE_ASSASSIN: + //case CLASS_TYPE_ASSASSIN: case CLASS_TYPE_BARD: case CLASS_TYPE_CELEBRANT_SHARESS: case CLASS_TYPE_CULTIST_SHATTERED_PEAK: @@ -580,7 +583,79 @@ int bKnowsAllClassSpells(int nClass) return TRUE; } + int GetSpellKnownMaxCount(int nLevel, int nSpellLevel, int nClass, object oPC) +{ + // If the character doesn't have any spell slots available on for this level, it can't know any spells of that level either + if(!GetSlotCount(nLevel, nSpellLevel, GetAbilityScoreForClass(nClass, oPC), nClass)) + { + if(DEBUG) DoDebug("GetSpellKnownMaxCount: No slots available for " + IntToString(nClass) + " level " + IntToString(nLevel) + " circle " + IntToString(nSpellLevel)); + return 0; + } + + int nKnown; + string sFile = Get2DACache("classes", "SpellKnownTable", nClass); + string sKnown = Get2DACache(sFile, "SpellLevel" + IntToString(nSpellLevel), nLevel - 1); + + if(DEBUG) + { + DoDebug("GetSpellKnownMaxCount Details:"); + DoDebug("- Class: " + IntToString(nClass)); + DoDebug("- Passed Level: " + IntToString(nLevel)); + DoDebug("- Base Class Level: " + IntToString(GetLevelByClass(nClass, oPC))); + DoDebug("- Effective Level: " + IntToString(GetSpellslotLevel(nClass, oPC))); + DoDebug("- Spell Level: " + IntToString(nSpellLevel)); + DoDebug("- SpellKnownTable: " + sFile); + DoDebug("- MaxKnown from 2DA: " + sKnown); + } + + if(sKnown == "") + { + nKnown = -1; + if(DEBUG) DoDebug("GetSpellKnownMaxCount: Problem getting known numbers"); + } + else + nKnown = StringToInt(sKnown); + + if(nKnown == -1) + return 0; + + // COMPLETELY REWROTE THIS SECTION + // Bard and Sorcerer logic for prestige class advancement + if(nClass == CLASS_TYPE_SORCERER || nClass == CLASS_TYPE_BARD) + { + int baseClassLevel = GetLevelByClass(nClass, oPC); + int effectiveLevel = GetSpellslotLevel(nClass, oPC); + + // Debug the values we're checking + if(DEBUG) + { + DoDebug("Spont caster check - Base level: " + IntToString(baseClassLevel) + + ", Effective level: " + IntToString(effectiveLevel)); + } + + // If they have prestige class advancement OR special feats, they should get spells + if(effectiveLevel > baseClassLevel || + GetHasFeat(FEAT_DRACONIC_GRACE, oPC) || + GetHasFeat(FEAT_DRACONIC_BREATH, oPC)) + { + // Allow them to get spells - do nothing here, return nKnown at the end + if(DEBUG) DoDebug("Spontaneous caster eligible for new spells"); + } + else + { + // No advancement, no special feats - no new spells + if(DEBUG) DoDebug("Spontaneous caster NOT eligible for new spells"); + return 0; + } + } + + if(DEBUG) DoDebug("Final spell known count: " + IntToString(nKnown)); + return nKnown; +} + + +/* int GetSpellKnownMaxCount(int nLevel, int nSpellLevel, int nClass, object oPC) { // If the character doesn't have any spell slots available on for this level, it can't know any spells of that level either // @todo Check rules. There might be cases where this doesn't hold @@ -588,22 +663,9 @@ int GetSpellKnownMaxCount(int nLevel, int nSpellLevel, int nClass, object oPC) return 0; int nKnown; string sFile; - // Bioware casters use their classes.2da-specified tables - /*if( nClass == CLASS_TYPE_WIZARD - || nClass == CLASS_TYPE_SORCERER - || nClass == CLASS_TYPE_BARD - || nClass == CLASS_TYPE_CLERIC - || nClass == CLASS_TYPE_DRUID - || nClass == CLASS_TYPE_PALADIN - || nClass == CLASS_TYPE_RANGER) - {*/ - sFile = Get2DACache("classes", "SpellKnownTable", nClass); - /*} - else - { - sFile = Get2DACache("classes", "FeatsTable", nClass); - sFile = "cls_spkn" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061231 - }*/ + + sFile = Get2DACache("classes", "SpellKnownTable", nClass); + string sKnown = Get2DACache(sFile, "SpellLevel" + IntToString(nSpellLevel), nLevel - 1); if(DEBUG) DoDebug("GetSpellKnownMaxCount(" + IntToString(nLevel) + ", " + IntToString(nSpellLevel) + ", " + IntToString(nClass) + ", " + GetName(oPC) + ") = " + sKnown); @@ -626,6 +688,7 @@ int GetSpellKnownMaxCount(int nLevel, int nSpellLevel, int nClass, object oPC) } return nKnown; } + */ int GetSpellKnownCurrentCount(object oPC, int nSpellLevel, int nClass) { @@ -693,6 +756,44 @@ int GetSpellKnownCurrentCount(object oPC, int nSpellLevel, int nClass) } int GetSpellUnknownCurrentCount(object oPC, int nSpellLevel, int nClass) +{ + // Get the lookup token created by MakeSpellbookLevelLoop() + string sTag = "SpellLvl_" + IntToString(nClass) + "_Level_" + IntToString(nSpellLevel); + object oCache = GetObjectByTag(sTag); + if(!GetIsObjectValid(oCache)) + { + if(DEBUG) DoDebug("GetSpellUnknownCurrentCount: " + sTag + " is not valid"); + + // Add code to create the missing lookup object + if(DEBUG) DoDebug("Attempting to create missing spell lookup token"); + ExecuteScript("prc_create_spellb", oPC); + + // Try again after creating it + oCache = GetObjectByTag(sTag); + if(!GetIsObjectValid(oCache)) + { + if(DEBUG) DoDebug("Still couldn't create spell lookup token"); + return 0; + } + else + { + if(DEBUG) DoDebug("Successfully created spell lookup token"); + } + } + + // Read the total number of spells on the given level and determine how many are already known + int nTotal = array_get_size(oCache, "Lkup"); + int nKnown = GetSpellKnownCurrentCount(oPC, nSpellLevel, nClass); + int nUnknown = nTotal - nKnown; + + if(DEBUG) DoDebug("GetSpellUnknownCurrentCount(" + GetName(oPC) + ", " + IntToString(nSpellLevel) + ", " + IntToString(nClass) + ") = " + IntToString(nUnknown)); + if(DEBUG) DoDebug(" Total spells in lookup: " + IntToString(nTotal) + ", Known spells: " + IntToString(nKnown)); + + return nUnknown; +} + + +/* int GetSpellUnknownCurrentCount(object oPC, int nSpellLevel, int nClass) { // Get the lookup token created by MakeSpellbookLevelLoop() string sTag = "SpellLvl_" + IntToString(nClass) + "_Level_" + IntToString(nSpellLevel); @@ -709,7 +810,7 @@ int GetSpellUnknownCurrentCount(object oPC, int nSpellLevel, int nClass) if(DEBUG) DoDebug("GetSpellUnknownCurrentCount(" + GetName(oPC) + ", " + IntToString(nSpellLevel) + ", " + IntToString(nClass) + ") = " + IntToString(nUnknown)); return nUnknown; -} +} */ void AddSpellUse(object oPC, int nSpellbookID, int nClass, string sFile, string sArrayName, int nSpellbookType, object oSkin, int nFeatID, int nIPFeatID, string sIDX = "") { @@ -850,7 +951,7 @@ void SetupSpells(object oPC, int nClass) int nAbility = GetAbilityScoreForClass(nClass, oPC); int nSpellbookType = GetSpellbookTypeForClass(nClass); - if(DEBUG) DoDebug("SetupSpells\n" + if(DEBUG) DoDebug("SetupSpells()\n" + "nClass = " + IntToString(nClass) + "\n" + "nSpellslotLevel = " + IntToString(nLevel) + "\n" + "nAbility = " + IntToString(nAbility) + "\n" @@ -1178,7 +1279,7 @@ void CastSpontaneousSpell(int nClass, int bInstantSpell = FALSE) else if(GetLocalInt(OBJECT_SELF, "PRC_metamagic_state") == 1) SetLocalInt(OBJECT_SELF, "MetamagicFeatAdjust", 0); } - + if (DEBUG) DoDebug("CastSpontaneousSpell(): nSpellLevel is: "+IntToString(nSpellLevel)+"."); CheckSpontSlots(nClass, nSpellID, nSpellLevel); if(GetLocalInt(OBJECT_SELF, "NSB_Cast")) ActionDoCommand(CheckSpontSlots(nClass, nSpellID, nSpellLevel, TRUE)); @@ -1330,6 +1431,8 @@ void NewSpellbookSpell(int nClass, int nSpellbookType, int nMetamagic = METAMAGI string sFile = GetFileForClass(nClass); int nSpellLevel = StringToInt(Get2DACache(sFile, "Level", nSpellbookID)); + + if (DEBUG) DoDebug("inc_newspellbook >> NewSpellbookSpell(): nSpellbookType is: "+IntToString(nSpellbookType)+"."); // Make sure the caster has uses of this spell remaining // 2009-9-20: Add metamagic feat abilities. -N-S @@ -1371,13 +1474,14 @@ void NewSpellbookSpell(int nClass, int nSpellbookType, int nMetamagic = METAMAGI else if(nSpellLevel > 9)//now test the spell level { nMetamagic = METAMAGIC_NONE; - ActionDoCommand(SendMessageToPC(oPC, "Modified spell level is to high! Casting spell without metamagic")); + ActionDoCommand(SendMessageToPC(oPC, "Modified spell level is too high! Casting spell without metamagic")); nSpellLevel = nSpellSlotLevel; } else if(GetLocalInt(oPC, "PRC_metamagic_state") == 1) SetLocalInt(oPC, "MetamagicFeatAdjust", 0); } - + + if (DEBUG) DoDebug("inc_newspellbook >> NewSpellbookSpell(): nSpellLevel is: "+IntToString(nSpellLevel)+"."); CheckSpontSlots(nClass, nSpellID, nSpellLevel); if(GetLocalInt(oPC, "NSB_Cast")) ActionDoCommand(CheckSpontSlots(nClass, nSpellID, nSpellLevel, TRUE)); @@ -1460,7 +1564,7 @@ void CheckPrepSlots(int nClass, int nSpellID, int nSpellbookID, int bIsAction = { DeleteLocalInt(OBJECT_SELF, "NSB_Cast"); int nCount = persistant_array_get_int(OBJECT_SELF, "NewSpellbookMem_" + IntToString(nClass), nSpellbookID); - if(DEBUG) DoDebug("NewSpellbookSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(nSpellbookID) + "] = " + IntToString(nCount)); + if(DEBUG) DoDebug("NewSpellbookSpell >> CheckPrepSlots: NewSpellbookMem_" + IntToString(nClass) + "[SpellbookID: " + IntToString(nSpellbookID) + "] = " + IntToString(nCount)); if(nCount < 1) { string sSpellName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID))); @@ -1486,7 +1590,7 @@ void CheckSpontSlots(int nClass, int nSpellID, int nSpellSlotLevel, int bIsActio { DeleteLocalInt(OBJECT_SELF, "NSB_Cast"); int nCount = persistant_array_get_int(OBJECT_SELF, "NewSpellbookMem_" + IntToString(nClass), nSpellSlotLevel); - if(DEBUG) DoDebug("NewSpellbookSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(nSpellSlotLevel) + "] = " + IntToString(nCount)); + if(DEBUG) DoDebug("NewSpellbookSpell >> CheckSpontSlots: NewSpellbookMem_" + IntToString(nClass) + "[SpellSlotLevel: " + IntToString(nSpellSlotLevel) + "] = " + IntToString(nCount)); if(nCount < 1) { // "You have no castings of spells of level " + IntToString(nSpellLevel) + " remaining" @@ -1517,6 +1621,3 @@ void DoCleanUp(int nMetamagic) DeleteLocalInt(OBJECT_SELF, "NSB_SpellLevel"); DeleteLocalInt(OBJECT_SELF, "NSB_SpellbookID"); } - -//:: Test Void -//:: void main (){} \ No newline at end of file diff --git a/src/include/inc_npc.nss b/src/include/inc_npc.nss index 6b99a4a..8385ddc 100644 --- a/src/include/inc_npc.nss +++ b/src/include/inc_npc.nss @@ -7,8 +7,11 @@ //::////////////////////////////////////////////// //::////////////////////////////////////////////// +//:: Levels up an NPC according to variables set on NPC. +void LevelUpSummon(object oSummon, int iTargetLvl); + // Get the master of oAssociate. -object GetMasterNPC(object oAssociate=OBJECT_SELF); +object GetMasterNPC(object oAssociate0 = OBJECT_SELF); // Returns the associate type of the specified creature. // - Returns ASSOCIATE_TYPE_NONE if the creature is not the associate of anyone. @@ -75,7 +78,6 @@ void DestroySummon(object 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); @@ -111,7 +113,7 @@ object CreateLocalNextNPC(object oMaster,int nAssociateType,string sTemplate,loc SetLocalObject(oMaster, IntToString(nAssociateType)+"oHench"+IntToString(nCount), oSummon); SetLocalInt(oSummon, "iAssocNth", nCount); - SetAssociateState(NW_ASC_HAVE_MASTER,TRUE,oSummon); + 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); @@ -122,6 +124,7 @@ object CreateLocalNextNPC(object oMaster,int nAssociateType,string sTemplate,loc return oSummon; } + object GetMasterNPC(object oAssociate=OBJECT_SELF) { object oMaster = GetLocalObject(oAssociate, "oMaster"); @@ -220,4 +223,173 @@ int GetAssociateHealMasterNPC() return FALSE; } +/** + * @brief Levels up a summoned creature based on its master's total casting level, + * while respecting configured HD limits and multiclass transition rules. + * Should only be called on the NPC onSpawn event. + * + * This function: + * - Retrieves the master’s total casting level and clamps it to the creature’s + * minimum and maximum HD (iMinHD, iMaxHD). + * - Repeatedly calls LevelUpHenchman() until the creature reaches that level, + * switching classes when the creature's stored "ClassXStart" thresholds are met. + * + * Local variables recognized on the summoned creature: + * + * | Variable Name | Purpose | + * |-----------------|-------------------------------------------------------------| + * | iMinHD | Minimum HD allowed | + * | iMaxHD | Maximum HD allowed | + * | Class2Start | Level to begin second class progression | + * | Class2 | Class type for second progression | + * | Class2Package | Package for second progression | + * | Class3Start | Level to begin third class progression | + * | Class3 | Class type for third progression | + * | Class3Package | Package for third progression | + * | Class4Start | Level to begin fourth class progression | + * | Class4 | Class type for fourth progression | + * | Class4Package | Package for fourth progression | + * + * Behavior notes: + * - Leveling continues until the creature reaches the master’s effective + * casting level (bounded by iMinHD/iMaxHD). + * - If LevelUpHenchman() returns 0, the creature shouts a failure message. + * - CLASS_TYPE_INVALID causes the creature to level in its current class. + * + * @param oCreature The summoned creature being leveled. Defaults to OBJECT_SELF. + * + * @see LevelUpHenchman + * @see GetLocalInt + * @see GetHitDice + */ +void LevelUpSummon(object oSummon, int iTargetLvl) +{ + int nCurrentHD = GetHitDice(oSummon); + int iNewHD = nCurrentHD; + // Read multiclassing info from locals + int iClass2Start = GetLocalInt(oSummon, "Class2Start"); + int iClass2 = GetLocalInt(oSummon, "Class2"); + int iClass2Package = GetLocalInt(oSummon, "Class2Package"); + + int iClass3Start = GetLocalInt(oSummon, "Class3Start"); + int iClass3 = GetLocalInt(oSummon, "Class3"); + int iClass3Package = GetLocalInt(oSummon, "Class3Package"); + + int iClass4Start = GetLocalInt(oSummon, "Class4Start"); + int iClass4 = GetLocalInt(oSummon, "Class4"); + int iClass4Package = GetLocalInt(oSummon, "Class4Package"); + + int iClass; // current class to level + int iPackage; // package to use + + // Main leveling loop + while (nCurrentHD < iTargetLvl && nCurrentHD > 0) + { + // Determine which class and package to use + if (iClass4Start != 0 && nCurrentHD >= iClass4Start) + { + iClass = iClass4; + iPackage = iClass4Package; + } + else if (iClass3Start != 0 && nCurrentHD >= iClass3Start) + { + iClass = iClass3; + iPackage = iClass3Package; + } + else if (iClass2Start != 0 && nCurrentHD >= iClass2Start) + { + iClass = iClass2; + iPackage = iClass2Package; + } + else + { + // Base class (first class in the sheet) + iClass = CLASS_TYPE_INVALID; // keeps current + iPackage = PACKAGE_INVALID; + } + + // Level up one HD + iNewHD = LevelUpHenchman(oSummon, iClass, TRUE, iPackage); + + if (iNewHD == 0) + { + SpeakString(GetName(oSummon) + " failed to level properly!", TALKVOLUME_SHOUT); + break; + } + + nCurrentHD = iNewHD; + } + + // Force the creature to rest to memorize spells + // PRCForceRest(oSummon); + +} + + + + + +/* void LevelUpSummon(object oSummon, int iTargetLvl) +{ + //get the default hit dice of the summon + int nDefaultHD = GetHitDice(oSummon); + + if (DEBUG) DoDebug("inc_npc >> LevelUpSummon: nDefaultHD = " +IntToString(nDefaultHD)+"."); + + if (DEBUG) DoDebug("inc_npc >> LevelUpSummon: iTargetLvl = " +IntToString(iTargetLvl)+"."); + + //get the multiclassing variables to see if we need to change classes from its base class + int iClass2Start = GetLocalInt(oSummon, "Class2Start"); + int iClass2 = GetLocalInt(oSummon, "Class2"); + int iClass2Package = GetLocalInt(oSummon, "Class2Package"); + + int iClass3Start = GetLocalInt(oSummon, "Class3Start"); + int iClass3 = GetLocalInt(oSummon, "Class3"); + int iClass3Package = GetLocalInt(oSummon, "Class3Package"); + + int iClass4Start = GetLocalInt(oSummon, "Class4Start"); + int iClass4 = GetLocalInt(oSummon, "Class4"); + int iClass4Package = GetLocalInt(oSummon, "Class4Package"); + + //check for zero cause thats an error + //if creatures are not leveling then best bet is they are not legal creatures + while( (nDefaultHD < iTargetLvl) && (nDefaultHD > 0) ) + { + //check the multiclassing numbers to change classes + if( (iClass4Start != 0) && (nDefaultHD >= iClass4Start) ) + { + //level up using the new class and Packageage + nDefaultHD = LevelUpHenchman(oSummon, iClass4 ,TRUE, iClass4Package); + + if(nDefaultHD == 0) + SpeakString(GetName(oSummon) + " Failed on fourth class", TALKVOLUME_SHOUT); + } + else if( (iClass3Start != 0) && (nDefaultHD >= iClass3Start) ) + { + //level up using the new class and Packageage + nDefaultHD = LevelUpHenchman(oSummon, iClass3 ,TRUE, iClass3Package); + + if(nDefaultHD == 0) + SpeakString(GetName(oSummon) + " Failed on third class", TALKVOLUME_SHOUT); + } + else if( (iClass2Start != 0) && (nDefaultHD >= iClass2Start) ) + { + //level up using the new class and Packageage + nDefaultHD = LevelUpHenchman(oSummon, iClass2 ,TRUE, iClass2Package); + + if(nDefaultHD == 0) + SpeakString(GetName(oSummon) + " Failed on second class", TALKVOLUME_SHOUT); + } + else + { + //just level up using the class it already has + nDefaultHD = LevelUpHenchman(oSummon, CLASS_TYPE_INVALID ,TRUE); + + if(nDefaultHD == 0) + SpeakString(GetName(oSummon) + " Failed to level properly", TALKVOLUME_SHOUT); + } + } +} + */ +//:: void main() {} \ No newline at end of file diff --git a/src/include/inc_rand_equip.nss b/src/include/inc_rand_equip.nss index 814f533..07f7191 100644 --- a/src/include/inc_rand_equip.nss +++ b/src/include/inc_rand_equip.nss @@ -3433,6 +3433,7 @@ int PrimoGetWeaponSize(object oItem) case BASE_ITEM_LIGHTFLAIL: case BASE_ITEM_KATANA: case BASE_ITEM_MAGICSTAFF: + case BASE_ITEM_CRAFTED_SCEPTER: case BASE_ITEM_LONGSWORD: case BASE_ITEM_TRIDENT: case BASE_ITEM_MORNINGSTAR: diff --git a/src/include/inc_rend.nss b/src/include/inc_rend.nss index 06e2b2f..07ae6b3 100644 --- a/src/include/inc_rend.nss +++ b/src/include/inc_rend.nss @@ -30,6 +30,7 @@ int GetDamageFromConstant(int nIPConst); void DoFrostRend(object oTarget, object oAttacker, object oWeapon); #include "moi_inc_moifunc" +#include "prc_inc_combat" ////////////////////////////////////////////////// /* Function defintions */ diff --git a/src/include/inc_sp_gain_mem.nss b/src/include/inc_sp_gain_mem.nss index d994896..b3981be 100644 --- a/src/include/inc_sp_gain_mem.nss +++ b/src/include/inc_sp_gain_mem.nss @@ -17,9 +17,6 @@ Created: May 1, 2008 //:: Updated for .35 by Jaysyn 2023/03/11 -//:: Test Void -//void main (){} - //::////////////////////////////////////////////// //:: Constants //::////////////////////////////////////////////// @@ -63,6 +60,14 @@ string GetMetaMagicString(int nMetaMagic); int GetMetaMagicFromFeat(int nFeat); int GetMetaMagicOfCaster(object oPC = OBJECT_SELF); +string GetFileForClass(int nClass); +int GetSpellslotLevel(int nClass, object oPC); +int GetSpellKnownMaxCount(int nLevel, int nSpellLevel, int nClass, object oPC); +int GetSpellbookTypeForClass(int nClass); + +#include "inc_pers_array" +#include "inc_2dacache" + // name of the new spellbook file (cls_spell_*) string GetNSBDefinitionFileName(int nClass) { diff --git a/src/include/inc_switch_setup.nss b/src/include/inc_switch_setup.nss index afffaae..86c526c 100644 --- a/src/include/inc_switch_setup.nss +++ b/src/include/inc_switch_setup.nss @@ -44,6 +44,7 @@ void CreateSwitchNameArray(); #include "prc_inc_array" // Needs direct include instead of inc_utility #include "prc_inc_switch" +#include "inc_2dacache" ////////////////////////////////////////////////// /* Function definitions */ @@ -221,9 +222,9 @@ void SetDefaultFileEnds() SetPRCSwitch("PRC_FILE_END_cls_spcr_bard", 144); SetPRCSwitch("PRC_FILE_END_cls_spcr_beguil", 142); SetPRCSwitch("PRC_FILE_END_cls_spcr_blkgrd", 47); - SetPRCSwitch("PRC_FILE_END_cls_spcr_dnecro", 137); + SetPRCSwitch("PRC_FILE_END_cls_spcr_dnecro", 138); SetPRCSwitch("PRC_FILE_END_cls_spcr_duskbl", 69); - SetPRCSwitch("PRC_FILE_END_cls_spcr_favsol", 290); + SetPRCSwitch("PRC_FILE_END_cls_spcr_favsol", 300); SetPRCSwitch("PRC_FILE_END_cls_spcr_harper", 35); SetPRCSwitch("PRC_FILE_END_cls_spcr_healer", 77); SetPRCSwitch("PRC_FILE_END_cls_spcr_hexbl", 73); @@ -251,9 +252,9 @@ void SetDefaultFileEnds() SetPRCSwitch("PRC_FILE_END_cls_spell_bard", 169); SetPRCSwitch("PRC_FILE_END_cls_spell_beguil", 119); SetPRCSwitch("PRC_FILE_END_cls_spell_blkgrd", 163); - SetPRCSwitch("PRC_FILE_END_cls_spell_dnecro", 134); + SetPRCSwitch("PRC_FILE_END_cls_spell_dnecro", 135); SetPRCSwitch("PRC_FILE_END_cls_spell_duskbl", 84); - SetPRCSwitch("PRC_FILE_END_cls_spell_favsol", 363); + SetPRCSwitch("PRC_FILE_END_cls_spell_favsol", 373); SetPRCSwitch("PRC_FILE_END_cls_spell_harper", 21); SetPRCSwitch("PRC_FILE_END_cls_spell_healer", 271); SetPRCSwitch("PRC_FILE_END_cls_spell_hexbl", 79); @@ -267,7 +268,7 @@ void SetDefaultFileEnds() SetPRCSwitch("PRC_FILE_END_cls_spell_sod", 110); SetPRCSwitch("PRC_FILE_END_cls_spell_sohei", 131); SetPRCSwitch("PRC_FILE_END_cls_spell_sol", 114); - SetPRCSwitch("PRC_FILE_END_cls_spell_sorc", 541); + SetPRCSwitch("PRC_FILE_END_cls_spell_sorc", 550); SetPRCSwitch("PRC_FILE_END_cls_spell_suel", 160); SetPRCSwitch("PRC_FILE_END_cls_spell_templ", 95); SetPRCSwitch("PRC_FILE_END_cls_spell_tfshad", 70); @@ -335,7 +336,7 @@ void SetDefaultFileEnds() SetPRCSwitch("PRC_FILE_END_craft_golem", 40); SetPRCSwitch("PRC_FILE_END_craft_ring", 41); SetPRCSwitch("PRC_FILE_END_craft_weapon", 46); - SetPRCSwitch("PRC_FILE_END_craft_wondrous", 115); + SetPRCSwitch("PRC_FILE_END_craft_wondrous", 131); SetPRCSwitch("PRC_FILE_END_creaturesize", 5); SetPRCSwitch("PRC_FILE_END_creaturespeed", 8); SetPRCSwitch("PRC_FILE_END_crtemplates", 10); @@ -355,7 +356,7 @@ void SetDefaultFileEnds() SetPRCSwitch("PRC_FILE_END_des_crft_poison", 100); SetPRCSwitch("PRC_FILE_END_des_crft_props", 27); SetPRCSwitch("PRC_FILE_END_des_crft_scroll", 3999); - SetPRCSwitch("PRC_FILE_END_des_crft_spells", 19348); + SetPRCSwitch("PRC_FILE_END_des_crft_spells", 20000); SetPRCSwitch("PRC_FILE_END_des_crft_weapon", 29); SetPRCSwitch("PRC_FILE_END_des_cutconvdur", 26); SetPRCSwitch("PRC_FILE_END_des_feat2item", 1000); @@ -408,7 +409,7 @@ void SetDefaultFileEnds() SetPRCSwitch("PRC_FILE_END_iprp_ammocost", 15); SetPRCSwitch("PRC_FILE_END_iprp_ammotype", 2); SetPRCSwitch("PRC_FILE_END_iprp_amount", 4); - SetPRCSwitch("PRC_FILE_END_iprp_aoe", 7); + SetPRCSwitch("PRC_FILE_END_iprp_aoe", 8); SetPRCSwitch("PRC_FILE_END_iprp_arcspell", 19); SetPRCSwitch("PRC_FILE_END_iprp_base1", -1); SetPRCSwitch("PRC_FILE_END_iprp_bladecost", 5); @@ -423,15 +424,15 @@ void SetDefaultFileEnds() SetPRCSwitch("PRC_FILE_END_iprp_damvulcost", 7); SetPRCSwitch("PRC_FILE_END_iprp_decvalue1", 9); SetPRCSwitch("PRC_FILE_END_iprp_decvalue2", 9); - SetPRCSwitch("PRC_FILE_END_iprp_feats", 24819); + SetPRCSwitch("PRC_FILE_END_iprp_feats", 26999); SetPRCSwitch("PRC_FILE_END_iprp_immuncost", 7); SetPRCSwitch("PRC_FILE_END_iprp_immunity", 9); SetPRCSwitch("PRC_FILE_END_iprp_incvalue1", 9); SetPRCSwitch("PRC_FILE_END_iprp_incvalue2", 9); SetPRCSwitch("PRC_FILE_END_iprp_kitcost", 50); SetPRCSwitch("PRC_FILE_END_iprp_lightcost", 4); - SetPRCSwitch("PRC_FILE_END_iprp_matcost", 77); - SetPRCSwitch("PRC_FILE_END_iprp_material", 77); + SetPRCSwitch("PRC_FILE_END_iprp_matcost", 145); + SetPRCSwitch("PRC_FILE_END_iprp_material", 145); SetPRCSwitch("PRC_FILE_END_iprp_maxpp", 8); SetPRCSwitch("PRC_FILE_END_iprp_meleecost", 20); SetPRCSwitch("PRC_FILE_END_iprp_metamagic", 6); @@ -458,11 +459,11 @@ void SetDefaultFileEnds() SetPRCSwitch("PRC_FILE_END_iprp_soakcost", 50); SetPRCSwitch("PRC_FILE_END_iprp_speed_dec", 9); SetPRCSwitch("PRC_FILE_END_iprp_speed_enh", 9); - SetPRCSwitch("PRC_FILE_END_iprp_spellcost", 243); + SetPRCSwitch("PRC_FILE_END_iprp_spellcost", 298); SetPRCSwitch("PRC_FILE_END_iprp_spellcstr", 42); SetPRCSwitch("PRC_FILE_END_iprp_spelllvcost", 9); SetPRCSwitch("PRC_FILE_END_iprp_spelllvlimm", 9); - SetPRCSwitch("PRC_FILE_END_iprp_spells", 1456); + SetPRCSwitch("PRC_FILE_END_iprp_spells", 1552); SetPRCSwitch("PRC_FILE_END_iprp_spellshl", 7); SetPRCSwitch("PRC_FILE_END_iprp_srcost", 99); SetPRCSwitch("PRC_FILE_END_iprp_staminacost", -1); @@ -492,9 +493,9 @@ void SetDefaultFileEnds() SetPRCSwitch("PRC_FILE_END_itmwizwands", 38); SetPRCSwitch("PRC_FILE_END_keymap", 70); SetPRCSwitch("PRC_FILE_END_lightcolor", 32); - SetPRCSwitch("PRC_FILE_END_loadhints", 88); + SetPRCSwitch("PRC_FILE_END_loadhints", 101); SetPRCSwitch("PRC_FILE_END_loadscreens", 259); - SetPRCSwitch("PRC_FILE_END_masterfeats", 113); + SetPRCSwitch("PRC_FILE_END_masterfeats", 125); SetPRCSwitch("PRC_FILE_END_materialcomp", 200); SetPRCSwitch("PRC_FILE_END_metamagic", 6); SetPRCSwitch("PRC_FILE_END_namefilter", 3); @@ -720,7 +721,7 @@ void SetDefaultFileEnds() SetPRCSwitch("PRC_FILE_END_polymorph", 155); SetPRCSwitch("PRC_FILE_END_portraits", 1300); SetPRCSwitch("PRC_FILE_END_prc_craft_alchem", 37); - SetPRCSwitch("PRC_FILE_END_prc_craft_gen_it", 204); + SetPRCSwitch("PRC_FILE_END_prc_craft_gen_it", 253); SetPRCSwitch("PRC_FILE_END_prc_craft_poison", 62); SetPRCSwitch("PRC_FILE_END_prc_domains", 59); SetPRCSwitch("PRC_FILE_END_prc_familiar", 10); @@ -767,7 +768,7 @@ void SetDefaultFileEnds() SetPRCSwitch("PRC_FILE_END_soundset", 453); SetPRCSwitch("PRC_FILE_END_soundsettype", 4); SetPRCSwitch("PRC_FILE_END_soundtypes", 1); - SetPRCSwitch("PRC_FILE_END_spells", 19348); + SetPRCSwitch("PRC_FILE_END_spells", 19400); //SetPRCSwitch("PRC_FILE_END_spellschools", 9); SetPRCSwitch("PRC_FILE_END_statescripts", 35); SetPRCSwitch("PRC_FILE_END_stringtokens", 92); @@ -866,6 +867,31 @@ void CreateSwitchNameArray() //if you add more switches, add them to this list array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_DEBUG); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_COMBAT_DEBUG); + +//craft + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_DISABLE_CRAFT); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_TIMER_MULTIPLIER); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_TIMER_MAX); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_TIMER_MIN); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_BREW_POTION_CASTER_LEVEL); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_SCRIBE_SCROLL_CASTER_LEVEL); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_WAND_CASTER_LEVEL); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_ROD_CASTER_LEVEL); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_STAFF_CASTER_LEVEL); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_BASE_ITEMS); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_BREWPOTION_MAXLEVEL); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_BREWPOTION_COSTMODIFIER); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_SCRIBESCROLL_COSTMODIFIER); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_CRAFTWAND_MAXLEVEL); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_CRAFTWAND_COSTMODIFIER); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_CREATEINFUSION_COSTMODIFIER); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_ARBITRARY); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_COST_SCALE); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_TIME_SCALE); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CREATE_INFUSION_CASTER_LEVEL); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CREATE_INFUSION_OPTIONAL_HERBS); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_SCEPTER_CASTER_LEVEL); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_MATERIAL_COMPONENTS); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_DISABLE_COMPONENTS_SHOP); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_PNP_TRUESEEING); @@ -876,6 +902,10 @@ void CreateSwitchNameArray() array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_BIOWARE_HARM); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_BIOWARE_NEUTRALIZE_POISON); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_BIOWARE_REMOVE_DISEASE); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_ALLOWED_TO_REMOVE_FRIENDLY_SPELLS); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_ALLOWED_TO_SEE_HOSTILE_SPELLS); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_BIO_UNLEARN); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_UNLEARN_SPELL_MAXNR); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_TIMESTOP_BIOWARE_DURATION); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_TIMESTOP_LOCAL); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_TIMESTOP_NO_HOSTILE); @@ -992,7 +1022,7 @@ void CreateSwitchNameArray() array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_USES_PER_WEAPON_POISON_COUNT); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_USES_PER_WEAPON_POISON_DIE); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_POISON_ALLOW_CLEAN_IN_EQUIP); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_POISON_USE_INGREDIENST); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_POISON_USE_INGREDIENTS); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_PSI_ASTRAL_CONSTRUCT_USE_2DA); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_PSI_ASTRAL_CONSTRUCT_DUR_MOD); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_PNP_RAPID_METABOLISM); @@ -1056,29 +1086,31 @@ void CreateSwitchNameArray() array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_LETOSCRIPT_UNICORN_SQL); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_LETOSCRIPT_GETNEWESTBIC); -//craft - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_DISABLE_CRAFT); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_TIMER_MULTIPLIER); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_TIMER_MAX); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_TIMER_MIN); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_BREW_POTION_CASTER_LEVEL); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_SCRIBE_SCROLL_CASTER_LEVEL); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_WAND_CASTER_LEVEL); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_ROD_CASTER_LEVEL); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_STAFF_CASTER_LEVEL); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_BASE_ITEMS); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_BREWPOTION_MAXLEVEL); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_BREWPOTION_COSTMODIFIER); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_SCRIBESCROLL_COSTMODIFIER); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_CRAFTWAND_MAXLEVEL); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_CRAFTWAND_COSTMODIFIER); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_ARBITRARY); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_COST_SCALE); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_TIME_SCALE); - //spells //shifter + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_WEREWOLF_HYBRID_USE_SHIFTER_SHAPECHANGE); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_WILDSHAPE_ALLOWS_ARMS_SLOT); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PNP_SHFT_USECR); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PNP_SHFT_S_HUGE); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PNP_SHFT_S_LARGE); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PNP_SHFT_S_MEDIUM); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PNP_SHFT_S_SMALL); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PNP_SHFT_S_TINY); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PNP_SHFT_F_OUTSIDER); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PNP_SHFT_F_ELEMENTAL); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PNP_SHFT_F_CONSTRUCT); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PNP_SHFT_F_UNDEAD); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PNP_SHFT_F_DRAGON); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PNP_SHFT_F_ABERRATION); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PNP_SHFT_F_OOZE); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PNP_SHFT_F_MAGICALBEAST); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PNP_SHFT_F_GIANT); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PNP_SHFT_F_VERMIN); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PNP_SHFT_F_BEAST); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PNP_SHFT_F_ANIMAL); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PNP_SHFT_F_MONSTROUSHUMANOID); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PNP_SHFT_F_HUMANOID); //general diff --git a/src/include/inv_inc_blast.nss b/src/include/inv_inc_blast.nss index 683b9cd..94709f6 100644 --- a/src/include/inv_inc_blast.nss +++ b/src/include/inv_inc_blast.nss @@ -1,4 +1,5 @@ #include "prc_inc_clsfunc" +#include "prc_inc_sp_tch" int GetBlastDamageDices(object oInvoker, int nInvokerLevel) { diff --git a/src/include/inv_inc_invknown.nss b/src/include/inv_inc_invknown.nss index dbd7acb..95800ad 100644 --- a/src/include/inv_inc_invknown.nss +++ b/src/include/inv_inc_invknown.nss @@ -135,6 +135,9 @@ int GetHasInvocation(int nInvocation, object oCreature = OBJECT_SELF); /* Includes */ ////////////////////////////////////////////////// +int GetPrimaryInvocationClass(object oCreature = OBJECT_SELF); +int GetInvocationPRCLevels(object oCaster); + #include "inc_item_props" #include "prc_x2_itemprop" #include "inc_lookups" diff --git a/src/include/inv_inc_invoke.nss b/src/include/inv_inc_invoke.nss index 0abd1e1..da67444 100644 --- a/src/include/inv_inc_invoke.nss +++ b/src/include/inv_inc_invoke.nss @@ -123,7 +123,7 @@ void DeleteLocalInvocation(object oObject, string sName); /* Includes */ ////////////////////////////////////////////////// -//#include "inv_inc_invfunc" //Access in parent +#include "inv_inc_invfunc" //Access in parent #include "prc_spellf_inc" ////////////////////////////////////////////////// diff --git a/src/include/inv_invokehook.nss b/src/include/inv_invokehook.nss index 92b0f1f..53010f3 100644 --- a/src/include/inv_invokehook.nss +++ b/src/include/inv_invokehook.nss @@ -77,6 +77,15 @@ int PreInvocationCastCode() int nContinue = !ExecuteScriptAndReturnInt("prespellcode", oInvoker); + //--------------------------------------------------------------------------- + // Block forsakers from using invocations + //--------------------------------------------------------------------------- + if(GetLevelByClass(CLASS_TYPE_FORSAKER, oInvoker) > 0) + { + SendMessageToPC(oInvoker, "Forsakers cannot use invocations."); + return FALSE; + } + //--------------------------------------------------------------------------- // Break any spell require maintaining concentration //--------------------------------------------------------------------------- @@ -168,3 +177,4 @@ int PreInvocationCastCode() return nContinue; } +//:: void main (){} \ No newline at end of file diff --git a/src/include/moi_inc_moifunc.nss b/src/include/moi_inc_moifunc.nss index d48a441..62af858 100644 --- a/src/include/moi_inc_moifunc.nss +++ b/src/include/moi_inc_moifunc.nss @@ -1170,7 +1170,10 @@ int GetMaxEssentiaCapacityFeat(object oMeldshaper) { int nMax = 1; // Always can invest one int nHD = GetHitDice(oMeldshaper); - if (nHD >= 31) nMax = 5; + if (nHD >= 61) nMax = 8; + else if (nHD >= 51) nMax = 7; + else if (nHD >= 41) nMax = 6; + else if (nHD >= 31) nMax = 5; else if (nHD >= 18) nMax = 4; else if (nHD >= 12) nMax = 3; else if (nHD >= 6) nMax = 2; @@ -1182,7 +1185,7 @@ int GetMaxEssentiaCapacityFeat(object oMeldshaper) // Don't allow more than they have if (nMax > GetTotalUsableEssentia(oMeldshaper)) nMax = GetTotalUsableEssentia(oMeldshaper); - //if (DEBUG) DoDebug("GetMaxEssentiaCapacityFeat: nHD "+IntToString(nHD)+" nMax "+IntToString(nMax)); + if(DEBUG) DoDebug("GetMaxEssentiaCapacityFeat: nHD "+IntToString(nHD)+" nMax "+IntToString(nMax)); return nMax; } diff --git a/src/include/nw_inc_gff.nss b/src/include/nw_inc_gff.nss new file mode 100644 index 0000000..533cf21 --- /dev/null +++ b/src/include/nw_inc_gff.nss @@ -0,0 +1,623 @@ +// This is a helper library for advanced use: It allows constructing arbitrary gff data. +// You can then spawn your object via JsonToObject(). +// +// The data format is the same as https://github.com/niv/neverwinter.nim@1.4.3+. +// +// Example: +// +// json j = GffCreateObject(OBJECT_TYPE_ITEM); +// j = GffAddInt(j, "BaseItem", BASE_ITEM_BELT); +// j = GffAddInt(j, "ModelPart1", 12); +// j = GffAddLocString(j, "LocalizedName", "hi!"); +// object belt = JsonToObject(j, GetLocation(OBJECT_SELF)); + + +const string GFF_FIELD_TYPE_STRUCT = "struct"; +const string GFF_FIELD_TYPE_LIST = "list"; +const string GFF_FIELD_TYPE_BYTE = "byte"; +const string GFF_FIELD_TYPE_CHAR = "char"; +const string GFF_FIELD_TYPE_WORD = "word"; +const string GFF_FIELD_TYPE_SHORT = "short"; +const string GFF_FIELD_TYPE_DWORD = "dword"; +const string GFF_FIELD_TYPE_INT = "int"; +const string GFF_FIELD_TYPE_DWORD64 = "dword64"; +const string GFF_FIELD_TYPE_INT64 = "int64"; +const string GFF_FIELD_TYPE_FLOAT = "float"; +const string GFF_FIELD_TYPE_DOUBLE = "double"; +const string GFF_FIELD_TYPE_RESREF = "resref"; +const string GFF_FIELD_TYPE_STRING = "cexostring"; +const string GFF_FIELD_TYPE_LOC_STRING = "cexolocstring"; + + +// Create a empty object of the given type. You need to manually fill in all +// GFF data with GffAddXXX. This will require understanding of the GFF file format +// and what data fields each object type requires. +json GffCreateObject(int nObjectType); +// Create a combined area format(CAF) object. You need to manually create the ARE and GIT objects with their required data fields. +json GffCreateArea(json jARE, json jGIT); + +// Returns the OBJECT_TYPE_* of jGff. +// Note: Will return 0 for invalid object types, including areas. +int GffGetObjectType(json jGff); +// Returns TRUE if jGff is a combined area format(CAF) object. +int GffGetIsArea(json jGff); + +// Returns TRUE if a field named sLabel of sType exists in jGff. +// * sLabel: Can be a json pointer(path) without the starting /, see the documentation of JsonPointer() for details. +// * sType: An optional GFF_FIELD_TYPE_*, leave empty to check if sLabel exists regardless of type. +int GffGetFieldExists(json jGff, string sLabel, string sType = ""); + + +// Add a new field, will overwrite any existing fields with the same label even if the type is different. +// Returns a json null value on error with GetJsonError() filled in. +// +// sLabel can be a json pointer(path) without the starting /, see the documentation of JsonPointer() for details. +// For example, to add the tag of an area to an empty combined area format(CAF) object you can do the following: +// json jArea = GffCreateArea(JsonObject(), JsonObject()); +// jArea = GffAddString(jArea, "ARE/value/Tag", "AREA_TAG"); + +json GffAddStruct(json jGff, string sLabel, json jStruct, int nType = -1); +json GffAddList(json jGff, string sLabel, json jList); +json GffAddByte(json jGff, string sLabel, int v); +json GffAddChar(json jGff, string sLabel, int v); +json GffAddWord(json jGff, string sLabel, int v); +json GffAddShort(json jGff, string sLabel, int v); +// Note: Only data of type int32 will fit, because that's all that NWScript supports. +json GffAddDword(json jGff, string sLabel, int v); +json GffAddInt(json jGff, string sLabel, int v); +// Note: Only data of type int32 will fit, because that's all that NWScript supports. +json GffAddDword64(json jGff, string sLabel, int v); +// Note: Only data of type int32 will fit, because that's all that NWScript supports. +json GffAddInt64(json jGff, string sLabel, int v); +json GffAddFloat(json jGff, string sLabel, float v); +// Note: Only data of type float will fit, because that's all that NWScript supports. +json GffAddDouble(json jGff, string sLabel, float v); +json GffAddResRef(json jGff, string sLabel, string v); +json GffAddString(json jGff, string sLabel, string v); +json GffAddLocString(json jGff, string sLabel, string v, int nStrRef = -1); + + +// Replace a field, the type must match and the field must exist. +// Returns a json null value on error with GetJsonError() filled in. +// +// sLabel can be a json pointer(path) without the starting /, see the documentation of JsonPointer() for details. +// For example, to replace the name of an area in a combined area format(CAF) object you can do the following: +// json jArea = ObjectToStruct(GetFirstArea()); +// jArea = GffReplaceLocString(jArea, "ARE/value/Name", "New Area Name"); + +json GffReplaceStruct(json jGff, string sLabel, json jStruct); +json GffReplaceList(json jGff, string sLabel, json jList); +json GffReplaceByte(json jGff, string sLabel, int v); +json GffReplaceChar(json jGff, string sLabel, int v); +json GffReplaceWord(json jGff, string sLabel, int v); +json GffReplaceShort(json jGff, string sLabel, int v); +// Note: Only data of type int32 will fit, because that's all that NWScript supports. +json GffReplaceDword(json jGff, string sLabel, int v); +json GffReplaceInt(json jGff, string sLabel, int v); +// Note: Only data of type int32 will fit, because that's all that NWScript supports. +json GffReplaceDword64(json jGff, string sLabel, int v); +// Note: Only data of type int32 will fit, because that's all that NWScript supports. +json GffReplaceInt64(json jGff, string sLabel, int v); +json GffReplaceFloat(json jGff, string sLabel, float v); +// Note: Only data of type float will fit, because that's all that NWScript supports. +json GffReplaceDouble(json jGff, string sLabel, float v); +json GffReplaceResRef(json jGff, string sLabel, string v); +json GffReplaceString(json jGff, string sLabel, string v); +json GffReplaceLocString(json jGff, string sLabel, string v, int nStrRef = -1); + + +// Remove a field, the type must match and the field must exist. +// Returns a json null value on error with GetJsonError() filled in. +// +// sLabel can be a json pointer(path) without the starting /, see the documentation of JsonPointer() for details. +// For example, to remove all placeables from an area in a combined area format(CAF) object you can do the following: +// json jArea = ObjectToStruct(GetFirstArea()); +// jArea = GffRemoveList(jArea, "GIT/value/Placeable List"); + +json GffRemoveStruct(json jGff, string sLabel); +json GffRemoveList(json jGff, string sLabel); +json GffRemoveByte(json jGff, string sLabel); +json GffRemoveChar(json jGff, string sLabel); +json GffRemoveWord(json jGff, string sLabel); +json GffRemoveShort(json jGff, string sLabel); +json GffRemoveDword(json jGff, string sLabel); +json GffRemoveInt(json jGff, string sLabel); +json GffRemoveDword64(json jGff, string sLabel); +json GffRemoveInt64(json jGff, string sLabel); +json GffRemoveFloat(json jGff, string sLabel); +json GffRemoveDouble(json jGff, string sLabel); +json GffRemoveResRef(json jGff, string sLabel); +json GffRemoveString(json jGff, string sLabel); +json GffRemoveLocString(json jGff, string sLabel); + + +// Get a field's value as json object. +// Returns a json null value on error with GetJsonError() filled in. +// +// Note: Json types do not implicitly convert between types, this means you cannot convert a JsonInt to a string with JsonGetString(), etc. +// You may need to check the type with JsonGetType() and then do the appropriate cast yourself. +// For GffGet*() functions the json type returned is noted in the function description. +// +// Example: +// INCORRECT: string s = JsonGetString(GffGetInt()); +// CORRECT: string s = IntToString(JsonGetInt(GffGetInt())); +// +// sLabel can be a json pointer(path) without the starting /, see the documentation of JsonPointer() for details. +// For example, to get the resref of an area in a combined area format(CAF) object you can do the following: +// json jResRef = GffGetResRef(ObjectToStruct(GetFirstArea()), "ARE/value/ResRef"); +// if (jResRef != JsonNull()) +// { +// string sResRef = JsonGetString(jResRef); +// } +// else +// WriteTimestampedLogEntry("Failed to get area ResRef: " + JsonGetError(jResRef)); + +// Returns the struct as JsonObject() on success. +json GffGetStruct(json jGff, string sLabel); +// Returns a JsonArray() with all the list elements on success. +json GffGetList(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetByte(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetChar(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetWord(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetShort(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetDword(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetInt(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetDword64(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetInt64(json jGff, string sLabel); +// Returns a JsonFloat() on success. +json GffGetFloat(json jGff, string sLabel); +// Returns a JsonFloat() on success. +json GffGetDouble(json jGff, string sLabel); +// Returns a JsonString() on success. +json GffGetResRef(json jGff, string sLabel); +// Returns a JsonString() on success. +json GffGetString(json jGff, string sLabel); +// Returns a JsonObject() on success. +// Key "0" will have a JsonString() with the string, if set. +// Key "id" will have a JsonInt() with the strref, if set. +json GffGetLocString(json jGff, string sLabel); + + +// *** Internal Helper Functions +json AddPatchOperation(json jPatchArray, string sOp, string sPath, json jValue) +{ + json jOperation = JsonObject(); + jOperation = JsonObjectSet(jOperation, "op", JsonString(sOp)); + jOperation = JsonObjectSet(jOperation, "path", JsonString(sPath)); + jOperation = JsonObjectSet(jOperation, "value", jValue); + return JsonArrayInsert(jPatchArray, jOperation); +} + +json GffAddField(json jGff, string sLabel, string sType, json jValue, int nType = -1) +{ + json jField = JsonObject(); + jField = JsonObjectSet(jField, "type", JsonString(sType)); + jField = JsonObjectSet(jField, "value", jValue); + if (sType == GFF_FIELD_TYPE_STRUCT && nType != -1) + jField = JsonObjectSet(jField, "__struct_id", JsonInt(nType)); + + return JsonPatch(jGff, AddPatchOperation(JsonArray(), "add", "/" + sLabel, jField)); +} + +json GffReplaceField(json jGff, string sLabel, string sType, json jValue) +{ + json jPatch = JsonArray(); + jPatch = AddPatchOperation(jPatch, "test", "/" + sLabel + "/type", JsonString(sType)); + jPatch = AddPatchOperation(jPatch, "replace", "/" + sLabel + "/value", jValue); + return JsonPatch(jGff, jPatch); +} + +json GffRemoveField(json jGff, string sLabel, string sType) +{ + json jPatch = JsonArray(); + jPatch = AddPatchOperation(jPatch, "test", "/" + sLabel + "/type", JsonString(sType)); + jPatch = AddPatchOperation(jPatch, "remove", "/" + sLabel, JsonNull()); + return JsonPatch(jGff, jPatch); +} + +json GffGetFieldType(json jGff, string sLabel) +{ + return JsonPointer(jGff, "/" + sLabel + "/type"); +} + +json GffGetFieldValue(json jGff, string sLabel) +{ + return JsonPointer(jGff, "/" + sLabel + "/value"); +} + +json GffGetField(json jGff, string sLabel, string sType) +{ + json jType = GffGetFieldType(jGff, sLabel); + if (jType == JsonNull()) + return jType; + else if (jType != JsonString(sType)) + return JsonNull("field type does not match"); + else + return GffGetFieldValue(jGff, sLabel); +} + +json GffLocString(string v, int nStrRef = -1) +{ + json jLocString = JsonObject(); + if (v != "") + jLocString = JsonObjectSet(jLocString, "0", JsonString(v)); // english/any + if (nStrRef != -1) + jLocString = JsonObjectSet(jLocString, "id", JsonInt(nStrRef)); + + return jLocString; +} +//*** + +json GffCreateObject(int nObjectType) +{ + string ot; + if (nObjectType == OBJECT_TYPE_CREATURE) ot = "UTC "; + else if (nObjectType == OBJECT_TYPE_ITEM) ot = "UTI "; + else if (nObjectType == OBJECT_TYPE_TRIGGER) ot = "UTT "; + else if (nObjectType == OBJECT_TYPE_DOOR) ot = "UTD "; + else if (nObjectType == OBJECT_TYPE_WAYPOINT) ot = "UTW "; + else if (nObjectType == OBJECT_TYPE_PLACEABLE) ot = "UTP "; + else if (nObjectType == OBJECT_TYPE_STORE) ot = "UTM "; + else if (nObjectType == OBJECT_TYPE_ENCOUNTER) ot = "UTE "; + + if (ot == "") return JsonNull("invalid object type"); + + json ret = JsonObject(); + ret = JsonObjectSet(ret, "__data_type", JsonString(ot)); + return ret; +} + +json GffCreateArea(json jARE, json jGIT) +{ + json jCAF = JsonObject(); + jCAF = JsonObjectSet(jCAF, "__data_type", JsonString("CAF ")); + jCAF = GffAddStruct(jCAF, "ARE", jARE, 0); + jCAF = GffAddStruct(jCAF, "GIT", jGIT, 1); + return jCAF; +} + + +int GffGetObjectType(json jGff) +{ + json jDataType = JsonObjectGet(jGff, "__data_type"); + if (jDataType == JsonNull()) + return 0; + else + { + string sObjectType = JsonGetString(jDataType); + + if (sObjectType == "UTC ") return OBJECT_TYPE_CREATURE; + else if (sObjectType == "UTI ") return OBJECT_TYPE_ITEM; + else if (sObjectType == "UTT ") return OBJECT_TYPE_TRIGGER; + else if (sObjectType == "UTD ") return OBJECT_TYPE_DOOR; + else if (sObjectType == "UTW ") return OBJECT_TYPE_WAYPOINT; + else if (sObjectType == "UTP ") return OBJECT_TYPE_PLACEABLE; + else if (sObjectType == "UTM ") return OBJECT_TYPE_STORE; + else if (sObjectType == "UTE ") return OBJECT_TYPE_ENCOUNTER; + } + + return 0; +} + +int GffGetIsArea(json jGff) +{ + return JsonObjectGet(jGff, "__data_type") == JsonString("CAF "); +} + +int GffGetFieldExists(json jGff, string sLabel, string sType = "") +{ + json jFieldType = GffGetFieldType(jGff, sLabel); + return sType == "" ? jFieldType != JsonNull() : jFieldType == JsonString(sType); +} + + +json GffAddStruct(json jGff, string sLabel, json jStruct, int nType = -1) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_STRUCT, jStruct, nType); +} + +json GffAddList(json jGff, string sLabel, json jList) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_LIST, jList); +} + +json GffAddByte(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_BYTE, JsonInt(v)); +} + +json GffAddChar(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_CHAR, JsonInt(v)); +} + +json GffAddWord(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_WORD, JsonInt(v)); +} + +json GffAddShort(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_SHORT, JsonInt(v)); +} + +json GffAddDword(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_DWORD, JsonInt(v)); +} + +json GffAddInt(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_INT, JsonInt(v)); +} + +json GffAddDword64(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_DWORD64, JsonInt(v)); +} + +json GffAddInt64(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_INT64, JsonInt(v)); +} + +json GffAddFloat(json jGff, string sLabel, float v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_FLOAT, JsonFloat(v)); +} + +json GffAddDouble(json jGff, string sLabel, float v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_DOUBLE, JsonFloat(v)); +} + +json GffAddResRef(json jGff, string sLabel, string v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_RESREF, JsonString(v)); +} + +json GffAddString(json jGff, string sLabel, string v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_STRING, JsonString(v)); +} + +json GffAddLocString(json jGff, string sLabel, string v, int nStrRef = -1) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_LOC_STRING, GffLocString(v, nStrRef)); +} + + +json GffReplaceStruct(json jGff, string sLabel, json jStruct) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_STRUCT, jStruct); +} + +json GffReplaceList(json jGff, string sLabel, json jList) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_LIST, jList); +} + +json GffReplaceByte(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_BYTE, JsonInt(v)); +} + +json GffReplaceChar(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_CHAR, JsonInt(v)); +} + +json GffReplaceWord(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_WORD, JsonInt(v)); +} + +json GffReplaceShort(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_SHORT, JsonInt(v)); +} + +json GffReplaceDword(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_DWORD, JsonInt(v)); +} + +json GffReplaceInt(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_INT, JsonInt(v)); +} + +json GffReplaceDword64(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_DWORD64, JsonInt(v)); +} + +json GffReplaceInt64(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_INT64, JsonInt(v)); +} + +json GffReplaceFloat(json jGff, string sLabel, float v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_FLOAT, JsonFloat(v)); +} + +json GffReplaceDouble(json jGff, string sLabel, float v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_DOUBLE, JsonFloat(v)); +} + +json GffReplaceResRef(json jGff, string sLabel, string v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_RESREF, JsonString(v)); +} + +json GffReplaceString(json jGff, string sLabel, string v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_STRING, JsonString(v)); +} + +json GffReplaceLocString(json jGff, string sLabel, string v, int nStrRef = -1) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_LOC_STRING, GffLocString(v, nStrRef)); +} + + +json GffRemoveStruct(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_STRUCT); +} + +json GffRemoveList(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_LIST); +} + +json GffRemoveByte(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_BYTE); +} + +json GffRemoveChar(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_CHAR); +} + +json GffRemoveWord(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_WORD); +} + +json GffRemoveShort(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_SHORT); +} + +json GffRemoveDword(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_DWORD); +} + +json GffRemoveInt(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_INT); +} + +json GffRemoveDword64(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_DWORD64); +} + +json GffRemoveInt64(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_INT64); +} + +json GffRemoveFloat(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_FLOAT); +} + +json GffRemoveDouble(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_DOUBLE); +} + +json GffRemoveResRef(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_RESREF); +} + +json GffRemoveString(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_STRING); +} + +json GffRemoveLocString(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_LOC_STRING); +} + + +json GffGetStruct(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_STRUCT); +} + +json GffGetList(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_LIST); +} + +json GffGetByte(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_BYTE); +} + +json GffGetChar(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_CHAR); +} + +json GffGetWord(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_WORD); +} + +json GffGetShort(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_SHORT); +} + +json GffGetDword(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_DWORD); +} + +json GffGetInt(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_INT); +} + +json GffGetDword64(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_DWORD64); +} + +json GffGetInt64(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_INT64); +} + +json GffGetFloat(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_FLOAT); +} + +json GffGetDouble(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_DOUBLE); +} + +json GffGetResRef(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_RESREF); +} + +json GffGetString(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_STRING); +} + +json GffGetLocString(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_LOC_STRING); +} diff --git a/src/include/nw_inc_nui.nss b/src/include/nw_inc_nui.nss index 96fc3da..a37f13f 100644 --- a/src/include/nw_inc_nui.nss +++ b/src/include/nw_inc_nui.nss @@ -40,6 +40,24 @@ const float NUI_STYLE_TERTIARY_HEIGHT = 30.0; const float NUI_STYLE_ROW_HEIGHT = 25.0; +// ----------------------- +// Bind params + +// These currently only affect presentation and serve as a +// optimisation to let the client do the heavy lifting on this. +// In particular, this enables you to bind an array of values and +// transform them all at once on the client, instead of having to +// have the server transform them before sending. + +// NB: These must be OR-ed together into a bitmask. + +const int NUI_NUMBER_FLAG_HEX = 0x001; + +// NB: These must be OR-ed together into a bitmask. + +const int NUI_TEXT_FLAG_LOWERCASE = 0x001; +const int NUI_TEXT_FLAG_UPPERCASE = 0x002; + // ----------------------- // Window @@ -47,24 +65,41 @@ const float NUI_STYLE_ROW_HEIGHT = 25.0; // * Set the window title to JsonBool(FALSE), Collapse to JsonBool(FALSE) and bClosable to FALSE // to hide the title bar. // Note: You MUST provide a way to close the window some other way, or the user will be stuck with it. -json // Window -NuiWindow( - json jRoot, // Layout-ish (NuiRow, NuiCol, NuiGroup) - json jTitle, // Bind:String - json jGeometry, // Bind:Rect Set x and/or y to -1.0 to center the window on that axis - // Set x and/or y to -2.0 to position the window's top left at the mouse cursor's position of that axis - // Set x and/or y to -3.0 to center the window on the mouse cursor's position of that axis - json jResizable, // Bind:Bool Set to JsonBool(TRUE) or JsonNull() to let user resize without binding. - json jCollapsed, // Bind:Bool Set to a static value JsonBool(FALSE) to disable collapsing. - // Set to JsonNull() to let user collapse without binding. - // For better UX, leave collapsing on. - json jClosable, // Bind:Bool You must provide a way to close the window if you set this to FALSE. - // For better UX, handle the window "closed" event. - json jTransparent, // Bind:Bool Do not render background - json jBorder, // Bind:Bool Do not render border - json jAcceptsInput = // Bind:Bool Set JsonBool(FALSE) to disable all input. - JSON_TRUE // All hover, clicks and keypresses will fall through. -); +// * Set a minimum size constraint equal to the maximmum size constraint in the same dimension to prevent +// a window from being resized in that dimension. +// - jRoot: Layout-ish (NuiRow, NuiCol, NuiGroup) +// - jTitle: Bind:String +// - jGeometry: Bind:Rect +// Set x and/or y to -1.0 to center the window on that axis. +// Set x and/or y to -2.0 to position the window's top left at the mouse cursor's position of that axis. +// Set x and/or y to -3.0 to center the window on the mouse cursor's position of that axis. +// - jResizable: Bind:Bool +// Set to JsonBool(TRUE) or JsonNull() to let user resize without binding. +// - jCollapsed: Bind:Bool +// Set to a static value JsonBool(FALSE) to disable collapsing. +// Set to JsonNull() to let user collapse without binding. +// For better UX, leave collapsing on. +// - jCloseable: Bind:Bool +// You provide a way to close the window if you set this to FALSE. +// For better UX, handle the window "closed" event. +// - jTransparent: Bind:Bool +// Do not render background +// - jBorder: Bind:Bool +// Do not render border +// - jAcceptsInput: Bind:Bool +// Set JsonBool(FALSE) to disable all input. +// All hover, clicks and keypresses will fall through. +// - jSizeConstraint: Bind:Rect +// Constrains minimum and maximum size of window. +// Set x to minimum width, y to minimum height, w to maximum width, h to maximum height. +// Set any individual constraint to 0.0 to ignore that constraint. +// - jEdgeConstraint: Bind:Rect +// Prevents a window from being rendered within the specified margins. +// Set x to left margin, y to top margin, w to right margin, h to bottom margin. +// Set any individual constraint to 0.0 to ignore that constraint +// - jFont: Bind:String +// Override font used on window, including decorations. See NuiStyleFont() for details. +json NuiWindow(json jRoot, json jTitle, json jGeometry, json jResizable,json jCollapsed,json jClosable, json jTransparent, json jBorder, json jAcceptsInput = JSON_TRUE, json jSizeConstraint = JSON_NULL, json jEdgeConstraint = JSON_NULL, json jFont = JSON_STRING); // ----------------------- // Values @@ -74,144 +109,111 @@ NuiWindow( // NuiSetBind(.., "mybindlabel", JsonString("hi")); // To create static values, just use the json types directly: // JsonString("hi"); -json // Bind -NuiBind( - string sId -); +// +// You can parametrise this particular bind with the given flags. +// These flags only apply to that particular usage of this bind value. +// +// - sId: string +// - nNumberFlags: bitmask of NUI_NUMBER_FLAG_* +// - nNumberPrecision: Precision to print number with (int or float) +// - nTextFlags: bitmask of NUI_TEXT_FLAG_* +json NuiBind(string sId, int nNumberFlags = 0, int nNumberPrecision = 0, int nTextFlags = 0); // Tag the given element with a id. // Only tagged elements will send events to the server. -json // Element -NuiId( - json jElem, // Element - string sId // String -); +json NuiId(json jElem, string sId); // A shim/helper that can be used to render or bind a strref where otherwise // a string value would go. -json -NuiStrRef( - int nStrRef // STRREF -); +json NuiStrRef(int nStrRef); // ----------------------- // Layout // A column will auto-space all elements inside of it and advise the parent // about it's desired size. -json // Layout -NuiCol( - json jList // Layout[] or Element[] -); +// - jList: Layout[] or Element[] +json NuiCol(json jList); // A row will auto-space all elements inside of it and advise the parent // about it's desired size. -json // Layout -NuiRow( - json jList // Layout[] or Element[] -); +// - jList: Layout[] or Element[] +json NuiRow(json jList); // A group, usually with a border and some padding, holding a single element. Can scroll. // Will not advise parent of size, so you need to let it fill a span (col/row) as if it was // a element. -json // Layout -NuiGroup( - json jChild, // Layout or Element - int bBorder = TRUE, - int nScroll = NUI_SCROLLBARS_AUTO -); +// - jChild: Layout or Element +json NuiGroup(json jChild, int bBorder = TRUE, int nScroll = NUI_SCROLLBARS_AUTO); // Modifiers/Attributes: These are all static and cannot be bound, since the UI system // cannot easily reflow once the layout is set up. You need to swap the layout if you // want to change element geometry. -json // Element -NuiWidth( - json jElem, // Element - float fWidth // Float: Element width in pixels (strength=required). -); +// - jElem: Element +// - fWidth: Float: Element width in pixels (strength=required). +json NuiWidth(json jElem, float fWidth); -json // Element -NuiHeight( - json jElem, // Element - float fHeight // Float: Height in pixels (strength=required). -); +// - jElem: Element +// - fHeight: Float: Height in pixels (strength=required). +json NuiHeight(json jElem, float fHeight); -json // Element -NuiAspect( - json jElem, // Element - float fAspect // Float: Ratio of x/y. -); +// - jElem: Element +// - fAspect: Float: Ratio of x/y +json NuiAspect(json jElem, float fAspect); // Set a margin on the widget. The margin is the spacing outside of the widget. -json // Element -NuiMargin( - json jElem, // Element - float fMargin // Float -); +json NuiMargin(json jElem, float fMargin); // Set padding on the widget. The margin is the spacing inside of the widget. -json // Element -NuiPadding( - json jElem, // Element - float fPadding // Float -); +json NuiPadding(json jElem, float fPadding); // Disabled elements are non-interactive and greyed out. -json // Element -NuiEnabled( - json jElem, // Element - json jEnabler // Bind:Bool -); +// - jElem: Element +// - jEnabled: Bind:Bool +json NuiEnabled(json jElem, json jEnabler); // Invisible elements do not render at all, but still take up layout space. -json // Element -NuiVisible( - json jElem, // Element - json jVisible // Bind:Bool -); +// - jElem: Element +// - jVisible: Bind:Bool +json NuiVisible(json jElem, json jVisible); // Tooltips show on mouse hover. -json // Element -NuiTooltip( - json jElem, // Element - json jTooltip // Bind:String -); +// - jElem: Element +// - jTooltip: Bind:String +json NuiTooltip(json jElem, json jTooltip); // Tooltips for disabled elements show on mouse hover. -json // Element -NuiDisabledTooltip( - json jElem, // Element - json jTooltip // Bind:String -); +// - jElem: Element +// - jTooltip: Bind:String +json NuiDisabledTooltip(json jElem, json jTooltip); // Encouraged elements have a breathing animated glow inside of it. -json // Element -NuiEncouraged( - json jElem, // Element - json jEncouraged // Bind:Bool -); +// - jElem: Element +// - jEncouraged: Bind:Bool +json NuiEncouraged(json jElem, json jEncouraged); // ----------------------- // Props & Style -json // Vec2 -NuiVec(float x, float y); +json NuiVec(float x, float y); -json // Rect -NuiRect(float x, float y, float w, float h); +json NuiRect(float x, float y, float w, float h); -json // Color -NuiColor(int r, int g, int b, int a = 255); +json NuiColor(int r, int g, int b, int a = 255); -// Style the foreground color of the widget. This is dependent on the widget +// Style the foreground color of a widget or window title. This is dependent on the widget // in question and only supports solid/full colors right now (no texture skinning). // For example, labels would style their text color; progress bars would style the bar. -json // Element -NuiStyleForegroundColor( - json jElem, // Element - json jColor // Bind:Color -); +// - jElem: Element +// - jColor: Bind:Color +json NuiStyleForegroundColor(json jElem, json jColor); + +// Override the font used for this element. The font and it's properties needs to be listed in +// nui_skin.tml, as all fonts are pre-baked into a texture atlas at content load. +// - jElem: Element +// - jColor: Bind:String ([[fonts]].name in nui_skin.tml) +json NuiStyleFont(json jElem, json jFont); // ----------------------- // Widgets @@ -219,119 +221,87 @@ NuiStyleForegroundColor( // A special widget that just takes up layout space. // If you add multiple spacers to a span, they will try to size equally. // e.g.: [ ] will try to center the button. -json // Element -NuiSpacer(); +json NuiSpacer(); // Create a label field. Labels are single-line stylable non-editable text fields. -json // Element -NuiLabel( - json jValue, // Bind:String - json jHAlign, // Bind:Int:NUI_HALIGN_* - json jVAlign // Bind:Int:NUI_VALIGN_* -); +// - jValue: Bind:String +// - jHAlign: Bind:Int:NUI_HALIGN_* +// - jVAlign: Bind:Int:NUI_VALIGN_* +json NuiLabel(json jValue, json jHAlign, json jVAlign); // Create a non-editable text field. Note: This text field internally implies a NuiGroup wrapped // around it, which is providing the optional border and scrollbars. -json // Element -NuiText( - json jValue, // Bind:String - int bBorder = TRUE, // Bool - int nScroll = NUI_SCROLLBARS_AUTO // Int:NUI_SCROLLBARS_* -); +// - jValue: Bind:String +// - bBorder: Bool +// - nScroll: Int:NUI_SCROLLBARS_* +json NuiText(json jValue, int bBorder = TRUE, int nScroll = NUI_SCROLLBARS_AUTO); // A clickable button with text as the label. // Sends "click" events on click. -json // Element -NuiButton( - json jLabel // Bind:String -); +// - jLabel: Bind:String +json NuiButton(json jLabel); // A clickable button with an image as the label. // Sends "click" events on click. -json // Element -NuiButtonImage( - json jResRef // Bind:ResRef -); +// - jResRef: Bind:String +json NuiButtonImage(json jResRef); // A clickable button with text as the label. // Same as the normal button, but this one is a toggle. // Sends "click" events on click. -json // Element -NuiButtonSelect( - json jLabel, // Bind:String - json jValue // Bind:Bool -); +// - jLabel: Bind:String +// - jValue: Bind:Bool +json NuiButtonSelect(json jLabel, json jValue); // A checkbox with a label to the right of it. -json // Element -NuiCheck( - json jLabel, // Bind:String - json jBool // Bind:Bool -); +// - jLabel: Bind:String +// - jBool: Bind:Bool +json NuiCheck(json jLabel, json jBool); // A image, with no border or padding. -json // Element -NuiImage( - json jResRef, // Bind:ResRef - json jAspect, // Bind:Int:NUI_ASPECT_* - json jHAlign, // Bind:Int:NUI_HALIGN_* - json jVAlign // Bind:Int:NUI_VALIGN_* -); +// - jResRef: Bind:String +// - jAspect: Bind:Int:NUI_ASPECT_* +// - jHAlign: Bind:Int:NUI_HALIGN_* +// - jVAlign: Bind:Int:NUI_VALIGN_* +json NuiImage(json jResRef, json jAspect, json jHAlign, json jVAlign); -// Optionally render only subregion of jImage. +// Optionally render only subregion of jImage. This property can be set on +// NuiImage and NuiButtonImage widgets. // jRegion is a NuiRect (x, y, w, h) to indicate the render region inside the image. -json // NuiImage -NuiImageRegion( - json jImage, // NuiImage - json jRegion // Bind:NuiRect -); +json NuiImageRegion(json jImage, json jRegion); // A combobox/dropdown. -json // Element -NuiCombo( - json jElements, // Bind:ComboEntry[] - json jSelected // Bind:Int (index into jElements) -); +// - jElements: Bind:ComboEntry[] +// - jSelected: Bind:Int (index into jElements) +json NuiCombo(json jElements, json jSelected); -json // ComboEntry -NuiComboEntry( - string sLabel, - int nValue -); +json NuiComboEntry(string sLabel, int nValue); // A floating-point slider. A good step size for normal-sized sliders is 0.01. -json // Element -NuiSliderFloat( - json jValue, // Bind:Float - json jMin, // Bind:Float - json jMax, // Bind:Float - json jStepSize // Bind:Float -); +// - jValue: Bind:Float +// - jMin: Bind:Float +// - jMax: Bind:Float +// - jStepSize: Bind:Float +json NuiSliderFloat(json jValue, json jMin, json jMax, json jStepSize); // A integer/discrete slider. -json // Element -NuiSlider( - json jValue, // Bind:Int - json jMin, // Bind:Int - json jMax, // Bind:Int - json jStepSize // Bind:Int -); +// - jValue: Bind:Int +// - jMin: Bind:Int +// - jMax: Bind:Int +// - jStepSize: Bind:Int +json NuiSlider(json jValue, json jMin, json jMax, json jStepSize); // A progress bar. Progress is always from 0.0 to 1.0. -json // Element -NuiProgress( - json jValue // Bind:Float (0.0->1.0) -); +// - jValue: Bind:Float (0.0->1.0 +json NuiProgress(json jValue); // A editable text field. -json // Element -NuiTextEdit( - json jPlaceholder, // Bind:String - json jValue, // Bind:String - int nMaxLength, // UInt >= 1, <= 65535 - int bMultiline, // Bool - int bWordWrap = TRUE // Bool -); +// - jPlaceholder: Bind:String +// - jValue: Bind:String +// - nMaxLength: UInt >= 1, <= 65535 +// - bMultiLine: Bool +// - bWordWrap: Bool +json NuiTextEdit(json jPlaceholder, json jValue, int nMaxLength, int bMultiline, int bWordWrap = TRUE); // Creates a list view of elements. // jTemplate needs to be an array of NuiListTemplateCell instances. @@ -339,67 +309,52 @@ NuiTextEdit( // e.g. when rendering a NuiLabel(), the bound label String should be an array of strings. // You can pass in one of the template jRowCount into jSize as a convenience. The array // size will be uses as the Int bind. -// jRowHeight defines the height of the rendered rows. -json // Element -NuiList( - json jTemplate, // NuiListTemplateCell[] (max: 16) - json jRowCount, // Bind:Int - float fRowHeight = NUI_STYLE_ROW_HEIGHT, - int bBorder = TRUE, - int nScroll = NUI_SCROLLBARS_Y // Note: Cannot be AUTO. -); +// fRowHeight defines the height of the rendered rows. +// - jTemplate: NuiListTemplateCell[] (max: 16) +// - jRowCount: Bind:Int +// - bBorder: Bool +// - nScroll: Int:NUI_SCROLLBARS_*, Note: Cannot be AUTO +json NuiList(json jTemplate, json jRowCount, float fRowHeight = NUI_STYLE_ROW_HEIGHT, int bBorder = TRUE, int nScroll = NUI_SCROLLBARS_Y); -json // NuiListTemplateCell -NuiListTemplateCell( - json jElem, // Element - float fWidth, // Float:0 = auto, >1 = pixel width - int bVariable // Bool:Cell can grow if space is available; otherwise static -); +// - jElem: Element +// - fWidth: Float:0 = auto, >1 = pixel width +// - bVariable: Bool:Cell can grow if space is available; otherwise static +json NuiListTemplateCell(json jElem, float fWidth, int bVariable); // A simple color picker, with no border or spacing. -json // Element -NuiColorPicker( - json jColor // Bind:Color -); +// - jColor: Bind:Color +json NuiColorPicker(json jColor); // A list of options (radio buttons). Only one can be selected // at a time. jValue is updated every time a different element is // selected. The special value -1 means "nothing". -json // Element -NuiOptions( - int nDirection, // NUI_DIRECTION_* - json jElements, // JsonArray of string labels - json jValue // Bind:Int -); +// - nDirection: NUI_DIRECTION_* +// - jElements: JsonArray of string labels +// - jValue: Bind:UInt +json NuiOptions(int nDirection, json jElements, json jValue); -// A group of buttons. Only one can be selected at a time. jValue -// is updated every time a different button is selected. The special +// A group of buttons. Only one can be selected at a time. jValue +// is updated every time a different button is selected. The special // value -1 means "nothing". -json // Element -NuiToggles( - int nDirection, // NUI_DIRECTION_* - json jElements, // JsonArray of string labels - json jValue // Bind:Int -); +// - nDirection: NUI_DIRECTION_* +// - jElements: JsonArray of string labels +// - jValue: Bind:Int +json NuiToggles(int nDirection, json jElements, json jValue); const int NUI_CHART_TYPE_LINES = 0; const int NUI_CHART_TYPE_COLUMN = 1; -json // NuiChartSlot -NuiChartSlot( - int nType, // Int:NUI_CHART_TYPE_* - json jLegend, // Bind:String - json jColor, // Bind:NuiColor - json jData // Bind:Float[] -); +// - nType: Int:NUI_CHART_TYPE_* +// - jLegend: Bind:String +// - jColor: Bind:NuiColor +// - jData: Bind:Float[] +json NuiChartSlot(int nType, json jLegend, json jColor, json jData); // Renders a chart. // Currently, min and max values are determined automatically and // cannot be influenced. -json // Element -NuiChart( - json jSlots // NuiChartSlot[] -); +// - jSlots: NuiChartSlot[] +json NuiChart( json jSlots); // ----------------------- // Draw Lists @@ -417,6 +372,7 @@ const int NUI_DRAW_LIST_ITEM_TYPE_ARC = 3; const int NUI_DRAW_LIST_ITEM_TYPE_TEXT = 4; const int NUI_DRAW_LIST_ITEM_TYPE_IMAGE = 5; const int NUI_DRAW_LIST_ITEM_TYPE_LINE = 6; +const int NUI_DRAW_LIST_ITEM_TYPE_RECT = 7; // You can order draw list items to be painted either before, or after the // builtin render of the widget in question. This enables you to paint "behind" @@ -438,100 +394,100 @@ const int NUI_DRAW_LIST_ITEM_RENDER_MOUSE_RIGHT = 4; // Only render while MMB is held down. const int NUI_DRAW_LIST_ITEM_RENDER_MOUSE_MIDDLE = 5; -json // DrawListItem -NuiDrawListPolyLine( - json jEnabled, // Bind:Bool - json jColor, // Bind:Color - json jFill, // Bind:Bool - json jLineThickness, // Bind:Float - json jPoints, // Bind:Float[] Always provide points in pairs - int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, // Int:NUI_DRAW_LIST_ITEM_ORDER_* - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS // Int:NUI_DRAW_LIST_ITEM_RENDER_* -); +// - jEnabled: Bind:Bool +// - jColor: Bind:Color +// - jFill: Bind:Bool +// - jLineThickness: Bind:Float +// - jPoints: Bind:Float[] Always provide points in pairs +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +json NuiDrawListPolyLine(json jEnabled, json jColor, json jFill, json jLineThickness, json jPoints, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE); -json // DrawListItem -NuiDrawListCurve( - json jEnabled, // Bind:Bool - json jColor, // Bind:Color - json jLineThickness, // Bind:Float - json jA, // Bind:Vec2 - json jB, // Bind:Vec2 - json jCtrl0, // Bind:Vec2 - json jCtrl1, // Bind:Vec2 - int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, // Int:NUI_DRAW_LIST_ITEM_ORDER_* - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS // Int:NUI_DRAW_LIST_ITEM_RENDER_* -); +// - jEnabled: Bind:Bool +// - jColor: Bind:Color +// - jLineThickness: Bind:Float +// - jA: Bind:Vec2 +// - jB: Bind:Vec2 +// - jCtrl0: Bind:Vec2 +// - jCtrl1: Bind:Vec2 +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +json NuiDrawListCurve(json jEnabled, json jColor, json jLineThickness, json jA, json jB, json jCtrl0, json jCtrl1, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE); -json // DrawListItem -NuiDrawListCircle( - json jEnabled, // Bind:Bool - json jColor, // Bind:Color - json jFill, // Bind:Bool - json jLineThickness, // Bind:Float - json jRect, // Bind:Rect - int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, // Int:NUI_DRAW_LIST_ITEM_ORDER_* - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS // Int:NUI_DRAW_LIST_ITEM_RENDER_* -); +// - jEnabled: Bind:Bool +// - jColor: Bind:Color +// - jFill: Bind:Bool +// - jLineThickness: Bind:Float +// - jRect: Bind:Rect +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +json NuiDrawListCircle(json jEnabled, json jColor, json jFill, json jLineThickness, json jRect, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE); -json // DrawListItem -NuiDrawListArc( - json jEnabled, // Bind:Bool - json jColor, // Bind:Color - json jFill, // Bind:Bool - json jLineThickness, // Bind:Float - json jCenter, // Bind:Vec2 - json jRadius, // Bind:Float - json jAMin, // Bind:Float - json jAMax, // Bind:Float - int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, // Int:NUI_DRAW_LIST_ITEM_ORDER_* - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS // Int:NUI_DRAW_LIST_ITEM_RENDER_* -); +// - jEnabled: Bind:Bool +// - jColor: Bind:Color +// - jFill: Bind:Bool +// - jLineThickness: Bind:Float +// - jCenter: Bind:Rect +// - jRadius: Bind:Float +// - jAMin: Bind:Float +// - jAMax: Bind:Float +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +json NuiDrawListArc(json jEnabled, json jColor, json jFill, json jLineThickness, json jCenter, json jRadius, json jAMin, json jAMax, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE); -json // DrawListItem -NuiDrawListText( - json jEnabled, // Bind:Bool - json jColor, // Bind:Color - json jRect, // Bind:Rect - json jText, // Bind:String - int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, // Int:NUI_DRAW_LIST_ITEM_ORDER_* - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS // Int:NUI_DRAW_LIST_ITEM_RENDER_* -); +// - jEnabled: Bind:Bool +// - jColor: Bind:Color +// - jRect: Bind:Rect +// - jText: Bind:String +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +// - jFont: Bind:String +json NuiDrawListText(json jEnabled, json jColor, json jRect, json jText, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE, json jFont = JSON_STRING); -json // DrawListItem -NuiDrawListImage( - json jEnabled, // Bind:Bool - json jResRef, // Bind:ResRef - json jPos, // Bind:Rect - json jAspect, // Bind:Int:NUI_ASPECT_* - json jHAlign, // Bind:Int:NUI_HALIGN_* - json jVAlign, // Bind:Int:NUI_VALIGN_* - int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, // Int:NUI_DRAW_LIST_ITEM_ORDER_* - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS // Int:NUI_DRAW_LIST_ITEM_RENDER_* -); +// - jEnabled: Bind:Bool +// - jResRef: Bind:String +// - jPos: Bind:Rect +// - jAspect: Bind:Int:NUI_ASPECT_* +// - jHAlign: Bind:Int:NUI_HALIGN_* +// - jVAlign: Bind:Int:NUI_VALIGN_* +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +json NuiDrawListImage(json jEnabled, json jResRef, json jPos, json jAspect, json jHAlign, json jVAlign, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE); -json // DrawListItemImage -NuiDrawListImageRegion( - json jDrawListImage, // DrawListItemImage - json jRegion // Bind:NuiRect -); +// - jDrawListImage: DrawListItemImage +// - jRegion: Bind:NuiRect +json NuiDrawListImageRegion(json jDrawListImage, json jRegion); -json // DrawListItem -NuiDrawListLine( - json jEnabled, // Bind:Bool - json jColor, // Bind:Color - json jLineThickness, // Bind:Float - json jA, // Bind:Vec2 - json jB, // Bind:Vec2 - int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, // Int:NUI_DRAW_LIST_ITEM_ORDER_* - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS // Int:NUI_DRAW_LIST_ITEM_RENDER_* -); +// - jEnabled: Bind:Bool +// - jColor: Bind:Color +// - jLineThickness: Bind:Float +// - jA: Bind:Vec2 +// - jB: Bind:Vec2 +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +json NuiDrawListLine(json jEnabled, json jColor, json jLineThickness, json jA, json jB, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE); -json // Element -NuiDrawList( - json jElem, // Element - json jScissor, // Bind:Bool Constrain painted elements to widget bounds. - json jList // DrawListItem[] -); +// - jEnabled: Bind:Bool +// - jColor: Bind:Color +// - jFill: Bind:Bool +// - jLineThickness: Bind:Float +// - jRext: Bind:Rect +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +json NuiDrawListRect(json jEnabled, json jColor, json jFill, json jLineThickness, json jRect, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE); + +// - jElem: Element +// - jScissor: Bind:Bool, Constrain painted elements to widget bounds. +// - jList: DrawListItem[] +json NuiDrawList(json jElem, json jScissor, json jList); // ----------------------- // Implementation @@ -546,21 +502,27 @@ NuiWindow( json jClosable, json jTransparent, json jBorder, - json jAcceptsInput + json jAcceptsInput = JSON_TRUE, + json jWindowConstraint = JSON_NULL, + json jEdgeConstraint = JSON_NULL, + json jFont = JSON_STRING ) { json ret = JsonObject(); // Currently hardcoded and here to catch backwards-incompatible data in the future. - ret = JsonObjectSet(ret, "version", JsonInt(1)); - ret = JsonObjectSet(ret, "title", jTitle); - ret = JsonObjectSet(ret, "root", jRoot); - ret = JsonObjectSet(ret, "geometry", jGeometry); - ret = JsonObjectSet(ret, "resizable", jResizable); - ret = JsonObjectSet(ret, "collapsed", jCollapsed); - ret = JsonObjectSet(ret, "closable", jClosable); - ret = JsonObjectSet(ret, "transparent", jTransparent); - ret = JsonObjectSet(ret, "border", jBorder); - ret = JsonObjectSet(ret, "accepts_input", jAcceptsInput); + JsonObjectSetInplace(ret, "version", JsonInt(1)); + JsonObjectSetInplace(ret, "title", jTitle); + JsonObjectSetInplace(ret, "root", jRoot); + JsonObjectSetInplace(ret, "geometry", jGeometry); + JsonObjectSetInplace(ret, "resizable", jResizable); + JsonObjectSetInplace(ret, "collapsed", jCollapsed); + JsonObjectSetInplace(ret, "closable", jClosable); + JsonObjectSetInplace(ret, "transparent", jTransparent); + JsonObjectSetInplace(ret, "border", jBorder); + JsonObjectSetInplace(ret, "accepts_input", jAcceptsInput); + JsonObjectSetInplace(ret, "size_constraint", jWindowConstraint); + JsonObjectSetInplace(ret, "edge_constraint", jEdgeConstraint); + JsonObjectSetInplace(ret, "font", jFont); return ret; } @@ -572,18 +534,26 @@ NuiElement( ) { json ret = JsonObject(); - ret = JsonObjectSet(ret, "type", JsonString(sType)); - ret = JsonObjectSet(ret, "label", jLabel); - ret = JsonObjectSet(ret, "value", jValue); + JsonObjectSetInplace(ret, "type", JsonString(sType)); + JsonObjectSetInplace(ret, "label", jLabel); + JsonObjectSetInplace(ret, "value", jValue); return ret; } json NuiBind( - string sId + string sId, + int nNumberFlags = 0, + int nNumberPrecision = 0, + int nTextFlags = 0 ) { - return JsonObjectSet(JsonObject(), "bind", JsonString(sId)); + json ret = JsonObject(); + JsonObjectSetInplace(ret, "bind", JsonString(sId)); + JsonObjectSetInplace(ret, "number_flags", JsonInt(nNumberFlags)); + JsonObjectSetInplace(ret, "number_precision", JsonInt(nNumberPrecision)); + JsonObjectSetInplace(ret, "text_flags", JsonInt(nTextFlags)); + return ret; } json @@ -601,7 +571,7 @@ NuiStrRef( ) { json ret = JsonObject(); - ret = JsonObjectSet(ret, "strref", JsonInt(nStrRef)); + JsonObjectSetInplace(ret, "strref", JsonInt(nStrRef)); return ret; } @@ -629,9 +599,9 @@ NuiGroup( ) { json ret = NuiElement("group", JsonNull(), JsonNull()); - ret = JsonObjectSet(ret, "children", JsonArrayInsert(JsonArray(), jChild)); - ret = JsonObjectSet(ret, "border", JsonBool(bBorder)); - ret = JsonObjectSet(ret, "scrollbars", JsonInt(nScroll)); + JsonObjectSetInplace(ret, "children", JsonArrayInsert(JsonArray(), jChild)); + JsonObjectSetInplace(ret, "border", JsonBool(bBorder)); + JsonObjectSetInplace(ret, "scrollbars", JsonInt(nScroll)); return ret; } @@ -720,8 +690,8 @@ json NuiVec(float x, float y) { json ret = JsonObject(); - ret = JsonObjectSet(ret, "x", JsonFloat(x)); - ret = JsonObjectSet(ret, "y", JsonFloat(y)); + JsonObjectSetInplace(ret, "x", JsonFloat(x)); + JsonObjectSetInplace(ret, "y", JsonFloat(y)); return ret; } @@ -729,10 +699,10 @@ json NuiRect(float x, float y, float w, float h) { json ret = JsonObject(); - ret = JsonObjectSet(ret, "x", JsonFloat(x)); - ret = JsonObjectSet(ret, "y", JsonFloat(y)); - ret = JsonObjectSet(ret, "w", JsonFloat(w)); - ret = JsonObjectSet(ret, "h", JsonFloat(h)); + JsonObjectSetInplace(ret, "x", JsonFloat(x)); + JsonObjectSetInplace(ret, "y", JsonFloat(y)); + JsonObjectSetInplace(ret, "w", JsonFloat(w)); + JsonObjectSetInplace(ret, "h", JsonFloat(h)); return ret; } @@ -740,10 +710,10 @@ json NuiColor(int r, int g, int b, int a = 255) { json ret = JsonObject(); - ret = JsonObjectSet(ret, "r", JsonInt(r)); - ret = JsonObjectSet(ret, "g", JsonInt(g)); - ret = JsonObjectSet(ret, "b", JsonInt(b)); - ret = JsonObjectSet(ret, "a", JsonInt(a)); + JsonObjectSetInplace(ret, "r", JsonInt(r)); + JsonObjectSetInplace(ret, "g", JsonInt(g)); + JsonObjectSetInplace(ret, "b", JsonInt(b)); + JsonObjectSetInplace(ret, "a", JsonInt(a)); return ret; } @@ -756,6 +726,15 @@ NuiStyleForegroundColor( return JsonObjectSet(jElem, "foreground_color", jColor); } +json +NuiStyleFont( + json jElem, + json jFont +) +{ + return JsonObjectSet(jElem, "font", jFont); +} + json NuiSpacer() { @@ -770,8 +749,8 @@ NuiLabel( ) { json ret = NuiElement("label", JsonNull(), jValue); - ret = JsonObjectSet(ret, "text_halign", jHAlign); - ret = JsonObjectSet(ret, "text_valign", jVAlign); + JsonObjectSetInplace(ret, "text_halign", jHAlign); + JsonObjectSetInplace(ret, "text_valign", jVAlign); return ret; } @@ -783,8 +762,8 @@ NuiText( ) { json ret = NuiElement("text", JsonNull(), jValue); - ret = JsonObjectSet(ret, "border", JsonBool(bBorder)); - ret = JsonObjectSet(ret, "scrollbars", JsonInt(nScroll)); + JsonObjectSetInplace(ret, "border", JsonBool(bBorder)); + JsonObjectSetInplace(ret, "scrollbars", JsonInt(nScroll)); return ret; } @@ -831,9 +810,9 @@ NuiImage( ) { json img = NuiElement("image", JsonNull(), jResRef); - img = JsonObjectSet(img, "image_aspect", jAspect); - img = JsonObjectSet(img, "image_halign", jHAlign); - img = JsonObjectSet(img, "image_valign", jVAlign); + JsonObjectSetInplace(img, "image_aspect", jAspect); + JsonObjectSetInplace(img, "image_halign", jHAlign); + JsonObjectSetInplace(img, "image_valign", jVAlign); return img; } @@ -873,9 +852,9 @@ NuiSliderFloat( ) { json ret = NuiElement("sliderf", JsonNull(), jValue); - ret = JsonObjectSet(ret, "min", jMin); - ret = JsonObjectSet(ret, "max", jMax); - ret = JsonObjectSet(ret, "step", jStepSize); + JsonObjectSetInplace(ret, "min", jMin); + JsonObjectSetInplace(ret, "max", jMax); + JsonObjectSetInplace(ret, "step", jStepSize); return ret; } @@ -888,9 +867,9 @@ NuiSlider( ) { json ret = NuiElement("slider", JsonNull(), jValue); - ret = JsonObjectSet(ret, "min", jMin); - ret = JsonObjectSet(ret, "max", jMax); - ret = JsonObjectSet(ret, "step", jStepSize); + JsonObjectSetInplace(ret, "min", jMin); + JsonObjectSetInplace(ret, "max", jMax); + JsonObjectSetInplace(ret, "step", jStepSize); return ret; } @@ -912,9 +891,9 @@ NuiTextEdit( ) { json ret = NuiElement("textedit", jPlaceholder, jValue); - ret = JsonObjectSet(ret, "max", JsonInt(nMaxLength)); - ret = JsonObjectSet(ret, "multiline", JsonBool(bMultiline)); - ret = JsonObjectSet(ret, "wordwrap", JsonBool(bWordWrap)); + JsonObjectSetInplace(ret, "max", JsonInt(nMaxLength)); + JsonObjectSetInplace(ret, "multiline", JsonBool(bMultiline)); + JsonObjectSetInplace(ret, "wordwrap", JsonBool(bWordWrap)); return ret; } @@ -928,11 +907,11 @@ NuiList( ) { json ret = NuiElement("list", JsonNull(), JsonNull()); - ret = JsonObjectSet(ret, "row_template", jTemplate); - ret = JsonObjectSet(ret, "row_count", jRowCount); - ret = JsonObjectSet(ret, "row_height", JsonFloat(fRowHeight)); - ret = JsonObjectSet(ret, "border", JsonBool(bBorder)); - ret = JsonObjectSet(ret, "scrollbars", JsonInt(nScroll)); + JsonObjectSetInplace(ret, "row_template", jTemplate); + JsonObjectSetInplace(ret, "row_count", jRowCount); + JsonObjectSetInplace(ret, "row_height", JsonFloat(fRowHeight)); + JsonObjectSetInplace(ret, "border", JsonBool(bBorder)); + JsonObjectSetInplace(ret, "scrollbars", JsonInt(nScroll)); return ret; } @@ -944,9 +923,9 @@ NuiListTemplateCell( ) { json ret = JsonArray(); - ret = JsonArrayInsert(ret, jElem); - ret = JsonArrayInsert(ret, JsonFloat(fWidth)); - ret = JsonArrayInsert(ret, JsonBool(bVariable)); + JsonArrayInsertInplace(ret, jElem); + JsonArrayInsertInplace(ret, JsonFloat(fWidth)); + JsonArrayInsertInplace(ret, JsonBool(bVariable)); return ret; } @@ -967,8 +946,8 @@ NuiOptions( ) { json ret = NuiElement("options", JsonNull(), jValue); - ret = JsonObjectSet(ret, "direction", JsonInt(nDirection)); - ret = JsonObjectSet(ret, "elements", jElements); + JsonObjectSetInplace(ret, "direction", JsonInt(nDirection)); + JsonObjectSetInplace(ret, "elements", jElements); return ret; } @@ -980,8 +959,8 @@ NuiToggles( ) { json ret = NuiElement("tabbar", JsonNull(), jValue); - ret = JsonObjectSet(ret, "direction", JsonInt(nDirection)); - ret = JsonObjectSet(ret, "elements", jElements); + JsonObjectSetInplace(ret, "direction", JsonInt(nDirection)); + JsonObjectSetInplace(ret, "elements", jElements); return ret; } @@ -994,10 +973,10 @@ NuiChartSlot( ) { json ret = JsonObject(); - ret = JsonObjectSet(ret, "type", JsonInt(nType)); - ret = JsonObjectSet(ret, "legend", jLegend); - ret = JsonObjectSet(ret, "color", jColor); - ret = JsonObjectSet(ret, "data", jData); + JsonObjectSetInplace(ret, "type", JsonInt(nType)); + JsonObjectSetInplace(ret, "legend", jLegend); + JsonObjectSetInplace(ret, "color", jColor); + JsonObjectSetInplace(ret, "data", jData); return ret; } @@ -1018,17 +997,19 @@ NuiDrawListItem( json jFill, json jLineThickness, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE ) { json ret = JsonObject(); - ret = JsonObjectSet(ret, "type", JsonInt(nType)); - ret = JsonObjectSet(ret, "enabled", jEnabled); - ret = JsonObjectSet(ret, "color", jColor); - ret = JsonObjectSet(ret, "fill", jFill); - ret = JsonObjectSet(ret, "line_thickness", jLineThickness); - ret = JsonObjectSet(ret, "order", JsonInt(nOrder)); - ret = JsonObjectSet(ret, "render", JsonInt(nRender)); + JsonObjectSetInplace(ret, "type", JsonInt(nType)); + JsonObjectSetInplace(ret, "enabled", jEnabled); + JsonObjectSetInplace(ret, "color", jColor); + JsonObjectSetInplace(ret, "fill", jFill); + JsonObjectSetInplace(ret, "line_thickness", jLineThickness); + JsonObjectSetInplace(ret, "order", JsonInt(nOrder)); + JsonObjectSetInplace(ret, "render", JsonInt(nRender)); + JsonObjectSetInplace(ret, "arrayBinds", JsonBool(nBindArrays)); return ret; } @@ -1040,11 +1021,12 @@ NuiDrawListPolyLine( json jLineThickness, json jPoints, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE ) { - json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_POLYLINE, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender); - ret = JsonObjectSet(ret, "points", jPoints); + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_POLYLINE, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "points", jPoints); return ret; } @@ -1058,14 +1040,15 @@ NuiDrawListCurve( json jCtrl0, json jCtrl1, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE ) { - json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_CURVE, jEnabled, jColor, JsonBool(0), jLineThickness, nOrder, nRender); - ret = JsonObjectSet(ret, "a", jA); - ret = JsonObjectSet(ret, "b", jB); - ret = JsonObjectSet(ret, "ctrl0", jCtrl0); - ret = JsonObjectSet(ret, "ctrl1", jCtrl1); + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_CURVE, jEnabled, jColor, JsonBool(0), jLineThickness, nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "a", jA); + JsonObjectSetInplace(ret, "b", jB); + JsonObjectSetInplace(ret, "ctrl0", jCtrl0); + JsonObjectSetInplace(ret, "ctrl1", jCtrl1); return ret; } @@ -1077,11 +1060,12 @@ NuiDrawListCircle( json jLineThickness, json jRect, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE ) { - json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_CIRCLE, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender); - ret = JsonObjectSet(ret, "rect", jRect); + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_CIRCLE, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "rect", jRect); return ret; } @@ -1096,14 +1080,15 @@ NuiDrawListArc( json jAMin, json jAMax, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE ) { - json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_ARC, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender); - ret = JsonObjectSet(ret, "c", jCenter); - ret = JsonObjectSet(ret, "radius", jRadius); - ret = JsonObjectSet(ret, "amin", jAMin); - ret = JsonObjectSet(ret, "amax", jAMax); + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_ARC, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "c", jCenter); + JsonObjectSetInplace(ret, "radius", jRadius); + JsonObjectSetInplace(ret, "amin", jAMin); + JsonObjectSetInplace(ret, "amax", jAMax); return ret; } @@ -1114,12 +1099,15 @@ NuiDrawListText( json jRect, json jText, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE, + json jFont = JSON_STRING ) { - json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_TEXT, jEnabled, jColor, JsonNull(), JsonNull(), nOrder, nRender); - ret = JsonObjectSet(ret, "rect", jRect); - ret = JsonObjectSet(ret, "text", jText); + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_TEXT, jEnabled, jColor, JsonNull(), JsonNull(), nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "rect", jRect); + JsonObjectSetInplace(ret, "text", jText); + ret = NuiStyleFont(ret, jFont); return ret; } @@ -1132,15 +1120,16 @@ NuiDrawListImage( json jHAlign, json jVAlign, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE ) { - json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_IMAGE, jEnabled, JsonNull(), JsonNull(), JsonNull(), nOrder, nRender); - ret = JsonObjectSet(ret, "image", jResRef); - ret = JsonObjectSet(ret, "rect", jRect); - ret = JsonObjectSet(ret, "image_aspect", jAspect); - ret = JsonObjectSet(ret, "image_halign", jHAlign); - ret = JsonObjectSet(ret, "image_valign", jVAlign); + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_IMAGE, jEnabled, JsonNull(), JsonNull(), JsonNull(), nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "image", jResRef); + JsonObjectSetInplace(ret, "rect", jRect); + JsonObjectSetInplace(ret, "image_aspect", jAspect); + JsonObjectSetInplace(ret, "image_halign", jHAlign); + JsonObjectSetInplace(ret, "image_valign", jVAlign); return ret; } @@ -1161,12 +1150,30 @@ NuiDrawListLine( json jA, json jB, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE ) { - json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_LINE, jEnabled, jColor, JsonNull(), jLineThickness, nOrder, nRender); - ret = JsonObjectSet(ret, "a", jA); - ret = JsonObjectSet(ret, "b", jB); + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_LINE, jEnabled, jColor, JsonNull(), jLineThickness, nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "a", jA); + JsonObjectSetInplace(ret, "b", jB); + return ret; +} + +json +NuiDrawListRect( + json jEnabled, + json jColor, + json jFill, + json jLineThickness, + json jRect, + int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE +) +{ + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_RECT, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "rect", jRect); return ret; } @@ -1178,7 +1185,7 @@ NuiDrawList( ) { json ret = JsonObjectSet(jElem, "draw_list", jList); - ret = JsonObjectSet(ret, "draw_list_scissor", jScissor); + JsonObjectSetInplace(ret, "draw_list_scissor", jScissor); return ret; } @@ -1190,4 +1197,3 @@ NuiDrawList( // json ret = NuiElement("canvas", JsonNull(), jList); // return ret; // } - diff --git a/src/include/pnp_shft_poly.nss b/src/include/pnp_shft_poly.nss index ce6d860..21b6663 100644 --- a/src/include/pnp_shft_poly.nss +++ b/src/include/pnp_shft_poly.nss @@ -10,9 +10,586 @@ void ShifterCheck(object oPC); #include "pnp_shft_main" #include "prc_inc_shifting" +//::////////////////Begin Werewolf////////////////// const string PRC_PNP_SHIFTING = "PRC_Shift"; -////////////////Begin Werewolf////////////////// +void LycanthropePoly(object oPC, int nPoly) +{ + effect eVis = EffectVisualEffect(VFX_IMP_POLYMORPH); + effect ePoly = SupernaturalEffect(EffectPolymorph(nPoly)); + + int bMonkGloves = GetLocalInt(oPC, "WEARING_MONK_GLOVES"); + int bArmsSlotAllowed = GetPRCSwitch(PRC_WILDSHAPE_ALLOWS_ARMS_SLOT); + + 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); + object oGlovesOld = GetItemInSlot(INVENTORY_SLOT_ARMS,oPC); + + if (GetIsObjectValid(oShield)) + { + int nShieldType = GetBaseItemType(oShield); + if (nShieldType != BASE_ITEM_LARGESHIELD && + nShieldType != BASE_ITEM_SMALLSHIELD && + nShieldType != BASE_ITEM_TOWERSHIELD) + { + oShield = OBJECT_INVALID; + } + } + + ShifterCheck(oPC); + ClearAllActions(); + + 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); + + //:: Weapon & Armor merge block + object oMergeWeaponSource = OBJECT_INVALID; + object oMergeArmorSource = OBJECT_INVALID; + + //:: Determine Weapon Merge Source + if (bWeapon) + { + if (bMonkGloves) + { + if (GetIsObjectValid(oGlovesOld)) + oMergeWeaponSource = oGlovesOld; + } + else + { + //:: Always attempt to merge melee weapon to creature weapon + oMergeWeaponSource = oWeaponOld; // even if empty, ensures proper state + } + } + else + { + //:: Weapon not requested, but arms-slot allowed monk gloves can merge via armor branch + if (bMonkGloves && bArmsSlotAllowed && GetIsObjectValid(oGlovesOld)) + oMergeWeaponSource = oGlovesOld; + } + + //:: Determine Armor Merge Source + if (bArmor && GetIsObjectValid(oArmorNew)) + { + if (!bMonkGloves) + { + if (bArmsSlotAllowed && GetIsObjectValid(oGlovesOld)) + oMergeArmorSource = oGlovesOld; + + if (GetIsObjectValid(oShield)) IPWildShapeCopyItemProperties(oShield, oArmorNew); + if (GetIsObjectValid(oHelmetOld)) IPWildShapeCopyItemProperties(oHelmetOld, oArmorNew); + if (GetIsObjectValid(oArmorOld)) IPWildShapeCopyItemProperties(oArmorOld, oArmorNew); + } + else + { + if (GetIsObjectValid(oShield)) IPWildShapeCopyItemProperties(oShield, oArmorNew); + if (GetIsObjectValid(oHelmetOld)) IPWildShapeCopyItemProperties(oHelmetOld, oArmorNew); + if (GetIsObjectValid(oArmorOld)) IPWildShapeCopyItemProperties(oArmorOld, oArmorNew); + } + } + else if (bArmor && !GetIsObjectValid(oArmorNew) && DEBUG) + { + DoDebug("LycanthropePoly: MergeA set, but oArmorNew invalid."); + } + + //:: Apply Weapon Merge + if (GetIsObjectValid(oMergeWeaponSource) || bWeapon) + { + //:: Always attempt to merge weapon properties even if source is OBJECT_INVALID + if (GetIsObjectValid(oWeaponNewLeft)) IPWildShapeCopyItemProperties(oMergeWeaponSource, oWeaponNewLeft, TRUE); + if (GetIsObjectValid(oWeaponNewRight)) IPWildShapeCopyItemProperties(oMergeWeaponSource, oWeaponNewRight, TRUE); + if (GetIsObjectValid(oWeaponNewBite)) IPWildShapeCopyItemProperties(oMergeWeaponSource, oWeaponNewBite, TRUE); + } + + //:: Apply Armor Merge + if (GetIsObjectValid(oMergeArmorSource)) + { + if (GetIsObjectValid(oArmorNew)) IPWildShapeCopyItemProperties(oMergeArmorSource, oArmorNew); + } + + //:: General item merge block + if (bItems && GetIsObjectValid(oArmorNew)) + { + if (GetIsObjectValid(oRing1Old)) IPWildShapeCopyItemProperties(oRing1Old, oArmorNew); + if (GetIsObjectValid(oRing2Old)) IPWildShapeCopyItemProperties(oRing2Old, oArmorNew); + if (GetIsObjectValid(oAmuletOld)) IPWildShapeCopyItemProperties(oAmuletOld, oArmorNew); + if (GetIsObjectValid(oCloakOld)) IPWildShapeCopyItemProperties(oCloakOld, oArmorNew); + if (GetIsObjectValid(oBootsOld)) IPWildShapeCopyItemProperties(oBootsOld, oArmorNew); + if (GetIsObjectValid(oBeltOld)) IPWildShapeCopyItemProperties(oBeltOld, oArmorNew); + } +} +//::////////////////End Werewolf////////////////// + + +/* //::////////////////Begin Werewolf////////////////// +const string PRC_PNP_SHIFTING = "PRC_Shift"; + +void LycanthropePoly(object oPC, int nPoly) +{ + effect eVis = EffectVisualEffect(VFX_IMP_POLYMORPH); + effect ePoly = SupernaturalEffect(EffectPolymorph(nPoly)); + + int bMonkGloves = GetLocalInt(oPC, "WEARING_MONK_GLOVES"); + int bArmsSlotAllowed = GetPRCSwitch(PRC_WILDSHAPE_ALLOWS_ARMS_SLOT); + + 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); + object oGlovesOld = GetItemInSlot(INVENTORY_SLOT_ARMS,oPC); + + if (GetIsObjectValid(oShield)) + { + int nShieldType = GetBaseItemType(oShield); + if (nShieldType != BASE_ITEM_LARGESHIELD && + nShieldType != BASE_ITEM_SMALLSHIELD && + nShieldType != BASE_ITEM_TOWERSHIELD) + { + oShield = OBJECT_INVALID; + } + } + + ShifterCheck(oPC); + ClearAllActions(); + + 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); + + //:: Weapon & Armor merge block + object oMergeWeaponSource = OBJECT_INVALID; + object oMergeArmorSource = OBJECT_INVALID; + + // ---- Determine Weapon Merge Source ---- + if (bWeapon) + { + if (bMonkGloves) + { + if (GetIsObjectValid(oGlovesOld)) + oMergeWeaponSource = oGlovesOld; + } + else + { + if (GetIsObjectValid(oWeaponOld)) + oMergeWeaponSource = oWeaponOld; + } + } + else + { + if (bMonkGloves && bArmsSlotAllowed && GetIsObjectValid(oGlovesOld)) + oMergeWeaponSource = oGlovesOld; + } + + // ---- Determine Armor Merge Source ---- + if (bArmor && GetIsObjectValid(oArmorNew)) + { + if (!bMonkGloves) + { + if (bArmsSlotAllowed && GetIsObjectValid(oGlovesOld)) + oMergeArmorSource = oGlovesOld; + + if (GetIsObjectValid(oShield)) IPWildShapeCopyItemProperties(oShield, oArmorNew); + if (GetIsObjectValid(oHelmetOld)) IPWildShapeCopyItemProperties(oHelmetOld, oArmorNew); + if (GetIsObjectValid(oArmorOld)) IPWildShapeCopyItemProperties(oArmorOld, oArmorNew); + } + else + { + if (GetIsObjectValid(oShield)) IPWildShapeCopyItemProperties(oShield, oArmorNew); + if (GetIsObjectValid(oHelmetOld)) IPWildShapeCopyItemProperties(oHelmetOld, oArmorNew); + if (GetIsObjectValid(oArmorOld)) IPWildShapeCopyItemProperties(oArmorOld, oArmorNew); + } + } + else if (bArmor && !GetIsObjectValid(oArmorNew) && DEBUG) + { + DoDebug("LycanthropePoly: MergeA set, but oArmorNew invalid."); + } + + // ---- Apply Weapon Merge ---- + if (GetIsObjectValid(oMergeWeaponSource)) + { + if (GetIsObjectValid(oWeaponNewLeft)) IPWildShapeCopyItemProperties(oMergeWeaponSource, oWeaponNewLeft, TRUE); + if (GetIsObjectValid(oWeaponNewRight)) IPWildShapeCopyItemProperties(oMergeWeaponSource, oWeaponNewRight, TRUE); + if (GetIsObjectValid(oWeaponNewBite)) IPWildShapeCopyItemProperties(oMergeWeaponSource, oWeaponNewBite, TRUE); + } + + // ---- Apply Armor Merge ---- + if (GetIsObjectValid(oMergeArmorSource)) + { + if (GetIsObjectValid(oArmorNew)) IPWildShapeCopyItemProperties(oMergeArmorSource, oArmorNew); + } + + //:: General item merge block + if (bItems && GetIsObjectValid(oArmorNew)) + { + if (GetIsObjectValid(oRing1Old)) IPWildShapeCopyItemProperties(oRing1Old, oArmorNew); + if (GetIsObjectValid(oRing2Old)) IPWildShapeCopyItemProperties(oRing2Old, oArmorNew); + if (GetIsObjectValid(oAmuletOld)) IPWildShapeCopyItemProperties(oAmuletOld, oArmorNew); + if (GetIsObjectValid(oCloakOld)) IPWildShapeCopyItemProperties(oCloakOld, oArmorNew); + if (GetIsObjectValid(oBootsOld)) IPWildShapeCopyItemProperties(oBootsOld, oArmorNew); + if (GetIsObjectValid(oBeltOld)) IPWildShapeCopyItemProperties(oBeltOld, oArmorNew); + } +} +//::////////////////End Werewolf////////////////// */ + + +/* //::////////////////Begin Werewolf////////////////// +const string PRC_PNP_SHIFTING = "PRC_Shift"; + +void LycanthropePoly(object oPC, int nPoly) +{ + effect eVis = EffectVisualEffect(VFX_IMP_POLYMORPH); + effect ePoly = SupernaturalEffect(EffectPolymorph(nPoly)); + + int bMonkGloves = GetLocalInt(oPC, "WEARING_MONK_GLOVES"); + int bArmsSlotAllowed = GetPRCSwitch(PRC_WILDSHAPE_ALLOWS_ARMS_SLOT); + + 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); + object oGlovesOld = GetItemInSlot(INVENTORY_SLOT_ARMS,oPC); + + if (GetIsObjectValid(oShield)) + { + int nShieldType = GetBaseItemType(oShield); + if (nShieldType != BASE_ITEM_LARGESHIELD && + nShieldType != BASE_ITEM_SMALLSHIELD && + nShieldType != BASE_ITEM_TOWERSHIELD) + { + oShield = OBJECT_INVALID; + } + } + + ShifterCheck(oPC); + ClearAllActions(); + + 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); + + //:: Weapon merge block + if (bWeapon) + { + object oMergeSource = OBJECT_INVALID; + + // Priority: monk gloves override if worn and arms-slot not allowed + if (bMonkGloves && !bArmsSlotAllowed) + { + if (GetIsObjectValid(oGlovesOld)) + oMergeSource = oGlovesOld; + } + else + { + // Otherwise use main-hand weapon if it exists + if (GetIsObjectValid(oWeaponOld)) + oMergeSource = oWeaponOld; + } + + // Apply merge to creature weapons if we have a source + if (GetIsObjectValid(oMergeSource)) + { + if (GetIsObjectValid(oWeaponNewLeft)) IPWildShapeCopyItemProperties(oMergeSource, oWeaponNewLeft, TRUE); + if (GetIsObjectValid(oWeaponNewRight)) IPWildShapeCopyItemProperties(oMergeSource, oWeaponNewRight, TRUE); + if (GetIsObjectValid(oWeaponNewBite)) IPWildShapeCopyItemProperties(oMergeSource, oWeaponNewBite, TRUE); + } + } + + //:: Armor merge block + if (bArmor && GetIsObjectValid(oArmorNew)) + { + if (GetIsObjectValid(oShield)) IPWildShapeCopyItemProperties(oShield, oArmorNew); + if (GetIsObjectValid(oHelmetOld)) IPWildShapeCopyItemProperties(oHelmetOld, oArmorNew); + if (GetIsObjectValid(oArmorOld)) IPWildShapeCopyItemProperties(oArmorOld, oArmorNew); + + // Arms-slot allowed -> apply gloves & bracers to creature weapons + if (bArmsSlotAllowed && GetIsObjectValid(oGlovesOld)) + { + if (DEBUG) DoDebug("LycanthropePoly: Arms-slot allowed -> applying gloves/bracers to creature weapons from armor branch."); + if (GetIsObjectValid(oWeaponNewLeft)) IPWildShapeCopyItemProperties(oGlovesOld, oWeaponNewLeft, TRUE); + if (GetIsObjectValid(oWeaponNewRight)) IPWildShapeCopyItemProperties(oGlovesOld, oWeaponNewRight, TRUE); + if (GetIsObjectValid(oWeaponNewBite)) IPWildShapeCopyItemProperties(oGlovesOld, oWeaponNewBite, TRUE); + } + } + else if (bArmor && !GetIsObjectValid(oArmorNew) && DEBUG) + { + DoDebug("LycanthropePoly: MergeA set, but oArmorNew invalid."); + } + + //:: General item merge block + if (bItems && GetIsObjectValid(oArmorNew)) + { + if (GetIsObjectValid(oRing1Old)) IPWildShapeCopyItemProperties(oRing1Old, oArmorNew); + if (GetIsObjectValid(oRing2Old)) IPWildShapeCopyItemProperties(oRing2Old, oArmorNew); + if (GetIsObjectValid(oAmuletOld)) IPWildShapeCopyItemProperties(oAmuletOld, oArmorNew); + if (GetIsObjectValid(oCloakOld)) IPWildShapeCopyItemProperties(oCloakOld, oArmorNew); + if (GetIsObjectValid(oBootsOld)) IPWildShapeCopyItemProperties(oBootsOld, oArmorNew); + if (GetIsObjectValid(oBeltOld)) IPWildShapeCopyItemProperties(oBeltOld, oArmorNew); + } +} +//::////////////////End Werewolf////////////////// + */ + +/* //::////////////////Begin Werewolf////////////////// +const string PRC_PNP_SHIFTING = "PRC_Shift"; + +void LycanthropePoly(object oPC, int nPoly) +{ + effect eVis = EffectVisualEffect(VFX_IMP_POLYMORPH); + effect ePoly = SupernaturalEffect(EffectPolymorph(nPoly)); + + int bMonkGloves = GetLocalInt(oPC, "WEARING_MONK_GLOVES"); + int bArmsSlotAllowed = GetPRCSwitch(PRC_WILDSHAPE_ALLOWS_ARMS_SLOT); + + 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); + object oGlovesOld = GetItemInSlot(INVENTORY_SLOT_ARMS,oPC); + + if (GetIsObjectValid(oShield)) + { + int nShieldType = GetBaseItemType(oShield); + if (nShieldType != BASE_ITEM_LARGESHIELD && + nShieldType != BASE_ITEM_SMALLSHIELD && + nShieldType != BASE_ITEM_TOWERSHIELD) + { + oShield = OBJECT_INVALID; + } + } + + ShifterCheck(oPC); + ClearAllActions(); + + 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); + + //:: Weapon merge block + //:: Only blocked if monk gloves are equipped AND arms-slot merge is NOT allowed + if (bWeapon && !bMonkGloves) + { + if (GetIsObjectValid(oWeaponOld)) + { + if (GetIsObjectValid(oWeaponNewLeft)) IPWildShapeCopyItemProperties(oWeaponOld, oWeaponNewLeft, TRUE); + if (GetIsObjectValid(oWeaponNewRight)) IPWildShapeCopyItemProperties(oWeaponOld, oWeaponNewRight, TRUE); + if (GetIsObjectValid(oWeaponNewBite)) IPWildShapeCopyItemProperties(oWeaponOld, oWeaponNewBite, TRUE); + } + } + else if (bWeapon && bMonkGloves && !bArmsSlotAllowed) + { + if (DEBUG) DoDebug("LycanthropePoly: Monk gloves overriding weapon merge (arms slot NOT allowed)."); + if (GetIsObjectValid(oGlovesOld)) + { + if (GetIsObjectValid(oWeaponNewLeft)) IPWildShapeCopyItemProperties(oGlovesOld, oWeaponNewLeft, TRUE); + if (GetIsObjectValid(oWeaponNewRight)) IPWildShapeCopyItemProperties(oGlovesOld, oWeaponNewRight, TRUE); + if (GetIsObjectValid(oWeaponNewBite)) IPWildShapeCopyItemProperties(oGlovesOld, oWeaponNewBite, TRUE); + } + } + + + //:: Armor merge block + //:: Apply armor and gloves (if arms-slot allowed) + + if (bArmor && GetIsObjectValid(oArmorNew)) + { + if (GetIsObjectValid(oShield)) IPWildShapeCopyItemProperties(oShield, oArmorNew); + if (GetIsObjectValid(oHelmetOld)) IPWildShapeCopyItemProperties(oHelmetOld, oArmorNew); + if (GetIsObjectValid(oArmorOld)) IPWildShapeCopyItemProperties(oArmorOld, oArmorNew); + + if (bArmsSlotAllowed && bMonkGloves && GetIsObjectValid(oGlovesOld)) + { + if (DEBUG) DoDebug("LycanthropePoly: Arms-slot allowed -> applying gloves to creature weapons from armor branch."); + if (GetIsObjectValid(oWeaponNewLeft)) IPWildShapeCopyItemProperties(oGlovesOld, oWeaponNewLeft, TRUE); + if (GetIsObjectValid(oWeaponNewRight)) IPWildShapeCopyItemProperties(oGlovesOld, oWeaponNewRight, TRUE); + if (GetIsObjectValid(oWeaponNewBite)) IPWildShapeCopyItemProperties(oGlovesOld, oWeaponNewBite, TRUE); + } + } + else if (bArmor && !GetIsObjectValid(oArmorNew) && DEBUG) + { + DoDebug("LycanthropePoly: MergeA set, but oArmorNew invalid."); + } + + //:: General item merge block + if (bItems && GetIsObjectValid(oArmorNew)) + { + if (GetIsObjectValid(oRing1Old)) IPWildShapeCopyItemProperties(oRing1Old, oArmorNew); + if (GetIsObjectValid(oRing2Old)) IPWildShapeCopyItemProperties(oRing2Old, oArmorNew); + if (GetIsObjectValid(oAmuletOld)) IPWildShapeCopyItemProperties(oAmuletOld, oArmorNew); + if (GetIsObjectValid(oCloakOld)) IPWildShapeCopyItemProperties(oCloakOld, oArmorNew); + if (GetIsObjectValid(oBootsOld)) IPWildShapeCopyItemProperties(oBootsOld, oArmorNew); + if (GetIsObjectValid(oBeltOld)) IPWildShapeCopyItemProperties(oBeltOld, oArmorNew); + } +} +//::////////////////End Werewolf////////////////// */ + + +/* //::////////////////Begin Werewolf////////////////// +const string PRC_PNP_SHIFTING = "PRC_Shift"; + +void LycanthropePoly(object oPC, int nPoly) +{ + effect eVis = EffectVisualEffect(VFX_IMP_POLYMORPH); + effect ePoly = SupernaturalEffect(EffectPolymorph(nPoly)); + + int bMonkGloves = GetLocalInt(oPC, "WEARING_MONK_GLOVES"); + int bArmsSlotAllowed = GetPRCSwitch(PRC_WILDSHAPE_ALLOWS_ARMS_SLOT); + + 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); + object oGlovesOld = GetItemInSlot(INVENTORY_SLOT_ARMS,oPC); + + if (GetIsObjectValid(oShield)) + { + int nShieldType = GetBaseItemType(oShield); + if (nShieldType != BASE_ITEM_LARGESHIELD && + nShieldType != BASE_ITEM_SMALLSHIELD && + nShieldType != BASE_ITEM_TOWERSHIELD) + { + oShield = OBJECT_INVALID; + } + } + + ShifterCheck(oPC); + ClearAllActions(); + + 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); + + //:: Weapon merge block + //:: Only blocked if monk gloves are equipped AND arms-slot merge is NOT allowed + if (bWeapon && !bMonkGloves) + { + if (GetIsObjectValid(oWeaponOld)) + { + if (GetIsObjectValid(oWeaponNewLeft)) IPWildShapeCopyItemProperties(oWeaponOld, oWeaponNewLeft, TRUE); + if (GetIsObjectValid(oWeaponNewRight)) IPWildShapeCopyItemProperties(oWeaponOld, oWeaponNewRight, TRUE); + if (GetIsObjectValid(oWeaponNewBite)) IPWildShapeCopyItemProperties(oWeaponOld, oWeaponNewBite, TRUE); + } + } + else if (bWeapon && bMonkGloves && !bArmsSlotAllowed) + { + if (DEBUG) DoDebug("LycanthropePoly: Monk gloves overriding weapon merge (arms slot NOT allowed)."); + if (GetIsObjectValid(oGlovesOld)) + { + if (GetIsObjectValid(oWeaponNewLeft)) IPWildShapeCopyItemProperties(oGlovesOld, oWeaponNewLeft, TRUE); + if (GetIsObjectValid(oWeaponNewRight)) IPWildShapeCopyItemProperties(oGlovesOld, oWeaponNewRight, TRUE); + if (GetIsObjectValid(oWeaponNewBite)) IPWildShapeCopyItemProperties(oGlovesOld, oWeaponNewBite, TRUE); + } + } + + + //:: Armor merge block + //:: Apply armor and gloves (if arms-slot allowed) + + if (bArmor && GetIsObjectValid(oArmorNew)) + { + if (GetIsObjectValid(oShield)) IPWildShapeCopyItemProperties(oShield, oArmorNew); + if (GetIsObjectValid(oHelmetOld)) IPWildShapeCopyItemProperties(oHelmetOld, oArmorNew); + if (GetIsObjectValid(oArmorOld)) IPWildShapeCopyItemProperties(oArmorOld, oArmorNew); + + if (bArmsSlotAllowed && bMonkGloves && GetIsObjectValid(oGlovesOld)) + { + if (DEBUG) DoDebug("LycanthropePoly: Arms-slot allowed -> applying gloves to creature weapons from armor branch."); + if (GetIsObjectValid(oWeaponNewLeft)) IPWildShapeCopyItemProperties(oGlovesOld, oWeaponNewLeft, TRUE); + if (GetIsObjectValid(oWeaponNewRight)) IPWildShapeCopyItemProperties(oGlovesOld, oWeaponNewRight, TRUE); + if (GetIsObjectValid(oWeaponNewBite)) IPWildShapeCopyItemProperties(oGlovesOld, oWeaponNewBite, TRUE); + } + } + else if (bArmor && !GetIsObjectValid(oArmorNew) && DEBUG) + { + DoDebug("LycanthropePoly: MergeA set, but oArmorNew invalid."); + } + + //:: General item merge block + if (bItems && GetIsObjectValid(oArmorNew)) + { + if (GetIsObjectValid(oRing1Old)) IPWildShapeCopyItemProperties(oRing1Old, oArmorNew); + if (GetIsObjectValid(oRing2Old)) IPWildShapeCopyItemProperties(oRing2Old, oArmorNew); + if (GetIsObjectValid(oAmuletOld)) IPWildShapeCopyItemProperties(oAmuletOld, oArmorNew); + if (GetIsObjectValid(oCloakOld)) IPWildShapeCopyItemProperties(oCloakOld, oArmorNew); + if (GetIsObjectValid(oBootsOld)) IPWildShapeCopyItemProperties(oBootsOld, oArmorNew); + if (GetIsObjectValid(oBeltOld)) IPWildShapeCopyItemProperties(oBeltOld, oArmorNew); + } +} +//::////////////////End Werewolf////////////////// */ + + +/* ////////////////Begin Werewolf////////////////// void LycanthropePoly(object oPC, int nPoly) { @@ -84,7 +661,7 @@ void LycanthropePoly(object oPC, int nPoly) } -////////////////End Werewolf////////////////// +////////////////End Werewolf////////////////// */ void ShifterCheck(object oPC) { @@ -246,4 +823,6 @@ void DoTail(object oPC, int nTailType) SetCreatureTailType(nTailType, oPC); //override any stored default appearance SetPersistantLocalInt(oPC, "AppearanceStoredTail", nTailType); -} \ No newline at end of file +} + +//::void main (){} \ No newline at end of file diff --git a/src/include/prc_add_spell_dc.nss b/src/include/prc_add_spell_dc.nss index 4cde6de..f2a0e2f 100644 --- a/src/include/prc_add_spell_dc.nss +++ b/src/include/prc_add_spell_dc.nss @@ -513,6 +513,8 @@ int PRCGetSpellSaveDC(int nSpellID = -1, int nSchool = -1, object oCaster = OBJE if(nClass == CLASS_TYPE_BARD) nDC += StringToInt(Get2DACache("Spells", "Bard", nSpellID)); + else if(nClass == CLASS_TYPE_ASSASSIN) + nDC += StringToInt(Get2DACache("Spells", "Assassin", nSpellID)); else if(nClass == CLASS_TYPE_CLERIC || nClass == CLASS_TYPE_UR_PRIEST || nClass == CLASS_TYPE_OCULAR) nDC += StringToInt(Get2DACache("Spells", "Cleric", nSpellID)); else if(nClass == CLASS_TYPE_DRUID) diff --git a/src/include/prc_add_spl_pen.nss b/src/include/prc_add_spl_pen.nss index e339ebd..d7ca3d6 100644 --- a/src/include/prc_add_spl_pen.nss +++ b/src/include/prc_add_spl_pen.nss @@ -54,11 +54,11 @@ int SPGetPenetrAOE(object oCaster = OBJECT_SELF, int nCasterLvl = 0); /* Includes */ ////////////////////////////////////////////////// -//#include "prc_inc_spells" +#include "prc_inc_spells" //#include "prc_alterations" //#include "prcsp_archmaginc" //#include "prc_inc_racial" - +#include "inc_2dacache" ////////////////////////////////////////////////// /* Function definitions */ diff --git a/src/include/prc_class_const.nss b/src/include/prc_class_const.nss index 286b574..04e96f1 100644 --- a/src/include/prc_class_const.nss +++ b/src/include/prc_class_const.nss @@ -143,7 +143,7 @@ const int CLASS_TYPE_MASTER_HARPER = 176; const int CLASS_TYPE_FRE_BERSERKER = 177; const int CLASS_TYPE_TEMPEST = 178; const int CLASS_TYPE_FOE_HUNTER = 179; -//:: Free = 180 +const int CLASS_TYPE_VERDANT_LORD = 180; const int CLASS_TYPE_ORC_WARLORD = 181; const int CLASS_TYPE_THRALL_OF_GRAZZT_A = 182; const int CLASS_TYPE_NECROCARNATE = 183; @@ -162,7 +162,7 @@ const int CLASS_TYPE_MASTER_OF_NINE = 195; const int CLASS_TYPE_ETERNAL_BLADE = 196; const int CLASS_TYPE_SHADOW_SUN_NINJA = 197; const int CLASS_TYPE_WITCHBORN_BINDER = 198; -const int CLASS_TYPE_BAELNORN = 199; +const int CLASS_TYPE_LION_OF_TALISID = 199; const int CLASS_TYPE_DISCIPLE_OF_MEPH = 200; const int CLASS_TYPE_SOUL_EATER = 201; const int CLASS_TYPE_HENSHIN_MYSTIC = 202; @@ -236,6 +236,7 @@ const int CLASS_TYPE_WITCH = -1; const int CLASS_TYPE_TEMPLAR = -1; const int CLASS_TYPE_MYSTIC = -1; const int CLASS_TYPE_NOBLE = -1; +const int CLASS_TYPE_BAELNORN = -2; //void main (){} \ No newline at end of file diff --git a/src/include/prc_craft_inc.nss b/src/include/prc_craft_inc.nss index 8d0c398..ee87ad8 100644 --- a/src/include/prc_craft_inc.nss +++ b/src/include/prc_craft_inc.nss @@ -444,6 +444,7 @@ int Get2DALineFromItemprop(string sFile, itemproperty ip, object oItem) } break; } + case ITEM_PROPERTY_ECHOBLADE: return 46; break; } } return -1; @@ -1529,7 +1530,12 @@ void ApplyItemProps(object oItem, string sFile, int nLine) break; //no more itemprops, no gaps, assuming no errors } if(sFile != "craft_weapon" && sFile != "craft_armour") - SetName(oItem, GetStringByStrRef(StringToInt(Get2DACache(sFile, "Name", nLine)))); + { + SetName(oItem, GetStringByStrRef(StringToInt(Get2DACache(sFile, "Name", nLine)))); + string sDescRef = Get2DACache(sFile, "CraftedDescription", nLine); + if(sDescRef != "") + SetDescription(oItem, GetStringByStrRef(StringToInt(sDescRef))); + } } //Partly ripped off the lexicon :P @@ -1620,7 +1626,8 @@ string GetCrafting2DA(object oItem) (nBase == BASE_ITEM_BOOTS) || (nBase == BASE_ITEM_GLOVES) || (nBase == BASE_ITEM_BRACER) || - (nBase == BASE_ITEM_CLOAK)) + (nBase == BASE_ITEM_CLOAK) || + (nBase == BASE_ITEM_CRAFTED_VIAL)) ) return "craft_wondrous"; @@ -1657,19 +1664,28 @@ int GetCraftingFeat(object oItem) if(nBase == BASE_ITEM_RING) return FEAT_FORGE_RING; //routing bioware feats through this convo + if((nBase == BASE_ITEM_CRAFTED_SCEPTER) || + (nBase == BASE_ITEM_CRAFTED_SCEPTER) + ) + return FEAT_CRAFT_SCEPTER; + if((nBase == BASE_ITEM_MAGICROD) || (nBase == BASE_ITEM_CRAFTED_ROD) ) return FEAT_CRAFT_ROD; + if((nBase == BASE_ITEM_MAGICSTAFF) || (nBase == BASE_ITEM_CRAFTED_STAFF) ) return FEAT_CRAFT_STAFF; + if((nBase == BASE_ITEM_MAGICWAND) || (nBase == BASE_ITEM_BLANK_WAND) ) return FEAT_CRAFT_WAND; + if(nBase == BASE_ITEM_BLANK_POTION) return FEAT_BREW_POTION; + if(nBase == BASE_ITEM_BLANK_SCROLL) return FEAT_SCRIBE_SCROLL; if(((nBase == BASE_ITEM_HELMET) || @@ -1678,7 +1694,8 @@ int GetCraftingFeat(object oItem) (nBase == BASE_ITEM_BOOTS) || (nBase == BASE_ITEM_GLOVES) || (nBase == BASE_ITEM_BRACER) || - (nBase == BASE_ITEM_CLOAK)) + (nBase == BASE_ITEM_CLOAK) || + (nBase == BASE_ITEM_CRAFTED_VIAL)) ) return FEAT_CRAFT_WONDROUS; diff --git a/src/include/prc_effect_inc.nss b/src/include/prc_effect_inc.nss index 6186f71..a41f7d9 100644 --- a/src/include/prc_effect_inc.nss +++ b/src/include/prc_effect_inc.nss @@ -75,6 +75,14 @@ void DeathlessFrenzyCheck(object oTarget); // * PRC Version of a Bioware function to disable include loops void PRCRemoveSpellEffects(int nSpell_ID, object oCaster, object oTarget); + +/** + * Target is immune to gaze attacks + * + * @return the Gaze Immunity effect + */ +effect EffectGazeImmune(); + /** * Dazzles the target: -1 Attack, Search, Spot, and VFX * @@ -82,6 +90,9 @@ void PRCRemoveSpellEffects(int nSpell_ID, object oCaster, object oTarget); */ effect EffectDazzle(); +//ebonfowl: adding this function to check if a target is already shaken +int GetIsShaken(object oTarget); + /** * Shaken effect: -2 to attack, all skills and saving throws * @@ -170,14 +181,11 @@ effect EffectAbilityBasedSkillIncrease(int iAbility, int iIncrease = 1); */ 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 +#include "inc_epicspelldef" ////////////////////////////////////////////////// /* Internal functions */ @@ -261,6 +269,8 @@ object GetObjectToApplyNewEffect(string sTag, object oPC, int nStripEffects = TR SetCreatureAppearanceType(oWP, APPEARANCE_TYPE_INVISIBLE_HUMAN_MALE); ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY), oWP); ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectCutsceneGhost(), oWP); + AssignCommand(oWP, ActionUseSkill(SKILL_HIDE, oWP)); + } //remove previous effects if(nStripEffects) @@ -583,7 +593,8 @@ effect PRCEffectHeal(int nHP, object oTarget) return EffectHeal(nHP); } -effect EffectAbilityBasedSkillIncrease(int iAbility, int iIncrease = 1){ +effect EffectAbilityBasedSkillIncrease(int iAbility, int iIncrease = 1) +{ effect eReturn; switch(iAbility) { @@ -639,7 +650,8 @@ effect EffectAbilityBasedSkillIncrease(int iAbility, int iIncrease = 1){ return eReturn; } -effect EffectAbilityBasedSkillDecrease(int iAbility, int iDecrease = 1){ +effect EffectAbilityBasedSkillDecrease(int iAbility, int iDecrease = 1) +{ effect eReturn; switch(iAbility) { @@ -695,7 +707,8 @@ effect EffectAbilityBasedSkillDecrease(int iAbility, int iDecrease = 1){ return eReturn; } -effect EffectDamageImmunityAll(){ +effect EffectDamageImmunityAll() +{ effect eReturn = EffectDamageImmunityIncrease(DAMAGE_TYPE_ACID, 100); eReturn = EffectLinkEffects(eReturn, EffectDamageImmunityIncrease(DAMAGE_TYPE_BLUDGEONING, 100)); eReturn = EffectLinkEffects(eReturn, EffectDamageImmunityIncrease(DAMAGE_TYPE_COLD, 100)); @@ -712,7 +725,8 @@ effect EffectDamageImmunityAll(){ return eReturn; } -effect EffectImmunityMiscAll(){ +effect EffectImmunityMiscAll() +{ effect eReturn = EffectImmunity(IMMUNITY_TYPE_ABILITY_DECREASE); eReturn = EffectLinkEffects(eReturn, EffectImmunity(IMMUNITY_TYPE_BLINDNESS)); eReturn = EffectLinkEffects(eReturn, EffectImmunity(IMMUNITY_TYPE_DEAFNESS)); @@ -732,6 +746,47 @@ effect EffectImmunityMiscAll(){ return eReturn; } +//:: Immunity to all gaze attacks +effect EffectGazeImmune() +{ + + effect eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_CHARM); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_CONFUSION); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DAZE); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DEATH); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DESTROY_CHAOS); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DESTROY_EVIL); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DESTROY_GOOD); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DESTROY_LAW); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DOMINATE); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DOOM); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_FEAR); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_PARALYSIS); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_PETRIFY); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_STUNNED); + + eReturn = TagEffect(eReturn, "PRCGazeImmune"); + + return eReturn; +} + +//:: Immunity to all perification attacks +effect EffectPetrificationImmune() +{ + effect eReturn = EffectSpellImmunity(SPELLABILITY_TOUCH_PETRIFY); + eReturn = EffectSpellImmunity(SPELLABILITY_BREATH_PETRIFY); + eReturn = EffectSpellImmunity(SPELL_FLESH_TO_STONE); + eReturn = EffectSpellImmunity(SPELL_STONEHOLD); + eReturn = EffectSpellImmunity(SPELL_EPIC_A_STONE); + eReturn = EffectSpellImmunity(POWER_CRYSTALLIZE); + eReturn = EffectSpellImmunity(MELD_BASILISK_MASK); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_PETRIFY); + + eReturn = TagEffect(eReturn, "PRCPetrificationImmune"); + + return eReturn; +} + int GetIsShaken(object oTarget) { effect eEffect = GetFirstEffect(oTarget); @@ -747,4 +802,13 @@ int GetIsShaken(object oTarget) eEffect = GetNextEffect(oTarget); } return FALSE; -} \ No newline at end of file +} + +// Forward declarations for size change effects +// Implementations are in prc_inc_size +effect EffectSizeChange(object oTarget, int nObjectType, int bEnlarge, int nChanges); +void DelayedSetVisualTransform(int nExpectedGeneration, object oTarget, int nTransform, float fValue); +void DelaySetVisualTransform(float fDelay, object oTarget, string sGenerationName, int nTransform, float fValue); + +//:: Test void +//::void main() {} \ No newline at end of file diff --git a/src/include/prc_feat_const.nss b/src/include/prc_feat_const.nss index c961dab..6fd8c94 100644 --- a/src/include/prc_feat_const.nss +++ b/src/include/prc_feat_const.nss @@ -4,6 +4,11 @@ //:: PRC Options Conversation const int FEAT_OPTIONS_CONVERSATION = 2285; +//;; Builder Feats +const int FEAT_ARCHETYPAL_FORM = 2918; +const int FEAT_INTRINSIC_ARMOR = 25990; +const int FEAT_INTRINSIC_WEAPON = 25991; + //:: Missing Bioware Feats const int FEAT_EPIC_PLANAR_TURNING = 854; @@ -152,6 +157,9 @@ const int FEAT_EPIC_DIAMOND_DRAGON = 25115; const int FEAT_EPIC_CRUSADER = 25116; const int FEAT_EPIC_SWORDSAGE = 25117; const int FEAT_EPIC_WARBLADE = 25118; +const int FEAT_EPIC_LION_OF_TALISID = 25600; +const int FEAT_EPIC_VERDANT_LORD = 25618; + //:: Vile Martial Strike Expansion const int FEAT_VILE_MARTIAL_EAGLE_CLAW = 24800; @@ -195,6 +203,31 @@ const int FEAT_CHARMING_THE_ARROW = 25998; //:: Skill Based Feats const int FEAT_JUMP = 2884; +//:: Lion of Talisid +const int FEAT_LOT_LIONS_COURAGE = 25614; +const int FEAT_LOT_LIONS_POUNCE = 25615; +const int FEAT_LOT_LIONS_SWIFTNESS = 25616; +const int FEAT_LOT_LEONALS_ROAR = 25617; + +//::: Verdant Lord +const int FEAT_VL_EXPERT_INFUSION = 25634; +const int FEAT_VL_SUN_SUSTENANCE = 25635; +const int FEAT_VL_SPONTANEITY = 25636; +const int FEAT_VL_PLANT_FACILITY = 25637; +const int FEAT_VL_WILD_SHAPE_TREANT = 25638; +const int FEAT_VL_ANIMATE_TREE = 25639; +const int FEAT_VL_GAEAS_EMBRACE = 25640; + +//:: Masters of the Wild feats +const int FEAT_CREATE_INFUSION = 25960; +const int FEAT_MAGICAL_ARTISAN_CREATE_INFUSION = 25961; +const int FEAT_PLANT_DEFIANCE = 25992; +const int FEAT_PLANT_CONTROL = 25993; + + //:: Lost Empires of Faerun feats +const int FEAT_CRAFT_SCEPTER = 25962; +const int FEAT_MAGICAL_ARTISAN_CRAFT_SCEPTER = 25963; + //:: Racial Feats const int FEAT_WEMIC_JUMP_8 = 4518; const int FEAT_URDINNIR_STONESKIN = 4644; @@ -782,6 +815,9 @@ const int FEAT_SUEL_IGNORE_SPELL_FAILURE = 2398; const int FEAT_SUEL_EXTENDED_SPELL = 2399; const int FEAT_SUEL_DISPELLING_STRIKE = 2400; +//:: Druid +const int FEAT_SPONT_SUMMON = 2372; + //Passive Feats const int FEAT_ETERNAL_FREEDOM = 4298; const int FEAT_INTUITIVE_ATTACK = 3166; @@ -1286,6 +1322,7 @@ const int FEAT_SOMATIC_WEAPONRY = 5186; // Forgotten Realms Campaign Setting const int FEAT_INSCRIBE_RUNE = 2462; +const int EPIC_FEAT_INSCRIBE_EPIC_RUNES = 2549; // Miniature Handbook const int FEAT_SHIELDMATE = 3258; @@ -1538,18 +1575,19 @@ const int FEAT_SELVETARMS_BLESSING = 2447; const int FEAT_RANGER_DUAL = 374; const int FEAT_CAMOUFLAGE = 4486; -//Exalted Feat -const int FEAT_SAC_VOW = 3388; -const int FEAT_VOW_OBED = 3389; -const int FEAT_EXALTED_TURNING = 3168; -const int FEAT_HAND_HEALER = 3167; -const int FEAT_NIMBUSLIGHT = 3165; -const int FEAT_HOLYRADIANCE = 3164; -const int FEAT_STIGMATA = 3163; -const int FEAT_SERVHEAVEN = 3355; -const int FEAT_RANGED_SMITE = 3356; -const int FEAT_VOW_PURITY = 5360; -const int FEAT_VOWOFPOVERTY = 26001; +//:: Exalted Feats +const int FEAT_SAC_VOW = 3388; +const int FEAT_VOW_OBED = 3389; +const int FEAT_EXALTED_TURNING = 3168; +const int FEAT_HAND_HEALER = 3167; +const int FEAT_NIMBUSLIGHT = 3165; +const int FEAT_HOLYRADIANCE = 3164; +const int FEAT_STIGMATA = 3163; +const int FEAT_SERVHEAVEN = 3355; +const int FEAT_RANGED_SMITE = 3356; +const int FEAT_VOW_PURITY = 5360; +const int FEAT_VOWOFPOVERTY = 26002; +const int FEAT_FAV_COMPANIONS = 25994; //Vile Feat const int FEAT_LICHLOVED = 3395; @@ -1868,12 +1906,12 @@ const int FEAT_SANCTIFY_MARTIAL_SICKLE = 3169; const int FEAT_SANCTIFY_MARTIAL_MINDBLADE = 3623; const int FEAT_SANCTIFY_MARTIAL_WHIP = 3596; const int FEAT_SANCTIFY_MARTIAL_TRIDENT = 3597; -const int FEAT_SANCTIFYKISTRIKE = 26002; -const int FEAT_HOLYKISTRIKE = 26003; -const int FEAT_FISTOFHEAVENS = 26004; -const int FEAT_VOWABSTINENCE = 26005; -const int FEAT_VOWCHASTITY = 26006; -const int FEAT_GIFTOFFAITH = 26007; +const int FEAT_SANCTIFYKISTRIKE = 26003; +const int FEAT_HOLYKISTRIKE = 26004; +const int FEAT_FISTOFHEAVENS = 26005; +const int FEAT_VOWABSTINENCE = 26006; +const int FEAT_VOWCHASTITY = 26007; +const int FEAT_GIFTOFFAITH = 26008; //heartwarder const int FEAT_CHARISMA_INC1 = 3230; @@ -3189,6 +3227,8 @@ const int FEAT_ETHEREAL = 4167; const int FEAT_TEMPLATE_ARCHLICH_MARKER = 22700; const int FEAT_TEMPLATE_ARCHLICH_TURN_UNDEAD = 22701; +const int FEAT_TEMPLATE_BAELNORN_MARKER = 22708; + const int FEAT_TEMPLATE_CELESTIAL_SMITE_EVIL = 22601; const int FEAT_TEMPLATE_CELESTIAL_MARKER = 22602; const int FEAT_TEMPLATE_FIENDISH_SMITE_GOOD = 22603; @@ -3695,6 +3735,9 @@ const int FEAT_EPIC_ARTIFICER = 4072; //////////////// END INFUSIONS ///////////////// //////////////////////////////////////////////////*/ +//:: Monk +const int FEAT_MONK_ABUNDANT_STEP = 2351; + //Justice of Weald and Woe const int FEAT_LUCKY_SHOT = 24021; @@ -3933,6 +3976,8 @@ const int FEAT_OPPORTUNISTIC_PIETY_HEAL = 5358; const int FEAT_OPPORTUNISTIC_PIETY_TURN = 5359; // Combat Maneuver Feats +const int FEAT_CM_CHARGE = 2823; +const int FEAT_CM_GRAPPLE = 3414; const int FEAT_CURLING_WAVE_STRIKE = 2809; const int FEAT_SIDESTEP_CHARGE = 3505; const int FEAT_POWERFUL_CHARGE = 3506; @@ -6203,6 +6248,38 @@ const int FEAT_SHINING_BLADE_SPELLCASTING_VASSAL = 19587; const int FEAT_SWIFT_WING_SPELLCASTING_VASSAL = 19588; const int FEAT_WARPRIEST_SPELLCASTING_VASSAL = 19589; +//:: Lion of Talisid marker feats +const int FEAT_LION_OF_TALISID_SPELLCASTING_ARCHIVIST = 25601; +const int FEAT_LION_OF_TALISID_SPELLCASTING_CLERIC = 25602; +const int FEAT_LION_OF_TALISID_SPELLCASTING_DRUID = 25603; +const int FEAT_LION_OF_TALISID_SPELLCASTING_FAVOURED_SOUL = 25604; +const int FEAT_LION_OF_TALISID_SPELLCASTING_HEALER = 25605; +const int FEAT_LION_OF_TALISID_SPELLCASTING_JOWAW = 25606; +const int FEAT_LION_OF_TALISID_SPELLCASTING_KOTMC = 25607; +const int FEAT_LION_OF_TALISID_SPELLCASTING_NENTYAR_HUNTER = 25608; +const int FEAT_LION_OF_TALISID_SPELLCASTING_RANGER = 25609; +const int FEAT_LION_OF_TALISID_SPELLCASTING_OASHAMAN = 25610; +const int FEAT_LION_OF_TALISID_SPELLCASTING_SOHEI = 25611; +const int FEAT_LION_OF_TALISID_SPELLCASTING_SOL = 25612; +const int FEAT_LION_OF_TALISID_SPELLCASTING_SPSHAMAN = 25613; + +//:: Verdant Lord marker feats +const int FEAT_VERDANT_LORD_SPELLCASTING_ARCHIVIST = 25619; +const int FEAT_VERDANT_LORD_SPELLCASTING_CLERIC = 25620; +const int FEAT_VERDANT_LORD_SPELLCASTING_DRUID = 25621; +const int FEAT_VERDANT_LORD_SPELLCASTING_FAVOURED_SOUL = 25622; +const int FEAT_VERDANT_LORD_SPELLCASTING_HEALER = 25623; +const int FEAT_VERDANT_LORD_SPELLCASTING_JOWAW = 25624; +const int FEAT_VERDANT_LORD_SPELLCASTING_KOTC = 25625; +const int FEAT_VERDANT_LORD_SPELLCASTING_KOTMC = 25626; +const int FEAT_VERDANT_LORD_SPELLCASTING_NENTYAR_HUNTER = 25627; +const int FEAT_VERDANT_LORD_SPELLCASTING_PALADIN = 25628; +const int FEAT_VERDANT_LORD_SPELLCASTING_RANGER = 25629; +const int FEAT_VERDANT_LORD_SPELLCASTING_OASHAMAN = 25630; +const int FEAT_VERDANT_LORD_SPELLCASTING_SOHEI = 25631; +const int FEAT_VERDANT_LORD_SPELLCASTING_SOL = 25632; +const int FEAT_VERDANT_LORD_SPELLCASTING_SPSHAMAN = 25633; + //:: No spellcasting or invoking marker feats const int FEAT_ASMODEUS_SPELLCASTING_NONE = 19590; const int FEAT_TIAMAT_SPELLCASTING_NONE = 19591; @@ -6210,6 +6287,7 @@ const int FEAT_DSONG_SPELLCASTING_NONE = 19592; const int FEAT_OLLAM_SPELLCASTING_NONE = 19593; //:: PRC8 Hidden Talent Feats +const int FEAT_HIDDEN_TALENT = 25900; const int FEAT_HIDDEN_TALENT_BIOFEEDBACK = 25901; const int FEAT_HIDDEN_TALENT_BITE_WOLF = 25902; const int FEAT_HIDDEN_TALENT_BOLT = 25903; diff --git a/src/include/prc_getbest_inc.nss b/src/include/prc_getbest_inc.nss index a17eb0a..a0efeca 100644 --- a/src/include/prc_getbest_inc.nss +++ b/src/include/prc_getbest_inc.nss @@ -400,5 +400,4 @@ int GetBestAvailableSpell(object oTarget) if(nBestSpell == 99999) nBestSpell = GetBestL1Spell(oTarget, nBestSpell); if(nBestSpell == 99999) nBestSpell = GetBestL0Spell(oTarget, nBestSpell); return nBestSpell; -} - +} \ No newline at end of file diff --git a/src/include/prc_inc_breath.nss b/src/include/prc_inc_breath.nss index 0d439f9..094029c 100644 --- a/src/include/prc_inc_breath.nss +++ b/src/include/prc_inc_breath.nss @@ -124,6 +124,8 @@ void ApplyBreath(struct breath BreathUsed, location lTargetArea, int bLinger = F ////////////////////////////////////////////////// #include "prc_alterations" +#include "prcsp_archmaginc" +#include "prc_inc_spells" ////////////////////////////////////////////////// /* Internal functions */ diff --git a/src/include/prc_inc_castlvl.nss b/src/include/prc_inc_castlvl.nss index 876ac84..0c1a8be 100644 --- a/src/include/prc_inc_castlvl.nss +++ b/src/include/prc_inc_castlvl.nss @@ -575,8 +575,8 @@ int PRCGetCasterLevel(object oCaster = OBJECT_SELF) iReturnLevel = GetLevelByClass(CLASS_TYPE_SHAPECHANGER); } - // Casting as a bard but don't have any levels in the class - if(iCastingClass == CLASS_TYPE_BARD && !GetLevelByClass(CLASS_TYPE_BARD, oCaster)) + // Casting as a bard but don't have any levels in the class //:: Double-dipping? +/* if(iCastingClass == CLASS_TYPE_BARD && !GetLevelByClass(CLASS_TYPE_BARD, oCaster)) { int nRace = GetRacialType(oCaster); @@ -584,7 +584,7 @@ int PRCGetCasterLevel(object oCaster = OBJECT_SELF) //otherwise use RHD instead of bard levels if(nRace == RACIAL_TYPE_GLOURA) iReturnLevel = GetLevelByClass(CLASS_TYPE_FEY); - } + } */ //Spell Rage ability if(GetHasSpellEffect(SPELL_SPELL_RAGE, oCaster) @@ -960,8 +960,10 @@ int GetArcanePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) } //:: End Bard Arcane PrC casting calculations - if(nCastingClass == CLASS_TYPE_BARD && nRace == RACIAL_TYPE_GLOURA && !GetLevelByClass(CLASS_TYPE_BARD, oCaster)) + if(nCastingClass == CLASS_TYPE_BARD || nCastingClass == CLASS_TYPE_BARD && nRace == RACIAL_TYPE_GLOURA && !GetLevelByClass(CLASS_TYPE_BARD, oCaster)) { + if(DEBUG) DoDebug("prc_inc_castlvl >> Found Fey RHD caster (not bard)"); + if(GetHasFeat(FEAT_ABCHAMP_SPELLCASTING_FEY, oCaster)) nArcane += GetLevelByClass(CLASS_TYPE_ABJURANT_CHAMPION, oCaster); @@ -1065,7 +1067,10 @@ int GetArcanePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nArcane += GetLevelByClass(CLASS_TYPE_UNSEEN_SEER, oCaster); if(GetHasFeat(FEAT_VIRTUOSO_SPELLCASTING_FEY, oCaster)) + { nArcane += GetLevelByClass(CLASS_TYPE_VIRTUOSO, oCaster); + if(DEBUG) DoDebug("prc_inc_castlvl >> Found Fey + Virtuoso PrC. Arcane caster level is "+IntToString(nArcane)+"."); + } if(GetHasFeat(FEAT_WWOC_SPELLCASTING_FEY, oCaster)) nArcane += GetLevelByClass(CLASS_TYPE_WAR_WIZARD_OF_CORMYR, oCaster); @@ -1143,8 +1148,8 @@ int GetArcanePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_DIABOLIST_SPELLCASTING_ASSASSIN, oCaster)) nArcane += GetLevelByClass(CLASS_TYPE_DIABOLIST, oCaster); - if(GetHasFeat(FEAT_DHEART_SPELLCASTING_ASSASSIN, oCaster)) - nArcane += GetLevelByClass(CLASS_TYPE_DRAGONHEART_MAGE, oCaster); + //if(GetHasFeat(FEAT_DHEART_SPELLCASTING_ASSASSIN, oCaster)) + //nArcane += GetLevelByClass(CLASS_TYPE_DRAGONHEART_MAGE, oCaster); if(GetHasFeat(FEAT_EKNIGHT_SPELLCASTING_ASSASSIN, oCaster)) nArcane += GetLevelByClass(CLASS_TYPE_ELDRITCH_KNIGHT, oCaster); @@ -3817,6 +3822,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_ARCHIVIST, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_ARCHIVIST, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); + /* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_ARCHIVIST, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */ @@ -3851,7 +3859,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_SWIFT_WING, oCaster); if(GetHasFeat(FEAT_TENEBROUS_APOSTATE_SPELLCASTING_ARCHIVIST, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oCaster); + + if(GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_ARCHIVIST, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_VERDANT_LORD, oCaster); if(GetHasFeat(FEAT_BFZ_SPELLCASTING_ARCHIVIST, oCaster)) nDivine += (GetLevelByClass(CLASS_TYPE_BFZ, oCaster) + 1) / 2; @@ -4143,7 +4154,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster); if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_CLERIC, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_CLERIC, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_CLERIC, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); @@ -4182,7 +4196,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_SWIFT_WING, oCaster); if(GetHasFeat(FEAT_TENEBROUS_APOSTATE_SPELLCASTING_CLERIC, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oCaster); + + if(GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_CLERIC, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_VERDANT_LORD, oCaster); if(GetHasFeat(FEAT_BFZ_SPELLCASTING_CLERIC, oCaster)) nDivine += (GetLevelByClass(CLASS_TYPE_BFZ, oCaster) + 1) / 2; @@ -4253,7 +4270,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster); if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_DRUID, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_DRUID, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); // if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_DRUID, oCaster)) // nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); @@ -4295,9 +4315,12 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_SWIFT_WING, oCaster); /* if(GetHasFeat(FEAT_TENEBROUS_APOSTATE_SPELLCASTING_DRUID, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oCaster); */ + + if(GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_DRUID, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_VERDANT_LORD, oCaster); - if(GetHasFeat(FEAT_BFZ_SPELLCASTING_DRUID, oCaster)) +/* if(GetHasFeat(FEAT_BFZ_SPELLCASTING_DRUID, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_BFZ, oCaster + 1) / 2 */ // if(GetHasFeat(FEAT_BRIMSTONE_SPEAKER_SPELLCASTING_DRUID, oCaster)) @@ -4365,10 +4388,13 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster); if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_FAVOURED_SOUL, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_FAVOURED_SOUL, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); - // if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_FAVOURED_SOUL, oCaster)) - // nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); + if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_FAVOURED_SOUL, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); if(GetHasFeat(FEAT_MORNINGLORD_SPELLCASTING_FAVOURED_SOUL, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MORNINGLORD, oCaster); @@ -4404,7 +4430,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_SWIFT_WING, oCaster); if(GetHasFeat(FEAT_TENEBROUS_APOSTATE_SPELLCASTING_FAVOURED_SOUL, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oCaster); + + if(GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_FAVOURED_SOUL, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_VERDANT_LORD, oCaster); if(GetHasFeat(FEAT_BFZ_SPELLCASTING_FAVOURED_SOUL, oCaster)) nDivine += (GetLevelByClass(CLASS_TYPE_BFZ, oCaster) + 1) / 2; @@ -4474,6 +4503,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_HEALER, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_HEALER, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); + /* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_HEALER, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */ @@ -4514,7 +4546,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oCaster); */ /* if(GetHasFeat(FEAT_BFZ_SPELLCASTING_HEALER, oCaster)) - nDivine += (GetLevelByClass(CLASS_TYPE_BFZ, oCaster) + 1) / 2; */ + nDivine += (GetLevelByClass(CLASS_TYPE_BFZ, oCaster) + 1) / 2; */ + + if(GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_HEALER, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_VERDANT_LORD, oCaster); if(GetHasFeat(FEAT_BRIMSTONE_SPEAKER_SPELLCASTING_HEALER, oCaster)) nDivine += (GetLevelByClass(CLASS_TYPE_BRIMSTONE_SPEAKER, oCaster) + 1) / 2; @@ -4581,6 +4616,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_JUSTICEWW, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_JOWAW, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); + // if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_JUSTICEWW, oCaster)) // nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); @@ -4618,7 +4656,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_SWIFT_WING, oCaster); if(GetHasFeat(FEAT_TENEBROUS_APOSTATE_SPELLCASTING_JUSTICEWW, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oCaster); + + if(GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_JOWAW, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_VERDANT_LORD, oCaster); if(GetHasFeat(FEAT_BFZ_SPELLCASTING_JUSTICEWW, oCaster)) nDivine += (GetLevelByClass(CLASS_TYPE_BFZ, oCaster) + 1) / 2; @@ -4719,6 +4760,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_SWIFT_WING_SPELLCASTING_KNIGHT_CHALICE, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_SWIFT_WING, oCaster); + + if(GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_KOTC, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_VERDANT_LORD, oCaster); /* if(GetHasFeat(FEAT_TENEBROUS_APOSTATE_SPELLCASTING_KNIGHT_CHALICE, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oCaster); @@ -4791,6 +4835,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_KNIGHT_MIDDLECIRCLE, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_KOTMC, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); + /* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_KNIGHT_MIDDLECIRCLE, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */ @@ -4823,6 +4870,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_SWIFT_WING_SPELLCASTING_KNIGHT_MIDDLECIRCLE, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_SWIFT_WING, oCaster); + + if(GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_KOTMC, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_VERDANT_LORD, oCaster); /* if(GetHasFeat(FEAT_TENEBROUS_APOSTATE_SPELLCASTING_KNIGHT_MIDDLECIRCLE, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oCaster); @@ -4896,7 +4946,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster); */ if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_NENTYAR_HUNTER, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_NENTYAR_HUNTER, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); /* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_NENTYAR_HUNTER, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */ @@ -4933,6 +4986,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_SWIFT_WING_SPELLCASTING_NENTYAR_HUNTER, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_SWIFT_WING, oCaster); + + if(GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_NENTYAR_HUNTER, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_VERDANT_LORD, oCaster); /* if(GetHasFeat(FEAT_TENEBROUS_APOSTATE_SPELLCASTING_NENTYAR_HUNTER, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oCaster); */ @@ -5135,6 +5191,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_SWIFT_WING_SPELLCASTING_PALADIN, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_SWIFT_WING, oCaster); + + if(GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_PALADIN, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_VERDANT_LORD, oCaster); /* if(GetHasFeat(FEAT_TENEBROUS_APOSTATE_SPELLCASTING_PALADIN, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oCaster); @@ -5207,7 +5266,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster); */ if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_RANGER, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_RANGER, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); if(GetHasFeat(FEAT_MORNINGLORD_SPELLCASTING_RANGER, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MORNINGLORD, oCaster); @@ -5240,7 +5302,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_SWIFT_WING, oCaster); if(GetHasFeat(FEAT_TENEBROUS_APOSTATE_SPELLCASTING_RANGER, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oCaster); + + if(GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_RANGER, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_VERDANT_LORD, oCaster); if(GetHasFeat(FEAT_BFZ_SPELLCASTING_RANGER, oCaster)) nDivine += (GetLevelByClass(CLASS_TYPE_BFZ, oCaster) + 1) / 2; @@ -5311,7 +5376,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster); if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_OASHAMAN, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_OASHAMAN, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_SHAMAN, oCaster); if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_OASHAMAN, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); @@ -5350,7 +5418,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_SWIFT_WING, oCaster); if(GetHasFeat(FEAT_TENEBROUS_APOSTATE_SPELLCASTING_OASHAMAN, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oCaster); + + if(GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_OASHAMAN, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_VERDANT_LORD, oCaster); if(GetHasFeat(FEAT_BFZ_SPELLCASTING_OASHAMAN, oCaster)) nDivine += (GetLevelByClass(CLASS_TYPE_BFZ, oCaster) + 1) / 2; @@ -5524,6 +5595,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_SOHEI, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_SOHEI, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); + // if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_SOHEI, oCaster)) // nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); @@ -5561,7 +5635,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_SWIFT_WING, oCaster); if(GetHasFeat(FEAT_TENEBROUS_APOSTATE_SPELLCASTING_SOHEI, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oCaster); + + if(GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_SOHEI, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_VERDANT_LORD, oCaster); if(GetHasFeat(FEAT_BFZ_SPELLCASTING_SOHEI, oCaster)) nDivine += (GetLevelByClass(CLASS_TYPE_BFZ, oCaster) + 1) / 2; @@ -5631,6 +5708,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_SOL, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_SOL, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); + /* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_SOL, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */ @@ -5663,6 +5743,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_SWIFT_WING_SPELLCASTING_SOL, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_SWIFT_WING, oCaster); + + if(GetHasFeat(FEAT_VERDANT_LORD_SPELLCASTING_SOL, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_VERDANT_LORD, oCaster); /* if(GetHasFeat(FEAT_TENEBROUS_APOSTATE_SPELLCASTING_SOL, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oCaster); diff --git a/src/include/prc_inc_chat_pow.nss b/src/include/prc_inc_chat_pow.nss index aced79a..f1c1b64 100644 --- a/src/include/prc_inc_chat_pow.nss +++ b/src/include/prc_inc_chat_pow.nss @@ -16,6 +16,7 @@ Command summary: */ #include "prc_inc_chat" +#include "inc_persist_loca" const string CMD_POWER_ATTACK = "pow-erattack"; diff --git a/src/include/prc_inc_clsfunc.nss b/src/include/prc_inc_clsfunc.nss index 3a6c251..9bd42ed 100644 --- a/src/include/prc_inc_clsfunc.nss +++ b/src/include/prc_inc_clsfunc.nss @@ -380,6 +380,7 @@ int Vile_Feat(int iTypeWeap) case BASE_ITEM_BASTARDSWORD: return GetHasFeat(FEAT_VILE_MARTIAL_BASTARDSWORD); case BASE_ITEM_BATTLEAXE: return GetHasFeat(FEAT_VILE_MARTIAL_BATTLEAXE); case BASE_ITEM_CLUB: return GetHasFeat(FEAT_VILE_MARTIAL_CLUB); + case BASE_ITEM_CRAFTED_SCEPTER: return GetHasFeat(FEAT_VILE_MARTIAL_CLUB); case BASE_ITEM_DAGGER: return GetHasFeat(FEAT_VILE_MARTIAL_DAGGER); case BASE_ITEM_DART: return GetHasFeat(FEAT_VILE_MARTIAL_DART); case BASE_ITEM_DIREMACE: return GetHasFeat(FEAT_VILE_MARTIAL_DIREMACE); @@ -402,6 +403,7 @@ int Vile_Feat(int iTypeWeap) case BASE_ITEM_LONGSWORD: return GetHasFeat(FEAT_VILE_MARTIAL_LONGSWORD); case BASE_ITEM_MORNINGSTAR: return GetHasFeat(FEAT_VILE_MARTIAL_MORNINGSTAR); case BASE_ITEM_QUARTERSTAFF: return GetHasFeat(FEAT_VILE_MARTIAL_QUARTERSTAFF); + case BASE_ITEM_MAGICSTAFF: return GetHasFeat(FEAT_VILE_MARTIAL_QUARTERSTAFF); case BASE_ITEM_RAPIER: return GetHasFeat(FEAT_VILE_MARTIAL_RAPIER); case BASE_ITEM_SCIMITAR: return GetHasFeat(FEAT_VILE_MARTIAL_SCIMITAR); case BASE_ITEM_SCYTHE: return GetHasFeat(FEAT_VILE_MARTIAL_SCYTHE); @@ -425,7 +427,7 @@ int Vile_Feat(int iTypeWeap) GetHasFeat(FEAT_VILE_MARTIAL_RAPIER) || GetHasFeat(FEAT_VILE_MARTIAL_ELVEN_THINBLADE)); - case BASE_ITEM_ELVEN_COURTBLADE: return GetHasFeat(FEAT_VILE_MARTIAL_GREATSWORD || + case BASE_ITEM_ELVEN_COURTBLADE: return (GetHasFeat(FEAT_VILE_MARTIAL_GREATSWORD) || GetHasFeat(FEAT_VILE_MARTIAL_ELVEN_COURTBLADE)); case BASE_ITEM_DOUBLE_SCIMITAR: return GetHasFeat(FEAT_VILE_MARTIAL_DBL_SCIMITAR); @@ -460,6 +462,7 @@ int GetSanctifedMartialFeat(int iTypeWeap) case BASE_ITEM_BASTARDSWORD: return FEAT_SANCTIFY_MARTIAL_BASTARDSWORD; case BASE_ITEM_BATTLEAXE: return FEAT_SANCTIFY_MARTIAL_BATTLEAXE; case BASE_ITEM_CLUB: return FEAT_SANCTIFY_MARTIAL_CLUB; + case BASE_ITEM_CRAFTED_SCEPTER: return FEAT_SANCTIFY_MARTIAL_CLUB; case BASE_ITEM_DAGGER: return FEAT_SANCTIFY_MARTIAL_DAGGER; case BASE_ITEM_DART: return FEAT_SANCTIFY_MARTIAL_DART; case BASE_ITEM_DIREMACE: return FEAT_SANCTIFY_MARTIAL_DIREMACE; @@ -482,6 +485,7 @@ int GetSanctifedMartialFeat(int iTypeWeap) case BASE_ITEM_LONGSWORD: return FEAT_SANCTIFY_MARTIAL_LONGSWORD; case BASE_ITEM_MORNINGSTAR: return FEAT_SANCTIFY_MARTIAL_MORNINGSTAR; case BASE_ITEM_QUARTERSTAFF: return FEAT_SANCTIFY_MARTIAL_QUARTERSTAFF; + case BASE_ITEM_MAGICSTAFF: return FEAT_SANCTIFY_MARTIAL_QUARTERSTAFF; case BASE_ITEM_RAPIER: return FEAT_SANCTIFY_MARTIAL_RAPIER; case BASE_ITEM_SCIMITAR: return FEAT_SANCTIFY_MARTIAL_SCIMITAR; case BASE_ITEM_SCYTHE: return FEAT_SANCTIFY_MARTIAL_SCYTHE; @@ -533,6 +537,7 @@ int Sanctify_Feat(int iTypeWeap) case BASE_ITEM_BASTARDSWORD: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_BASTARDSWORD); case BASE_ITEM_BATTLEAXE: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_BATTLEAXE); case BASE_ITEM_CLUB: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_CLUB); + case BASE_ITEM_CRAFTED_SCEPTER: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_CLUB); case BASE_ITEM_DAGGER: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_DAGGER); case BASE_ITEM_DART: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_DART); case BASE_ITEM_DIREMACE: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_DIREMACE); @@ -555,6 +560,7 @@ int Sanctify_Feat(int iTypeWeap) case BASE_ITEM_LONGSWORD: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_LONGSWORD); case BASE_ITEM_MORNINGSTAR: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_MORNINGSTAR); case BASE_ITEM_QUARTERSTAFF: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_QUARTERSTAFF); + case BASE_ITEM_MAGICSTAFF: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_QUARTERSTAFF); case BASE_ITEM_RAPIER: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_RAPIER); case BASE_ITEM_SCIMITAR: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_SCIMITAR); case BASE_ITEM_SCYTHE: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_SCYTHE); diff --git a/src/include/prc_inc_combat.nss b/src/include/prc_inc_combat.nss index f5a2411..6b143b5 100644 --- a/src/include/prc_inc_combat.nss +++ b/src/include/prc_inc_combat.nss @@ -1082,6 +1082,7 @@ int GetIsTwoHandedMeleeWeaponType(int iWeaponType) case BASE_ITEM_HEAVYFLAIL: return TRUE; case BASE_ITEM_SCYTHE: return TRUE; case BASE_ITEM_QUARTERSTAFF: return TRUE; + //case BASE_ITEM_MAGICSTAFF: return TRUE; case BASE_ITEM_ELVEN_COURTBLADE: return TRUE; case BASE_ITEM_MAUL: return TRUE; case BASE_ITEM_FALCHION: return TRUE; @@ -1093,7 +1094,7 @@ int GetIsTwoHandedMeleeWeapon(object oWeap) { return GetIsTwoHandedMeleeWeaponType(GetBaseItemType(oWeap)); } - + int GetIsCreatureWeaponType(int iWeaponType) { // any of the three creature weapon types that produce bludgeoning, piercing or slashing damage @@ -1130,6 +1131,7 @@ int GetIsSimpleWeaponType(int iWeaponType) { case BASE_ITEM_MORNINGSTAR: return 1; case BASE_ITEM_QUARTERSTAFF: return 1; + case BASE_ITEM_MAGICSTAFF: return 1; case BASE_ITEM_SHORTSPEAR: return 1; case BASE_ITEM_HEAVYCROSSBOW: return 1; case BASE_ITEM_INVALID: return 1; @@ -1139,8 +1141,8 @@ int GetIsSimpleWeaponType(int iWeaponType) case BASE_ITEM_CSLSHPRCWEAP: return 1; case BASE_ITEM_GLOVES: return 1; case BASE_ITEM_BRACER: return 1; - - case BASE_ITEM_CLUB: return 2; + case BASE_ITEM_CRAFTED_SCEPTER: return 1; + case BASE_ITEM_DAGGER: return 2; case BASE_ITEM_LIGHTMACE: return 2; case BASE_ITEM_SICKLE: return 2; @@ -1204,6 +1206,7 @@ int GetIsDoubleSidedWeaponType(int iWeaponType) return ( iWeaponType == BASE_ITEM_DIREMACE || iWeaponType == BASE_ITEM_DOUBLEAXE || iWeaponType == BASE_ITEM_TWOBLADEDSWORD + || iWeaponType == BASE_ITEM_DOUBLE_SCIMITAR ); } @@ -1276,6 +1279,19 @@ struct WeaponFeat GetAllFeatsOfWeaponType(int iWeaponType) sFeat.VileMartialStrike = FEAT_VILE_MARTIAL_CLUB; break; } + case BASE_ITEM_CRAFTED_SCEPTER: { + sFeat.Focus = FEAT_WEAPON_FOCUS_CLUB; + sFeat.Specialization = FEAT_WEAPON_SPECIALIZATION_CLUB; + sFeat.EpicFocus = FEAT_EPIC_WEAPON_FOCUS_CLUB; + sFeat.EpicSpecialization = FEAT_EPIC_WEAPON_SPECIALIZATION_CLUB; + sFeat.ImprovedCritical = FEAT_IMPROVED_CRITICAL_CLUB; + sFeat.OverwhelmingCritical = FEAT_EPIC_OVERWHELMING_CRITICAL_CLUB; + sFeat.DevastatingCritical = FEAT_EPIC_DEVASTATING_CRITICAL_CLUB; + sFeat.WeaponOfChoice = FEAT_WEAPON_OF_CHOICE_CLUB; + sFeat.SanctifyMartialStrike = FEAT_SANCTIFY_MARTIAL_CLUB; + sFeat.VileMartialStrike = FEAT_VILE_MARTIAL_CLUB; + break; + } case BASE_ITEM_DAGGER: { sFeat.Focus = FEAT_WEAPON_FOCUS_DAGGER; sFeat.Specialization = FEAT_WEAPON_SPECIALIZATION_DAGGER; @@ -1562,6 +1578,19 @@ struct WeaponFeat GetAllFeatsOfWeaponType(int iWeaponType) sFeat.VileMartialStrike = FEAT_VILE_MARTIAL_QUARTERSTAFF; break; } + case BASE_ITEM_MAGICSTAFF: { + sFeat.Focus = FEAT_WEAPON_FOCUS_STAFF; + sFeat.Specialization = FEAT_WEAPON_SPECIALIZATION_STAFF; + sFeat.EpicFocus = FEAT_EPIC_WEAPON_FOCUS_QUARTERSTAFF; + sFeat.EpicSpecialization = FEAT_EPIC_WEAPON_SPECIALIZATION_QUARTERSTAFF; + sFeat.ImprovedCritical = FEAT_IMPROVED_CRITICAL_STAFF; + sFeat.OverwhelmingCritical = FEAT_EPIC_OVERWHELMING_CRITICAL_QUARTERSTAFF; + sFeat.DevastatingCritical = FEAT_EPIC_DEVASTATING_CRITICAL_QUARTERSTAFF; + sFeat.WeaponOfChoice = FEAT_WEAPON_OF_CHOICE_QUARTERSTAFF; + sFeat.SanctifyMartialStrike = FEAT_SANCTIFY_MARTIAL_QUARTERSTAFF; + sFeat.VileMartialStrike = FEAT_VILE_MARTIAL_QUARTERSTAFF; + break; + } case BASE_ITEM_RAPIER: { sFeat.Focus = FEAT_WEAPON_FOCUS_RAPIER; sFeat.Specialization = FEAT_WEAPON_SPECIALIZATION_RAPIER; @@ -8074,7 +8103,12 @@ void AttackLoopLogic(object oDefender, object oAttacker, if (DEBUG) DoDebug("entered AttackLoopLogic: bFirstAttack = " + IntToString(bFirstAttack) + ", cleave = " + IntToString(bIsCleaveAttack) + ", current action = " + GetActionName(iAction)); if (DEBUG) DoDebug("AttackLoopLogic: iMainAttacks = " + IntToString(iMainAttacks) + ", iOffHandAttacks = " + IntToString(iOffHandAttacks) + ", iBonusAttacks = " + IntToString(iBonusAttacks)); - int bIsRangedAttack = sAttackVars.bIsRangedWeapon || sAttackVars.iTouchAttackType == TOUCH_ATTACK_RANGED_SPELL || sAttackVars.iTouchAttackType == TOUCH_ATTACK_RANGED; + //int bIsRangedAttack = sAttackVars.bIsRangedWeapon || sAttackVars.iTouchAttackType == TOUCH_ATTACK_RANGED_SPELL || sAttackVars.iTouchAttackType == TOUCH_ATTACK_RANGED; + + int bIsRangedAttack = sAttackVars.bIsRangedWeapon || + sAttackVars.iTouchAttackType == TOUCH_ATTACK_RANGED_SPELL || + sAttackVars.iTouchAttackType == TOUCH_ATTACK_RANGED || + GetLocalInt(oAttacker, "WhirlingBlade"); // check for valid target etc., but only if it is not a cleave or circle kick (in this case we checked all of this before) if (!bIsCleaveAttack) diff --git a/src/include/prc_inc_combmove.nss b/src/include/prc_inc_combmove.nss index b81aab4..180925b 100644 --- a/src/include/prc_inc_combmove.nss +++ b/src/include/prc_inc_combmove.nss @@ -273,6 +273,7 @@ void TigerBlooded(object oInitiator, object oTarget); #include "prc_inc_combat" #include "prc_inc_sp_tch" +#include "prc_feat_const" ////////////////////////////////////////////////// /* Internal functions */ @@ -1140,6 +1141,9 @@ void DoCharge(object oPC, object oTarget, int nDoAttack = TRUE, int nGenerateAoO nPounce = TRUE; if (GetHasSpellEffect(VESTIGE_CHUPOCLOPS, oPC) && GetLocalInt(oPC, "ExploitVestige") != VESTIGE_CHUPOCLOPS_POUNCE) nPounce = TRUE; + //:: Lion of Talisid + if(GetHasFeat(FEAT_LOT_LIONS_POUNCE, oPC)) + nPounce = TRUE; // Checks for a White Raven Stance // If it exists, +1 damage/initiator level @@ -1318,7 +1322,29 @@ int DoTrip(object oPC, object oTarget, int nExtraBonus, int nGenerateAoO = TRUE, DelayCommand(0.0, PerformAttack(oTarget, oPC, eNone, 0.0, 0, 0, 0, "Improved Trip Free Attack Hit", "Improved Trip Free Attack Miss")); } } - else // If you fail, enemy gets a counter trip attempt, using Strength + else // If you fail, enemy gets a counter trip attempt, using Strength + { + if(!nCounterTrip) + { + nTargetStat = GetAbilityModifier(ABILITY_STRENGTH, oTarget) + GetCombatMoveCheckBonus(oTarget, COMBAT_MOVE_TRIP, FALSE, TRUE); + FloatingTextStringOnCreature("You have failed on your Trip attempt",oPC, FALSE); + // Roll counter trip attempt + nTargetCheck = nTargetStat + nTargetBonus + d20(); + nPCCheck = nPCStat + nPCBonus + d20(); + // If counters aren't allowed, don't knock em down + // Its down here to allow the text message to go through + SendMessageToPC(oPC, "Enemy Counter Trip Check: "+IntToString(nPCCheck)+" vs "+IntToString(nTargetCheck)); + + SetLocalInt(oPC, "TripDifference", nTargetCheck - nPCCheck); + DelayCommand(2.0, DeleteLocalInt(oPC, "TripDifference")); + } + if (nTargetCheck >= nPCCheck && nCounterTrip) + { + // Knock em down + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectKnockdown()), oPC, 6.0); + } + } +/* else // If you fail, enemy gets a counter trip attempt, using Strength { nTargetStat = GetAbilityModifier(ABILITY_STRENGTH, oTarget) + GetCombatMoveCheckBonus(oTarget, COMBAT_MOVE_TRIP, FALSE, TRUE); FloatingTextStringOnCreature("You have failed on your Trip attempt",oPC, FALSE); @@ -1335,7 +1361,7 @@ int DoTrip(object oPC, object oTarget, int nExtraBonus, int nGenerateAoO = TRUE, } SetLocalInt(oPC, "TripDifference", nTargetCheck - nPCCheck); DelayCommand(2.0, DeleteLocalInt(oPC, "TripDifference")); - } + } */ } else FloatingTextStringOnCreature("You have failed on your Trip attempt",oPC, FALSE); @@ -1938,10 +1964,21 @@ void TigerBlooded(object oInitiator, object oTarget) int DoDisarm(object oPC, object oTarget, int nExtraBonus = 0, int nGenerateAoO = TRUE, int nCounter = TRUE) { object oTargetWep = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget); + + int bNoDisarm = GetHasFeat(FEAT_INTRINSIC_WEAPON, oTarget); + + string sName = GetName(oTarget); + + if(bNoDisarm) + { + FloatingTextStringOnCreature(sName+" is wielding an intrinsic weapon", oPC, FALSE); + AssignCommand(oPC, ActionAttack(oTarget)); + return FALSE; + } if (!GetIsObjectValid(oTargetWep) || GetPlotFlag(oTargetWep) || (!GetIsCreatureDisarmable(oTarget) && !GetPRCSwitch(PRC_PNP_DISARM)) || GetLocalInt(oTarget, "TigerFangDisarm")) { - FloatingTextStringOnCreature("Target is not a legal target", oPC, FALSE); + FloatingTextStringOnCreature(sName+" is not a legal target", oPC, FALSE); AssignCommand(oPC, ActionAttack(oTarget)); return FALSE; } @@ -2312,7 +2349,10 @@ void DoShieldCharge(object oPC, object oTarget, int nSlam = FALSE) if(GetLevelByClass(CLASS_TYPE_CELEBRANT_SHARESS, oPC) >= 5) nPounce = TRUE; if(GetRacialType(oPC) == RACIAL_TYPE_MARRUSAULT) - nPounce = TRUE; + nPounce = TRUE; + //:: Lion of Talisid + if(GetHasFeat(FEAT_LOT_LIONS_POUNCE, oPC)) + nPounce = TRUE; // Checks for a White Raven Stance // If it exists, +1 damage/initiator level diff --git a/src/include/prc_inc_core.nss b/src/include/prc_inc_core.nss index 30af518..df73451 100644 --- a/src/include/prc_inc_core.nss +++ b/src/include/prc_inc_core.nss @@ -133,6 +133,7 @@ const int METAMAGIC_QUICKEN_LEVEL = 4; #include "prc_inc_damage" #include "prc_inc_sb_const" // Spell Book Constants #include "x0_i0_position" +#include "inc_newspellbook" /* access to prc_inc_nwscript via prc_inc_damage @@ -410,6 +411,8 @@ int PRCGetSpellLevelForClass(int nSpell, int nClass) sSpellLevel = Get2DACache("spells", "Cleric", nSpell); else if (nClass == CLASS_TYPE_BARD) sSpellLevel = Get2DACache("spells", "Bard", nSpell); + else if (nClass == CLASS_TYPE_ASSASSIN) + sSpellLevel = Get2DACache("spells", "Assassin", nSpell); else if (nClass == CLASS_TYPE_CULTIST_SHATTERED_PEAK) sSpellLevel = Get2DACache("spells", "Cultist", nSpell); else if (nClass == CLASS_TYPE_NENTYAR_HUNTER) @@ -462,7 +465,7 @@ int PRCGetSpellLevelForClass(int nSpell, int nClass) return nSpellLevel; } -// returns the spelllevel of nSpell as it can be cast by oCreature +// returns the spell circle level of nSpell as it can be cast by oCreature int PRCGetSpellLevel(object oCreature, int nSpell) { /*if (!PRCGetHasSpell(nSpell, oCreature)) @@ -605,7 +608,7 @@ int PRCGetHasSpell(int nRealSpellID, object oCreature = OBJECT_SELF) if(nSpellbookType == SPELLBOOK_TYPE_PREPARED) { nCount = persistant_array_get_int(oCreature, "NewSpellbookMem_" + IntToString(nClass), j); - if(DEBUG) DoDebug("PRCGetHasSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(j) + "] = " + IntToString(nCount)); + if(DEBUG) DoDebug("prc_inc_core >> PRCGetHasSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(j) + "] = " + IntToString(nCount)); if(nCount > 0) { nUses += nCount; @@ -615,7 +618,7 @@ int PRCGetHasSpell(int nRealSpellID, object oCreature = OBJECT_SELF) { nSpellLevel = StringToInt(Get2DACache(sFile, "Level", j)); nCount = persistant_array_get_int(oCreature, "NewSpellbookMem_" + IntToString(nClass), nSpellLevel); - if(DEBUG) DoDebug("PRCGetHasSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(j) + "] = " + IntToString(nCount)); + if(DEBUG) DoDebug("prc_inc_core >> PRCGetHasSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(j) + "] = " + IntToString(nCount)); if(nCount > 0) { nUses += nCount; diff --git a/src/include/prc_inc_descrptr.nss b/src/include/prc_inc_descrptr.nss index bbee255..d814a6c 100644 --- a/src/include/prc_inc_descrptr.nss +++ b/src/include/prc_inc_descrptr.nss @@ -169,8 +169,8 @@ int GetSubschoolFlags(int nSpellID); /* Includes */ ////////////////////////////////////////////////// -#include "inc_2dacache" // already has access via inc_utility -//#include "inc_utility" +#include "inc_2dacache" +#include "inc_utility" ////////////////////////////////////////////////// /* Function definitions */ diff --git a/src/include/prc_inc_factotum.nss b/src/include/prc_inc_factotum.nss index 46be9c4..eee86b1 100644 --- a/src/include/prc_inc_factotum.nss +++ b/src/include/prc_inc_factotum.nss @@ -49,6 +49,8 @@ const int BRILLIANCE_SLOT_3 = 3919; ////////////////////////////////////////////////// /* Function definitions */ ////////////////////////////////////////////////// +void TriggerInspiration(object oPC, int nCombat); + void PrepareArcDilSpell(object oPC, int nSpell) { @@ -188,7 +190,8 @@ void SetInspiration(object oPC) for(i = FEAT_FONT_INSPIRATION_1; i <= FEAT_FONT_INSPIRATION_10; i++) if(GetHasFeat(i, oPC)) nFont++; - nInspiration += nFont * (1 + nFont + 1) / 2; + //nInspiration += nFont * (1 + nFont + 1) / 2; + nInspiration += nFont * (nFont + 1) / 2; SetLocalInt(oPC, "InspirationPool", nInspiration); FloatingTextStringOnCreature("Encounter begins with "+IntToString(nInspiration)+" inspiration", oPC, FALSE); } @@ -201,6 +204,8 @@ void ClearInspiration(object oPC) int ExpendInspiration(object oPC, int nCost) { + if (nCost <= 0) return FALSE; + int nInspiration = GetLocalInt(oPC, "InspirationPool"); if (nInspiration >= nCost) { @@ -261,6 +266,21 @@ void FactotumTriggerAbil(object oPC, int nAbil) IPSafeAddItemProperty(oSkin, ipIP, 60.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE); } +void TriggerInspiration(object oPC, int nCombat) +{ + SetLocalInt(oPC, "InspirationHBRunning", TRUE); + DelayCommand(0.249, DeleteLocalInt(oPC, "InspirationHBRunning")); + int nCurrent = GetIsInCombat(oPC); + // We just entered combat + if (nCurrent == TRUE && nCombat == FALSE) + SetInspiration(oPC); + else if (nCurrent == FALSE && nCombat == TRUE) // Just left combat + ClearInspiration(oPC); + + DelayCommand(0.25, TriggerInspiration(oPC, nCurrent)); +} + + /*void AddCunningBrillianceAbility(object oPC, int nAbil) { if (DEBUG) DoDebug("AddCunningBrillianceAbility "+IntToString(nAbil)); diff --git a/src/include/prc_inc_fork.nss b/src/include/prc_inc_fork.nss index 3e46b83..3b82eeb 100644 --- a/src/include/prc_inc_fork.nss +++ b/src/include/prc_inc_fork.nss @@ -23,11 +23,14 @@ const int FEAT_TYPE_IMPROVED_CRITICAL = 5; const int FEAT_TYPE_OVERWHELMING_CRITICAL = 6; const int FEAT_TYPE_DEVASTATING_CRITICAL = 7; const int FEAT_TYPE_WEAPON_OF_CHOICE = 8; +const int FEAT_TYPE_WEAPON_PROFICIENCY = 9; ////////////////////////////////////////////////// /* Function prototypes */ ////////////////////////////////////////////////// + int GetProficiencyFeatOfWeaponType(int iWeaponType); + /** * Returns the appropriate weapon feat given a weapon type. * @@ -210,10 +213,86 @@ int GetFeatOfWeaponType(int iWeaponType, int iFeatType) case FEAT_TYPE_OVERWHELMING_CRITICAL: return GetOverwhelmingCriticalFeatOfWeaponType(iWeaponType); case FEAT_TYPE_DEVASTATING_CRITICAL: return GetDevastatingCriticalFeatOfWeaponType(iWeaponType); case FEAT_TYPE_WEAPON_OF_CHOICE: return GetWeaponOfChoiceFeatOfWeaponType(iWeaponType); + case FEAT_TYPE_WEAPON_PROFICIENCY: return GetProficiencyFeatOfWeaponType(iWeaponType); } return -1; } +int GetProficiencyFeatOfWeaponType(int iWeaponType) +{ + switch(iWeaponType) + { + case BASE_ITEM_CBLUDGWEAPON: + case BASE_ITEM_CPIERCWEAPON: + case BASE_ITEM_CSLASHWEAPON: + case BASE_ITEM_CSLSHPRCWEAP: return FEAT_WEAPON_PROFICIENCY_CREATURE; + case BASE_ITEM_INVALID: return FEAT_IMPROVED_UNARMED_STRIKE; + + case BASE_ITEM_BASTARDSWORD: return FEAT_WEAPON_PROFICIENCY_BASTARD_SWORD; + case BASE_ITEM_BATTLEAXE: return FEAT_WEAPON_PROFICIENCY_BATTLEAXE; + case BASE_ITEM_CLUB: return FEAT_WEAPON_PROFICIENCY_CLUB; + case BASE_ITEM_CRAFTED_SCEPTER: return FEAT_WEAPON_PROFICIENCY_CLUB; + case BASE_ITEM_DAGGER: return FEAT_WEAPON_PROFICIENCY_DAGGER; + case BASE_ITEM_DART: return FEAT_WEAPON_PROFICIENCY_DART; + case BASE_ITEM_DIREMACE: return FEAT_WEAPON_PROFICIENCY_DIRE_MACE; + case BASE_ITEM_DOUBLEAXE: return FEAT_WEAPON_PROFICIENCY_DOUBLE_AXE; + case BASE_ITEM_DWARVENWARAXE: return FEAT_WEAPON_PROFICIENCY_DWARVEN_WARAXE; + case BASE_ITEM_GREATAXE: return FEAT_WEAPON_PROFICIENCY_GREATAXE; + case BASE_ITEM_GREATSWORD: return FEAT_WEAPON_PROFICIENCY_GREATSWORD; + case BASE_ITEM_HALBERD: return FEAT_WEAPON_PROFICIENCY_HALBERD; + case BASE_ITEM_HANDAXE: return FEAT_WEAPON_PROFICIENCY_HANDAXE; + case BASE_ITEM_HEAVYCROSSBOW: return FEAT_WEAPON_PROFICIENCY_HEAVY_XBOW; + case BASE_ITEM_HEAVYFLAIL: return FEAT_WEAPON_PROFICIENCY_HEAVY_FLAIL; + case BASE_ITEM_KAMA: return FEAT_WEAPON_PROFICIENCY_KAMA; + case BASE_ITEM_KATANA: return FEAT_WEAPON_PROFICIENCY_KATANA; + case BASE_ITEM_KUKRI: return FEAT_WEAPON_PROFICIENCY_KUKRI; + case BASE_ITEM_LIGHTCROSSBOW: return FEAT_WEAPON_PROFICIENCY_LIGHT_XBOW; + case BASE_ITEM_LIGHTFLAIL: return FEAT_WEAPON_PROFICIENCY_LIGHT_FLAIL; + case BASE_ITEM_LIGHTHAMMER: return FEAT_WEAPON_PROFICIENCY_LIGHT_HAMMER; + case BASE_ITEM_LIGHTMACE: return FEAT_WEAPON_PROFICIENCY_LIGHT_MACE; + case BASE_ITEM_LONGBOW: return FEAT_WEAPON_PROFICIENCY_LONGBOW; + case BASE_ITEM_LONGSWORD: return FEAT_WEAPON_PROFICIENCY_LONGSWORD; + case BASE_ITEM_MORNINGSTAR: return FEAT_WEAPON_PROFICIENCY_MORNINGSTAR; + case BASE_ITEM_QUARTERSTAFF: return FEAT_WEAPON_PROFICIENCY_QUARTERSTAFF; + case BASE_ITEM_MAGICSTAFF: return FEAT_WEAPON_PROFICIENCY_QUARTERSTAFF; + case BASE_ITEM_RAPIER: return FEAT_WEAPON_PROFICIENCY_RAPIER; + case BASE_ITEM_SCIMITAR: return FEAT_WEAPON_PROFICIENCY_SCIMITAR; + case BASE_ITEM_SCYTHE: return FEAT_WEAPON_PROFICIENCY_SCYTHE; + case BASE_ITEM_SHORTBOW: return FEAT_WEAPON_PROFICIENCY_SHORTBOW; + case BASE_ITEM_SHORTSPEAR: return FEAT_WEAPON_PROFICIENCY_SHORTSPEAR; + case BASE_ITEM_SHORTSWORD: return FEAT_WEAPON_PROFICIENCY_SHORTSWORD; + case BASE_ITEM_SHURIKEN: return FEAT_WEAPON_PROFICIENCY_SHURIKEN; + case BASE_ITEM_SICKLE: return FEAT_WEAPON_PROFICIENCY_SICKLE; + case BASE_ITEM_SLING: return FEAT_WEAPON_PROFICIENCY_SLING; + case BASE_ITEM_THROWINGAXE: return FEAT_WEAPON_PROFICIENCY_THROWING_AXE; + case BASE_ITEM_TRIDENT: return FEAT_WEAPON_PROFICIENCY_TRIDENT; + case BASE_ITEM_TWOBLADEDSWORD: return FEAT_WEAPON_PROFICIENCY_TWO_BLADED_SWORD; + case BASE_ITEM_WARHAMMER: return FEAT_WEAPON_PROFICIENCY_WARHAMMER; + case BASE_ITEM_WHIP: return FEAT_WEAPON_PROFICIENCY_WHIP; + + //:: new item types + case BASE_ITEM_DOUBLE_SCIMITAR: return FEAT_WEAPON_PROFICIENCY_DOUBLE_SCIMITAR; + case BASE_ITEM_EAGLE_CLAW: return FEAT_WEAPON_PROFICIENCY_EAGLE_CLAW; + case BASE_ITEM_ELVEN_COURTBLADE: return FEAT_WEAPON_PROFICIENCY_ELVEN_COURTBLADE; + case BASE_ITEM_ELVEN_LIGHTBLADE: return FEAT_WEAPON_PROFICIENCY_ELVEN_LIGHTBLADE; + case BASE_ITEM_ELVEN_THINBLADE: return FEAT_WEAPON_PROFICIENCY_ELVEN_THINBLADE; + case BASE_ITEM_FALCHION: return FEAT_WEAPON_PROFICIENCY_FALCHION; + case BASE_ITEM_GOAD: return FEAT_WEAPON_PROFICIENCY_GOAD; + case BASE_ITEM_HEAVY_MACE: return FEAT_WEAPON_PROFICIENCY_HEAVY_MACE; + case BASE_ITEM_HEAVY_PICK: return FEAT_WEAPON_PROFICIENCY_HEAVY_PICK; + case BASE_ITEM_KATAR: return FEAT_WEAPON_PROFICIENCY_KATAR; + case BASE_ITEM_LIGHT_LANCE: return FEAT_WEAPON_PROFICIENCY_LIGHT_LANCE; + case BASE_ITEM_LIGHT_PICK: return FEAT_WEAPON_PROFICIENCY_LIGHT_PICK; + case BASE_ITEM_MAUL: return FEAT_WEAPON_PROFICIENCY_MAUL; + case BASE_ITEM_NUNCHAKU: return FEAT_WEAPON_PROFICIENCY_NUNCHAKU; + case BASE_ITEM_SAI: return FEAT_WEAPON_PROFICIENCY_SAI; + case BASE_ITEM_SAP: return FEAT_WEAPON_PROFICIENCY_SAP; + } + + return -1; +} + + int GetFocusFeatOfWeaponType(int iWeaponType) { switch(iWeaponType) @@ -226,6 +305,7 @@ int GetFocusFeatOfWeaponType(int iWeaponType) case BASE_ITEM_BASTARDSWORD: return FEAT_WEAPON_FOCUS_BASTARD_SWORD; case BASE_ITEM_BATTLEAXE: return FEAT_WEAPON_FOCUS_BATTLE_AXE; case BASE_ITEM_CLUB: return FEAT_WEAPON_FOCUS_CLUB; + case BASE_ITEM_CRAFTED_SCEPTER: return FEAT_WEAPON_FOCUS_CLUB; case BASE_ITEM_DAGGER: return FEAT_WEAPON_FOCUS_DAGGER; case BASE_ITEM_DART: return FEAT_WEAPON_FOCUS_DART; case BASE_ITEM_DIREMACE: return FEAT_WEAPON_FOCUS_DIRE_MACE; @@ -248,6 +328,7 @@ int GetFocusFeatOfWeaponType(int iWeaponType) case BASE_ITEM_LONGSWORD: return FEAT_WEAPON_FOCUS_LONG_SWORD; case BASE_ITEM_MORNINGSTAR: return FEAT_WEAPON_FOCUS_MORNING_STAR; case BASE_ITEM_QUARTERSTAFF: return FEAT_WEAPON_FOCUS_STAFF; + case BASE_ITEM_MAGICSTAFF: return FEAT_WEAPON_FOCUS_STAFF; case BASE_ITEM_RAPIER: return FEAT_WEAPON_FOCUS_RAPIER; case BASE_ITEM_SCIMITAR: return FEAT_WEAPON_FOCUS_SCIMITAR; case BASE_ITEM_SCYTHE: return FEAT_WEAPON_FOCUS_SCYTHE; @@ -296,6 +377,7 @@ int GetSpecializationFeatOfWeaponType(int iWeaponType) case BASE_ITEM_BASTARDSWORD: return FEAT_WEAPON_SPECIALIZATION_BASTARD_SWORD; case BASE_ITEM_BATTLEAXE: return FEAT_WEAPON_SPECIALIZATION_BATTLE_AXE; case BASE_ITEM_CLUB: return FEAT_WEAPON_SPECIALIZATION_CLUB; + case BASE_ITEM_CRAFTED_SCEPTER: return FEAT_WEAPON_SPECIALIZATION_CLUB; case BASE_ITEM_DAGGER: return FEAT_WEAPON_SPECIALIZATION_DAGGER; case BASE_ITEM_DART: return FEAT_WEAPON_SPECIALIZATION_DART; case BASE_ITEM_DIREMACE: return FEAT_WEAPON_SPECIALIZATION_DIRE_MACE; @@ -318,6 +400,7 @@ int GetSpecializationFeatOfWeaponType(int iWeaponType) case BASE_ITEM_LONGSWORD: return FEAT_WEAPON_SPECIALIZATION_LONG_SWORD; case BASE_ITEM_MORNINGSTAR: return FEAT_WEAPON_SPECIALIZATION_MORNING_STAR; case BASE_ITEM_QUARTERSTAFF: return FEAT_WEAPON_SPECIALIZATION_STAFF; + case BASE_ITEM_MAGICSTAFF: return FEAT_WEAPON_SPECIALIZATION_STAFF; case BASE_ITEM_RAPIER: return FEAT_WEAPON_SPECIALIZATION_RAPIER; case BASE_ITEM_SCIMITAR: return FEAT_WEAPON_SPECIALIZATION_SCIMITAR; case BASE_ITEM_SCYTHE: return FEAT_WEAPON_SPECIALIZATION_SCYTHE; @@ -366,6 +449,7 @@ int GetEpicFocusFeatOfWeaponType(int iWeaponType) case BASE_ITEM_BASTARDSWORD: return FEAT_EPIC_WEAPON_FOCUS_BASTARDSWORD; case BASE_ITEM_BATTLEAXE: return FEAT_EPIC_WEAPON_FOCUS_BATTLEAXE; case BASE_ITEM_CLUB: return FEAT_EPIC_WEAPON_FOCUS_CLUB; + case BASE_ITEM_CRAFTED_SCEPTER: return FEAT_EPIC_WEAPON_FOCUS_CLUB; case BASE_ITEM_DAGGER: return FEAT_EPIC_WEAPON_FOCUS_DAGGER; case BASE_ITEM_DART: return FEAT_EPIC_WEAPON_FOCUS_DART; case BASE_ITEM_DIREMACE: return FEAT_EPIC_WEAPON_FOCUS_DIREMACE; @@ -388,6 +472,7 @@ int GetEpicFocusFeatOfWeaponType(int iWeaponType) case BASE_ITEM_LONGSWORD: return FEAT_EPIC_WEAPON_FOCUS_LONGSWORD; case BASE_ITEM_MORNINGSTAR: return FEAT_EPIC_WEAPON_FOCUS_MORNINGSTAR; case BASE_ITEM_QUARTERSTAFF: return FEAT_EPIC_WEAPON_FOCUS_QUARTERSTAFF; + case BASE_ITEM_MAGICSTAFF: return FEAT_EPIC_WEAPON_FOCUS_QUARTERSTAFF; case BASE_ITEM_RAPIER: return FEAT_EPIC_WEAPON_FOCUS_RAPIER; case BASE_ITEM_SCIMITAR: return FEAT_EPIC_WEAPON_FOCUS_SCIMITAR; case BASE_ITEM_SCYTHE: return FEAT_EPIC_WEAPON_FOCUS_SCYTHE; @@ -436,6 +521,7 @@ int GetEpicSpecializationFeatOfWeaponType(int iWeaponType) case BASE_ITEM_BASTARDSWORD: return FEAT_EPIC_WEAPON_SPECIALIZATION_BASTARDSWORD; case BASE_ITEM_BATTLEAXE: return FEAT_EPIC_WEAPON_SPECIALIZATION_BATTLEAXE; case BASE_ITEM_CLUB: return FEAT_EPIC_WEAPON_SPECIALIZATION_CLUB; + case BASE_ITEM_CRAFTED_SCEPTER: return FEAT_EPIC_WEAPON_SPECIALIZATION_CLUB; case BASE_ITEM_DAGGER: return FEAT_EPIC_WEAPON_SPECIALIZATION_DAGGER; case BASE_ITEM_DART: return FEAT_EPIC_WEAPON_SPECIALIZATION_DART; case BASE_ITEM_DIREMACE: return FEAT_EPIC_WEAPON_SPECIALIZATION_DIREMACE; @@ -458,7 +544,8 @@ int GetEpicSpecializationFeatOfWeaponType(int iWeaponType) case BASE_ITEM_LONGSWORD: return FEAT_EPIC_WEAPON_SPECIALIZATION_LONGSWORD; case BASE_ITEM_MORNINGSTAR: return FEAT_EPIC_WEAPON_SPECIALIZATION_MORNINGSTAR; case BASE_ITEM_QUARTERSTAFF: return FEAT_EPIC_WEAPON_SPECIALIZATION_QUARTERSTAFF; - case BASE_ITEM_RAPIER: return FEAT_EPIC_WEAPON_SPECIALIZATION_RAPIER; + case BASE_ITEM_MAGICSTAFF: return FEAT_EPIC_WEAPON_SPECIALIZATION_QUARTERSTAFF; + case BASE_ITEM_RAPIER: return FEAT_EPIC_WEAPON_SPECIALIZATION_RAPIER; case BASE_ITEM_SCIMITAR: return FEAT_EPIC_WEAPON_SPECIALIZATION_SCIMITAR; case BASE_ITEM_SCYTHE: return FEAT_EPIC_WEAPON_SPECIALIZATION_SCYTHE; case BASE_ITEM_SHORTBOW: return FEAT_EPIC_WEAPON_SPECIALIZATION_SHORTBOW; @@ -506,6 +593,7 @@ int GetImprovedCriticalFeatOfWeaponType(int iWeaponType) case BASE_ITEM_BASTARDSWORD: return FEAT_IMPROVED_CRITICAL_BASTARD_SWORD; case BASE_ITEM_BATTLEAXE: return FEAT_IMPROVED_CRITICAL_BATTLE_AXE; case BASE_ITEM_CLUB: return FEAT_IMPROVED_CRITICAL_CLUB; + case BASE_ITEM_CRAFTED_SCEPTER: return FEAT_IMPROVED_CRITICAL_CLUB; case BASE_ITEM_DAGGER: return FEAT_IMPROVED_CRITICAL_DAGGER; case BASE_ITEM_DART: return FEAT_IMPROVED_CRITICAL_DART; case BASE_ITEM_DIREMACE: return FEAT_IMPROVED_CRITICAL_DIRE_MACE; @@ -528,6 +616,7 @@ int GetImprovedCriticalFeatOfWeaponType(int iWeaponType) case BASE_ITEM_LONGSWORD: return FEAT_IMPROVED_CRITICAL_LONG_SWORD; case BASE_ITEM_MORNINGSTAR: return FEAT_IMPROVED_CRITICAL_MORNING_STAR; case BASE_ITEM_QUARTERSTAFF: return FEAT_IMPROVED_CRITICAL_STAFF; + case BASE_ITEM_MAGICSTAFF: return FEAT_IMPROVED_CRITICAL_STAFF; case BASE_ITEM_RAPIER: return FEAT_IMPROVED_CRITICAL_RAPIER; case BASE_ITEM_SCIMITAR: return FEAT_IMPROVED_CRITICAL_SCIMITAR; case BASE_ITEM_SCYTHE: return FEAT_IMPROVED_CRITICAL_SCYTHE; @@ -576,6 +665,7 @@ int GetOverwhelmingCriticalFeatOfWeaponType(int iWeaponType) case BASE_ITEM_BASTARDSWORD: return FEAT_EPIC_OVERWHELMING_CRITICAL_BASTARDSWORD; case BASE_ITEM_BATTLEAXE: return FEAT_EPIC_OVERWHELMING_CRITICAL_BATTLEAXE; case BASE_ITEM_CLUB: return FEAT_EPIC_OVERWHELMING_CRITICAL_CLUB; + case BASE_ITEM_CRAFTED_SCEPTER: return FEAT_EPIC_OVERWHELMING_CRITICAL_CLUB; case BASE_ITEM_DAGGER: return FEAT_EPIC_OVERWHELMING_CRITICAL_DAGGER; case BASE_ITEM_DART: return FEAT_EPIC_OVERWHELMING_CRITICAL_DART; case BASE_ITEM_DIREMACE: return FEAT_EPIC_OVERWHELMING_CRITICAL_DIREMACE; @@ -598,6 +688,7 @@ int GetOverwhelmingCriticalFeatOfWeaponType(int iWeaponType) case BASE_ITEM_LONGSWORD: return FEAT_EPIC_OVERWHELMING_CRITICAL_LONGSWORD; case BASE_ITEM_MORNINGSTAR: return FEAT_EPIC_OVERWHELMING_CRITICAL_MORNINGSTAR; case BASE_ITEM_QUARTERSTAFF: return FEAT_EPIC_OVERWHELMING_CRITICAL_QUARTERSTAFF; + case BASE_ITEM_MAGICSTAFF: return FEAT_EPIC_OVERWHELMING_CRITICAL_QUARTERSTAFF; case BASE_ITEM_RAPIER: return FEAT_EPIC_OVERWHELMING_CRITICAL_RAPIER; case BASE_ITEM_SCIMITAR: return FEAT_EPIC_OVERWHELMING_CRITICAL_SCIMITAR; case BASE_ITEM_SCYTHE: return FEAT_EPIC_OVERWHELMING_CRITICAL_SCYTHE; @@ -646,6 +737,7 @@ int GetDevastatingCriticalFeatOfWeaponType(int iWeaponType) case BASE_ITEM_BASTARDSWORD: return FEAT_EPIC_DEVASTATING_CRITICAL_BASTARDSWORD; case BASE_ITEM_BATTLEAXE: return FEAT_EPIC_DEVASTATING_CRITICAL_BATTLEAXE; case BASE_ITEM_CLUB: return FEAT_EPIC_DEVASTATING_CRITICAL_CLUB; + case BASE_ITEM_CRAFTED_SCEPTER: return FEAT_EPIC_DEVASTATING_CRITICAL_CLUB; case BASE_ITEM_DAGGER: return FEAT_EPIC_DEVASTATING_CRITICAL_DAGGER; case BASE_ITEM_DART: return FEAT_EPIC_DEVASTATING_CRITICAL_DART; case BASE_ITEM_DIREMACE: return FEAT_EPIC_DEVASTATING_CRITICAL_DIREMACE; @@ -668,6 +760,7 @@ int GetDevastatingCriticalFeatOfWeaponType(int iWeaponType) case BASE_ITEM_LONGSWORD: return FEAT_EPIC_DEVASTATING_CRITICAL_LONGSWORD; case BASE_ITEM_MORNINGSTAR: return FEAT_EPIC_DEVASTATING_CRITICAL_MORNINGSTAR; case BASE_ITEM_QUARTERSTAFF: return FEAT_EPIC_DEVASTATING_CRITICAL_QUARTERSTAFF; + case BASE_ITEM_MAGICSTAFF: return FEAT_EPIC_DEVASTATING_CRITICAL_QUARTERSTAFF; case BASE_ITEM_RAPIER: return FEAT_EPIC_DEVASTATING_CRITICAL_RAPIER; case BASE_ITEM_SCIMITAR: return FEAT_EPIC_DEVASTATING_CRITICAL_SCIMITAR; case BASE_ITEM_SCYTHE: return FEAT_EPIC_DEVASTATING_CRITICAL_SCYTHE; @@ -711,6 +804,7 @@ int GetWeaponOfChoiceFeatOfWeaponType(int iWeaponType) case BASE_ITEM_BASTARDSWORD: return FEAT_WEAPON_OF_CHOICE_BASTARDSWORD; case BASE_ITEM_BATTLEAXE: return FEAT_WEAPON_OF_CHOICE_BATTLEAXE; case BASE_ITEM_CLUB: return FEAT_WEAPON_OF_CHOICE_CLUB; + case BASE_ITEM_CRAFTED_SCEPTER: return FEAT_WEAPON_OF_CHOICE_CLUB; case BASE_ITEM_DAGGER: return FEAT_WEAPON_OF_CHOICE_DAGGER; case BASE_ITEM_DIREMACE: return FEAT_WEAPON_OF_CHOICE_DIREMACE; case BASE_ITEM_DOUBLEAXE: return FEAT_WEAPON_OF_CHOICE_DOUBLEAXE; @@ -729,6 +823,7 @@ int GetWeaponOfChoiceFeatOfWeaponType(int iWeaponType) case BASE_ITEM_LONGSWORD: return FEAT_WEAPON_OF_CHOICE_LONGSWORD; case BASE_ITEM_MORNINGSTAR: return FEAT_WEAPON_OF_CHOICE_MORNINGSTAR; case BASE_ITEM_QUARTERSTAFF: return FEAT_WEAPON_OF_CHOICE_QUARTERSTAFF; + case BASE_ITEM_MAGICSTAFF: return FEAT_WEAPON_OF_CHOICE_QUARTERSTAFF; case BASE_ITEM_RAPIER: return FEAT_WEAPON_OF_CHOICE_RAPIER; case BASE_ITEM_SCIMITAR: return FEAT_WEAPON_OF_CHOICE_SCIMITAR; case BASE_ITEM_SCYTHE: return FEAT_WEAPON_OF_CHOICE_SCYTHE; @@ -787,6 +882,7 @@ int GetWeaponSize(object oWeapon) case BASE_ITEM_GREATAXE: case BASE_ITEM_HEAVYFLAIL: case BASE_ITEM_QUARTERSTAFF: + //case BASE_ITEM_MAGICSTAFF: case BASE_ITEM_SCYTHE: case BASE_ITEM_SHORTSPEAR: case BASE_ITEM_ELVEN_COURTBLADE: @@ -823,6 +919,7 @@ int PRCLargeWeaponCheck(int iBaseType, int nSize) case BASE_ITEM_GREATAXE: case BASE_ITEM_HEAVYFLAIL: case BASE_ITEM_QUARTERSTAFF: + //case BASE_ITEM_MAGICSTAFF: case BASE_ITEM_SCYTHE: case BASE_ITEM_SHORTSPEAR: case BASE_ITEM_ELVEN_COURTBLADE: @@ -834,4 +931,6 @@ int PRCLargeWeaponCheck(int iBaseType, int nSize) } } return sTest != "" && sTest != IntToString(nSize); -} \ No newline at end of file +} + +//::void main(){} \ No newline at end of file diff --git a/src/include/prc_inc_function.nss b/src/include/prc_inc_function.nss index 93f7aa1..a3b24e5 100644 --- a/src/include/prc_inc_function.nss +++ b/src/include/prc_inc_function.nss @@ -108,8 +108,8 @@ void SetupCharacterData(object oPC) case CLASS_TYPE_ALIENIST: sScript = "prc_alienist"; break; case CLASS_TYPE_ARCANE_DUELIST: sScript = "prc_arcduel"; break; case CLASS_TYPE_ARCHIVIST: sScript = "prc_archivist"; iData |= 0x01; break; - case CLASS_TYPE_ASSASSIN: iData |= 0x03; break; - case CLASS_TYPE_BAELNORN: sScript = "prc_baelnorn"; break; + case CLASS_TYPE_ASSASSIN: break; + //case CLASS_TYPE_BAELNORN: sScript = "prc_baelnorn"; break; case CLASS_TYPE_BARD: iData |= 0x07; break; case CLASS_TYPE_BATTLESMITH: sScript = "prc_battlesmith"; break; case CLASS_TYPE_BEGUILER: iData |= 0x03; break; @@ -121,7 +121,7 @@ void SetupCharacterData(object oPC) case CLASS_TYPE_BLIGHTLORD: sScript = "prc_blightlord"; break; case CLASS_TYPE_BLOODCLAW_MASTER: sScript = "tob_bloodclaw"; break; case CLASS_TYPE_BONDED_SUMMONNER: sScript = "prc_bondedsumm"; break; - case CLASS_TYPE_CELEBRANT_SHARESS: iData |= 0x03; break; + case CLASS_TYPE_CELEBRANT_SHARESS: iData |= 0x07; break; case CLASS_TYPE_CHILD_OF_NIGHT: sScript = "shd_childnight"; break; case CLASS_TYPE_COC: sScript = "prc_coc"; break; case CLASS_TYPE_COMBAT_MEDIC: sScript = "prc_cbtmed"; break; @@ -180,6 +180,7 @@ void SetupCharacterData(object oPC) case CLASS_TYPE_LASHER: sScript = "prc_lasher"; break; case CLASS_TYPE_LEGENDARY_DREADNOUGHT: sScript = "prc_legendread"; break; case CLASS_TYPE_LICH: sScript = "pnp_lich_level"; break; + case CLASS_TYPE_LION_OF_TALISID: sScript = "prc_lot"; break; case CLASS_TYPE_MAGEKILLER: sScript = "prc_magekill"; break; case CLASS_TYPE_MASTER_HARPER: sScript = "prc_masterh"; break; case CLASS_TYPE_MASTER_OF_NINE: sScript = "tob_masterofnine"; break; @@ -245,6 +246,7 @@ void SetupCharacterData(object oPC) case CLASS_TYPE_TOTEM_RAGER: sScript = "moi_totemrager"; break; case CLASS_TYPE_TRUENAMER: sScript = "true_truenamer"; iData |= 0x01; break; case CLASS_TYPE_VASSAL: sScript = "prc_vassal"; break; + case CLASS_TYPE_VERDANT_LORD: sScript = "prc_verdantlord"; break; case CLASS_TYPE_VIGILANT: sScript = "prc_vigilant"; break; case CLASS_TYPE_WARBLADE: sScript = "tob_warblade"; iData |= 0x01; break; case CLASS_TYPE_WARCHIEF: sScript = "prc_warchief"; break; @@ -429,7 +431,7 @@ void EvalPRCFeats(object oPC) ExecuteScript("moi_events", oPC); if (GetIsBinder(oPC)) - ExecuteScript("bnd_events", oPC); + ExecuteScript("bnd_events", oPC); // check if character with crafting feat has appropriate base item in her inventory // x - moved from prc_onhb_indiv.nss @@ -2264,6 +2266,8 @@ void FeatSpecialUsePerDay(object oPC) FeatUsePerDay(oPC, FEAT_FM_FOREST_DOMINION, ABILITY_CHARISMA, 3); FeatUsePerDay(oPC, FEAT_SOD_DEATH_TOUCH, -1, (GetLevelByClass(CLASS_TYPE_SLAYER_OF_DOMIEL, oPC)+4)/4); FeatUsePerDay(oPC, FEAT_SUEL_DISPELLING_STRIKE, -1, (GetLevelByClass(CLASS_TYPE_SUEL_ARCHANAMACH, oPC) + 2) / 4); + FeatUsePerDay(oPC, FEAT_PLANT_CONTROL, ABILITY_CHARISMA, 3); + FeatUsePerDay(oPC, FEAT_PLANT_DEFIANCE, ABILITY_CHARISMA, 3); FeatDiabolist(oPC); FeatAlaghar(oPC); ShadowShieldUses(oPC); diff --git a/src/include/prc_inc_hextor.nss b/src/include/prc_inc_hextor.nss index affe360..531ba9a 100644 --- a/src/include/prc_inc_hextor.nss +++ b/src/include/prc_inc_hextor.nss @@ -1,4 +1,6 @@ #include "prc_feat_const" +#include "inc_item_props" +#include "prc_inc_spells" const string BRUTAL_STRIKE_MODE_VAR = "PRC_BRUTAL_STRIKE_MODE"; diff --git a/src/include/prc_inc_itmrstr.nss b/src/include/prc_inc_itmrstr.nss index 156f530..dd852f0 100644 --- a/src/include/prc_inc_itmrstr.nss +++ b/src/include/prc_inc_itmrstr.nss @@ -36,6 +36,8 @@ void CheckForPnPHolyAvenger(object oItem); #include "inc_utility" #include "prc_inc_newip" +#include "prc_inc_castlvl" +#include "inc_newspellbook" ////////////////////////////////////////////////// diff --git a/src/include/prc_inc_json.nss b/src/include/prc_inc_json.nss new file mode 100644 index 0000000..f15c675 --- /dev/null +++ b/src/include/prc_inc_json.nss @@ -0,0 +1,1993 @@ +//::////////////////////////////////////////////// +//:: ;-. ,-. ,-. ,-. +//:: | ) | ) / ( ) +//:: |-' |-< | ;-: +//:: | | \ \ ( ) +//:: ' ' ' `-' `-' +//::////////////////////////////////////////////// +//:: +/* + Library for json related functions. + +*/ +//:: +//::////////////////////////////////////////////// +//:: Script: prc_inc_json.nss +//:: Author: Jaysyn +//:: Created: 2025-08-14 12:52:32 +//::////////////////////////////////////////////// +#include "nw_inc_gff" +#include "inc_debug" +#include "prc_inc_racial" +#include "prc_inc_nwscript" +#include "prc_inc_spells" +#include "prc_inc_util" +#include "prc_inc_fork" +#include "prc_inc_natweap" + +//:: Get a random General feat. +void ApplyParagonBonusFeat(object oCreature, int iFeat); + +//::---------------------------------------------| +//:: Helper functions | +//::---------------------------------------------| +int GetHealerCompanionBonus(int nHealerLvl) +{ + // No bonus before 12th level + if (nHealerLvl < 12) + return 0; + + int nBonus = 0; + + // Non-epic improvements: 12, 15, 18, 21 (every 3 levels) + if (nHealerLvl >= 12) + { + int nPreEpicIntervals = ( (nHealerLvl < 21) ? (nHealerLvl - 12) : (21 - 12) ) / 3; + nBonus += 2 + (nPreEpicIntervals * 2); + } + + // Epic improvements: 24, 28, 32, 36... (every 4 levels) + if (nHealerLvl >= 24) + { + int nEpicIntervals = (nHealerLvl - 24) / 4; + // First epic improvement is +2 at 24 + nBonus += 2 + (nEpicIntervals * 2); + } + + return nBonus; +} + +/* int GetHealerCompanionBonus(int nHealerLvl) +{ + if (nHealerLvl < 12) + return 0; + + // Shift so that 12–14 yields interval 0 + int nIntervals = (nHealerLvl - 12) / 3; + + return 2 + (nIntervals * 2); +} */ + + +//:: Function to calculate the maximum possible hitpoints for oCreature +int GetMaxPossibleHP(object oCreature) +{ + int nMaxHP = 0; // Stores the total maximum hitpoints + int i = 1; // Initialize position for class index + int nConb = GetAbilityModifier(ABILITY_CONSTITUTION, oCreature); + int nRacial = MyPRCGetRacialType(oCreature); + int nSize = PRCGetCreatureSize(oCreature); + + // Loop through each class position the creature may have, checking each class in turn + while (TRUE) + { + // Get the class ID at position i + int nClassID = GetClassByPosition(i, oCreature); + + // If class is invalid (no more classes to check), break out of loop + if (nClassID == CLASS_TYPE_INVALID) + break; + + // Get the number of levels in this class + int nClassLevels = GetLevelByClass(nClassID, oCreature); + + // Get the row index of the class in classes.2da by using class ID as the row index + int nHitDie = StringToInt(Get2DAString("classes", "HitDie", nClassID)); + + // Add maximum HP for this class (Hit Die * number of levels in this class) + nMaxHP += nClassLevels * nHitDie; + + // Move to the next class position + i++; + } + + if(nRacial == RACIAL_TYPE_CONSTRUCT || nRacial == RACIAL_TYPE_UNDEAD) + { + nConb = 0; + } + + nMaxHP += nConb * GetHitDice(oCreature); + + if(nRacial == RACIAL_TYPE_CONSTRUCT) + { + if(nSize == CREATURE_SIZE_FINE) nMaxHP += 0; + if(nSize == CREATURE_SIZE_DIMINUTIVE) nMaxHP += 0; + if(nSize == CREATURE_SIZE_TINY) nMaxHP += 0; + if(nSize == CREATURE_SIZE_SMALL) nMaxHP += 10; + if(nSize == CREATURE_SIZE_MEDIUM) nMaxHP += 20; + if(nSize == CREATURE_SIZE_LARGE) nMaxHP += 30; + if(nSize == CREATURE_SIZE_HUGE) nMaxHP += 40; + if(nSize == CREATURE_SIZE_GARGANTUAN) nMaxHP += 60; + } + + return nMaxHP; +} + +// Returns how many feats a creature should gain when its HD increases +int CalculateFeatsFromHD(int nOriginalHD, int nNewHD) +{ + // HD increase + int nHDIncrease = nNewHD - nOriginalHD; + + if (nHDIncrease <= 0) + return 0; // No new feats if HD did not increase + + // D&D 3E: 1 feat per 3 HD + int nBonusFeats = nHDIncrease / 3; + + return nBonusFeats; +} + +// Returns how many stat boosts a creature needs based on its HD +int GetStatBoostsFromHD(int nCreatureHD, int nModiferCap) +{ + // Make sure we don't get negative boosts + int nBoosts = (40 - nCreatureHD) / 4; + if (nBoosts < 0) + { + nBoosts = 0; + } + return nBoosts; +} + +// Struct to hold size modifiers +struct SizeModifiers +{ + int strMod; + int dexMod; + int conMod; + int naturalAC; + int attackBonus; + int dexSkillMod; +}; + +//:: Returns ability mod for score +int GetAbilityModFromValue(int nAbilityValue) +{ + int nMod = (nAbilityValue - 10) / 2; + + // Adjust if below 10 and odd + if (nAbilityValue < 10 && (nAbilityValue % 2) != 0) + { + nMod = nMod - 1; + } + return nMod; +} + +//:: Get a random General feat. +void PickParagonBonusFeat(object oCreature) +{ +//:: Paragon creatures get a +15 to all ability scores, +//:: so can always meet feat pre-reqs. + +//:: Detect spellcasting classes (FOR FUTURE USE) + int i; + for (i = 1; i <= 8; i++) + { + if (GetIsArcaneClass(GetClassByPosition(i, oCreature))) + { + SetLocalInt(oCreature, "ParagonArcaneCaster", 0); + } + if (GetIsDivineClass(GetClassByPosition(i, oCreature))) + { + SetLocalInt(oCreature, "ParagonDivineCaster", 0); + } + } + switch (Random(18)) + { + //:: Dodge -> Mobility -> Spring Attack + case 0: + { + int iDodge = GetHasFeat(FEAT_DODGE, oCreature); + int iMobility = GetHasFeat(FEAT_MOBILITY, oCreature); + int iSpringAttack = GetHasFeat(FEAT_SPRING_ATTACK, oCreature); + + //:: Grant only the first missing feat in the chain + if (iDodge == 0) + { + ApplyParagonBonusFeat(oCreature, FEAT_DODGE); + } + else if (iMobility == 0) + { + ApplyParagonBonusFeat(oCreature, FEAT_MOBILITY); + } + else if (iSpringAttack == 0) + { + ApplyParagonBonusFeat(oCreature, FEAT_SPRING_ATTACK); + } + } + break; + //:: Power Attack -> Cleave -> Imp Power Attack -> Great Cleave + case 1: + { + int iPower = GetHasFeat(FEAT_POWER_ATTACK, oCreature); + int iCleave = GetHasFeat(FEAT_CLEAVE, oCreature); + int iImpPower = GetHasFeat(FEAT_IMPROVED_POWER_ATTACK, oCreature); + int iGrCleave = GetHasFeat(FEAT_GREAT_CLEAVE, oCreature); + + //:: Grant only the first missing feat in the chain + if (iPower == 0) + { + ApplyParagonBonusFeat(oCreature, FEAT_POWER_ATTACK); + } + else if (iCleave == 0) + { + ApplyParagonBonusFeat(oCreature, FEAT_CLEAVE); + } + else if (iImpPower == 0) + { + ApplyParagonBonusFeat(oCreature, FEAT_IMPROVED_POWER_ATTACK); + } + else if (iGrCleave == 0) + { + ApplyParagonBonusFeat(oCreature, FEAT_GREAT_CLEAVE); + } + } + break; + //:: Expertise -> Imp Expertise -> Whirlwind Attack -> Imp Whirlwind Attack + case 2: + { + int iEx = GetHasFeat(FEAT_EXPERTISE, oCreature); + int iImpEx = GetHasFeat(FEAT_IMPROVED_EXPERTISE, oCreature); + int iWhirl = GetHasFeat(FEAT_WHIRLWIND_ATTACK, oCreature); + int iImpWhirl = GetHasFeat(FEAT_IMPROVED_WHIRLWIND, oCreature); + + //:: Grant only the first missing feat in the chain + if (iEx == 0) + { + ApplyParagonBonusFeat(oCreature, FEAT_EXPERTISE); + } + else if (iImpEx == 0) + { + ApplyParagonBonusFeat(oCreature, FEAT_IMPROVED_EXPERTISE); + } + else if (iWhirl == 0) + { + ApplyParagonBonusFeat(oCreature, FEAT_WHIRLWIND_ATTACK); + } + else if (iImpWhirl == 0) + { + ApplyParagonBonusFeat(oCreature, FEAT_IMPROVED_WHIRLWIND); + } + } + break; + //:: Disarm -> Expertise -> Improved Disarm -> Imp Expertise + case 3: + { + int iDisarm = GetHasFeat(FEAT_DISARM, oCreature); + int iEx = GetHasFeat(FEAT_EXPERTISE, oCreature); + int iImpDisarm = GetHasFeat(FEAT_IMPROVED_DISARM, oCreature); + int iImpEx = GetHasFeat(FEAT_IMPROVED_EXPERTISE, oCreature); + + //:: Grant only the first missing feat in the chain + if (iDisarm == 0) + { + ApplyParagonBonusFeat(oCreature, FEAT_DISARM); + } + else if (iEx == 0) + { + ApplyParagonBonusFeat(oCreature, FEAT_EXPERTISE); + } + else if (iImpDisarm == 0) + { + ApplyParagonBonusFeat(oCreature, FEAT_IMPROVED_DISARM); + } + else if (iImpEx == 0) + { + ApplyParagonBonusFeat(oCreature, FEAT_IMPROVED_EXPERTISE); + } + } + break; + //:: Toughness + case 4: + { + ApplyParagonBonusFeat(oCreature, FEAT_TOUGHNESS); + } + break; + //:: Great Fortitude + case 5: + { + ApplyParagonBonusFeat(oCreature, FEAT_GREAT_FORTITUDE); + } + break; + //:: Lightining Reflexes + case 6: + { + ApplyParagonBonusFeat(oCreature, FEAT_LIGHTNING_REFLEXES); + } + break; + //:: Iron Will -> Unnatural Will + case 7: + { + int iIronWill = GetHasFeat(FEAT_IRON_WILL, oCreature); + int iUnnaturalWill = GetHasFeat(FEAT_UNNATURAL_WILL, oCreature); + + //:: Grant only the first missing feat in the chain + if (iIronWill == 0) + { + ApplyParagonBonusFeat(oCreature, FEAT_IRON_WILL); + } + else if (iUnnaturalWill == 0) + { + ApplyParagonBonusFeat(oCreature, FEAT_UNNATURAL_WILL); + } + } + break; + //:: Blind-Fight + case 8: + { + ApplyParagonBonusFeat(oCreature, FEAT_BLIND_FIGHT); + } + break; + //:: Improved Initiative + case 9: + { + ApplyParagonBonusFeat(oCreature, FEAT_IMPROVED_INITIATIVE); + } + break; + //:: Alertness + case 10: + { + ApplyParagonBonusFeat(oCreature, FEAT_ALERTNESS); + } + break; + //:: Blooded + case 11: + { + ApplyParagonBonusFeat(oCreature, FEAT_BLOODED); + } + break; + //:: Side-step Charge + case 12: + { + ApplyParagonBonusFeat(oCreature, FEAT_SIDESTEP_CHARGE); + } + break; + //:: Thug + case 13: + { + ApplyParagonBonusFeat(oCreature, FEAT_THUG); + } + break; + //:: Dive for Cover + case 14: + { + ApplyParagonBonusFeat(oCreature, FEAT_DIVE_FOR_COVER); + } + break; + //:: Endurance -> Strong Stomach + case 15: + { + int iEndurance = GetHasFeat(FEAT_ENDURANCE, oCreature); + int iStrStomach = GetHasFeat(FEAT_STRONG_STOMACH, oCreature); + + //:: Grant only the first missing feat in the chain + if (iEndurance == 0) + { + ApplyParagonBonusFeat(oCreature, FEAT_ENDURANCE); + } + else if (iStrStomach == 0) + { + ApplyParagonBonusFeat(oCreature, FEAT_STRONG_STOMACH); + } + } + break; + //:: Resist Disease + case 16: + { + ApplyParagonBonusFeat(oCreature, FEAT_RESIST_DISEASE); + } + break; + //:: Resist Poison + case 17: + { + ApplyParagonBonusFeat(oCreature, FEAT_RESIST_POISON); + } + break; + } +} + +//:: Check & apply the feat using EffectBonusFeat if it +//:: doesn't exist on the creature already +void ApplyParagonBonusFeat(object oCreature, int iFeat) +{ + // If the creature does not already have the feat, apply it + if (!GetHasFeat(iFeat, oCreature)) + { + effect eFeat = EffectBonusFeat(iFeat); + effect eLink = UnyieldingEffect(eFeat); + ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oCreature); + } + else + { + DelayCommand(0.0f, PickParagonBonusFeat(oCreature)); + } +} + +//:: Apply Paragon effects to a non-PC creature +void ApplyParagonEffects(object oCreature, int nBaseHD, int nBaseCR) +{ +//:: Declare major variables + int nNewCR; + + effect eParagon; + +//:: Set maximum hit points for each HD + int nParagonHP = (GetMaxPossibleHP(oCreature) + (nBaseHD * GetAbilityModifier(ABILITY_CONSTITUTION, oCreature))); + SetCurrentHitPoints(oCreature, nParagonHP); + +//:: Tripling the speed for all movement types + eParagon = EffectLinkEffects(eParagon, EffectMovementSpeedIncrease(300)); + +//:: +25 luck bonus on all attack rolls + eParagon = EffectLinkEffects(eParagon, EffectAttackIncrease(25)); + +//:: +20 luck bonus on damage rolls for melee and thrown ranged attacks + eParagon = EffectLinkEffects(eParagon, EffectDamageIncrease(20)); + +//:: AC Bonuses: +12 insight, +12 luck + eParagon = EffectLinkEffects(eParagon, EffectACIncrease(12, AC_DODGE_BONUS)); + eParagon = EffectLinkEffects(eParagon, EffectACIncrease(12, AC_DEFLECTION_BONUS)); + +//:: Boost caster & SLA level by 15 + SetLocalInt(oCreature, PRC_CASTERLEVEL_ADJUSTMENT, 15); + +//:: Fire and cold resistance 10, or keep the higher existing resistance if applicable + eParagon = EffectLinkEffects(eParagon, EffectDamageResistance(DAMAGE_TYPE_FIRE, 10)); + eParagon = EffectLinkEffects(eParagon, EffectDamageResistance(DAMAGE_TYPE_COLD, 10)); + +//:: Damage Reduction 20/epic or retain existing DR if higher + eParagon = EffectLinkEffects(eParagon, EffectDamageReduction(20, DAMAGE_POWER_ENERGY)); + +//:: Spell Resistance equal to CR +10, or retain existing SR if higher + int iExSR = GetSpellResistance(oCreature); + int nSpellResistance; + + if (iExSR < nBaseCR + 10) + { + nSpellResistance = nBaseCR + 10; + } + else + { + nSpellResistance = 0; + } + + eParagon = EffectLinkEffects(eParagon, EffectSpellResistanceIncrease(nSpellResistance)); + +//:: Fast Healing 20 + eParagon = EffectLinkEffects(eParagon, EffectRegenerate(20, 6.0f)); + +//:: Saving Throws: +10 insight bonus on all saving throws + eParagon = EffectLinkEffects(eParagon, EffectSavingThrowIncrease(SAVING_THROW_ALL, 10)); + +//:: Skills: +10 competence bonus to all skill checks + int nSkillID = 0; + + while (TRUE) + { + //:: Get & check skill + string sSkillLabel = Get2DACache("skills", "Label", nSkillID); + + //:: Break when out of skills + if (sSkillLabel == "") + break; + + //:: Apply the skill increase effect for the current skill + eParagon = EffectLinkEffects(eParagon, EffectSkillIncrease(nSkillID, 10)); + + + //:: Move to the next skill ID + nSkillID++; + } + +//:: Two free general feats. + PickParagonBonusFeat(oCreature); + PickParagonBonusFeat(oCreature); + + eParagon = UnyieldingEffect(eParagon); + + ApplyEffectToObject(DURATION_TYPE_PERMANENT, eParagon, oCreature); +} + +// Build and return all effects for the Celestial Template +effect CelestialTemplateEffects(int nHD) +{ + int nResist; + int nDRAmount; + int nDRBypass; + + // ------------------------- + // Elemental Resistances + // ------------------------- + // 1–7 HD = 5 + // 8+ HD = 10 + if (nHD >= 8) + { + nResist = 10; + } + else + { + nResist = 5; + } + + // ------------------------- + // Damage Reduction + // ------------------------- + // 1–3 HD = none + // 4–11 HD = 5/magic + // 12+ HD = 10/magic + if (nHD >= 12) + { + nDRAmount = 10; + nDRBypass = DAMAGE_POWER_PLUS_ONE; // DR 10/magic + } + else if (nHD >= 4) + { + nDRAmount = 5; + nDRBypass = DAMAGE_POWER_PLUS_ONE; // DR 5/magic + } + else + { + nDRAmount = 0; + nDRBypass = 0; // no DR + } + + // ------------------------- + // Build Effects + // ------------------------- + effect eEffects; + effect eRes; + + // Acid + eRes = EffectDamageResistance(DAMAGE_TYPE_ACID, nResist, 0); + eEffects = eRes; + + // Cold + eRes = EffectDamageResistance(DAMAGE_TYPE_COLD, nResist, 0); + eEffects = EffectLinkEffects(eEffects, eRes); + + // Electricity + eRes = EffectDamageResistance(DAMAGE_TYPE_ELECTRICAL, nResist, 0); + eEffects = EffectLinkEffects(eEffects, eRes); + + // DR if any + if (nDRAmount > 0) + { + effect eDR = EffectDamageReduction(nDRAmount, nDRBypass, 0); + eEffects = EffectLinkEffects(eEffects, eDR); + } + + eEffects = UnyieldingEffect(eEffects); + + return eEffects; +} + + + +void ReallyEquipItemInSlot(object oNPC, object oItem, int nSlot) +{ + if (GetItemInSlot(nSlot) != oItem) + { + //ClearAllActions(); + AssignCommand(oNPC, ActionEquipItem(oItem, nSlot)); + DelayCommand(0.5, ReallyEquipItemInSlot(oNPC, oItem, nSlot)); + } +} + +// Get the size of a JSON array +int GetJsonArraySize(json jArray) +{ + int iSize = 0; + while (JsonArrayGet(jArray, iSize) != JsonNull()) + { + iSize++; + } + return iSize; +} + +int CheckForWeapon(object oCreature) +{ + if (GetIsWeapon(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oCreature)) == 1 || GetIsWeapon(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oCreature)) == 1) + { + // oCreature has a weapon in at least one hand + return TRUE; + } + else + { + // oCreature doesn't have a weapon in either hand + return FALSE; + } +} + +//:: Adds Psuedonatural resistances & DR. +void ApplyPseudonaturalEffects(object oCreature) +{ + if(!GetIsObjectValid(oCreature)) return; + + int nHD = GetHitDice(oCreature); + if(DEBUG) DoDebug("prc_inc_json >> ApplyPseudonaturalEffects: nHD is: "+IntToString(nHD)+"."); + // ------------------------- + // Spell Resistance + // SR = 10 + HD (max 25) + // ------------------------- + int nSR = 10 + nHD; + if(nSR > 25) nSR = 25; + + effect eSR = EffectSpellResistanceIncrease(nSR); + eSR = TagEffect(eSR, "PSEUDO_SR"); + eSR = EffectLinkEffects(eSR, UnyieldingEffect(eSR)); + ApplyEffectToObject(DURATION_TYPE_PERMANENT, eSR, oCreature); + + // ------------------------- + // Acid/Electricity Resistance + // Reference Table: + // HD 1–3 : Resist 5 + // HD 4–7 : Resist 5 + // HD 8–11 : Resist 10 + // HD >=12 : Resist 15 + // ------------------------- + int nResist; + + if(nHD <= 7) nResist = 5; + else if(nHD <=11) nResist = 10; + else nResist = 15; + + effect eResAcid = EffectDamageResistance(DAMAGE_TYPE_ACID, nResist); + eResAcid = TagEffect(eResAcid, "PSEUDO_RES_ACID"); + eResAcid = EffectLinkEffects(eResAcid, UnyieldingEffect(eResAcid)); + + effect eResElec = EffectDamageResistance(DAMAGE_TYPE_ELECTRICAL, nResist); + eResElec = TagEffect(eResElec, "PSEUDO_RES_ELEC"); + eResElec = EffectLinkEffects(eResElec, UnyieldingEffect(eResElec)); + + ApplyEffectToObject(DURATION_TYPE_PERMANENT, eResAcid, oCreature); + ApplyEffectToObject(DURATION_TYPE_PERMANENT, eResElec, oCreature); + + // ------------------------- + // Damage Reduction + // Reference Table: + // HD 1–3 : none + // HD 4–7 : DR 5 / magic + // HD 8–11 : DR 5 / magic + // HD >=12 : DR 10 / magic + // ------------------------- + + int nDR; + if(nHD <= 3) { nDR = 0; } + else if(nHD <= 11) { nDR = 5; } + else { nDR = 10; } + + effect eDR = EffectDamageReduction(nDR, DAMAGE_POWER_PLUS_ONE, 0, FALSE); + eDR = TagEffect(eDR, "PSEUDO_DR_MAGIC"); + eDR = EffectLinkEffects(eDR, UnyieldingEffect(eDR)); + ApplyEffectToObject(DURATION_TYPE_PERMANENT, eDR, oCreature); +} + + +//::---------------------------------------------| +//:: JSON functions | +//::---------------------------------------------| + +//:: Returns the Constitution value from a GFF creature UTC +int json_GetCONValue(json jCreature) +{ + int nCon = 0; // default if missing + + // Check if the Con field exists + if (GffGetFieldExists(jCreature, "Con")) + { + nCon = JsonGetInt(GffGetByte(jCreature, "Con")); + } + + return nCon; +} + +//:: Returns the Challenge Rating from a GFF creature UTC +float json_GetChallengeRating(json jCreature) +{ + float fCR = 0.25; // default if missing + + if (GffGetFieldExists(jCreature, "ChallengeRating")) + { + json jCR = GffGetFloat(jCreature, "ChallengeRating"); + if (jCR != JsonNull()) + { + fCR = JsonGetFloat(jCR); + } + } + + return fCR; +} + +//:: Returns the integer value of a VarTable entry named sVarName, or 0 if not found. +int json_GetLocalIntFromVarTable(json jCreature, string sVarName) +{ + json jVarTable = GffGetList(jCreature, "VarTable"); + if (jVarTable == JsonNull()) + return 0; + + int nCount = JsonGetLength(jVarTable); + int i; + for (i = 0; i < nCount; i++) + { + json jEntry = JsonArrayGet(jVarTable, i); + if (jEntry == JsonNull()) continue; + + // Get the Name field using GFF functions + json jName = GffGetString(jEntry, "Name"); + if (jName == JsonNull()) continue; + string sName = JsonGetString(jName); + + if (sName == sVarName) + { + // Get the Type field to verify it's an integer + json jType = GffGetDword(jEntry, "Type"); + if (jType != JsonNull()) + { + int nType = JsonGetInt(jType); + if (nType == 1) // Type 1 = integer + { + // Get the Value field using GFF functions + json jValue = GffGetInt(jEntry, "Value"); + if (jValue == JsonNull()) return 0; + return JsonGetInt(jValue); + } + } + } + } + + return 0; +} + +//:: Returns the string value of a VarTable entry named sVarName, or "" if not found. +string json_GetLocalStringFromVarTable(json jCreature, string sVarName) +{ + json jVarTable = GffGetList(jCreature, "VarTable"); + if (jVarTable == JsonNull()) + return ""; + + int nCount = JsonGetLength(jVarTable); + int i; + for (i = 0; i < nCount; i++) + { + json jEntry = JsonArrayGet(jVarTable, i); + if (jEntry == JsonNull()) continue; + + // Get the Name field using GFF functions + json jName = GffGetString(jEntry, "Name"); + if (jName == JsonNull()) continue; + string sName = JsonGetString(jName); + + if (sName == sVarName) + { + // Get the Type field to verify it's a string + json jType = GffGetDword(jEntry, "Type"); + if (jType != JsonNull()) + { + int nType = JsonGetInt(jType); + if (nType == 3) // Type 3 = string + { + // Get the Value field using GFF functions + json jValue = GffGetString(jEntry, "Value"); + if (jValue == JsonNull()) return ""; + return JsonGetString(jValue); + } + } + } + } + + return ""; +} + +//:: Returns the total Hit Dice from a JSON'd creature GFF. +int json_GetCreatureHD(json jCreature) +{ + int nHD = 0; + + json jClasses = GffGetList(jCreature, "ClassList"); + if (jClasses == JsonNull()) + return 0; + + int nCount = JsonGetLength(jClasses); + int i; + for (i = 0; i < nCount; i = i + 1) + { + json jClass = JsonArrayGet(jClasses, i); + if (jClass == JsonNull()) + continue; + + json jLevel = GffGetShort(jClass, "ClassLevel"); // Use GffGetShort, not GffGetField + if (jLevel != JsonNull()) + { + int nLevel = JsonGetInt(jLevel); + nHD += nLevel; + } + } + + if (nHD <= 0) nHD = 1; + return nHD; +} + +json json_RecalcMaxHP(json jCreature, int iHitDieValue) +{ + int iHD = json_GetCreatureHD(jCreature); + + //:: Retrieve the RacialType field + json jRacialTypeField = JsonObjectGet(jCreature, "Race"); + int nRacialType = JsonGetInt(jRacialTypeField); + + //:: Retrieve the CreatureSize from the creature appearance field + json jAppearanceField = JsonObjectGet(jCreature, "Appearance_Type"); + int nAppearance = JsonGetInt(jAppearanceField); + + int nSize = StringToInt(Get2DAString("appearance", "SizeCategory", nAppearance)); + + //CEP adds other sizes, take them into account too + if(nSize == 20) + nSize = CREATURE_SIZE_DIMINUTIVE; + else if(nSize == 21) + nSize = CREATURE_SIZE_FINE; + else if(nSize == 22) + nSize = CREATURE_SIZE_GARGANTUAN; + else if(nSize == 23) + nSize = CREATURE_SIZE_COLOSSAL; + + int iNewMaxHP = (iHitDieValue * iHD); + + if(nRacialType == RACIAL_TYPE_CONSTRUCT) + { + if(nSize == CREATURE_SIZE_FINE) iNewMaxHP += 0; + if(nSize == CREATURE_SIZE_DIMINUTIVE) iNewMaxHP += 0; + if(nSize == CREATURE_SIZE_TINY) iNewMaxHP += 0; + if(nSize == CREATURE_SIZE_SMALL) iNewMaxHP += 10; + if(nSize == CREATURE_SIZE_MEDIUM) iNewMaxHP += 20; + if(nSize == CREATURE_SIZE_LARGE) iNewMaxHP += 30; + if(nSize == CREATURE_SIZE_HUGE) iNewMaxHP += 40; + if(nSize == CREATURE_SIZE_GARGANTUAN) iNewMaxHP += 60; + } + + if(DEBUG) DoDebug("prc_inc_json >> json_RecalcMaxHP | New MaxHP is: "+IntToString(iNewMaxHP)+ "."); + + jCreature = GffReplaceShort(jCreature, "MaxHitPoints", iNewMaxHP); + jCreature = GffReplaceShort(jCreature, "CurrentHitPoints", iNewMaxHP); + jCreature = GffReplaceShort(jCreature, "HitPoints", iNewMaxHP); + +/* SendMessageToPC(GetFirstPC(), "HD = " + IntToString(iHD)); + SendMessageToPC(GetFirstPC(), "HitDieValue = " + IntToString(iHitDieValue)); + SendMessageToPC(GetFirstPC(), "CON = " + IntToString(iCON)); + SendMessageToPC(GetFirstPC(), "Mod = " + IntToString(iMod)); + SendMessageToPC(GetFirstPC(), "New HP = " + IntToString(iNewMaxHP)); */ + + return jCreature; +} + +//:: Reads ABILITY_TO_INCREASE from creature's VarTable and applies stat boosts based on increased HD +json json_ApplyAbilityBoostFromHD(json jCreature, int nOriginalHD) +{ + if (jCreature == JsonNull()) + return jCreature; + + // Get the ability to increase from VarTable + int nAbilityToIncrease = json_GetLocalIntFromVarTable(jCreature, "ABILITY_TO_INCREASE"); + if (nAbilityToIncrease < 0 || nAbilityToIncrease > 5) + { + DoDebug("json_ApplyAbilityBoostFromHD: Invalid ABILITY_TO_INCREASE value: " + IntToString(nAbilityToIncrease)); + return jCreature; // Invalid ability index + } + + // Calculate total current HD from ClassList + json jClassList = GffGetList(jCreature, "ClassList"); + if (jClassList == JsonNull()) + { + DoDebug("json_ApplyAbilityBoostFromHD: Failed to get ClassList"); + return jCreature; + } + + int nCurrentTotalHD = 0; + int nClassCount = JsonGetLength(jClassList); + int i; + + for (i = 0; i < nClassCount; i++) + { + json jClass = JsonArrayGet(jClassList, i); + if (jClass != JsonNull()) + { + json jClassLevel = GffGetShort(jClass, "ClassLevel"); + if (jClassLevel != JsonNull()) + { + nCurrentTotalHD += JsonGetInt(jClassLevel); + } + } + } + + if(DEBUG) DoDebug("prc_inc_json >> json_ApplyAbilityBoostFromHD: nCurrentTotalHD = "+IntToString(nCurrentTotalHD)+"."); + + if (nCurrentTotalHD <= 0) + { + DoDebug("json_ApplyAbilityBoostFromHD: No valid Hit Dice found"); + return jCreature; + } + + // Calculate stat boosts based on crossing level thresholds + // Characters get stat boosts at levels 4, 8, 12, 16, 20, etc. + int nOriginalBoosts = nOriginalHD / 4; // How many boosts they already had + int nCurrentBoosts = nCurrentTotalHD / 4; // How many they should have now + int nBoosts = nCurrentBoosts - nOriginalBoosts; // Additional boosts to apply + + if (nBoosts <= 0) + { + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: No boosts needed (Original boosts: " + IntToString(nOriginalBoosts) + ", Current boosts: " + IntToString(nCurrentBoosts) + ")"); + return jCreature; + } + + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Applying " + IntToString(nBoosts) + " boosts to ability " + IntToString(nAbilityToIncrease) + " for HD increase from " + IntToString(nOriginalHD) + " to " + IntToString(nCurrentTotalHD)); + + // Determine which ability to boost and apply the increases + string sAbilityField; + switch (nAbilityToIncrease) + { + case 0: sAbilityField = "Str"; break; + case 1: sAbilityField = "Dex"; break; + case 2: sAbilityField = "Con"; break; + case 3: sAbilityField = "Int"; break; + case 4: sAbilityField = "Wis"; break; + case 5: sAbilityField = "Cha"; break; + default: + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Unknown ability index: " + IntToString(nAbilityToIncrease)); + return jCreature; + } + + // Get current ability score + json jCurrentAbility = GffGetByte(jCreature, sAbilityField); + if (jCurrentAbility == JsonNull()) + { + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Failed to get " + sAbilityField + " score"); + return jCreature; + } + + int nCurrentScore = JsonGetInt(jCurrentAbility); + int nNewScore = nCurrentScore + nBoosts; + + // Clamp to valid byte range + if (nNewScore < 1) nNewScore = 1; + if (nNewScore > 250) nNewScore = 250; + + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Increasing " + sAbilityField + " from " + IntToString(nCurrentScore) + " to " + IntToString(nNewScore)); + + // Apply the ability score increase + jCreature = GffReplaceByte(jCreature, sAbilityField, nNewScore); + if (jCreature == JsonNull()) + { + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Failed to update " + sAbilityField); + return JsonNull(); + } + + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Successfully applied ability boosts"); + return jCreature; +} + +//:: Adjust a skill by its ID +json json_AdjustCreatureSkillByID(json jCreature, int nSkillID, int nMod) +{ + // Get the SkillList + json jSkillList = GffGetList(jCreature, "SkillList"); + if (jSkillList == JsonNull()) + { + if(DEBUG) DoDebug("json_AdjustCreatureSkillByID: Failed to get SkillList"); + return jCreature; + } + + // Check if we have enough skills in the list + int nSkillCount = JsonGetLength(jSkillList); + if (nSkillID >= nSkillCount) + { + if(DEBUG) DoDebug("json_AdjustCreatureSkillByID: Skill ID " + IntToString(nSkillID) + " exceeds skill list length " + IntToString(nSkillCount)); + return jCreature; + } + + // Get the skill struct at the correct index + json jSkill = JsonArrayGet(jSkillList, nSkillID); + if (jSkill == JsonNull()) + { + if(DEBUG) DoDebug("json_AdjustCreatureSkillByID: Failed to get skill at index " + IntToString(nSkillID)); + return jCreature; + } + + // Get current rank + json jRank = GffGetByte(jSkill, "Rank"); + if (jRank == JsonNull()) + { + if(DEBUG) DoDebug("json_AdjustCreatureSkillByID: Failed to get Rank for skill ID " + IntToString(nSkillID)); + return jCreature; + } + + int nCurrentRank = JsonGetInt(jRank); + int nNewRank = nCurrentRank + nMod; + + // Clamp to valid range + if (nNewRank < 0) nNewRank = 0; + if (nNewRank > 127) nNewRank = 127; + + // Update the rank in the skill struct + jSkill = GffReplaceByte(jSkill, "Rank", nNewRank); + if (jSkill == JsonNull()) + { + if(DEBUG) DoDebug("json_AdjustCreatureSkillByID: Failed to replace Rank for skill ID " + IntToString(nSkillID)); + return JsonNull(); + } + + // Replace the skill in the array + jSkillList = JsonArraySet(jSkillList, nSkillID, jSkill); + + // Replace the SkillList in the creature + jCreature = GffReplaceList(jCreature, "SkillList", jSkillList); + + return jCreature; +} + +//:: Reads FutureFeat1..FutureFeatN from the template's VarTable and appends them to FeatList if missing. +json json_AddFeatsFromCreatureVars(json jCreature, int nOriginalHD) +{ + if (jCreature == JsonNull()) + return jCreature; + + // Calculate current total HD + int nCurrentHD = json_GetCreatureHD(jCreature); + int nAddedHD = nCurrentHD - nOriginalHD; + + if (nAddedHD <= 0) + { + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: No additional HD to process (Current: " + IntToString(nCurrentHD) + ", Original: " + IntToString(nOriginalHD) + ")"); + return jCreature; + } + + // Calculate how many feats the creature should get based on added HD + // Characters get a feat at levels 1, 3, 6, 9, 12, 15, 18, etc. + // For added levels, we need to check what feat levels they cross + int nOriginalFeats = (nOriginalHD + 2) / 3; // Feats from original HD + int nCurrentFeats = (nCurrentHD + 2) / 3; // Feats from current HD + int nNumFeats = nCurrentFeats - nOriginalFeats; // Additional feats earned + + if (nNumFeats <= 0) + { + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: No additional feats earned from " + IntToString(nAddedHD) + " added HD"); + return jCreature; + } + + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Processing " + IntToString(nNumFeats) + " feats for " + IntToString(nAddedHD) + " added HD (Original: " + IntToString(nOriginalHD) + ", Current: " + IntToString(nCurrentHD) + ")"); + + // Get or create FeatList + json jFeatArray = GffGetList(jCreature, "FeatList"); + if (jFeatArray == JsonNull()) + jFeatArray = JsonArray(); + + int nOriginalFeatCount = JsonGetLength(jFeatArray); + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Original feat count: " + IntToString(nOriginalFeatCount)); + + int nAdded = 0; + int i = 0; + int nMaxIterations = 100; // Safety valve + int nIterations = 0; + + while (nAdded < nNumFeats && nIterations < nMaxIterations) + { + nIterations++; + string sVarName = "FutureFeat" + IntToString(i); + + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Checking " + sVarName); + + int nFeat = json_GetLocalIntFromVarTable(jCreature, sVarName); + + if (nFeat <= 0) + { + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: " + sVarName + " not found or invalid"); + i++; + continue; + } + + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Found " + sVarName + " = " + IntToString(nFeat)); + + // Check if feat already exists + int bHasFeat = FALSE; + int nFeatCount = JsonGetLength(jFeatArray); + int j; + + for (j = 0; j < nFeatCount; j++) + { + json jFeatStruct = JsonArrayGet(jFeatArray, j); + if (jFeatStruct != JsonNull()) + { + json jFeatValue = GffGetWord(jFeatStruct, "Feat"); + if (jFeatValue != JsonNull() && JsonGetInt(jFeatValue) == nFeat) + { + bHasFeat = TRUE; + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Feat " + IntToString(nFeat) + " already exists"); + break; + } + } + } + + // Insert if missing + if (!bHasFeat) + { + json jNewFeat = JsonObject(); + jNewFeat = JsonObjectSet(jNewFeat, "__struct_id", JsonInt(1)); + jNewFeat = GffAddWord(jNewFeat, "Feat", nFeat); + + if (jNewFeat == JsonNull()) + { + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Failed to create feat struct for feat " + IntToString(nFeat)); + break; + } + + jFeatArray = JsonArrayInsert(jFeatArray, jNewFeat); + nAdded++; + + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Added feat " + IntToString(nFeat) + " (" + IntToString(nAdded) + "/" + IntToString(nNumFeats) + ")"); + } + + i++; + + // Safety break if we've checked too many variables + if (i > 100) + { + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Safety break - checked too many FutureFeat variables"); + break; + } + } + + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Completed. Added " + IntToString(nAdded) + " feats in " + IntToString(nIterations) + " iterations"); + + // Save back the modified FeatList only if we added something + if (nAdded > 0) + { + jCreature = GffReplaceList(jCreature, "FeatList", jFeatArray); + if (jCreature == JsonNull()) + { + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Failed to replace FeatList"); + return JsonNull(); + } + } + + return jCreature; +} + +//:: Get the size of a JSON array +int json_GetArraySize(json jArray) +{ + int iSize = 0; + while (JsonArrayGet(jArray, iSize) != JsonNull()) + { + iSize++; + } + return iSize; +} + +//:: Directly updates oCreature's Base Natural AC if iNewAC is higher. +//:: +json json_UpdateBaseAC(json jCreature, int iNewAC) +{ + //json jBaseAC = GffGetByte(jCreature, "Creature/value/NaturalAC/value"); + json jBaseAC = GffGetByte(jCreature, "NaturalAC"); + + if (jBaseAC == JsonNull()) + { + return JsonNull(); + } + else if (JsonGetInt(jBaseAC) > iNewAC) + { + return jCreature; + } + else + { + jCreature = GffReplaceByte(jCreature, "NaturalAC", iNewAC); + + return jCreature; + } +} + +//:: Increases jCreature's Natural AC by iAddAC. +//:: +json json_IncreaseBaseAC(json jCreature, int iAddAC) +{ + json jBaseAC = GffGetByte(jCreature, "NaturalAC"); + + if (jBaseAC == JsonNull()) + { + return JsonNull(); + } + else + { + int nBaseAC = JsonGetInt(jBaseAC); // convert JSON number -> int + int nNewAC = nBaseAC + iAddAC; + + jCreature = GffReplaceByte(jCreature, "NaturalAC", nNewAC); + return jCreature; + } +} + +//:: Directly modifies jCreature's Challenge Rating. +//:: This is useful for most XP calculations. +json json_UpdateCR(json jCreature, int nBaseCR, int nCRMod) +{ + int nNewCR; + +//:: Add CRMod to current CR + nNewCR = nBaseCR + nCRMod; + +//:: Modify Challenge Rating + jCreature = GffReplaceFloat(jCreature, "ChallengeRating", IntToFloat(nNewCR)); + + return jCreature; +} + +//:: Directly modifies ability scores in a creature's JSON GFF. +//:: +json json_UpdateTemplateStats(json jCreature, int iModStr = 0, int iModDex = 0, int iModCon = 0, int iModInt = 0, int iModWis = 0, int iModCha = 0) +{ + int iCurrent; + + // STR + if (!GffGetFieldExists(jCreature, "Str", GFF_FIELD_TYPE_BYTE)) + jCreature = GffAddByte(jCreature, "Str", 10); + iCurrent = JsonGetInt(GffGetByte(jCreature, "Str")); + jCreature = GffReplaceByte(jCreature, "Str", iCurrent + iModStr); + + // DEX + if (!GffGetFieldExists(jCreature, "Dex", GFF_FIELD_TYPE_BYTE)) + jCreature = GffAddByte(jCreature, "Dex", 10); + iCurrent = JsonGetInt(GffGetByte(jCreature, "Dex")); + jCreature = GffReplaceByte(jCreature, "Dex", iCurrent + iModDex); + + // CON + if (!GffGetFieldExists(jCreature, "Con", GFF_FIELD_TYPE_BYTE)) + jCreature = GffAddByte(jCreature, "Con", 10); + iCurrent = JsonGetInt(GffGetByte(jCreature, "Con")); + jCreature = GffReplaceByte(jCreature, "Con", iCurrent + iModCon); + + // INT + if (!GffGetFieldExists(jCreature, "Int", GFF_FIELD_TYPE_BYTE)) + jCreature = GffAddByte(jCreature, "Int", 10); + iCurrent = JsonGetInt(GffGetByte(jCreature, "Int")); + jCreature = GffReplaceByte(jCreature, "Int", iCurrent + iModInt); + + // WIS + if (!GffGetFieldExists(jCreature, "Wis", GFF_FIELD_TYPE_BYTE)) + jCreature = GffAddByte(jCreature, "Wis", 10); + iCurrent = JsonGetInt(GffGetByte(jCreature, "Wis")); + jCreature = GffReplaceByte(jCreature, "Wis", iCurrent + iModWis); + + // CHA + if (!GffGetFieldExists(jCreature, "Cha", GFF_FIELD_TYPE_BYTE)) + jCreature = GffAddByte(jCreature, "Cha", 10); + iCurrent = JsonGetInt(GffGetByte(jCreature, "Cha")); + jCreature = GffReplaceByte(jCreature, "Cha", iCurrent + iModCha); + + return jCreature; +} + +//:: Directly modifies oCreature's ability scores. +//:: +json json_UpdateCreatureStats(json jCreature, object oBaseCreature, int iModStr = 0, int iModDex = 0, int iModCon = 0, int iModInt = 0, int iModWis = 0, int iModCha = 0) +{ +//:: Retrieve and modify ability scores + int iCurrentStr = GetAbilityScore(oBaseCreature, ABILITY_STRENGTH); + int iCurrentDex = GetAbilityScore(oBaseCreature, ABILITY_DEXTERITY); + int iCurrentCon = GetAbilityScore(oBaseCreature, ABILITY_CONSTITUTION); + int iCurrentInt = GetAbilityScore(oBaseCreature, ABILITY_INTELLIGENCE); + int iCurrentWis = GetAbilityScore(oBaseCreature, ABILITY_WISDOM); + int iCurrentCha = GetAbilityScore(oBaseCreature, ABILITY_CHARISMA); + + jCreature = GffReplaceByte(jCreature, "Str", iCurrentStr + iModStr); + jCreature = GffReplaceByte(jCreature, "Dex", iCurrentDex + iModDex); + jCreature = GffReplaceByte(jCreature, "Con", iCurrentCon + iModCon); + jCreature = GffReplaceByte(jCreature, "Int", iCurrentInt + iModInt); + jCreature = GffReplaceByte(jCreature, "Wis", iCurrentWis + iModWis); + jCreature = GffReplaceByte(jCreature, "Cha", iCurrentCha + iModCha); + + return jCreature; +} + +//:: Increases a creature's Hit Dice in its JSON GFF data by nAmount +json json_AddHitDice(json jCreature, int nAmount) +{ + if (jCreature == JsonNull() || nAmount <= 0) + return jCreature; + + // Get the ClassList + json jClasses = GffGetList(jCreature, "ClassList"); + if (jClasses == JsonNull() || JsonGetLength(jClasses) == 0) + return jCreature; + + // Grab the first class entry + json jFirstClass = JsonArrayGet(jClasses, 0); + + json jCurrentLevel = GffGetShort(jFirstClass, "ClassLevel"); + int nCurrentLevel = JsonGetInt(jCurrentLevel); + int nNewLevel = nCurrentLevel + nAmount; + + // Replace ClassLevel only + jFirstClass = GffReplaceShort(jFirstClass, "ClassLevel", nNewLevel); + + // Put modified class back into the array + jClasses = JsonArraySet(jClasses, 0, jFirstClass); + + // Replace ClassList in the creature JSON + jCreature = GffReplaceList(jCreature, "ClassList", jClasses); + + return jCreature; +} + +//:: Adjusts a creature's size by nSizeChange (-4 to +4) and updates ability scores accordingly. +json json_AdjustCreatureSize(json jCreature, int nSizeDelta, int nIncorporeal = FALSE) +{ + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Entering function. nSizeDelta=" + IntToString(nSizeDelta)); + + if (jCreature == JsonNull() || nSizeDelta == 0) + { + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Exiting: jCreature is null or nSizeDelta is 0"); + return jCreature; + } + + // Get Appearance_Type using GFF functions + json jAppearanceType = GffGetWord(jCreature, "Appearance_Type"); + if (jAppearanceType == JsonNull()) + { + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed to get Appearance_Type"); + return jCreature; + } + + int nAppearance = JsonGetInt(jAppearanceType); + int nCurrentSize = StringToInt(Get2DAString("appearances", "Size", nAppearance)); + + // Default to Medium (4) if invalid + if (nCurrentSize < 0 || nCurrentSize > 8) nCurrentSize = 4; + + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Appearance_Type =" + IntToString(nAppearance) + ", Size =" + IntToString(nCurrentSize)); + + int nSteps = nSizeDelta; + + // Calculate modifiers based on size change + int strMod = nSteps * 4; + int dexMod = nSteps * -1; + int conMod = nSteps * 2; + int naturalAC = nSteps * 1; + int dexSkillMod = nSteps * -2; + + if(nIncorporeal) + { + strMod = 0; + } + + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Applying stat modifiers: STR=" + IntToString(strMod) + + " DEX=" + IntToString(dexMod) + + " CON=" + IntToString(conMod)); + + // Update ability scores using GFF functions with error checking + json jStr = GffGetByte(jCreature, "Str"); + if (jStr != JsonNull()) + { + int nNewStr = JsonGetInt(jStr) + strMod; + if (nNewStr < 1) nNewStr = 1; + if (nNewStr > 255) nNewStr = 255; + + jCreature = GffReplaceByte(jCreature, "Str", nNewStr); + if (jCreature == JsonNull()) + { + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed to update Str"); + return JsonNull(); + } + } + + json jDex = GffGetByte(jCreature, "Dex"); + if (jDex != JsonNull()) + { + int nNewDex = JsonGetInt(jDex) + dexMod; + if (nNewDex < 1) nNewDex = 1; + if (nNewDex > 255) nNewDex = 255; + + jCreature = GffReplaceByte(jCreature, "Dex", nNewDex); + if (jCreature == JsonNull()) + { + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed to update Dex"); + return JsonNull(); + } + } + + json jCon = GffGetByte(jCreature, "Con"); + if (jCon != JsonNull()) + { + int nNewCon = JsonGetInt(jCon) + conMod; + if (nNewCon < 1) nNewCon = 1; + if (nNewCon > 255) nNewCon = 255; + + jCreature = GffReplaceByte(jCreature, "Con", nNewCon); + if (jCreature == JsonNull()) + { + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed to update Con"); + return JsonNull(); + } + } + + // Update Natural AC + json jNaturalAC = GffGetByte(jCreature, "NaturalAC"); + if (jNaturalAC != JsonNull()) + { + int nCurrentNA = JsonGetInt(jNaturalAC); + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Current NaturalAC: " + IntToString(nCurrentNA)); + + int nNewNA = nCurrentNA + naturalAC; + if (nNewNA < 0) nNewNA = 0; + if (nNewNA > 255) nNewNA = 255; + + jCreature = GffReplaceByte(jCreature, "NaturalAC", nNewNA); + if (jCreature == JsonNull()) + { + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed to update NaturalAC"); + return JsonNull(); + } + } + + // Adjust all Dexterity-based skills by finding them in skills.2da + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Adjusting DEX-based skills"); + + int nSkillID = 0; + while (TRUE) + { + string sKeyAbility = Get2DAString("skills", "KeyAbility", nSkillID); + + // Break when we've reached the end of skills + if (sKeyAbility == "") + break; + + // If this skill uses Dexterity, adjust it + if (sKeyAbility == "DEX") + { + string sSkillLabel = Get2DAString("skills", "Label", nSkillID); + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Adjusting DEX skill: " + sSkillLabel + " (ID: " + IntToString(nSkillID) + ")"); + + jCreature = json_AdjustCreatureSkillByID(jCreature, nSkillID, dexSkillMod); + if (jCreature == JsonNull()) + { + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed adjusting skill ID " + IntToString(nSkillID)); + return JsonNull(); + } + } + + nSkillID++; + } + + if(DEBUG) DoDebug("json_AdjustCreatureSize completed successfully"); + return jCreature; +} + +//:: Changes jCreature's creature type. +json json_ModifyRacialType(json jCreature, int nNewRacialType) +{ + if(DEBUG)DoDebug("prc_inc_json >> json_ModifyRacialType: Entering function"); + + // Retrieve the RacialType field + json jRacialTypeField = JsonObjectGet(jCreature, "Race"); + + if (JsonGetType(jRacialTypeField) == JSON_TYPE_NULL) + { + DoDebug("prc_inc_json >> json_ModifyRacialType: JsonGetType error 1: " + JsonGetError(jRacialTypeField)); + //SpeakString("JsonGetType error 1: " + JsonGetError(jRacialTypeField)); + return JsonNull(); + } + + // Retrieve the value to modify + json jRacialTypeValue = JsonObjectGet(jRacialTypeField, "value"); + + if (JsonGetType(jRacialTypeValue) != JSON_TYPE_INTEGER) + { + DoDebug("prc_inc_json >> json_ModifyRacialType: JsonGetType error 2: " + JsonGetError(jRacialTypeValue)); + //SpeakString("JsonGetType error 2: " + JsonGetError(jRacialTypeValue)); + return JsonNull(); + } + + jCreature = GffReplaceByte(jCreature, "Race", nNewRacialType); + + // Return the new creature object + return jCreature; +} + +//:: Updates CR for Celestial template +json json_UpdateCelestialCR(json jCreature, int nBaseCR, int nHD) +{ + int nNewCR; + + //:: Calculate CR based on HD + if (nHD <= 3) + { + nNewCR = nBaseCR; + } + else if (nHD <= 7) + { + nNewCR = nBaseCR + 1; + } + else + { + nNewCR = nBaseCR + 2; + } + + //:: Modify Challenge Rating + jCreature = GffReplaceFloat(jCreature, "ChallengeRating", IntToFloat(nNewCR)); + return jCreature; +} + +//:: Adds Celestial SLA's to creature +json json_AddCelestialPowers(json jCreature) +{ + // Get the existing SpecAbilityList + json jSpecAbilityList = GffGetList(jCreature, "SpecAbilityList"); + if (jSpecAbilityList == JsonNull()) + { + jSpecAbilityList = JsonArray(); + } + + //:: Add Smite Evil 1x / day + json jSpecAbility = JsonObject(); + jSpecAbility = GffAddWord(jSpecAbility, "Spell", SPELLABILITY_SMITE_EVIL); + jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", json_GetCreatureHD(jCreature)); + jSpecAbility = GffAddByte(jSpecAbility, "SpellFlags", 1); + jSpecAbilityList = JsonArrayInsert(jSpecAbilityList, jSpecAbility); + + //:: Add the list to the creature + jCreature = GffAddList(jCreature, "SpecAbilityList", jSpecAbilityList); + return jCreature; +} + +//:: Apply Celestial template to a creature JSON template +json json_MakeCelestial(json jCreature, int nBaseHD, int nBaseCR) +{ + if (jCreature == JsonNull()) + return JsonNull(); + + //:: Get current HD for scaling + int nHD = json_GetCreatureHD(jCreature); + if (nHD <= 0) + { + DoDebug("prc_inc_json >> json_MakeCelestial: Invalid HD"); + return JsonNull(); + } + + //:: Get current CR + float fCR = json_GetChallengeRating(jCreature); + + //:: Update CR using Celestial formula + jCreature = json_UpdateCelestialCR(jCreature, FloatToInt(fCR), nHD); + if (jCreature == JsonNull()) + { + DoDebug("prc_inc_json >> json_MakeCelestial: json_UpdateCelestialCR failed"); + return JsonNull(); + } + + //:: Ensure Intelligence is at least 4 + json jInt = GffGetByte(jCreature, "Int"); + if (jInt != JsonNull() && JsonGetInt(jInt) < 4) + { + jCreature = GffReplaceByte(jCreature, "Int", 4); + } + + //:: Add celestial Smite Evil + jCreature = json_AddCelestialPowers(jCreature); + if (jCreature == JsonNull()) + { + DoDebug("prc_inc_json >> json_MakeCelestial: json_AddCelestialPowers failed"); + return JsonNull(); + } + + //:: Change creature type if animal/beast/vermin to magical beast + int nRacialType = JsonGetInt(GffGetByte(jCreature, "Race")); + if (nRacialType == RACIAL_TYPE_ANIMAL || nRacialType == RACIAL_TYPE_VERMIN || nRacialType == RACIAL_TYPE_BEAST) + { + jCreature = json_ModifyRacialType(jCreature, RACIAL_TYPE_MAGICAL_BEAST); + } + + //:: Update creature CR + jCreature = json_UpdateCelestialCR(jCreature, nBaseCR, nHD); + if (jCreature == JsonNull()) + { + DoDebug("prc_inc_json >> json_MakeCelestial: json_UpdateCelestialCR failed"); + return JsonNull(); + } + + return jCreature; +} + +//:: Spawns a Celestial Companion from a template +object MakeCelestialCompanionFromTemplate(string sResref, location lSpawnLoc, int nHealerLvl) +{ + int nBonus = GetHealerCompanionBonus(nHealerLvl); + + json jCelestial = TemplateToJson(sResref, RESTYPE_UTC); + if (jCelestial == JSON_NULL) + { + DoDebug("prc_inc_json >> MakeCelestialCompanionFromTemplate: TemplateToJson failed — bad resref or resource missing."); + return OBJECT_INVALID; + } + + //:: Get local vars to transfer over. + int iMinHD = json_GetLocalIntFromVarTable(jCelestial, "iMinHD"); + int iMaxHD = json_GetLocalIntFromVarTable(jCelestial, "iMaxHD"); + int nOriginalHD = json_GetLocalIntFromVarTable(jCelestial, "nOriginalHD"); + int iClass2 = json_GetLocalIntFromVarTable(jCelestial, "Class2"); + int iClass2Package = json_GetLocalIntFromVarTable(jCelestial, "Class2Package"); + int iClass2Start = json_GetLocalIntFromVarTable(jCelestial, "Class2Start"); + int iBaseCL = json_GetLocalIntFromVarTable(jCelestial, "iBaseCL"); + int iMagicUse = json_GetLocalIntFromVarTable(jCelestial, "X2_L_BEH_MAGIC"); + string sAI = json_GetLocalStringFromVarTable(jCelestial, "X2_SPECIAL_COMBAT_AI_SCRIPT"); + + //:: Get the original Challenge Rating + int nBaseCR = FloatToInt(json_GetChallengeRating(jCelestial)); + + //:: Apply celestial template modifications + jCelestial = json_MakeCelestial(jCelestial, nBonus, nBaseCR); + if (jCelestial == JSON_NULL) + { + DoDebug("prc_inc_json >> MakeCelestialCompanionFromTemplate failed — json_MakeCelestial returned invalid JSON."); + return OBJECT_INVALID; + } + + //:: Apply +2 Natural AC bonus per 3 Healer levels + jCelestial = json_IncreaseBaseAC(jCelestial, nBonus); + if (jCelestial == JSON_NULL) + { + DoDebug("prc_inc_json >> MakeCelestialCompanionFromTemplate failed — json_IncreaseBaseAC returned invalid JSON."); + return OBJECT_INVALID; + } + + //:: +2 STR, DEX & INT per 3 Healer levels + jCelestial = json_UpdateTemplateStats(jCelestial, nBonus, nBonus, 0, nBonus, 0, 0); + if (jCelestial == JSON_NULL) + { + DoDebug("prc_inc_json >> MakeCelestialCompanionFromTemplate failed — json_UpdateTemplateStats returned invalid JSON."); + return OBJECT_INVALID; + } + + //:: The Companion always has Improved Evasion if the healer qualifies, + //:: but adding it this way gives the base creature more utility for builders. + if (nHealerLvl > 7) + { + //:: Add Improved Evasion feat directly to FeatList + json jFeatList = GffGetList(jCelestial, "FeatList"); + if (jFeatList == JsonNull()) + jFeatList = JsonArray(); + + //:: Check if creature already has Improved Evasion + int bHasFeat = FALSE; + int nFeatCount = JsonGetLength(jFeatList); + int j; + + for (j = 0; j < nFeatCount; j++) + { + json jFeatStruct = JsonArrayGet(jFeatList, j); + if (jFeatStruct != JsonNull()) + { + json jFeatValue = GffGetWord(jFeatStruct, "Feat"); + if (jFeatValue != JsonNull() && JsonGetInt(jFeatValue) == FEAT_IMPROVED_EVASION) + { + bHasFeat = TRUE; + break; + } + } + } + + //:: Add feat only if not already present + if (!bHasFeat) + { + json jNewFeat = JsonObject(); + jNewFeat = JsonObjectSet(jNewFeat, "__struct_id", JsonInt(1)); + jNewFeat = GffAddWord(jNewFeat, "Feat", FEAT_IMPROVED_EVASION); + + jFeatList = JsonArrayInsert(jFeatList, jNewFeat); + jCelestial = GffReplaceList(jCelestial, "FeatList", jFeatList); + } + } + + //:: Spawn the creature + object oCelestial = JsonToObject(jCelestial, lSpawnLoc); + + //:: Set variables for LevelUpSummon() + SetLocalInt(oCelestial, "TEMPLATE_CELESTIAL", 1); + SetLocalInt(oCelestial, "iMinHD", iMinHD); + SetLocalInt(oCelestial, "iMaxHD", iMaxHD); + SetLocalInt(oCelestial, "nOriginalHD", nOriginalHD); + SetLocalInt(oCelestial, "Class2", iClass2); + SetLocalInt(oCelestial, "Class2Package", iClass2Package); + SetLocalInt(oCelestial, "Class2Start", iClass2Start); + SetLocalInt(oCelestial, "iBaseCL", iBaseCL); + SetLocalInt(oCelestial, "X2_L_BEH_MAGIC", iMagicUse); + SetLocalString(oCelestial, "X2_SPECIAL_COMBAT_AI_SCRIPT", sAI); + + return oCelestial; +} + +//:: Spawns a Celestial creature from a template +object MakeCelestialCreatureFromTemplate(string sResref, location lSpawnLoc) +{ + json jCelestial = TemplateToJson(sResref, RESTYPE_UTC); + if (jCelestial == JSON_NULL) + { + DoDebug("prc_inc_json >> MakeCelestialCreatureFromTemplate: TemplateToJson failed — bad resref or resource missing."); + return OBJECT_INVALID; + } + + //:: Get current HD + int nCurrentHD = json_GetCreatureHD(jCelestial); + if (nCurrentHD <= 0) + { + DoDebug("make_celestial >> MakeCelestialCreatureFromTemplate failed — template missing HD data."); + return OBJECT_INVALID; + } + + //:: Get current CR + int nBaseCR = 1; + nBaseCR = FloatToInt(json_GetChallengeRating(jCelestial)); + if (nBaseCR <= 0) + { + DoDebug("make_celestial >> MakeCelestialCreatureFromTemplate failed — template missing CR data."); + return OBJECT_INVALID; + } + + //:: Get local vars to transfer over. + int iMinHD = json_GetLocalIntFromVarTable(jCelestial, "iMinHD"); + int iMaxHD = json_GetLocalIntFromVarTable(jCelestial, "iMaxHD"); + int nOriginalHD = json_GetLocalIntFromVarTable(jCelestial, "nOriginalHD"); + int iClass2 = json_GetLocalIntFromVarTable(jCelestial, "Class2"); + int iClass2Package = json_GetLocalIntFromVarTable(jCelestial, "Class2Package"); + int iClass2Start = json_GetLocalIntFromVarTable(jCelestial, "Class2Start"); + int iBaseCL = json_GetLocalIntFromVarTable(jCelestial, "iBaseCL"); + int iMagicUse = json_GetLocalIntFromVarTable(jCelestial, "X2_L_BEH_MAGIC"); + string sAI = json_GetLocalStringFromVarTable(jCelestial, "X2_SPECIAL_COMBAT_AI_SCRIPT"); + + //:: Apply celestial template modifications + jCelestial = json_MakeCelestial(jCelestial, nCurrentHD, nBaseCR); + if (jCelestial == JSON_NULL) + { + DoDebug("make_celestial >> MakeCelestialCreatureFromTemplate failed — MakeCelestial returned invalid JSON."); + return OBJECT_INVALID; + } + + //:: Spawn the creature + object oCelestial = JsonToObject(jCelestial, lSpawnLoc); + + //:: Set variables + SetLocalInt(oCelestial, "TEMPLATE_CELESTIAL", 1); + SetLocalInt(oCelestial, "iMinHD", iMinHD); + SetLocalInt(oCelestial, "iMaxHD", iMaxHD); + SetLocalInt(oCelestial, "nOriginalHD", nOriginalHD); + SetLocalInt(oCelestial, "Class2", iClass2); + SetLocalInt(oCelestial, "Class2Package", iClass2Package); + SetLocalInt(oCelestial, "Class2Start", iClass2Start); + SetLocalInt(oCelestial, "Class2Start", iClass2Start); + SetLocalInt(oCelestial, "iBaseCL", iBaseCL); + SetLocalInt(oCelestial, "X2_L_BEH_MAGIC", iMagicUse); + SetLocalString(oCelestial, "X2_SPECIAL_COMBAT_AI_SCRIPT", sAI); + + return oCelestial; +} + +//:: Adds Paragon SLA's to jCreature. +//:: +json json_AddParagonPowers(json jCreature) +{ + // Get the existing SpecAbilityList (if it exists) + json jSpecAbilityList = GffGetList(jCreature, "SpecAbilityList"); + + // Create the SpecAbilityList if it doesn't exist + if (jSpecAbilityList == JsonNull()) + { + jSpecAbilityList = JsonArray(); + } + +//:: Greater Dispelling 3x / Day + int i; + for (i = 0; i < 3; i++) + { + json jSpecAbility = JsonObject(); + jSpecAbility = GffAddWord(jSpecAbility, "Spell", 67); + jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", 15); + jSpecAbility = GffAddByte(jSpecAbility, "SpellFlags", 1); + + // Manually add to the array + jSpecAbilityList = JsonArrayInsert(jSpecAbilityList, jSpecAbility); + } + +//:: Add Haste 3x / Day + for (i = 0; i < 3; i++) + { + json jSpecAbility = JsonObject(); + jSpecAbility = GffAddWord(jSpecAbility, "Spell", 78); + jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", 15); + jSpecAbility = GffAddByte(jSpecAbility, "SpellFlags", 1); + + // Manually add to the array + jSpecAbilityList = JsonArrayInsert(jSpecAbilityList, jSpecAbility); + } + +//:: See Invisiblity 3x / Day + for (i = 0; i < 3; i++) + { + json jSpecAbility = JsonObject(); + jSpecAbility = GffAddWord(jSpecAbility, "Spell", 157); + jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", 15); + jSpecAbility = GffAddByte(jSpecAbility, "SpellFlags", 1); + + // Manually add to the array + jSpecAbilityList = JsonArrayInsert(jSpecAbilityList, jSpecAbility); + } + +//:: Add the list to the creature + jCreature = GffAddList(jCreature, "SpecAbilityList", jSpecAbilityList); + + return jCreature; +} + +//:: Directly modifies jCreature's Challenge Rating. +//:: This is useful for most XP calculations. +//:: +json json_UpdateParagonCR(json jCreature, int nBaseCR, int nBaseHD) +{ + int nNewCR; + +//:: Calculate additional CR by HD + if(nBaseHD <= 6) + { + nNewCR = nBaseCR + 18; + } + else if(nBaseHD <= 16) + { + nNewCR = nBaseCR + 15; + } + else + {nNewCR = nBaseCR + 12;} + +//:: Modify Challenge Rating + jCreature = GffReplaceFloat(jCreature, "ChallengeRating"/* /value" */, IntToFloat(nNewCR)); + + return jCreature; +} + +//:: Adds Psuedonatural SLA's to jCreature. +//:: +json json_AddPsuedonaturalPowers(json jCreature) +{ + // Get the existing SpecAbilityList (if it exists) + json jSpecAbilityList = GffGetList(jCreature, "SpecAbilityList"); + + // Create the SpecAbilityList if it doesn't exist + if (jSpecAbilityList == JsonNull()) + { + jSpecAbilityList = JsonArray(); + } + +//:: True Strike 1x / Day + int i; + for (i = 0; i < 1; i++) + { + json jSpecAbility = JsonObject(); + jSpecAbility = GffAddWord(jSpecAbility, "Spell", 415); + jSpecAbility = GffAddByte(jSpecAbility, "SpellCasterLevel", 15); + jSpecAbility = GffAddByte(jSpecAbility, "SpellFlags", 1); + + // Manually add to the array + jSpecAbilityList = JsonArrayInsert(jSpecAbilityList, jSpecAbility); + } + +//:: Add the list to the creature + jCreature = GffAddList(jCreature, "SpecAbilityList", jSpecAbilityList); + + return jCreature; +} + +//:: Directly modifies jCreature's Challenge Rating. +//:: This is useful for most XP calculations. +//:: +json json_UpdatePsuedonaturalCR(json jCreature, int nBaseCR, int nBaseHD) +{ + int nNewCR; + +//:: Calculate additional CR by HD + if (nBaseHD >= 4 && nBaseHD <= 11) + { + nNewCR = nBaseCR + 1; + } + else if (nBaseHD >= 12) + { + nNewCR = nBaseCR + 2; + } + +//:: Modify Challenge Rating + jCreature = GffReplaceFloat(jCreature, "ChallengeRating"/* /value" */, IntToFloat(nNewCR)); + + return jCreature; +} + + +//:: Spawns a Psuedonatural creature from a template +object MakePsuedonaturalCreatureFromTemplate(string sResref, location lSpawnLoc) +{ + json jPsuedo = TemplateToJson(sResref, RESTYPE_UTC); + if (jPsuedo == JSON_NULL) + { + DoDebug("prc_inc_json >> SpawnPsuedonaturalCreatureFromTemplate: TemplateToJson failed — bad resref or resource missing."); + return OBJECT_INVALID; + } + + //:: Get current HD + int nCurrentHD = json_GetCreatureHD(jPsuedo); + if (nCurrentHD <= 0) + { + DoDebug("make_psuedonat >> MakePsuedonaturalCreatureFromTemplate failed — template missing HD data."); + return OBJECT_INVALID; + } + + //:: Get current CR + int nBaseCR = 1; + nBaseCR = json_GetCreatureHD(jPsuedo); + if (nBaseCR <= 0) + { + DoDebug("make_psuedonat >> MakePsuedonaturalCreatureFromTemplate failed — template missing CR data."); + return OBJECT_INVALID; + } + + //:: Get local vars to transfer over. + int iMinHD = json_GetLocalIntFromVarTable(jPsuedo, "iMinHD"); + int iMaxHD = json_GetLocalIntFromVarTable(jPsuedo, "iMaxHD"); + int nOriginalHD = json_GetLocalIntFromVarTable(jPsuedo, "nOriginalHD"); + int iClass2 = json_GetLocalIntFromVarTable(jPsuedo, "Class2"); + int iClass2Package = json_GetLocalIntFromVarTable(jPsuedo, "Class2Package"); + int iClass2Start = json_GetLocalIntFromVarTable(jPsuedo, "Class2Start"); + int iMagicUse = json_GetLocalIntFromVarTable(jPsuedo, "X2_L_BEH_MAGIC"); + string sAI = json_GetLocalStringFromVarTable(jPsuedo, "X2_SPECIAL_COMBAT_AI_SCRIPT"); + + //:: Adds True Strike 1x / day to jCreature. + jPsuedo = json_AddPsuedonaturalPowers(jPsuedo); + + //:: Change jCreature's racialtype to outsider + jPsuedo = json_ModifyRacialType(jPsuedo, RACIAL_TYPE_OUTSIDER); + + jPsuedo = json_UpdatePsuedonaturalCR(jPsuedo, nBaseCR, nCurrentHD); + + //:: Spawn the creature + object oPsuedo = JsonToObject(jPsuedo, lSpawnLoc); + + //:: Set variables + SetLocalInt(oPsuedo, "TEMPLATE_PSUEDONATURAL", 1); + SetLocalInt(oPsuedo, "iMinHD", iMinHD); + SetLocalInt(oPsuedo, "iMaxHD", iMaxHD); + SetLocalInt(oPsuedo, "nOriginalHD", nOriginalHD); + SetLocalInt(oPsuedo, "Class2", iClass2); + SetLocalInt(oPsuedo, "Class2Package", iClass2Package); + SetLocalInt(oPsuedo, "Class2Start", iClass2Start); + SetLocalInt(oPsuedo, "X2_L_BEH_MAGIC", iMagicUse); + SetLocalString(oPsuedo, "X2_SPECIAL_COMBAT_AI_SCRIPT", sAI); + + return oPsuedo; + +} + +//:: Test void +//::void main (){} \ No newline at end of file diff --git a/src/include/prc_inc_material.nss b/src/include/prc_inc_material.nss index f69e26d..bb84f86 100644 --- a/src/include/prc_inc_material.nss +++ b/src/include/prc_inc_material.nss @@ -16,26 +16,28 @@ const int MATERIAL_TYPE_UNKNOWN = 0; const int MATERIAL_TYPE_BONE = 1; const int MATERIAL_TYPE_CERAMIC = 2; const int MATERIAL_TYPE_CRYSTAL = 3; -const int MATERIAL_TYPE_FABRIC = 4; +const int MATERIAL_TYPE_FIBER = 4; const int MATERIAL_TYPE_LEATHER = 5; const int MATERIAL_TYPE_METAL = 6; const int MATERIAL_TYPE_PAPER = 7; const int MATERIAL_TYPE_ROPE = 8; const int MATERIAL_TYPE_STONE = 9; const int MATERIAL_TYPE_WOOD = 10; +const int MATERIAL_TYPE_BOTANICAL = 11; const string MATERIAL_TYPE_NAME_INVALID = ""; const string MATERIAL_TYPE_NAME_UNKNOWN = "Unknown"; const string MATERIAL_TYPE_NAME_BONE = "Bone"; const string MATERIAL_TYPE_NAME_CERAMIC = "Ceramic"; const string MATERIAL_TYPE_NAME_CRYSTAL = "Crystal"; -const string MATERIAL_TYPE_NAME_FABRIC = "Fabric"; +const string MATERIAL_TYPE_NAME_FIBER = "Fiber"; const string MATERIAL_TYPE_NAME_LEATHER = "Leather"; const string MATERIAL_TYPE_NAME_METAL = "Metal"; const string MATERIAL_TYPE_NAME_PAPER = "Paper"; const string MATERIAL_TYPE_NAME_ROPE = "Rope"; const string MATERIAL_TYPE_NAME_STONE = "Stone"; const string MATERIAL_TYPE_NAME_WOOD = "Wood"; +const string MATERIAL_TYPE_NAME_BOTANICAL = "Bontanical"; //:: Material Itemproperty Constants //:://////////////////////////////////////////////////////////////////////////////// @@ -163,7 +165,8 @@ const int IP_MATERIAL_OBSIDIAN = 140; const int IP_MATERIAL_BAMBOO = 141; const int IP_MATERIAL_POTTERY = 142; const int IP_MATERIAL_GLASSTEEL = 143; -const int IP_NUM_MATERIALS = 143; +const int IP_MATERIAL_HERB = 144; +const int IP_NUM_MATERIALS = 144; const string IP_MATERIAL_NAME_INVALID = ""; const string IP_MATERIAL_NAME_UNKNOWN = "Unknown"; @@ -288,6 +291,7 @@ const string IP_MATERIAL_NAME_OBSIDIAN = "Obsidian"; const string IP_MATERIAL_NAME_BAMBOO = "Bamboo"; const string IP_MATERIAL_NAME_POTTERY = "Pottery"; const string IP_MATERIAL_NAME_GLASSTEEL = "Glassteel"; +const string IP_MATERIAL_NAME_HERB = "Herbs"; //:://///////////////////////////////////////////////////////////// // GetMaterialName( int iMaterialType, int bLowerCase = FALSE) @@ -426,8 +430,9 @@ string GetMaterialName( int iMaterialType, int bLowerCase = FALSE) case IP_MATERIAL_ROPE_GIANT_HAIR: sName = IP_MATERIAL_NAME_ROPE_GIANT_HAIR; break; case IP_MATERIAL_OBSIDIAN: sName = IP_MATERIAL_NAME_OBSIDIAN; break; case IP_MATERIAL_BAMBOO: sName = IP_MATERIAL_NAME_BAMBOO; break; - case IP_MATERIAL_POTTERY: sName = IP_MATERIAL_NAME_POTTERY; break; - case IP_MATERIAL_GLASSTEEL: sName = IP_MATERIAL_NAME_GLASSTEEL; break; + case IP_MATERIAL_POTTERY: sName = IP_MATERIAL_NAME_POTTERY; break; + case IP_MATERIAL_GLASSTEEL: sName = IP_MATERIAL_NAME_GLASSTEEL; break; + case IP_MATERIAL_HERB: sName = IP_MATERIAL_NAME_HERB; break; default: return ""; } @@ -573,6 +578,7 @@ int GetIPMaterial( string sMaterialName) else if( sMaterialName == GetStringUpperCase(IP_MATERIAL_NAME_BAMBOO)) return IP_MATERIAL_BAMBOO; else if( sMaterialName == GetStringUpperCase(IP_MATERIAL_NAME_POTTERY)) return IP_MATERIAL_POTTERY; else if( sMaterialName == GetStringUpperCase(IP_MATERIAL_NAME_GLASSTEEL)) return IP_MATERIAL_GLASSTEEL; + else if( sMaterialName == GetStringUpperCase(IP_MATERIAL_NAME_HERB)) return IP_MATERIAL_HERB; return IP_MATERIAL_INVALID; } @@ -806,6 +812,9 @@ int GetMaterialType(int nMaterial) || nMaterial == IP_MATERIAL_DRAKE_IVORY ) return MATERIAL_TYPE_BONE; + else if ( nMaterial == IP_MATERIAL_HERB ) + return MATERIAL_TYPE_BOTANICAL; + else if ( nMaterial == IP_MATERIAL_ELUKIAN_CLAY || nMaterial == IP_MATERIAL_POTTERY ) return MATERIAL_TYPE_CERAMIC; @@ -814,7 +823,7 @@ int GetMaterialType(int nMaterial) || nMaterial == IP_MATERIAL_COTTON || nMaterial == IP_MATERIAL_SILK || nMaterial == IP_MATERIAL_WOOL ) - return MATERIAL_TYPE_FABRIC; + return MATERIAL_TYPE_FIBER; else if ( nMaterial == IP_MATERIAL_GEM || nMaterial == IP_MATERIAL_GEM_ALEXANDRITE diff --git a/src/include/prc_inc_nat_hb.nss b/src/include/prc_inc_nat_hb.nss index c8f7c27..10bc2fb 100644 --- a/src/include/prc_inc_nat_hb.nss +++ b/src/include/prc_inc_nat_hb.nss @@ -1,9 +1,68 @@ +//:: prc_inc_nat_hb +//:: +//:: void main(){} + + void DoNaturalWeaponHB(object oPC = OBJECT_SELF); #include "prc_inc_combat" #include "prc_inc_template" - -object GetProperTarget(object oPC, object oTarget) +/** + * Finds a valid enemy target in melee range when the original target is invalid. + * Now includes input validation, LOS checks, configurable radius, and target priority. + * + * @param oPC The creature seeking a new target + * @param oTarget The original (invalid) target + * @param fRadius Search radius in meters (optional, defaults to melee range) + * @return A valid enemy target or OBJECT_INVALID if none found + */ +object GetProperTarget(object oPC, object oTarget, float fRadius = MELEE_RANGE_METERS) +{ + // Input validation + if(!GetIsObjectValid(oPC)) + { + DoDebug("GetProperTarget(): Invalid oPC parameter"); + return OBJECT_INVALID; + } + + // Use target list system for better target selection + PurgeTargetList(oPC); + + location lPC = GetLocation(oPC); + object oTest = MyFirstObjectInShape(SHAPE_SPHERE, fRadius, lPC, TRUE, OBJECT_TYPE_CREATURE); + + while(GetIsObjectValid(oTest)) + { + // Basic validation checks + if(oTest != oPC && // Not self + GetIsEnemy(oPC, oTest) && // Is enemy + GetIsInMeleeRange(oPC, oTest) && // In melee range + !GetIsDead(oTest) && // Is alive + LineOfSightObject(oPC, oTest)) // Has line of sight + { + // Add to target list with priority based on distance (nearest first) + AddToTargetList(oTest, oPC, INSERTION_BIAS_DISTANCE, FALSE); + } + + oTest = MyNextObjectInShape(SHAPE_SPHERE, fRadius, lPC, TRUE, OBJECT_TYPE_CREATURE); + } + + // Get the highest priority target (nearest enemy) + object oBestTarget = GetTargetListHead(oPC); + PurgeTargetList(oPC); + + if(GetIsObjectValid(oBestTarget)) + { + DoDebug("GetProperTarget(): Selected target " + GetName(oBestTarget) + + " for " + GetName(oPC)); + return oBestTarget; + } + + // No valid target found + DoDebug("GetProperTarget(): No valid target found for " + GetName(oPC)); + return OBJECT_INVALID; +} +/* object GetProperTarget(object oPC, object oTarget) { location lTarget = GetLocation(oPC); // Use the function to get the closest creature as a target @@ -21,7 +80,7 @@ object GetProperTarget(object oPC, object oTarget) } return oTarget; -} +} */ void DoNaturalAttack(object oWeapon) { @@ -289,59 +348,72 @@ void DoOverflowOnhandAttack(int nAttackMod) ); } -void DoNaturalWeaponHB(object oPC = OBJECT_SELF) +/* void DoNaturalWeaponHB(object oPC = OBJECT_SELF) { //not in combat, abort if(!GetIsInCombat(oPC)) return; -// if(DEBUG) DoDebug("entered DoNaturalWeaponHB"); + if(DEBUG) DoDebug("prc_inc_nat_hb: entered DoNaturalWeaponHB"); float fDelay = 0.1 + IntToFloat(Random(10))/100.0; //no natural weapons, abort //in a different form, abort for now fix it later - if(array_exists(oPC, ARRAY_NAT_SEC_WEAP_RESREF) - && !GetIsPolyMorphedOrShifted(oPC)) +if(array_exists(oPC, ARRAY_NAT_SEC_WEAP_RESREF) + && !GetIsPolyMorphedOrShifted(oPC)) +{ + DoDebug("prc_inc_nat_hb >> DoNaturalWeaponHB: creature has natural secondary weapons"); + UpdateSecondaryWeaponSizes(oPC); + int i; + while(i < array_get_size(oPC, ARRAY_NAT_SEC_WEAP_RESREF)) { - // DoDebug("DoNaturalWeaponHB: creature has natural secondary weapons"); - UpdateSecondaryWeaponSizes(oPC); - int i; - while(i < array_get_size(oPC, ARRAY_NAT_SEC_WEAP_RESREF)) + string sResRef = array_get_string(oPC, ARRAY_NAT_SEC_WEAP_RESREF, i); + if(sResRef != "") { - //get the resref to use - string sResRef = array_get_string(oPC, ARRAY_NAT_SEC_WEAP_RESREF, i); - //if null, move to next - if(sResRef != "") + // Get stored weapon object, or create if doesn't exist + object oWeapon = GetLocalObject(oPC, "NAT_SEC_WEAP_" + sResRef); + + if(!GetIsObjectValid(oWeapon)) { - //get the created item - object oWeapon = GetObjectByTag(sResRef); + DoDebug("prc_inc_nat_hb >> DoNaturalWeaponHB: creating and storing creature weapon " + sResRef); + oWeapon = CreateItemOnObject(sResRef, oPC); + if(!GetIsObjectValid(oWeapon)) { - object oLimbo = GetObjectByTag("HEARTOFCHAOS"); - location lLimbo = GetLocation(oLimbo); - if(!GetIsObjectValid(oLimbo)) - lLimbo = GetStartingLocation(); - oWeapon = CreateObject(OBJECT_TYPE_ITEM, sResRef, lLimbo); + DoDebug("prc_inc_nat_hb >> DoNaturalWeaponHB: ERROR - CreateItemOnObject FAILED for " + sResRef); } + else + { + DoDebug("prc_inc_nat_hb >> DoNaturalWeaponHB: SUCCESS - weapon created, tag=" + GetTag(oWeapon) + ", name=" + GetName(oWeapon)); + SetIdentified(oWeapon, TRUE); + SetLocalObject(oPC, "NAT_SEC_WEAP_" + sResRef, oWeapon); + } + } + else + { + DoDebug("prc_inc_nat_hb >> DoNaturalWeaponHB: using stored creature weapon object"); + } - // DoDebug(COLOR_WHITE + "DoNaturalWeaponHB: scheduling a secondary natural attack with "+GetName(oWeapon)+" at delay "+FloatToString(fDelay)); - //do the attack within a delay - /* - // motu99: commented this out; AssignCommand ist not needed, because OBJECT_SELF is oPC - using AssignCommand will only degrade performance - AssignCommand(oPC, DelayCommand(fDelay, DoNaturalAttack(oWeapon))); - */ - + // Double-check validity before scheduling + if(GetIsObjectValid(oWeapon)) + { + DoDebug("prc_inc_nat_hb >> DoNaturalWeaponHB: scheduling a secondary natural attack with "+GetName(oWeapon)+" at delay "+FloatToString(fDelay)); DelayCommand(fDelay, DoNaturalAttack(oWeapon)); - //calculate the delay to use next time fDelay += 2.05; if(fDelay > 6.0) - fDelay -= 6.0; + fDelay -= 6.0; + } + else + { + DoDebug("prc_inc_nat_hb >> DoNaturalWeaponHB: ERROR - weapon object is INVALID, cannot schedule attack"); } - i++; } + i++; } +} + int iMod = 5; // motu99: added check for monk weapon if(GetHasMonkWeaponEquipped(oPC)) iMod = 3; @@ -357,10 +429,10 @@ void DoNaturalWeaponHB(object oPC = OBJECT_SELF) for(i = 0; i < nOverflowAttackCount; i++) { // DoDebug(COLOR_WHITE + "DoNaturalWeaponHB(): scheduling a scripted overflow attack with attack mod "+IntToString(nAttackPenalty)+" at delay "+FloatToString(fDelay)); - /* + // motu99: see comment above why this is commented out - AssignCommand(oPC, DelayCommand(fDelay, DoOverflowOnhandAttack(nAttackPenalty))); - */ + //AssignCommand(oPC, DelayCommand(fDelay, DoOverflowOnhandAttack(nAttackPenalty))); + DelayCommand(fDelay, DoOverflowOnhandAttack(nAttackPenalty)); //calculate the delay to use @@ -399,6 +471,128 @@ void DoNaturalWeaponHB(object oPC = OBJECT_SELF) } } } + */ + +void DoNaturalWeaponHB(object oPC = OBJECT_SELF) +{ + //not in combat, abort + if(!GetIsInCombat(oPC)) + return; + + if(DEBUG) DoDebug("prc_inc_nat_hb: entered DoNaturalWeaponHB"); + + float fDelay = 0.1 + IntToFloat(Random(10))/100.0; + + //no natural weapons, abort + //in a different form, abort for now fix it later + if(array_exists(oPC, ARRAY_NAT_SEC_WEAP_RESREF) + && !GetIsPolyMorphedOrShifted(oPC)) + { + DoDebug("prc_inc_nat_hb >> DoNaturalWeaponHB: creature has natural secondary weapons"); + UpdateSecondaryWeaponSizes(oPC); + int i; + while(i < array_get_size(oPC, ARRAY_NAT_SEC_WEAP_RESREF)) + { + //get the resref to use + string sResRef = array_get_string(oPC, ARRAY_NAT_SEC_WEAP_RESREF, i); + //if null, move to next + if(sResRef != "") + { + //get the created item + object oWeapon = GetObjectByTag(sResRef); + if(!GetIsObjectValid(oWeapon)) + { + object oLimbo = GetObjectByTag("HEARTOFCHAOS"); + location lLimbo = GetLocation(oLimbo); + if(!GetIsObjectValid(oLimbo)) + lLimbo = GetStartingLocation(); + oWeapon = CreateObject(OBJECT_TYPE_ITEM, sResRef, lLimbo); + DoDebug(PRC_TEXT_WHITE + "prc_inc_nat_hb >> DoNaturalWeaponHB: creature weapon object found!!!"); + } + + // Check for enhancements after creating the weapon object + int nEnhance = GetLocalInt(oPC, "PRC_NAT_WEAPON_ENHANCE"); + if(nEnhance > 0) + { + + DoDebug(PRC_TEXT_WHITE + "prc_inc_nat_hb >> DoNaturalWeaponHB: Applying enhancement."); + float fDuration = GetLocalFloat(oPC, "PRC_NAT_WEAPON_ENH_DUR"); + IPSafeAddItemProperty(oWeapon, ItemPropertyEnhancementBonus(nEnhance), fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE); + } + + if(DEBUG) DoDebug("prc_inc_nat_hb >> DoNaturalWeaponHB: scheduling a secondary natural attack with "+GetName(oWeapon)+" at delay "+FloatToString(fDelay)); + //do the attack within a delay + // motu99: commented this out; AssignCommand ist not needed, because OBJECT_SELF is oPC - using AssignCommand will only degrade performance + //AssignCommand(oPC, DelayCommand(fDelay, DoNaturalAttack(oWeapon))); + + DelayCommand(fDelay, DoNaturalAttack(oWeapon)); + + //calculate the delay to use next time + fDelay += 2.05; + if(fDelay > 6.0) + fDelay -= 6.0; + } + i++; + } + } + + int iMod = 5; // motu99: added check for monk weapon + if(GetHasMonkWeaponEquipped(oPC)) iMod = 3; + + // check for overflow (main hand) attacks + int nOverflowAttackCount = GetLocalInt(oPC, "OverflowBaseAttackCount"); + if(nOverflowAttackCount) + { + int i; + // the first overflow attack would be the seventh main hand attack, at an AB of -30 + int nAttackPenalty = -6 * iMod; // -30 for normal bab, -18 for monks + // DoDebug("DoNaturalWeaponHB(): number of scripted overflow attacks: "+IntToString(nOverflowAttackCount)); + for(i = 0; i < nOverflowAttackCount; i++) + { + // DoDebug(COLOR_WHITE + "DoNaturalWeaponHB(): scheduling a scripted overflow attack with attack mod "+IntToString(nAttackPenalty)+" at delay "+FloatToString(fDelay)); + + // motu99: see comment above why this is commented out + // AssignCommand(oPC, DelayCommand(fDelay, DoOverflowOnhandAttack(nAttackPenalty))); + + DelayCommand(fDelay, DoOverflowOnhandAttack(nAttackPenalty)); + + //calculate the delay to use + fDelay += 2.05; + if(fDelay > 6.0) + fDelay -= 6.0; + //calculate new attack penalty + nAttackPenalty -= iMod; // motu99: usually -5, for monks -3 (unarmed or kama) + } + } + + // motu99: this is only here for debugging in order to test PerformAttackRound() + // must be deleted after debugging!!! + //if (GetPRCSwitch(PRC_PNP_TRUESEEING)) DelayCommand(0.01, DoOffhandAttackRound()); + + + // check for overflow offhand attacks + int nOffhandAttackCount = GetLocalInt(oPC, "OffhandOverflowAttackCount"); +// if (DEBUG) DoDebug("DoNaturalWeaponHB: number of scripted offhand attacks = "+IntToString(nOffhandAttackCount)); + if(nOffhandAttackCount) + { + int i; + int nAttackPenalty = -2 * iMod; // offhand attacks always come at -5 per additional attack (but for monks we assume -3) + for(i = 0; i < nOffhandAttackCount; i++) + { + // DoDebug(COLOR_WHITE + "DoNaturalWeaponHB(): scheduling a scripted offhand attack with attack mod "+IntToString(nAttackPenalty)+" at delay "+FloatToString(fDelay)); + + DelayCommand(fDelay, DoOffhandAttack(nAttackPenalty)); + + //calculate the delay to use + fDelay += 2.05; + if(fDelay > 6.0) + fDelay -= 6.0; + //calculate new attack penalty + nAttackPenalty -= iMod; + } + } +} + /* * motu99's test functions. Not actually used by PRC scripts diff --git a/src/include/prc_inc_natweap.nss b/src/include/prc_inc_natweap.nss index 8d3668b..78115a5 100644 --- a/src/include/prc_inc_natweap.nss +++ b/src/include/prc_inc_natweap.nss @@ -277,6 +277,32 @@ void ClearNaturalWeapons(object oPC) array_delete(oPC, ARRAY_NAT_PRI_WEAP_ATTACKS); } +/** + * @brief Adds a natural primary weapon to a creature (PC/NPC). + * + * This function manages a creature's natural primary weapons by storing their + * resource references and attack counts in persistent arrays. If the weapon + * being added is the first natural weapon, it may automatically become the + * creature's active primary natural weapon, unless the creature is a Monk or + * Brawler. Optionally, the weapon can be forced to become the active primary + * weapon regardless of class. + * + * @param oPC The creature object to which the natural weapon will be added. + * @param sResRef The resource reference string of the natural weapon. + * @param nCount (Optional) The number of attacks this natural weapon provides. + * Default is 1. + * @param nForceUse (Optional) If TRUE, forces this weapon to become the active + * primary natural weapon regardless of the creature's class. + * Default is FALSE. + * + * @details + * - Creates persistent arrays for weapon references and attack counts if they + * do not already exist. + * - Checks if the weapon is already present to avoid duplicates. + * - Adds the weapon and attack count to the arrays. + * - Sets the primary natural weapon index to this weapon if it is the first + * natural weapon added, unless the creature is a Monk or Brawler. + */ void AddNaturalPrimaryWeapon(object oPC, string sResRef, int nCount = 1, int nForceUse = FALSE) { int nFirstNaturalWeapon = FALSE; diff --git a/src/include/prc_inc_nwscript.nss b/src/include/prc_inc_nwscript.nss index 8ebc821..4671756 100644 --- a/src/include/prc_inc_nwscript.nss +++ b/src/include/prc_inc_nwscript.nss @@ -572,7 +572,10 @@ int GetMaxEssentiaCapacity(object oMeldshaper, int nClass, int nMeld) { int nMax = 1; // Always can invest one int nHD = GetHitDice(oMeldshaper); - if (nHD >= 31) nMax = 5; + if (nHD >= 61) nMax = 8; + else if (nHD >= 51) nMax = 7; + else if (nHD >= 41) nMax = 6; + else if (nHD >= 31) nMax = 5; else if (nHD >= 18) nMax = 4; else if (nHD >= 12) nMax = 3; else if (nHD >= 6) nMax = 2; diff --git a/src/include/prc_inc_onhit.nss b/src/include/prc_inc_onhit.nss index 3f0da67..ab68887 100644 --- a/src/include/prc_inc_onhit.nss +++ b/src/include/prc_inc_onhit.nss @@ -808,7 +808,24 @@ int GetIsOnHitCastSpell(object oSpellTarget = OBJECT_INVALID, object oSpellCastI if (DEBUG) DoDebug("GetIsOnHitCastSpell: item "+GetName(oSpellCastItem)+" is armor; attacker = "+GetName(oAttacker)+", defender = "+GetName(oDefender)); } // is the spell type item a weapon? - else if (iWeaponType == StringToInt(Get2DACache("baseitems", "WeaponType", iBaseType))) + int nWT = StringToInt(Get2DACache("baseitems", "WeaponType", iBaseType)); + if (nWT > 0) + { + if (oSpellTarget == OBJECT_INVALID) + oSpellTarget = PRCGetSpellTargetObject(oSpellOrigin); + + oAttacker = oSpellOrigin; + oDefender = oSpellTarget; + + if (DEBUG) DoDebug("GetIsOnHitCastSpell: item "+GetName(oSpellCastItem)+" is weapon [WT="+IntToString(nWT)+"]; attacker="+GetName(oAttacker)+", defender="+GetName(oDefender)); + } + else + { + if (DEBUG) DoDebug("GetIsOnHitCastSpell: item "+GetName(oSpellCastItem)+" is neither weapon nor armor; returning FALSE"); + return FALSE; + } + +/* else if (iWeaponType == StringToInt(Get2DACache("baseitems", "WeaponType", iBaseType))) { // determine the target, if not already given if (oSpellTarget == OBJECT_INVALID) @@ -823,7 +840,7 @@ int GetIsOnHitCastSpell(object oSpellTarget = OBJECT_INVALID, object oSpellCastI { if (DEBUG) DoDebug("GetIsOnHitCastSpell: item "+GetName(oSpellCastItem)+" is neither weapon nor armor; returning FALSE"); return FALSE; - } + } */ // the spell origin must possess the item that cast the spell (at least for the aurora engine, in prc_inc_combat that may differ) diff --git a/src/include/prc_inc_shifting.nss b/src/include/prc_inc_shifting.nss index 7cac1ed..1e0fadc 100644 --- a/src/include/prc_inc_shifting.nss +++ b/src/include/prc_inc_shifting.nss @@ -1370,7 +1370,9 @@ void _prc_inc_shifting_ShiftIntoTemplateAux(object oShifter, int nShifterType, o if(GetIsObjectValid(oShifterCWpR)) MyDestroyObject(oShifterCWpR); if(GetIsObjectValid(oShifterCWpL)) MyDestroyObject(oShifterCWpL); if(GetIsObjectValid(oShifterCWpB)) MyDestroyObject(oShifterCWpB); - oShifterCWpR = oShifterCWpL = oShifterCWpR = OBJECT_INVALID; + oShifterCWpR = OBJECT_INVALID; + oShifterCWpL = OBJECT_INVALID; + oShifterCWpB = OBJECT_INVALID; // Copy the template's weapons and assign equipping diff --git a/src/include/prc_inc_size.nss b/src/include/prc_inc_size.nss new file mode 100644 index 0000000..286015b --- /dev/null +++ b/src/include/prc_inc_size.nss @@ -0,0 +1,154 @@ +#include "prc_inc_util" +#include "prc_inc_spells" +#include "prc_inc_function" + +// Wrapper function for delayed visual transform with generation tracking +void DelayedSetVisualTransform(int nExpectedGeneration, object oTarget, int nTransform, float fValue) +{ + // Read current generation at execution time, not when scheduled + if (nExpectedGeneration != GetLocalInt(oTarget, "PRC_SIZE_GENERATION")) + { + // Generation has changed, don't apply the transform + return; + } + SetObjectVisualTransform(oTarget, nTransform, fValue); +} + +// Main wrapper function that handles generation tracking +void DelaySetVisualTransform(float fDelay, object oTarget, string sGenerationName, int nTransform, float fValue) +{ + int nExpectedGeneration = GetLocalInt(oTarget, sGenerationName); + DelayCommand(fDelay, DelayedSetVisualTransform(nExpectedGeneration, oTarget, nTransform, fValue)); +} + +/** + * Creates a size change effect that can enlarge or reduce a creature + * + * @param oTarget Object to affect + * @param nObjectType Object type filter (OBJECT_TYPE_CREATURE, etc.) + * @param bEnlarge TRUE to enlarge, FALSE to reduce + * @param nChanges Number of size categories to change (0 = reset to original) + * @return The size change effect + */ + +effect EffectSizeChange(object oTarget, int nObjectType, int bEnlarge, int nChanges) +{ + effect eBlank; + + // Increment generation for any size change + int nGeneration = PRC_NextGeneration(GetLocalInt(oTarget, "PRC_SIZE_GENERATION")); + SetLocalInt(oTarget, "PRC_SIZE_GENERATION", nGeneration); + + // Store original size if not already stored - READ ACTUAL CURRENT SCALE + if(GetLocalFloat(oTarget, "PRC_ORIGINAL_SIZE") == 0.0f) + { + float fCurrentScale = GetObjectVisualTransform(oTarget, OBJECT_VISUAL_TRANSFORM_SCALE); + SetLocalFloat(oTarget, "PRC_ORIGINAL_SIZE", fCurrentScale); + } + + // Reset to original size + if(nChanges == 0) + { + float fOriginalSize = GetLocalFloat(oTarget, "PRC_ORIGINAL_SIZE"); + DelaySetVisualTransform(0.0f, oTarget, "PRC_SIZE_GENERATION", OBJECT_VISUAL_TRANSFORM_SCALE, fOriginalSize); + // DON'T delete PRC_ORIGINAL_SIZE here - keep it for future casts + return eBlank; + } + + // Get the original scale + float fOriginalScale = GetLocalFloat(oTarget, "PRC_ORIGINAL_SIZE"); + + // Calculate scale factor relative to original size + float fScale = fOriginalScale; + if(bEnlarge) + fScale = fOriginalScale * pow(1.5f, IntToFloat(nChanges)); + else + fScale = fOriginalScale * pow(0.5f, IntToFloat(nChanges)); + + // Create the effect link with sanctuary VFX + effect eReturn = EffectLinkEffects(EffectVisualEffect(VFX_DUR_SANCTUARY), + EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE)); + + if(bEnlarge) + { + eReturn = EffectLinkEffects(eReturn, EffectAttackDecrease(nChanges)); + eReturn = EffectLinkEffects(eReturn, EffectAbilityDecrease(ABILITY_DEXTERITY, 2 * nChanges)); + eReturn = EffectLinkEffects(eReturn, EffectAbilityIncrease(ABILITY_STRENGTH, 2 * nChanges)); + eReturn = EffectLinkEffects(eReturn, EffectACDecrease(nChanges)); + eReturn = TagEffect(eReturn, "PRC_SIZE_INCREASE"); + } + else + { + eReturn = EffectLinkEffects(eReturn, EffectAttackIncrease(nChanges)); + eReturn = EffectLinkEffects(eReturn, EffectAbilityIncrease(ABILITY_DEXTERITY, 2 * nChanges)); + eReturn = EffectLinkEffects(eReturn, EffectAbilityDecrease(ABILITY_STRENGTH, 2 * nChanges)); + eReturn = EffectLinkEffects(eReturn, EffectACIncrease(nChanges)); + eReturn = TagEffect(eReturn, "PRC_SIZE_DECREASE"); + } + + // Apply visual transform using wrapper + DelaySetVisualTransform(0.0f, oTarget, "PRC_SIZE_GENERATION", OBJECT_VISUAL_TRANSFORM_SCALE, fScale); + + return eReturn; +} + + + + +/* effect EffectSizeChange(object oTarget, int nObjectType, int bEnlarge, int nChanges) +{ + effect eBlank; + + // Increment generation for any size change + int nGeneration = PRC_NextGeneration(GetLocalInt(oTarget, "PRC_SIZE_GENERATION")); + SetLocalInt(oTarget, "PRC_SIZE_GENERATION", nGeneration); + + // Store original size if not already stored (fixed check) + if(GetLocalFloat(oTarget, "PRC_ORIGINAL_SIZE") == 0.0f) + { + SetLocalFloat(oTarget, "PRC_ORIGINAL_SIZE", 1.0f); + } + + // Reset to original size + if(nChanges == 0) + { + float fOriginalSize = GetLocalFloat(oTarget, "PRC_ORIGINAL_SIZE"); + DelaySetVisualTransform(0.0f, oTarget, "PRC_SIZE_GENERATION", OBJECT_VISUAL_TRANSFORM_SCALE, fOriginalSize); + DeleteLocalFloat(oTarget, "PRC_ORIGINAL_SIZE"); + return eBlank; + } + + // Calculate scale factor using pow() for multi-step changes + float fScale = 1.0f; + if(bEnlarge) + fScale = pow(1.5f, IntToFloat(nChanges)); // 1.5, 2.25, 3.375... + else + fScale = pow(0.5f, IntToFloat(nChanges)); // 0.5, 0.25, 0.125... + + // Create the effect link based on enlarge/reduce + effect eReturn; + if(bEnlarge) + { + eReturn = EffectLinkEffects(EffectAttackDecrease(nChanges), + EffectAbilityDecrease(ABILITY_DEXTERITY, 2 * nChanges)); + eReturn = EffectLinkEffects(eReturn, EffectAbilityIncrease(ABILITY_STRENGTH, 2 * nChanges)); + eReturn = EffectLinkEffects(eReturn, EffectACDecrease(nChanges)); + eReturn = TagEffect(eReturn, "PRC_SIZE_INCREASE"); + } + else + { + eReturn = EffectLinkEffects(EffectAttackIncrease(nChanges), + EffectAbilityIncrease(ABILITY_DEXTERITY, 2 * nChanges)); + eReturn = EffectLinkEffects(eReturn, EffectAbilityDecrease(ABILITY_STRENGTH, 2 * nChanges)); + eReturn = EffectLinkEffects(eReturn, EffectACIncrease(nChanges)); + eReturn = TagEffect(eReturn, "PRC_SIZE_DECREASE"); + } + + // Apply visual transform using wrapper + DelaySetVisualTransform(0.0f, oTarget, "PRC_SIZE_GENERATION", OBJECT_VISUAL_TRANSFORM_SCALE, fScale); + + return eReturn; +} + */ + +//:: void main(){} \ No newline at end of file diff --git a/src/include/prc_inc_skills.nss b/src/include/prc_inc_skills.nss index bbca299..1bfc354 100644 --- a/src/include/prc_inc_skills.nss +++ b/src/include/prc_inc_skills.nss @@ -115,11 +115,11 @@ int PerformJump(object oPC, location lLoc, int bDoKnockDown = TRUE) iBonus = 4; } } - /*if (GetHasSpellEffect(MOVE_TC_LEAPING_DRAGON, oPC)) + if (GetHasSpellEffect(MOVE_TC_LEAPING_DRAGON, oPC)) { bIsRunningJump = TRUE; - iBonus = 10; - } */ + //iBonus = 10; //:: This is granted in the stance. + } // PnP rules are height * 6 for run and height * 2 for jump. // I can't get height so that is assumed to be 6. // Changed maxed jump distance because the NwN distance is rather short @@ -363,8 +363,11 @@ int PRCIsFlying(object oCreature) bFlying = TRUE; } if(!bFlying - && ((nWings > 0 && nWings < 79) || nWings == 90))//CEP and Project Q wing models - bFlying = TRUE; + && ((nWings > 0 && nWings < 79) + || (nWings > 1959 && nWings < 1962) + || (nWings > 1962 && nWings < 1966) + || nWings == 90))//CEP and Project Q wing models + bFlying = TRUE; if (GetHasSpellEffect(MOVE_SH_BALANCE_SKY, oCreature)) bFlying = TRUE; @@ -374,6 +377,12 @@ int PRCIsFlying(object oCreature) if(GetRacialType(oCreature) == RACIAL_TYPE_GLOURA) bFlying = TRUE; + + if(GetRacialType(oCreature) == RACIAL_TYPE_AVARIEL) + bFlying = TRUE; + + if(GetRacialType(oCreature) == RACIAL_TYPE_FEYRI) + bFlying = TRUE; if(GetRacialType(oCreature) == RACIAL_TYPE_SPIRETOPDRAGON) bFlying = TRUE; diff --git a/src/include/prc_inc_spells.nss b/src/include/prc_inc_spells.nss index 19e73d7..1c7ad71 100644 --- a/src/include/prc_inc_spells.nss +++ b/src/include/prc_inc_spells.nss @@ -20,6 +20,11 @@ /* Function prototypes */ ////////////////////////////////////////////////// + + +//:: Calculates total Shield AC bonuses from all sources +int GetTotalShieldACBonus(object oCreature); + //:: Handles psuedo-Foritifcation void DoFortification(object oPC = OBJECT_SELF, int nFortification = 25); @@ -376,23 +381,53 @@ const int TYPE_DIVINE = -2; /* Function definitions */ ////////////////////////////////////////////////// + +// Returns TRUE if nSpellID is a subradial spell, FALSE otherwise +int GetIsSubradialSpell(int nSpellID) +{ + string sMaster = Get2DACache("spells", "Master", nSpellID); + + // If the Master column is numeric, this spell is a subradial of that master + if (sMaster != "" && sMaster != "****") + { + return TRUE; + } + + return FALSE; +} + +// Returns the masterspell SpellID for a subradial spell. +int GetMasterSpellFromSubradial(int nSpellID) +{ + string sMaster = Get2DAString("spells", "Master", nSpellID); + + if (sMaster != "****") + { + return StringToInt(sMaster); + } + + return -1; // No master +} + + + int GetPrCAdjustedClassLevel(int nClass, object oCaster = OBJECT_SELF) { int iTemp; // is it arcane, divine or neither? if(GetIsArcaneClass(nClass, oCaster) && nClass != CLASS_TYPE_SUBLIME_CHORD) { - if (GetPrimaryArcaneClass(oCaster) == nClass) // adjust for any PrCs + if (GetPrimaryArcaneClass(oCaster) == nClass) // adjust for any PrCs iTemp = GetArcanePRCLevels(oCaster, nClass); } else if(GetIsDivineClass(nClass, oCaster)) { - if (GetPrimaryDivineClass(oCaster) == nClass) // adjust for any PrCs - iTemp = GetDivinePRCLevels(oCaster, nClass); + if (GetPrimaryDivineClass(oCaster) == nClass) // adjust for any PrCs + iTemp = GetDivinePRCLevels(oCaster, nClass); } else // a non-caster class or a PrC { - return 0; + return 0; } // add the caster class levels return iTemp += GetLevelByClass(nClass, oCaster); @@ -412,7 +447,9 @@ int GetPrCAdjustedCasterLevelByType(int nClassType, object oCaster = OBJECT_SELF { int nClassLvl; int nClass1, nClass2, nClass3, nClass4, nClass5, nClass6, nClass7, nClass8; - int nClass1Lvl, nClass2Lvl, nClass3Lvl, nClass4Lvl, nClass5Lvl, nClass6Lvl, nClass7Lvl, nClass8Lvl; + int nClass1Lvl = 0, nClass2Lvl = 0, nClass3Lvl = 0, nClass4Lvl = 0, + nClass5Lvl = 0, nClass6Lvl = 0, nClass7Lvl = 0, nClass8Lvl = 0; + nClass1 = GetClassByPosition(1, oCaster); nClass2 = GetClassByPosition(2, oCaster); @@ -974,11 +1011,16 @@ int PRCMySavingThrow(int nSavingThrow, object oTarget, int nDC, int nSaveType = // Plague Resistant gives a +4 bonus on disease saves if(GetHasFeat(FEAT_PLAGUE_RESISTANT, oTarget)) nDC -= 4; + // Racial +2 vs disease saves + if(GetHasFeat(FEAT_RACE_HARDINESS_VS_DISEASE, oTarget)) + nDC -= 2; // +4/+2 bonus on saves against disease, done here if(GetLevelByClass(CLASS_TYPE_DREAD_NECROMANCER, oTarget) > 13) nDC -= 4; else if(GetLevelByClass(CLASS_TYPE_DREAD_NECROMANCER, oTarget) > 3) nDC -= 2; + + } else if(nSaveType == SAVING_THROW_TYPE_POISON) { @@ -2223,6 +2265,78 @@ int GetControlledCelestialTotalHD(object oPC = OBJECT_SELF) return nTotalHD; } +//:: Calculates total Shield AC bonuses from all sources +int GetTotalShieldACBonus(object oCreature) +{ + int nShieldBonus = 0; + object oItem; + + // Check left hand for shield + oItem = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oCreature); + if (GetIsObjectValid(oItem)) + { + int nBaseItem = GetBaseItemType(oItem); + if (nBaseItem == BASE_ITEM_SMALLSHIELD || + nBaseItem == BASE_ITEM_LARGESHIELD || + nBaseItem == BASE_ITEM_TOWERSHIELD) + { + nShieldBonus += GetItemACValue(oItem); + if(DEBUG) DoDebug("prc_inc_spells >> GetTotalShieldACBonus: Found Shield AC, bonus = " + IntToString(nShieldBonus)+"."); + } + } + + // Check creature weapon slots for shield AC bonus + oItem = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oCreature); + if (GetIsObjectValid(oItem)) + nShieldBonus += GetItemACValue(oItem); + + oItem = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oCreature); + if (GetIsObjectValid(oItem)) + nShieldBonus += GetItemACValue(oItem); + + oItem = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oCreature); + if (GetIsObjectValid(oItem)) + nShieldBonus += GetItemACValue(oItem); + + // Add shield AC bonuses from magical effects + effect eEffect = GetFirstEffect(oCreature); + while (GetIsEffectValid(eEffect)) + { + int nACType = GetEffectInteger(eEffect, 0); + int nACAmount = GetEffectInteger(eEffect, 1); + + if(GetEffectType(eEffect) == EFFECT_TYPE_AC_INCREASE && nACType == AC_SHIELD_ENCHANTMENT_BONUS) + { + if(DEBUG) DoDebug("prc_inc_spells >> GetTotalShieldACBonus: Found Shield AC effect, bonus = " + IntToString(nACAmount)+"."); + nShieldBonus += nACAmount; + } + + eEffect = GetNextEffect(oCreature); + } + return nShieldBonus; +} + + + + // Add shield AC bonuses from magical effects +/* effect eEffect = GetFirstEffect(oCreature); + while (GetIsEffectValid(eEffect)) + { + if (GetEffectType(eEffect) == EFFECT_TYPE_AC_INCREASE && + GetEffectInteger(eEffect, 1) == AC_SHIELD_ENCHANTMENT_BONUS) + { + int nMod = GetEffectInteger(eEffect, 0); + int nType = GetEffectInteger(eEffect, 1); + nShieldBonus += GetEffectInteger(eEffect, 0); + string s = "Found AC effect: bonus = " + IntToString(nMod) + ", type = " + IntToString(nType); + SendMessageToPC(GetFirstPC(), s); + } + eEffect = GetNextEffect(oCreature); + } + + return nShieldBonus; +}*/ +// //:: Handles psuedo-Foritifcation void DoFortification(object oPC = OBJECT_SELF, int nFortification = 25) { @@ -2275,7 +2389,7 @@ void DoFortification(object oPC = OBJECT_SELF, int nFortification = 25) IPSafeAddItemProperty(oHide, ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_BACKSTAB)); } } - +// // wrapper for DecrementRemainingSpellUses, works for newspellbook 'fake' spells too // should also find and decrement metamagics for newspellbooks diff --git a/src/include/prc_inc_switch.nss b/src/include/prc_inc_switch.nss index 4913e3d..e2a3dfe 100644 --- a/src/include/prc_inc_switch.nss +++ b/src/include/prc_inc_switch.nss @@ -70,11 +70,13 @@ 43 PRC_CRAFTING_BASE_ITEMS int 1 44 PRC_XP_USE_SIMPLE_LA int 1 45 PRC_XP_USE_SIMPLE_RACIAL_HD int 1 +46 PRC_CREATE_INFUSION_CASTER_LEVEL int 1 +47 PRC_CREATE_INFUSION_OPTIONAL_HERBS int 0 */ /* This variable MUST be updated with every new version of the PRC!!! */ - const string PRC_VERSION = "PRC 3.9.0"; + const string PRC_VERSION = "PRC8 4.76"; /* This variable MUST be updated every time 'assemble_spellbooks.bat' is run!!! */ @@ -89,11 +91,11 @@ * This allows material components in NWN through the materialcomp.2da * Just put the SpellID and UTC resref in, MINUS the .utc on the end. * This also requires the names of the items, formatted like so ("" included): "Object Name" - * + * * Set switch to 2 to activate this * Deducts gold instead of requiring material components * Put the gold value in the Cost column - + * Set switch to 3 to activate both at the same time * WARNING: This will slow spellcasting down due to 2da reads and inventory loops */ @@ -127,7 +129,7 @@ const string PRC_BIOWARE_NEUTRALIZE_POISON = "PRC_BIOWARE_NEUTRALIZE_P /** Remove the cap PRC added to this spell */ const string PRC_BIOWARE_REMOVE_DISEASE = "PRC_BIOWARE_REMOVE_DISEASE"; -/** +/** * This replaces the 3.0 Spell Focus bonuses with the 3.5 edition ones */ const string PRC_35_SPELL_FOCUS = "PRC_35_SPELL_FOCUS"; @@ -261,8 +263,8 @@ const string PRC_165_DEATH_IMMUNITY = "PRC_165_DEATH_IMMUNITY"; /* * PRC_ACTIVATE_MAX_SPELL_DC_CAP: activate a max cap on DC casted by creature/player - * PRC_SET_MAX_SPELL_DC_CAP: the max value ex: 99 - * + * PRC_SET_MAX_SPELL_DC_CAP: the max value ex: 99 + * */ const string PRC_ACTIVATE_MAX_SPELL_DC_CAP = "PRC_ACTIVATE_MAX_SPELL_DC_CAP"; const string PRC_SET_MAX_SPELL_DC_CAP = "PRC_SET_MAX_SPELL_DC_CAP"; @@ -289,8 +291,8 @@ const string PRC_DC_BASE_OVERRIDE = "PRC_DC_BASE_OVERRIDE"; const string PRC_DC_ADJUSTMENT = "PRC_DC_ADJUSTMENT"; /* - * By default when calculating caster level for characters with PrCs, the highest class rule will - * be used (ie. Bard 2/Wizard 4/Elemental Savant 6 - Wizard is the highest arcane class so levels + * By default when calculating caster level for characters with PrCs, the highest class rule will + * be used (ie. Bard 2/Wizard 4/Elemental Savant 6 - Wizard is the highest arcane class so levels * form PrC will be added to that class, and the caster level will be 2 for Bard and 10 for Wizard). * When this is set, the first class rule will be used (with the same character caster level would * be 8 for Bard and 4 for Wizard). @@ -570,12 +572,12 @@ const string PRC_SOUL_EATER_MAX_SLAVES = "PRC_SOUL_EATER_MAX_SLAVES"; * For the Psionic Slayer prestige class, this switch limits the Favored Enemy selection * to the Aberration racial type. * - * This switch is provided to allow builders to more closely represent the Pen and Paper + * This switch is provided to allow builders to more closely represent the Pen and Paper * Illithid Slayer class, instead of the broader Open Game License "Slayer" class. * - * Type: Int + * Type: Int * Values: 0 [Default] (Favored Enemy racial type is not limited) - * 1 (Favored Enemy race is limited to Aberration only) + * 1 (Favored Enemy race is limited to Aberration only) */ const string PRC_PSIONIC_SLAYER_FAV_ENEMY_ABERRATION_ONLY = "PRC_PSIONIC_SLAYER_FAV_ENEMY_ABERRATION_ONLY"; @@ -583,20 +585,20 @@ const string PRC_PSIONIC_SLAYER_FAV_ENEMY_ABERRATION_ONLY = "PRC_PSIONIC_S * For the Psionic Slayer prestige class, this switch requires a character to make a "kill" * of a specific type of creature before the class becomes available. * - * Use of this switch requires that the module builder add a "Psionic Slayer Kill Token" - * (included in the PRC Items) to the designated creature. + * Use of this switch requires that the module builder add a "Psionic Slayer Kill Token" + * (included in the PRC Items) to the designated creature. * - * Alternately, a script or item can be made that will run the script "prc_psysly_killt" + * Alternately, a script or item can be made that will run the script "prc_psysly_killt" * on the PC. This script will set the flag that allows the target PC to take the Psionic Slayer Class. - * Example code: - * ExecuteScript("prc_psysly_killt", oPC); // Where oPC is an player charcter object + * Example code: + * ExecuteScript("prc_psysly_killt", oPC); // Where oPC is an player charcter object * - * This switch is provided to allow builders to more closely represent the Pen and Paper + * This switch is provided to allow builders to more closely represent the Pen and Paper * Illithid Slayer class, instead of the broader Open Game License "Slayer" class. * - * Type: Int + * Type: Int * Values: 0 [Default] (Kill Token / Script NOT required for taking the Psionic Slayer Class) - * 1 (Kill Token / Script REQUIRED before the Psionic Slayer Class is available to take) + * 1 (Kill Token / Script REQUIRED before the Psionic Slayer Class is available to take) */ const string PRC_PSIONIC_SLAYER_REQUIRE_KILL_TOKEN = "PRC_PSIONIC_SLAYER_REQUIRE_KILL_TOKEN"; @@ -605,19 +607,19 @@ const string PRC_PSIONIC_SLAYER_REQUIRE_KILL_TOKEN = "PRC_PSIONIC_SLAYER_R * By default the Werewolf class uses the Bioware Polymorph effect to perfrom its * Hybrid Form Shapchange. * - * This switch allows the Werewolf class to be toggled to use the PRC Shifter - * Shapchange code instead. + * This switch allows the Werewolf class to be toggled to use the PRC Shifter + * Shapchange code instead. * - * Type: Int + * Type: Int * Values: 0 [Default] (Werewolf Hybrid Shapchange uses Bioware Polymorph) - * 1 (Werewolf Hybrid Shapchange uses PRC Shifter shape change code) + * 1 (Werewolf Hybrid Shapchange uses PRC Shifter shape change code) */ -const string PRC_WEREWOLF_HYBRID_USE_SHIFTER_SHAPCHANGE = "PRC_WEREWOLF_HYBRID_USE_SHIFTER_SHAPCHANGE"; +const string PRC_WEREWOLF_HYBRID_USE_SHIFTER_SHAPECHANGE = "PRC_WEREWOLF_HYBRID_USE_SHIFTER_SHAPECHANGE"; /** * Sets the max bonus for the PnP Shifter shifting systems * - * Type: Int + * Type: Int * Values: any greater than 0 */ const string PRC_PNP_SHIFTER_BONUS = "PRC_PNP_SHIFTER_BONUS"; @@ -781,7 +783,7 @@ const string PRC_STAFF_CASTER_LEVEL = "PRC_STAFF_CASTER_LEVEL"; /** * [DEFUNCT] * A wand must be equipped before it can cast a spell - * + * * Any value above 0 turns off the requirement to have a wand equipped to use it * * This switch is defunct, wands must *always* be equipped to use them. @@ -929,7 +931,7 @@ const string PRC_PNP_FAMILIAR_FEEDING = "PRC_PNP_FAMILIAR_FEEDING /** * Use PRC henchmen-familiars instead of BioWare's - this will allow - * new classes to have familiars, but summoned creatures will no longer + * new classes to have familiars, but summoned creatures will no longer * be 'true' familiars (ie. can't possess PRC familiar) */ const string PRC_FAMILIARS = "PRC_FAMILIARS"; @@ -1112,7 +1114,7 @@ const string PRC_SPELL_ALIGNMENT_RESTRICT = "PRC_SPELL_ALIGNMENT_REST * Disable registration of custom cohorts */ const string PRC_DISABLE_REGISTER_COHORTS = "PRC_DISABLE_REGISTER_COHORTS"; - + /* * Disable cohorts starting with gear */ @@ -1142,19 +1144,19 @@ const string PRC_SPELL_ALIGNMENT_RESTRICT = "PRC_SPELL_ALIGNMENT_REST * Medium armor is a 25% speed reduction, Heavy is a 33% reduction */ const string PRC_PNP_ARMOR_SPEED = "PRC_PNP_ARMOR_SPEED"; - + /* * Applies a 99% speed boost when out of combat * Warning that it will likely cause PCs to be overly speedy when combat starts * Potential problem causer */ const string PRC_FAST_TRAVEL_SPEED = "PRC_FAST_TRAVEL_SPEED"; - + /* * Applys a Discipline bonus equal to BAB to all characters if turned on * Bonus only applies to characters with 0 ranks in Discipline */ - const string PRC_PNP_KNOCKDOWN = "PRC_PNP_KNOCKDOWN"; + const string PRC_PNP_KNOCKDOWN = "PRC_PNP_KNOCKDOWN"; /* * by Bioware rules, PCs have approximatly a 7th faster movement than NPCs @@ -1202,8 +1204,11 @@ const string PRC_SPELL_ALIGNMENT_RESTRICT = "PRC_SPELL_ALIGNMENT_REST */ const string PRC_APPEARNCE_CHANGE_DISABLE = "PRC_APPEARNCE_CHANGE_DISABLE"; - - +/* + * Allow "Monk" gloves to merge with a creature weapons when Wildshaped. + * Will also merge bracers with creature hides when Wildshaped. +*/ +const string PRC_WILDSHAPE_ALLOWS_ARMS_SLOT = "PRC_WILDSHAPE_ALLOWS_ARMS_SLOT"; /******************************************************************************\ * Death/Bleeding system * @@ -1221,7 +1226,7 @@ const string PRC_PNP_DEATH_ENABLE = "PRC_PNP_DEATH_ENA * if FALSE, dont bleed just die * By PnP this would be 1 round, or 6 seconds */ -const string PRC_DEATH_OR_BLEED = "PRC_DEATH_OR_BLEED"; +const string PRC_DEATH_OR_BLEED = "PRC_DEATH_OR_BLEED"; /* * Damage when bleeding @@ -1314,7 +1319,7 @@ const string PRC_ACP_DELAY = "PRC_ACP_DELAY"; /****************************************************************************** -* File End switches +* File End switches ******************************************************************************/ /** @@ -1488,10 +1493,10 @@ const string PRC_POISON_IS_FOOD_SCRIPT_NAME = "PRC_POISON_IS_FOOD_SCRIP const string PRC_POISON_ALLOW_CLEAN_IN_EQUIP = "PRC_POISON_ALLOW_CLEAN_IN_EQUIP"; /** - * + * * Default: crafting requires only gold and xp */ -const string PRC_CRAFT_POISON_USE_INGREDIENST = "PRC_CRAFT_POISON_USE_INGREDIENST"; +const string PRC_CRAFT_POISON_USE_INGREDIENTS = "PRC_CRAFT_POISON_USE_INGREDIENTS"; /******************************************************************************\ * PRGT system switches * @@ -1540,10 +1545,10 @@ const string PRC_PSI_ASTRAL_CONSTRUCT_DUR_MOD = "PRC_PSI_ASTRAL_CONSTRUCT /** * If this is set, The Astral Seed power will attempt to use the provided string as - * the ResRef to create the Astral Seed object instead of the of the phylactery + * the ResRef to create the Astral Seed object instead of the of the phylactery * ResRef("x2_plc_phylact"). * May be used by builders to create an object that CAN be destroyed, or has other traits, - * as desired. + * as desired. * Type: String * Values: "" [Default] (Blank, or not set: Use default phylactery ResRef for Astral Seed) * STRING (Entered String will be used as the ResRef of created Astral Seed object) @@ -1551,14 +1556,14 @@ const string PRC_PSI_ASTRAL_CONSTRUCT_DUR_MOD = "PRC_PSI_ASTRAL_CONSTRUCT const string PRC_PSI_ASTRAL_SEED_RESREF = "PRC_PSI_ASTRAL_SEED_RESREF"; /** - * By default the Astral Seed power respawns the player, and then makes them immobile for + * By default the Astral Seed power respawns the player, and then makes them immobile for * 24-game-hours. - * If this switch is set, it will adjust the imobility time period; shortening it, lengthing it, or + * If this switch is set, it will adjust the imobility time period; shortening it, lengthing it, or * effectively eliminating it. * Type: Int * Values: 0 [Default] (Not set: Use default 24 hour duration) * -1 (Any negative value will result in a fixed duratoion of 2 seconds, which effectively eliminates the wait period) - * 1 (Any potitive value: multiply duration by the value provided and then divide result by 1000. + * 1 (Any potitive value: multiply duration by the value provided and then divide result by 1000. * Values less than 1000 will shorten the duration, values higher than 1000 will lengthen it.) */ const string PRC_PSI_ASTRAL_SEED_RESPAWN_DELAY_X1000 = "PRC_PSI_ASTRAL_SEED_RESPAWN_DELAY_X1000"; @@ -1569,7 +1574,7 @@ const string PRC_PSI_ASTRAL_SEED_RESPAWN_DELAY_X1000 = "PRC_PSI_ASTRAL_SE * If this flag is set, the XP loss is completely eliminated. The standard PRC event hook script * of "prc_pw_astralseed" may be used to script any additional effects to occure upon Astral Seed * respawning, including scripting specific XP loss amount. - * Type: Int + * Type: Int * Values: 0 [Default] (Not set: lose 1 level worth of XP upon Astral Seed respawn) * 1 (Any potitive value: Remove all XP loss from Astral Seed respawn) */ @@ -1906,7 +1911,7 @@ const string PRC_CRAFT_TIMER_MAX = "PRC_CRAFT_TIMER_MAX"; */ const string PRC_CRAFT_TIMER_MIN = "PRC_CRAFT_TIMER_MIN"; -/** +/* * These three switches modify Bioware crafting so that the items produced have the * casterlevel of the spellcaster who created them. Normally under Bioware, it is possible * for a level 3 caster to produce level 9 items and for a level 40 caster to only produce @@ -1952,6 +1957,23 @@ const string PRC_CRAFT_ROD_CASTER_LEVEL = "PRC_CRAFT_ROD_CASTER_LEVE */ const string PRC_CRAFT_STAFF_CASTER_LEVEL = "PRC_CRAFT_STAFF_CASTER_LEVEL"; +/* + * As above, except it applies to scepters + */ +const string PRC_CRAFT_SCEPTER_CASTER_LEVEL = "PRC_CRAFT_SCEPTER_CASTER_LEVEL"; + +/* + * As above, except it applies to herbal infusions + */ +const string PRC_CREATE_INFUSION_CASTER_LEVEL = "PRC_CREATE_INFUSION_CASTER_LEVEL"; + +/* + * Builder's Option: Enables the optional PnP herbs for creating infusions. + * Each herb is keyed to a spell circle level & spell school as shown on pg. 33 + * of the Master's of the Wild sourcebook. + */ +const string PRC_CREATE_INFUSION_OPTIONAL_HERBS = "PRC_CREATE_INFUSION_OPTIONAL_HERBS"; + /* * Characters with a crafting feat always have the appropriate base item in their inventory */ @@ -1961,45 +1983,59 @@ const string PRC_CRAFTING_BASE_ITEMS = "PRC_CRAFTING_BASE_ITEMS"; * Max level of spells brewed into potions * defaults to 3 */ -const string X2_CI_BREWPOTION_MAXLEVEL = "X2_CI_BREWPOTION_MAXLEVEL"; +//const string X2_CI_BREWPOTION_MAXLEVEL = "X2_CI_BREWPOTION_MAXLEVEL"; +const string PRC_X2_BREWPOTION_MAXLEVEL = "PRC_X2_BREWPOTION_MAXLEVEL"; /* * cost modifier of spells brewed into poitions * defaults to 50 */ -const string X2_CI_BREWPOTION_COSTMODIFIER = "X2_CI_BREWPOTION_COSTMODIFIER"; +const string PRC_X2_BREWPOTION_COSTMODIFIER = "PRC_X2_BREWPOTION_COSTMODIFIER"; /* * cost modifier of spells scribed into scrolls * defaults to 25 */ -const string X2_CI_SCRIBESCROLL_COSTMODIFIER = "X2_CI_SCRIBESCROLL_COSTMODIFIER"; +const string PRC_X2_SCRIBESCROLL_COSTMODIFIER = "PRC_X2_SCRIBESCROLL_COSTMODIFIER"; + +/* + * cost modifier of spells infused into herbs + * defaults to 25 + */ +const string PRC_X2_CREATEINFUSION_COSTMODIFIER = "PRC_X2_CREATEINFUSION_COSTMODIFIER"; /* * Max level of spells crafted into wands * defaults to 4 */ -const string X2_CI_CRAFTWAND_MAXLEVEL = "X2_CI_CRAFTWAND_MAXLEVEL"; +const string PRC_X2_CRAFTWAND_MAXLEVEL = "PRC_X2_CRAFTWAND_MAXLEVEL"; /* * cost modifier of spells crafted into wands * defaults to 750 */ -const string X2_CI_CRAFTWAND_COSTMODIFIER = "X2_CI_CRAFTWAND_COSTMODIFIER"; +const string PRC_X2_CRAFTWAND_COSTMODIFIER = "PRC_X2_CRAFTWAND_COSTMODIFIER"; /* * cost modifier of spells crafted into rods * note that adding a second spell costs 75% and 3 or more costs 50% * defaults to 750 */ -const string X2_CI_CRAFTROD_COSTMODIFIER = "X2_CI_CRAFTROD_COSTMODIFIER"; +const string PRC_X2_CRAFTROD_COSTMODIFIER = "PRC_X2_CRAFTROD_COSTMODIFIER"; + +/* + * cost modifier of spells crafted into scepters + * note that adding a second spell costs 75% + * defaults to 750 + */ +const string PRC_X2_CRAFTSCEPTER_COSTMODIFIER = "PRC_X2_CRAFTSCEPTER_COSTMODIFIER"; /* * cost modifier of spells crafted into staffs * note that adding a second spell costs 75% and 3 or more costs 50% * defaults to 750 */ -const string X2_CI_CRAFTSTAFF_COSTMODIFIER = "X2_CI_CRAFTSTAFF_COSTMODIFIER"; +const string PRC_X2_CRAFTSTAFF_COSTMODIFIER = "PRC_X2_CRAFTSTAFF_COSTMODIFIER"; /** * Allows the use of arbitrary itemproperties and uses NWN item costs @@ -2321,7 +2357,7 @@ const string PRC_XP_GIVE_XP_TO_NPCS = "PRC_XP_GIVE_XP_TO_NPCS"; /** * Setting this switch will turn off the messages about being too far awy to gain XP */ -const string PRC_XP_DISABLE_SPAM = "PRC_XP_DISABLE_SPAM"; +const string PRC_XP_DISABLE_SPAM = "PRC_XP_DISABLE_SPAM"; /** * PCs must be in the same area as the CR to gain XP. @@ -2880,13 +2916,13 @@ const string PRC_PERFECTED_MAP_MULTIPLIER = "PRC_PERFECTED_MAP_MULTIP \******************************************************************************/ /** - * Sets how many seconds it takes to contact a vestige. + * Sets how many seconds it takes to contact a vestige. * Any number less than 6 is ignored */ const string PRC_CONTACT_VESTIGE_TIMER = "PRC_CONTACT_VESTIGE_TIMER"; /** - * Sets how many seconds it takes to bind a vestige. + * Sets how many seconds it takes to bind a vestige. * Any number less than 12 is ignored */ const string PRC_BIND_VESTIGE_TIMER = "PRC_BIND_VESTIGE_TIMER"; @@ -2920,6 +2956,20 @@ const string PRC_PW_SECURITY_CD_CHECK = "PRC_PW_SECURITY_CD_CHECK"; */ const string PRC_DEBUG = "PRC_DEBUG"; +/******************************************************************************\ +* Duration NUI Switches * +\******************************************************************************/ + +/** + * Toggles allowing player to remove friendly PC spells on player through Duration NUI + * instead of just their own spells. + */ +const string PRC_ALLOWED_TO_REMOVE_FRIENDLY_SPELLS = "PRC_ALLOWED_TO_REMOVE_FRIENDLY_SPELLS"; +/** + * Toggles allowing players to see the duration of hostile spells on them. + */ +const string PRC_ALLOWED_TO_SEE_HOSTILE_SPELLS = "PRC_ALLOWED_TO_SEE_HOSTILE_SPELLS"; + diff --git a/src/include/prc_inc_turning.nss b/src/include/prc_inc_turning.nss index 5504819..2b6852f 100644 --- a/src/include/prc_inc_turning.nss +++ b/src/include/prc_inc_turning.nss @@ -10,21 +10,12 @@ //::////////////////////////////////////////////// //::////////////////////////////////////////////// +#include "prc_spell_const" + ////////////////////////////////////////////////// /* Function prototypes */ ////////////////////////////////////////////////// - - - - - - - - - - - //gets the number of class levels that count for turning int GetTurningClassLevel(object oCaster = OBJECT_SELF, int nTurnType = SPELL_TURN_UNDEAD); @@ -191,6 +182,20 @@ int GetIsTurnOrRebuke(object oTarget, int nTurnType, int nTargetRace) break; } + case SPELL_PLANT_DEFIANCE: + { + if(nTargetRace == RACIAL_TYPE_PLANT) + nReturn = ACTION_TURN; + + break; + } + case SPELL_PLANT_CONTROL: + { + if(nTargetRace == RACIAL_TYPE_PLANT) + nReturn = ACTION_REBUKE; + + break; + } case SPELL_TURN_PLANT: { // Plant domain rebukes or commands plants @@ -383,6 +388,13 @@ int GetTurningClassLevel(object oCaster = OBJECT_SELF, int nTurnType = SPELL_TUR if (nTurnType == SPELL_OPPORTUNISTIC_PIETY_TURN) return GetLevelByClass(CLASS_TYPE_FACTOTUM, oCaster); + + if (nTurnType == SPELL_PLANT_DEFIANCE || nTurnType == SPELL_PLANT_CONTROL) + { + int nDivineLvl = GetPrCAdjustedCasterLevelByType(TYPE_DIVINE, oCaster); + + return nDivineLvl; + } //Baelnorn & Archlich adds all class levels. if(GetLevelByClass(CLASS_TYPE_BAELNORN, oCaster) || GetHasFeat(FEAT_TEMPLATE_ARCHLICH_MARKER, oCaster)) //:: Archlich diff --git a/src/include/prc_inc_unarmed.nss b/src/include/prc_inc_unarmed.nss index a08f912..27c3245 100644 --- a/src/include/prc_inc_unarmed.nss +++ b/src/include/prc_inc_unarmed.nss @@ -91,6 +91,107 @@ float DamageAvg(int iDamage); /* Function defintions */ ////////////////////////////////////////////////// +// StepDie: increases a damage die by 'nSteps' steps according to d20 SRD progression +// Increment the unarmed damage by nSteps +int StepDie(int nDamage, int nSteps) +{ + int i; + for (i = 0; i < nSteps; i++) + { + switch (nDamage) + { + // 1-dice increments + case IP_CONST_MONSTERDAMAGE_1d2: nDamage = IP_CONST_MONSTERDAMAGE_1d3; break; + case IP_CONST_MONSTERDAMAGE_1d3: nDamage = IP_CONST_MONSTERDAMAGE_1d4; break; + case IP_CONST_MONSTERDAMAGE_1d4: nDamage = IP_CONST_MONSTERDAMAGE_1d6; break; + case IP_CONST_MONSTERDAMAGE_1d6: nDamage = IP_CONST_MONSTERDAMAGE_1d8; break; + case IP_CONST_MONSTERDAMAGE_1d8: nDamage = IP_CONST_MONSTERDAMAGE_1d10; break; + case IP_CONST_MONSTERDAMAGE_1d10: nDamage = IP_CONST_MONSTERDAMAGE_1d12; break; + case IP_CONST_MONSTERDAMAGE_1d12: nDamage = IP_CONST_MONSTERDAMAGE_2d8; break; + + // 2-dice increments + //case IP_CONST_MONSTERDAMAGE_2d3: nDamage = IP_CONST_MONSTERDAMAGE_2d4; break; + case IP_CONST_MONSTERDAMAGE_2d4: nDamage = IP_CONST_MONSTERDAMAGE_2d6; break; + case IP_CONST_MONSTERDAMAGE_2d6: nDamage = IP_CONST_MONSTERDAMAGE_2d8; break; + case IP_CONST_MONSTERDAMAGE_2d8: nDamage = IP_CONST_MONSTERDAMAGE_2d10; break; + case IP_CONST_MONSTERDAMAGE_2d10: nDamage = IP_CONST_MONSTERDAMAGE_2d12; break; + case IP_CONST_MONSTERDAMAGE_2d12: nDamage = IP_CONST_MONSTERDAMAGE_3d10; break; + + // 3-dice increments + case IP_CONST_MONSTERDAMAGE_3d4: nDamage = IP_CONST_MONSTERDAMAGE_3d6; break; + case IP_CONST_MONSTERDAMAGE_3d6: nDamage = IP_CONST_MONSTERDAMAGE_3d8; break; + case IP_CONST_MONSTERDAMAGE_3d8: nDamage = IP_CONST_MONSTERDAMAGE_3d10; break; + case IP_CONST_MONSTERDAMAGE_3d10: nDamage = IP_CONST_MONSTERDAMAGE_3d12; break; + case IP_CONST_MONSTERDAMAGE_3d12: nDamage = IP_CONST_MONSTERDAMAGE_4d8; break; + + // 4-dice increments + case IP_CONST_MONSTERDAMAGE_4d4: nDamage = IP_CONST_MONSTERDAMAGE_4d6; break; + case IP_CONST_MONSTERDAMAGE_4d6: nDamage = IP_CONST_MONSTERDAMAGE_4d8; break; + case IP_CONST_MONSTERDAMAGE_4d8: nDamage = IP_CONST_MONSTERDAMAGE_4d10; break; + case IP_CONST_MONSTERDAMAGE_4d10: nDamage = IP_CONST_MONSTERDAMAGE_4d12; break; + case IP_CONST_MONSTERDAMAGE_4d12: nDamage = IP_CONST_MONSTERDAMAGE_5d8; break; + + // 5-dice increments + case IP_CONST_MONSTERDAMAGE_5d4: nDamage = IP_CONST_MONSTERDAMAGE_5d6; break; + case IP_CONST_MONSTERDAMAGE_5d6: nDamage = IP_CONST_MONSTERDAMAGE_5d8; break; + case IP_CONST_MONSTERDAMAGE_5d8: nDamage = IP_CONST_MONSTERDAMAGE_5d10; break; + case IP_CONST_MONSTERDAMAGE_5d10: nDamage = IP_CONST_MONSTERDAMAGE_5d12; break; + case IP_CONST_MONSTERDAMAGE_5d12: nDamage = IP_CONST_MONSTERDAMAGE_6d10; break; + + // 6-dice increments + //case IP_CONST_MONSTERDAMAGE_6d4: nDamage = IP_CONST_MONSTERDAMAGE_6d6; break; + case IP_CONST_MONSTERDAMAGE_6d6: nDamage = IP_CONST_MONSTERDAMAGE_6d8; break; + case IP_CONST_MONSTERDAMAGE_6d8: nDamage = IP_CONST_MONSTERDAMAGE_6d10; break; + case IP_CONST_MONSTERDAMAGE_6d10: nDamage = IP_CONST_MONSTERDAMAGE_6d12; break; + case IP_CONST_MONSTERDAMAGE_6d12: nDamage = IP_CONST_MONSTERDAMAGE_7d10; break; + + // 7-dice increments + case IP_CONST_MONSTERDAMAGE_7d4: nDamage = IP_CONST_MONSTERDAMAGE_7d6; break; + case IP_CONST_MONSTERDAMAGE_7d6: nDamage = IP_CONST_MONSTERDAMAGE_7d8; break; + case IP_CONST_MONSTERDAMAGE_7d8: nDamage = IP_CONST_MONSTERDAMAGE_7d10; break; + case IP_CONST_MONSTERDAMAGE_7d10: nDamage = IP_CONST_MONSTERDAMAGE_7d12; break; + case IP_CONST_MONSTERDAMAGE_7d12: nDamage = IP_CONST_MONSTERDAMAGE_9d10; break; + + // 8-dice increments + //case IP_CONST_MONSTERDAMAGE_8d4: nDamage = IP_CONST_MONSTERDAMAGE_8d6; break; + case IP_CONST_MONSTERDAMAGE_8d6: nDamage = IP_CONST_MONSTERDAMAGE_8d8; break; + case IP_CONST_MONSTERDAMAGE_8d8: nDamage = IP_CONST_MONSTERDAMAGE_8d10; break; + case IP_CONST_MONSTERDAMAGE_8d10: nDamage = IP_CONST_MONSTERDAMAGE_8d12; break; + case IP_CONST_MONSTERDAMAGE_8d12: nDamage = IP_CONST_MONSTERDAMAGE_10d10; break; + + // 9-dice increments + //case IP_CONST_MONSTERDAMAGE_9d4: nDamage = IP_CONST_MONSTERDAMAGE_9d6; break; + case IP_CONST_MONSTERDAMAGE_9d6: nDamage = IP_CONST_MONSTERDAMAGE_9d8; break; + case IP_CONST_MONSTERDAMAGE_9d8: nDamage = IP_CONST_MONSTERDAMAGE_9d10; break; + case IP_CONST_MONSTERDAMAGE_9d10: nDamage = IP_CONST_MONSTERDAMAGE_9d12; break; + case IP_CONST_MONSTERDAMAGE_9d12: nDamage = IP_CONST_MONSTERDAMAGE_6d20; break; + + // 10-dice increments + //case IP_CONST_MONSTERDAMAGE_10d4: nDamage = IP_CONST_MONSTERDAMAGE_10d6; break; + case IP_CONST_MONSTERDAMAGE_10d6: nDamage = IP_CONST_MONSTERDAMAGE_10d8; break; + case IP_CONST_MONSTERDAMAGE_10d8: nDamage = IP_CONST_MONSTERDAMAGE_10d10; break; + case IP_CONST_MONSTERDAMAGE_10d10: nDamage = IP_CONST_MONSTERDAMAGE_10d12; break; + case IP_CONST_MONSTERDAMAGE_10d12: nDamage = IP_CONST_MONSTERDAMAGE_7d20; break; + + // d20 increments + case IP_CONST_MONSTERDAMAGE_1d20: nDamage = IP_CONST_MONSTERDAMAGE_3d8; break; + case IP_CONST_MONSTERDAMAGE_2d20: nDamage = IP_CONST_MONSTERDAMAGE_4d12; break; + case IP_CONST_MONSTERDAMAGE_3d20: nDamage = IP_CONST_MONSTERDAMAGE_8d8; break; + case IP_CONST_MONSTERDAMAGE_4d20: nDamage = IP_CONST_MONSTERDAMAGE_8d12; break; + case IP_CONST_MONSTERDAMAGE_5d20: nDamage = IP_CONST_MONSTERDAMAGE_9d12; break; //:: Everything breaks down here + case IP_CONST_MONSTERDAMAGE_6d20: nDamage = IP_CONST_MONSTERDAMAGE_1d20; break; + case IP_CONST_MONSTERDAMAGE_7d20: nDamage = IP_CONST_MONSTERDAMAGE_8d20; break; + case IP_CONST_MONSTERDAMAGE_8d20: nDamage = IP_CONST_MONSTERDAMAGE_9d20; break; + case IP_CONST_MONSTERDAMAGE_9d20: nDamage = IP_CONST_MONSTERDAMAGE_10d20; break; + + default: break; // top tier or unknown + } + } + + return nDamage; +} + + // Clean up any extras in the inventory. void CleanExtraFists(object oCreature) { @@ -168,12 +269,169 @@ void ApplyUnarmedAttackEffects(object oCreature) } // Determines the amount of damage a character can do. -// IoDM: +1 dice at level 4, +2 dice at level 8 +// IoDM: +1 die at level 4, +2 dice at level 8 // Sacred Fist: Levels add to monk levels, or stand alone as monk levels. // Shou: 1d6 at level 1, 1d8 at level 2, 1d10 at level 3, 2d6 at level 5 // Monk: 1d6 at level 1, 1d8 at level 4, 1d10 at level 8, 2d6 at level 12, 2d8 at level 16, 2d10 at level 20 // Frostrager: 1d6 at level 1, 1d8 at level 4 int FindUnarmedDamage(object oCreature) +{ + int iDamage = 0; + int iMonk = GetLevelByClass(CLASS_TYPE_MONK, oCreature) + GetLocalInt(oCreature, "LiPengMonk"); + int iShou = GetLevelByClass(CLASS_TYPE_SHOU, oCreature); + int iBrawler = GetLevelByClass(CLASS_TYPE_BRAWLER, oCreature); + int iSacredFist = GetLevelByClass(CLASS_TYPE_SACREDFIST, oCreature); + int iEnlightenedFist = GetLevelByClass(CLASS_TYPE_ENLIGHTENEDFIST, oCreature); + int iHenshin = GetLevelByClass(CLASS_TYPE_HENSHIN_MYSTIC, oCreature); + int iZuoken = GetLevelByClass(CLASS_TYPE_FIST_OF_ZUOKEN, oCreature); + int iShadowSunNinja = GetLevelByClass(CLASS_TYPE_SHADOW_SUN_NINJA, oCreature); + int iFrost = GetLevelByClass(CLASS_TYPE_FROSTRAGER, oCreature); + int iAscetic = GetLevelByClass(CLASS_TYPE_NINJA, oCreature); + int iRonove = 0; + int iMonkDamage = 1; + int iShouDamage = 1; + int iBrawlerDamage = 1; + int iFrostDamage = 1; + int iSUSDamage = 1; + int iDieIncrease = 0; + int iSize; + + if (GetHasSpellEffect(VESTIGE_RONOVE, oCreature) && GetLevelByClass(CLASS_TYPE_BINDER, oCreature)) + iRonove = GetLocalInt(oCreature, "RonovesFists"); + + //:: Determine creature size + if( GetIsPolyMorphedOrShifted(oCreature) || GetPRCSwitch(PRC_APPEARANCE_SIZE)) + { + iSize = PRCGetCreatureSize(oCreature) - CREATURE_SIZE_MEDIUM + 5; + } + else + { + iSize = 5; // medium + if (GetHasFeat(FEAT_TINY, oCreature)) iSize = 3; + if (GetHasFeat(FEAT_SMALL, oCreature)) iSize = 4; + if (GetHasFeat(FEAT_LARGE, oCreature)) iSize = 6; + if (GetHasFeat(FEAT_HUGE, oCreature)) iSize = 7; + iSize += PRCGetCreatureSize(oCreature) - PRCGetCreatureSize(oCreature, PRC_SIZEMASK_NONE); + if (iSize < 1) iSize = 1; + if (iSize > 9) iSize = 9; + } + + // Sacred Fist code break protection + if (GetHasFeat(FEAT_SF_CODE, oCreature)) iSacredFist = 0; + + // Combine monk-like levels + iMonk += iSacredFist + iHenshin + iEnlightenedFist + iShou + iZuoken + iShadowSunNinja; + + // Superior Unarmed Strike + if (GetHasFeat(FEAT_SUPERIOR_UNARMED_STRIKE, oCreature)) + { + iMonk += 4; + int nHD = GetHitDice(oCreature); + if (nHD >= 16) iSUSDamage = IP_CONST_MONSTERDAMAGE_2d6; + else if (nHD >= 12) iSUSDamage = IP_CONST_MONSTERDAMAGE_1d10; + else if (nHD >= 8) iSUSDamage = IP_CONST_MONSTERDAMAGE_1d8; + else if (nHD >= 4) iSUSDamage = IP_CONST_MONSTERDAMAGE_1d6; + else if (nHD >= 3) iSUSDamage = IP_CONST_MONSTERDAMAGE_1d4; + } + + // Ascetic Stalker + if (GetHasFeat(FEAT_ASCETIC_STALKER, oCreature)) + iMonk += iAscetic; + + // Cap monk progression + if (iMonk > 16 && !GetPRCSwitch(PRC_3_5e_FIST_DAMAGE)) iMonk = 16; + else if (iMonk > 20) iMonk = 20; + + // Ronove replacement + if (iRonove > iMonk) iMonk = iRonove; + + // Monk damage calculation (2DA row) + if (iMonk > 0) iMonkDamage = iMonk / 4 + 3; + if (iSize == 5 && iMonkDamage == 7 && !GetPRCSwitch(PRC_3_5e_FIST_DAMAGE)) + iMonkDamage = 8; + + // Shou Disciple base damage + if (iShou > 0) + { + int nRow; + if (iShou == 1) nRow = 3; + else if (iShou == 2) nRow = 4; + else if (iShou == 3) nRow = 5; + else if (iShou == 4) nRow = 5; + else if (iShou == 5) nRow = 6; + else nRow = 3; + + if (nRow > 6) nRow = 6; + + iShouDamage = StringToInt(Get2DACache("unarmed_dmg", "size" + IntToString(iSize), nRow)); + } + + // Frostrager + if (iFrost > 0) iFrostDamage = IP_CONST_MONSTERDAMAGE_1d6; + if (iFrost > 3) iFrostDamage = IP_CONST_MONSTERDAMAGE_1d8; + + // Brawler + if (iBrawler > 0) iBrawlerDamage = iBrawler / 6 + 3; + if (iBrawler >= 36) iBrawlerDamage += 2; + + // Armor/shield penalties + if (iMonkDamage > 1) + { + object oArmor = GetItemInSlot(INVENTORY_SLOT_CHEST, oCreature); + object oShield = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oCreature); + int bShieldEq = GetBaseItemType(oShield) == BASE_ITEM_SMALLSHIELD || + GetBaseItemType(oShield) == BASE_ITEM_LARGESHIELD || + GetBaseItemType(oShield) == BASE_ITEM_TOWERSHIELD; + if (GetBaseAC(oArmor) > 0 || bShieldEq) + iMonkDamage = 1; + } + + if (iShouDamage > 1) + { + object oArmor = GetItemInSlot(INVENTORY_SLOT_CHEST, oCreature); + object oShield = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oCreature); + int bShieldEq = GetBaseItemType(oShield) == BASE_ITEM_SMALLSHIELD || + GetBaseItemType(oShield) == BASE_ITEM_LARGESHIELD || + GetBaseItemType(oShield) == BASE_ITEM_TOWERSHIELD; + if (GetBaseAC(oArmor) > 3 || bShieldEq) + iShouDamage = 1; + } + + // Determine IoDM die increase + if (GetHasFeat(FEAT_INCREASE_DAMAGE2, oCreature)) iDieIncrease = 2; + else if (GetHasFeat(FEAT_INCREASE_DAMAGE1, oCreature)) iDieIncrease = 1; + + // Lookup monk damage in 2DA + iMonkDamage = StringToInt(Get2DACache("unarmed_dmg","size" + IntToString(iSize), iMonkDamage)); + + // 3.0e monk special cases + if (iSize <= 5 && !GetPRCSwitch(PRC_3_5e_FIST_DAMAGE)) + { + if (iMonkDamage == IP_CONST_MONSTERDAMAGE_2d6) iMonkDamage = IP_CONST_MONSTERDAMAGE_1d12; + if (iMonkDamage == IP_CONST_MONSTERDAMAGE_2d10) iMonkDamage = IP_CONST_MONSTERDAMAGE_1d20; + } + + // Apply IoDM die increase last, after 2DA lookups + if (iMonkDamage > 0) iMonkDamage = StepDie(iMonkDamage, iDieIncrease); + if (iShouDamage > 0) iShouDamage = StepDie(iShouDamage, iDieIncrease); + if (iBrawlerDamage > 0) iBrawlerDamage = StepDie(iBrawlerDamage, iDieIncrease); + if (iFrostDamage > 0) iFrostDamage = StepDie(iFrostDamage, iDieIncrease); + if (iSUSDamage > 0) iSUSDamage = StepDie(iSUSDamage, iDieIncrease); + + // Select best damage + iDamage = iMonkDamage; + iDamage = (DamageAvg(iShouDamage ) > DamageAvg(iDamage)) ? iShouDamage : iDamage; + iDamage = (DamageAvg(iFrostDamage ) > DamageAvg(iDamage)) ? iFrostDamage : iDamage; + iDamage = (DamageAvg(iSUSDamage ) > DamageAvg(iDamage)) ? iSUSDamage : iDamage; + iDamage = (DamageAvg(iBrawlerDamage) > DamageAvg(iDamage)) ? iBrawlerDamage : iDamage; + + if (DEBUG) DoDebug("prc_inc_unarmed: iDamage "+IntToString(iDamage)); + + return iDamage; +} + + +/* int FindUnarmedDamage(object oCreature) { int iDamage = 0; int iMonk = GetLevelByClass(CLASS_TYPE_MONK, oCreature) + GetLocalInt(oCreature, "LiPengMonk"); @@ -195,36 +453,30 @@ int FindUnarmedDamage(object oCreature) int iDieIncrease = 0; int iSize; - if (GetHasSpellEffect(VESTIGE_RONOVE, oCreature) && GetLevelByClass(CLASS_TYPE_BINDER, oCreature)) iRonove = GetLocalInt(oCreature, "RonovesFists"); + if (GetHasSpellEffect(VESTIGE_RONOVE, oCreature) && GetLevelByClass(CLASS_TYPE_BINDER, oCreature)) + iRonove = GetLocalInt(oCreature, "RonovesFists"); - // if the creature is shifted, use model size - // otherwise, we want to stick to what the feats say they "should" be. - // No making pixies with Dragon Appearance for "huge" fist damage. - if( GetIsPolyMorphedOrShifted(oCreature) - || GetPRCSwitch(PRC_APPEARANCE_SIZE)) + // Determine creature size + if( GetIsPolyMorphedOrShifted(oCreature) || GetPRCSwitch(PRC_APPEARANCE_SIZE)) { - iSize = PRCGetCreatureSize(oCreature) - CREATURE_SIZE_MEDIUM + 5; // medium is size 5 for us + iSize = PRCGetCreatureSize(oCreature) - CREATURE_SIZE_MEDIUM + 5; } else { - // Determine creature size by feats. - iSize = 5; // medium is size 5 for us + iSize = 5; // medium if (GetHasFeat(FEAT_TINY, oCreature)) iSize = 3; if (GetHasFeat(FEAT_SMALL, oCreature)) iSize = 4; if (GetHasFeat(FEAT_LARGE, oCreature)) iSize = 6; if (GetHasFeat(FEAT_HUGE, oCreature)) iSize = 7; - // include size changes iSize += PRCGetCreatureSize(oCreature) - PRCGetCreatureSize(oCreature, PRC_SIZEMASK_NONE); - // cap if needed if (iSize < 1) iSize = 1; if (iSize > 9) iSize = 9; } - // Sacred Fist cannot add their levels if they've broken their code. + // Sacred Fist code break protection if (GetHasFeat(FEAT_SF_CODE, oCreature)) iSacredFist = 0; - // several classes add their levels to the monk class, - // or use monk progression if the character has no monk levels + // Combine monk-like levels iMonk += iSacredFist + iHenshin + iEnlightenedFist + iShou + iZuoken + iShadowSunNinja; // Superior Unarmed Strike @@ -232,49 +484,66 @@ int FindUnarmedDamage(object oCreature) { iMonk += 4; int nHD = GetHitDice(oCreature); - if (nHD >= 16) iSUSDamage = IP_CONST_MONSTERDAMAGE_2d6; + if (nHD >= 16) iSUSDamage = IP_CONST_MONSTERDAMAGE_2d6; else if (nHD >= 12) iSUSDamage = IP_CONST_MONSTERDAMAGE_1d10; - else if (nHD >= 8) iSUSDamage = IP_CONST_MONSTERDAMAGE_1d8; - else if (nHD >= 4) iSUSDamage = IP_CONST_MONSTERDAMAGE_1d6; - else if (nHD >= 3) iSUSDamage = IP_CONST_MONSTERDAMAGE_1d4; + else if (nHD >= 8) iSUSDamage = IP_CONST_MONSTERDAMAGE_1d8; + else if (nHD >= 4) iSUSDamage = IP_CONST_MONSTERDAMAGE_1d6; + else if (nHD >= 3) iSUSDamage = IP_CONST_MONSTERDAMAGE_1d4; } // Ascetic Stalker if (GetHasFeat(FEAT_ASCETIC_STALKER, oCreature)) iMonk += iAscetic; - // In 3.0e, Monk progression stops after level 16: - if (iMonk > 16 && !GetPRCSwitch(PRC_3_5e_FIST_DAMAGE) ) iMonk = 16; - // in 3.5e, monk progression stops at 20. - else if(iMonk > 20) iMonk = 20; + // Cap monk progression + if (iMonk > 16 && !GetPRCSwitch(PRC_3_5e_FIST_DAMAGE)) iMonk = 16; + else if (iMonk > 20) iMonk = 20; - // Ronove is in place of monk, does not stack + // Ronove replacement if (iRonove > iMonk) iMonk = iRonove; - // monks damage progesses every four levels, starts at 1d6 - if (iMonk > 0) - iMonkDamage = iMonk / 4 + 3; + // Monk damage calculation + if (iMonk > 0) iMonkDamage = iMonk / 4 + 3; - // For medium monks in 3.0e skip 2d8 and go to 1d20 - if(iSize == 5 && iMonkDamage == 7 && !GetPRCSwitch(PRC_3_5e_FIST_DAMAGE) ) iMonkDamage = 8; + if(iSize == 5 && iMonkDamage == 7 && !GetPRCSwitch(PRC_3_5e_FIST_DAMAGE)) + iMonkDamage = 8; // Shou Disciple either adds its level to existing class or does its own damage, depending // on which is better. Here we will determine how much damage the Shou Disciple does // without stacking. - if (iShou > 0) iShouDamage = iShou + 2; // Lv. 1: 1d6, Lv. 2: 1d8, Lv. 3: 1d10 - if (iShou > 3) iShouDamage--; // Lv. 4: 1d10, Lv. 5: 2d6 - iShouDamage = StringToInt(Get2DACache("unarmed_dmg","size" + IntToString(iSize), iShouDamage)); - - // Frostrager does not stack with other damage types - if (iFrost > 0) iFrostDamage = IP_CONST_MONSTERDAMAGE_1d6; // Lv. 1: 1d6 - if (iFrost > 3) iFrostDamage = IP_CONST_MONSTERDAMAGE_1d8; // Lv. 3: 1d8 + //if (iShou > 0) iShouDamage = iShou + 2; // Lv. 1: 1d6, Lv. 2: 1d8, Lv. 3: 1d10 + //if (iShou > 3) iShouDamage--; // Lv. 4: 1d10, Lv. 5: 2d6 + //iShouDamage = StringToInt(Get2DACache("unarmed_dmg","size" + IntToString(iSize), iShouDamage)); + + if (iShou > 0) + { + // Determine 2DA row for Shou progression + int nRow; + if (iShou == 1) nRow = 3; // monk1 + else if (iShou == 2) nRow = 4; // monk2 + else if (iShou == 3) nRow = 5; // monk3 + else if (iShou == 4) nRow = 6; // monk4 + else if (iShou == 5) nRow = 7; // monk5 + else if (iShou == 6) nRow = 8; // monk6 + else if (iShou == 7) nRow = 9; // monk7 + else nRow = 10; // monk8+ + + nRow += iDieIncrease; + if (nRow > 10) nRow = 10; // clamp to max row - // Brawler follows monk progression except for the last one (3d8) - if (iBrawler > 0) iBrawlerDamage = iBrawler / 6 + 3; // 1d6, 1d8, 1d10, 2d6, 2d8, 2d10 - if (iBrawler >= 36) iBrawlerDamage += 2; // 3d8 + // Lookup damage in unarmed_damage.2da using size column + iShouDamage = StringToInt(Get2DACache("unarmed_dmg","size" + IntToString(iSize), nRow)); + } - // Monks and monk-like classes deal no additional damage when wearing any armor, at - // least in NWN. This is to reflect that. No shields too. + // Frostrager + if (iFrost > 0) iFrostDamage = IP_CONST_MONSTERDAMAGE_1d6; + if (iFrost > 3) iFrostDamage = IP_CONST_MONSTERDAMAGE_1d8; + + // Brawler + if (iBrawler > 0) iBrawlerDamage = iBrawler / 6 + 3; + if (iBrawler >= 36) iBrawlerDamage += 2; + + // Armor/shield penalties if (iMonkDamage > 1) { object oArmor = GetItemInSlot(INVENTORY_SLOT_CHEST, oCreature); @@ -284,13 +553,10 @@ int FindUnarmedDamage(object oCreature) GetBaseItemType(oShield) == BASE_ITEM_TOWERSHIELD; if (GetBaseAC(oArmor) > 0 || bShieldEq) - { iMonkDamage = 1; - } } -// Shou Disciples can wear light armor - if (iShouDamage > 1) + if (iShouDamage > 1) { object oArmor = GetItemInSlot(INVENTORY_SLOT_CHEST, oCreature); object oShield = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oCreature); @@ -299,53 +565,31 @@ int FindUnarmedDamage(object oCreature) GetBaseItemType(oShield) == BASE_ITEM_TOWERSHIELD; if (GetBaseAC(oArmor) > 3 || bShieldEq) - { - iShouDamage = 1; - } + iShouDamage = 1; } - // For Initiate of Draconic Mysteries - if (GetHasFeat(FEAT_INCREASE_DAMAGE2, oCreature)) iDieIncrease = 2; - else if (GetHasFeat(FEAT_INCREASE_DAMAGE1, oCreature)) iDieIncrease = 1; - - //:: Expansion / Compression powers - int nExpansion = GetLocalInt(oCreature, "PRC_Power_Expansion_SizeIncrease"); - int nCompression = GetLocalInt(oCreature, "PRC_Power_Compression_SizeReduction"); - - if (nExpansion) - { - iSize += nExpansion; - } - - if (nCompression) - { - iSize -= nCompression; - } + // IoDM die increase + if (GetHasFeat(FEAT_INCREASE_DAMAGE2, oCreature)) iDieIncrease += 2; + else if (GetHasFeat(FEAT_INCREASE_DAMAGE1, oCreature)) iDieIncrease += 1; iMonkDamage += iDieIncrease; iShouDamage += iDieIncrease; iBrawlerDamage += iDieIncrease; iFrostDamage += iDieIncrease; iSUSDamage += iDieIncrease; - - //FloatingTextStringOnCreature("prc_inc_unarmed: Size is: "+IntToString(iSize)+".", oCreature); - //FloatingTextStringOnCreature("prc_inc_unarmed: Pre 2DA Lookup >> iMonkDamage = "+IntToString(iMonkDamage)+".", oCreature); - // now, read the damage from the table in unarmed_dmg.2da + // Lookup final monk damage in 2DA iMonkDamage = StringToInt(Get2DACache("unarmed_dmg","size" + IntToString(iSize), iMonkDamage)); - iShouDamage = StringToInt(Get2DACache("unarmed_dmg","size" + IntToString(iSize), iShouDamage)); - - //FloatingTextStringOnCreature("prc_inc_unarmed: Post 2DA Lookup >> iMonkDamage = "+IntToString(iMonkDamage)+".", oCreature); - // Medium+ monks have some special values on the table in 3.0: + // 3.0e monk special cases if (iSize >= 5 && !GetPRCSwitch(PRC_3_5e_FIST_DAMAGE)) { if (iMonkDamage == IP_CONST_MONSTERDAMAGE_2d6) iMonkDamage = IP_CONST_MONSTERDAMAGE_1d12; if (iMonkDamage == IP_CONST_MONSTERDAMAGE_2d10) iMonkDamage = IP_CONST_MONSTERDAMAGE_1d20; } + // Select best damage iDamage = iMonkDamage; - // Future unarmed classes: if you do your own damage, add in "comparisons" below here. iDamage = (DamageAvg(iShouDamage ) > DamageAvg(iDamage)) ? iShouDamage : iDamage; iDamage = (DamageAvg(iFrostDamage ) > DamageAvg(iDamage)) ? iFrostDamage : iDamage; iDamage = (DamageAvg(iSUSDamage ) > DamageAvg(iDamage)) ? iSUSDamage : iDamage; @@ -354,6 +598,8 @@ int FindUnarmedDamage(object oCreature) return iDamage; } + */ + // Adds appropriate feats to the skin. Stolen from SoulTaker + expanded with overwhelming/devastating critical. void UnarmedFeats(object oCreature) @@ -426,13 +672,13 @@ void UnarmedFists(object oCreature) // Sacred Fists who break their code get no benefits. if (GetHasFeat(FEAT_SF_CODE,oCreature)) iSacFist = 0; - + // The monk adds all these classes. - int iMonkEq = iMonk + iShou + iSacFist + iHenshin + iZuoken + iShadowSunNinja; - + int iMonkEq = iMonk + iShou + iSacFist + iHenshin + iZuoken + iShadowSunNinja; + // Ascetic Stalker if (GetHasFeat(FEAT_ASCETIC_STALKER, oCreature)) - iMonkEq += iAscetic; + iMonkEq += iAscetic; // Determine the type of damage the character should do. string sWeapType; diff --git a/src/include/prc_inc_wpnrest.nss b/src/include/prc_inc_wpnrest.nss index 401b323..0a59892 100644 --- a/src/include/prc_inc_wpnrest.nss +++ b/src/include/prc_inc_wpnrest.nss @@ -1,6 +1,6 @@ //:://///////////////////////////////////////////// //:: Weapon Restriction System Include -//:: prc_inc_restwpn.nss +//:: prc_inc_wpnrest.nss //:://///////////////////////////////////////////// /* Functions to support PnP Weapon Proficiency and @@ -15,6 +15,56 @@ #include "inc_item_props" #include "prc_x2_itemprop" +//:: Detects if "monk" gloves are being equipped & set a +//:: variable if TRUE for use with other functions +void DetectMonkGloveEquip(object oItem) +{ + int nItemType = GetBaseItemType(oItem); + + object oPC = GetItemPossessor(oItem); + if (!GetIsObjectValid(oItem)) + { + if (DEBUG) DoDebug("prc_inc_wpnrest >> DetectMonkGloveEquip(): Unable to determine item possessor"); + return; + } + + if(nItemType != BASE_ITEM_GLOVES && nItemType != BASE_ITEM_BRACER) {return;} + + else if (nItemType == BASE_ITEM_BRACER) + { + if(DEBUG) DoDebug("prc_inc_wpnrest >> DetectMonkGloveEquip(): Bracer found!"); + DeleteLocalInt(oPC, "WEARING_MONK_GLOVES"); + return; + } + else + { + itemproperty ipG = GetFirstItemProperty(oItem); + + while(GetIsItemPropertyValid(ipG)) + { + int nTypeG = GetItemPropertyType(ipG); + + // Damage related properties we care about + if(nTypeG == ITEM_PROPERTY_DAMAGE_BONUS + || nTypeG == ITEM_PROPERTY_ATTACK_BONUS + || nTypeG == ITEM_PROPERTY_DAMAGE_BONUS_VS_ALIGNMENT_GROUP + || nTypeG == ITEM_PROPERTY_DAMAGE_BONUS_VS_RACIAL_GROUP + || nTypeG == ITEM_PROPERTY_DAMAGE_BONUS_VS_SPECIFIC_ALIGNMENT) + { + if(DEBUG) DoDebug("prc_inc_wpnrest >> DetectMonkGloves(): Monk gloves found!"); + SetLocalInt(oPC, "WEARING_MONK_GLOVES", 1); + return; + } + else + { + if(DEBUG) DoDebug("prc_inc_wpnrest >> DetectMonkGloves(): Monk gloves not found! You should never see this."); + DeleteLocalInt(oPC, "WEARING_MONK_GLOVES"); + return; + } + } + } +} + /** * All of the following functions use the following parameters: * @@ -23,6 +73,69 @@ * @param nHand The hand the weapon is wielded in. In the form of * ATTACK_BONUS_ONHAND or ATTACK_BONUS_OFFHAND. */ +//:: returns TRUE if the wielded weapon works with the Swashbuckler's class abilities. +int GetHasSwashbucklerWeapon(object oPC) +{ + object oWeap = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC); + if (!GetIsObjectValid(oWeap)) return FALSE; + + int nType = GetBaseItemType(oWeap); + + switch (nType) + { + case BASE_ITEM_DAGGER: + case BASE_ITEM_KATAR: + case BASE_ITEM_HANDAXE: + case BASE_ITEM_KAMA: + case BASE_ITEM_KUKRI: + case BASE_ITEM_LIGHTHAMMER: + case BASE_ITEM_LIGHTMACE: + case BASE_ITEM_LIGHT_PICK: + case BASE_ITEM_RAPIER: + case BASE_ITEM_SHORTSWORD: + case BASE_ITEM_SICKLE: + case BASE_ITEM_WHIP: + case BASE_ITEM_SAI: + case BASE_ITEM_SAP: + case BASE_ITEM_NUNCHAKU: + case BASE_ITEM_GOAD: + case BASE_ITEM_ELVEN_LIGHTBLADE: + case BASE_ITEM_ELVEN_THINBLADE: + case BASE_ITEM_EAGLE_CLAW: + return TRUE; + } + + // Iaijutsu Master allows katana + if (GetLevelByClass(CLASS_TYPE_IAIJUTSU_MASTER, oPC) > 0) + { + if (nType == BASE_ITEM_KATANA) return TRUE; + } + + return FALSE; +} + +//:: returns TRUE if the wielded weapon works with the Champion of Corellon's Elegant Strike. +int GetHasCorellonWeapon(object oPC) +{ + object oWeap = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC); + if (!GetIsObjectValid(oWeap)) return FALSE; + + int nType = GetBaseItemType(oWeap); + + switch (nType) + { + case BASE_ITEM_SCIMITAR: + case BASE_ITEM_LONGSWORD: + case BASE_ITEM_RAPIER: + case BASE_ITEM_ELVEN_COURTBLADE: + case BASE_ITEM_ELVEN_LIGHTBLADE: + case BASE_ITEM_ELVEN_THINBLADE: + return TRUE; + } + + return FALSE; +} + void DoRacialEquip(object oPC, int nBaseType); //return if PC has proficiency in an item @@ -40,13 +153,31 @@ int IsProficient(object oPC, int nBaseItem) case BASE_ITEM_CLUB: return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC) - || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC) - || GetHasFeat(FEAT_WEAPON_PROFICIENCY_CLUB, oPC); + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_CLUB, oPC); + + case BASE_ITEM_HEAVYCROSSBOW: + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_HEAVY_XBOW, oPC); + + case BASE_ITEM_LIGHTCROSSBOW: + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_LIGHT_XBOW, oPC); case BASE_ITEM_DAGGER: return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC) - || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC) - || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DAGGER, oPC); + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DAGGER, oPC); case BASE_ITEM_LONGSWORD: return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oPC) @@ -152,10 +283,17 @@ int IsProficient(object oPC, int nBaseItem) || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC); case BASE_ITEM_QUARTERSTAFF: - return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC) + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_QUARTERSTAFF, oPC) + ||GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC) || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC) - || GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC); + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC); + case BASE_ITEM_MAGICSTAFF: + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_QUARTERSTAFF, oPC) + ||GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC); + case BASE_ITEM_RAPIER: return GetHasFeat(FEAT_WEAPON_PROFICIENCY_RAPIER, oPC) || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oPC) @@ -295,167 +433,185 @@ int GetWeaponProfFeatByType(int nBaseType) { switch(nBaseType) { - case BASE_ITEM_SHORTSWORD: - return FEAT_WEAPON_PROFICIENCY_SHORTSWORD; + case BASE_ITEM_CLUB: + return FEAT_WEAPON_PROFICIENCY_CLUB; + + case BASE_ITEM_QUARTERSTAFF: + return FEAT_WEAPON_PROFICIENCY_QUARTERSTAFF; - case BASE_ITEM_LONGSWORD: - return FEAT_WEAPON_PROFICIENCY_LONGSWORD; + case BASE_ITEM_MAGICSTAFF: + return FEAT_WEAPON_PROFICIENCY_QUARTERSTAFF; + + case BASE_ITEM_DAGGER: + return FEAT_WEAPON_PROFICIENCY_DAGGER; - case BASE_ITEM_BATTLEAXE: - return FEAT_WEAPON_PROFICIENCY_BATTLEAXE; + case BASE_ITEM_HEAVYCROSSBOW: + return FEAT_WEAPON_PROFICIENCY_HEAVY_XBOW; - case BASE_ITEM_BASTARDSWORD: - return FEAT_WEAPON_PROFICIENCY_BASTARD_SWORD; + case BASE_ITEM_LIGHTCROSSBOW: + return FEAT_WEAPON_PROFICIENCY_LIGHT_XBOW; + + case BASE_ITEM_SHORTSWORD: + return FEAT_WEAPON_PROFICIENCY_SHORTSWORD; - case BASE_ITEM_LIGHTFLAIL: - return FEAT_WEAPON_PROFICIENCY_LIGHT_FLAIL; + case BASE_ITEM_LONGSWORD: + return FEAT_WEAPON_PROFICIENCY_LONGSWORD; - case BASE_ITEM_WARHAMMER: - return FEAT_WEAPON_PROFICIENCY_WARHAMMER; + case BASE_ITEM_BATTLEAXE: + return FEAT_WEAPON_PROFICIENCY_BATTLEAXE; - case BASE_ITEM_LONGBOW: - return FEAT_WEAPON_PROFICIENCY_LONGBOW; + case BASE_ITEM_BASTARDSWORD: + return FEAT_WEAPON_PROFICIENCY_BASTARD_SWORD; - case BASE_ITEM_LIGHTMACE: - return FEAT_WEAPON_PROFICIENCY_LIGHT_MACE; + case BASE_ITEM_LIGHTFLAIL: + return FEAT_WEAPON_PROFICIENCY_LIGHT_FLAIL; - case BASE_ITEM_HALBERD: - return FEAT_WEAPON_PROFICIENCY_HALBERD; + case BASE_ITEM_WARHAMMER: + return FEAT_WEAPON_PROFICIENCY_WARHAMMER; - case BASE_ITEM_SHORTBOW: + case BASE_ITEM_LONGBOW: + return FEAT_WEAPON_PROFICIENCY_LONGBOW; + + case BASE_ITEM_LIGHTMACE: + return FEAT_WEAPON_PROFICIENCY_LIGHT_MACE; + + case BASE_ITEM_HALBERD: + return FEAT_WEAPON_PROFICIENCY_HALBERD; + + case BASE_ITEM_SHORTBOW: return FEAT_WEAPON_PROFICIENCY_SHORTBOW; - case BASE_ITEM_TWOBLADEDSWORD: + case BASE_ITEM_TWOBLADEDSWORD: return FEAT_WEAPON_PROFICIENCY_TWO_BLADED_SWORD; - case BASE_ITEM_GREATSWORD: + case BASE_ITEM_GREATSWORD: return FEAT_WEAPON_PROFICIENCY_GREATSWORD; - case BASE_ITEM_GREATAXE: + case BASE_ITEM_GREATAXE: return FEAT_WEAPON_PROFICIENCY_GREATAXE; - case BASE_ITEM_DART: + case BASE_ITEM_DART: return FEAT_WEAPON_PROFICIENCY_DART; - case BASE_ITEM_DIREMACE: + case BASE_ITEM_DIREMACE: return FEAT_WEAPON_PROFICIENCY_DIRE_MACE; - case BASE_ITEM_DOUBLEAXE: + case BASE_ITEM_DOUBLEAXE: return FEAT_WEAPON_PROFICIENCY_DOUBLE_AXE; - case BASE_ITEM_HEAVYFLAIL: + case BASE_ITEM_HEAVYFLAIL: return FEAT_WEAPON_PROFICIENCY_HEAVY_FLAIL; - case BASE_ITEM_LIGHTHAMMER: + case BASE_ITEM_LIGHTHAMMER: return FEAT_WEAPON_PROFICIENCY_LIGHT_HAMMER; - case BASE_ITEM_HANDAXE: + case BASE_ITEM_HANDAXE: return FEAT_WEAPON_PROFICIENCY_HANDAXE; - case BASE_ITEM_KAMA: + case BASE_ITEM_KAMA: return FEAT_WEAPON_PROFICIENCY_KAMA; - case BASE_ITEM_KATANA: + case BASE_ITEM_KATANA: return FEAT_WEAPON_PROFICIENCY_KATANA; - case BASE_ITEM_KUKRI: + case BASE_ITEM_KUKRI: return FEAT_WEAPON_PROFICIENCY_KUKRI; - case BASE_ITEM_MORNINGSTAR: + case BASE_ITEM_MORNINGSTAR: return FEAT_WEAPON_PROFICIENCY_MORNINGSTAR; - case BASE_ITEM_RAPIER: + case BASE_ITEM_RAPIER: return FEAT_WEAPON_PROFICIENCY_RAPIER; - case BASE_ITEM_SCIMITAR: + case BASE_ITEM_SCIMITAR: return FEAT_WEAPON_PROFICIENCY_SCIMITAR; - case BASE_ITEM_SCYTHE: + case BASE_ITEM_SCYTHE: return FEAT_WEAPON_PROFICIENCY_SCYTHE; - case BASE_ITEM_SHORTSPEAR: + case BASE_ITEM_SHORTSPEAR: return FEAT_WEAPON_PROFICIENCY_SHORTSPEAR; - case BASE_ITEM_SHURIKEN: + case BASE_ITEM_SHURIKEN: return FEAT_WEAPON_PROFICIENCY_SHURIKEN; - case BASE_ITEM_SICKLE: + case BASE_ITEM_SICKLE: return FEAT_WEAPON_PROFICIENCY_SICKLE; - case BASE_ITEM_SLING: + case BASE_ITEM_SLING: return FEAT_WEAPON_PROFICIENCY_SLING; - case BASE_ITEM_THROWINGAXE: + case BASE_ITEM_THROWINGAXE: return FEAT_WEAPON_PROFICIENCY_THROWING_AXE; - case BASE_ITEM_CSLASHWEAPON: + case BASE_ITEM_CSLASHWEAPON: return FEAT_WEAPON_PROFICIENCY_CREATURE; - case BASE_ITEM_CPIERCWEAPON: + case BASE_ITEM_CPIERCWEAPON: return FEAT_WEAPON_PROFICIENCY_CREATURE; - case BASE_ITEM_CBLUDGWEAPON: + case BASE_ITEM_CBLUDGWEAPON: return FEAT_WEAPON_PROFICIENCY_CREATURE; - case BASE_ITEM_CSLSHPRCWEAP: + case BASE_ITEM_CSLSHPRCWEAP: return FEAT_WEAPON_PROFICIENCY_CREATURE; - case BASE_ITEM_TRIDENT: + case BASE_ITEM_TRIDENT: return FEAT_WEAPON_PROFICIENCY_TRIDENT; - case BASE_ITEM_DWARVENWARAXE: + case BASE_ITEM_DWARVENWARAXE: return FEAT_WEAPON_PROFICIENCY_DWARVEN_WARAXE; - case BASE_ITEM_WHIP: + case BASE_ITEM_WHIP: return FEAT_WEAPON_PROFICIENCY_WHIP; - case BASE_ITEM_ELVEN_LIGHTBLADE: + case BASE_ITEM_ELVEN_LIGHTBLADE: return FEAT_WEAPON_PROFICIENCY_ELVEN_LIGHTBLADE; - case BASE_ITEM_ELVEN_THINBLADE: + case BASE_ITEM_ELVEN_THINBLADE: return FEAT_WEAPON_PROFICIENCY_ELVEN_THINBLADE; - case BASE_ITEM_ELVEN_COURTBLADE: + case BASE_ITEM_ELVEN_COURTBLADE: return FEAT_WEAPON_PROFICIENCY_ELVEN_COURTBLADE; - case BASE_ITEM_HEAVY_PICK: + case BASE_ITEM_HEAVY_PICK: return FEAT_WEAPON_PROFICIENCY_HEAVY_PICK; - case BASE_ITEM_LIGHT_PICK: + case BASE_ITEM_LIGHT_PICK: return FEAT_WEAPON_PROFICIENCY_LIGHT_PICK; - case BASE_ITEM_SAI: + case BASE_ITEM_SAI: return FEAT_WEAPON_PROFICIENCY_SAI; - case BASE_ITEM_NUNCHAKU: + case BASE_ITEM_NUNCHAKU: return FEAT_WEAPON_PROFICIENCY_NUNCHAKU; - case BASE_ITEM_FALCHION: + case BASE_ITEM_FALCHION: return FEAT_WEAPON_PROFICIENCY_FALCHION; - case BASE_ITEM_SAP: + case BASE_ITEM_SAP: return FEAT_WEAPON_PROFICIENCY_SAP; - case BASE_ITEM_KATAR: + case BASE_ITEM_KATAR: return FEAT_WEAPON_PROFICIENCY_KATAR; - case BASE_ITEM_HEAVY_MACE: + case BASE_ITEM_HEAVY_MACE: return FEAT_WEAPON_PROFICIENCY_HEAVY_MACE; - case BASE_ITEM_MAUL: + case BASE_ITEM_MAUL: return FEAT_WEAPON_PROFICIENCY_MAUL; - case BASE_ITEM_DOUBLE_SCIMITAR: + case BASE_ITEM_DOUBLE_SCIMITAR: return FEAT_WEAPON_PROFICIENCY_DOUBLE_SCIMITAR; - case BASE_ITEM_GOAD: + case BASE_ITEM_GOAD: return FEAT_WEAPON_PROFICIENCY_GOAD; - case BASE_ITEM_EAGLE_CLAW: + case BASE_ITEM_EAGLE_CLAW: return FEAT_WEAPON_PROFICIENCY_EAGLE_CLAW; - default: - return FEAT_WEAPON_PROFICIENCY_SIMPLE; + default: + return FEAT_WEAPON_PROFICIENCY_SIMPLE; } return 0; @@ -720,6 +876,7 @@ int IsMeleeWeapon(int nBaseItemType) case BASE_ITEM_CLOAK: case BASE_ITEM_CRAFTED_ROD: case BASE_ITEM_CRAFTED_STAFF: + case BASE_ITEM_CRAFTED_SCEPTER: case BASE_ITEM_CRAFTMATERIALMED: case BASE_ITEM_CRAFTMATERIALSML: case BASE_ITEM_CREATUREITEM: diff --git a/src/include/prc_ipfeat_const.nss b/src/include/prc_ipfeat_const.nss index a1829be..672fd04 100644 --- a/src/include/prc_ipfeat_const.nss +++ b/src/include/prc_ipfeat_const.nss @@ -262,7 +262,7 @@ const int IP_CONST_FEAT_WEAPON_PROFICIENCY_LIGHT_LANCE = 4638; const int IP_CONST_FEAT_WEAPON_PROFICIENCY_HEAVY_PICK = 4639; const int IP_CONST_FEAT_WEAPON_PROFICIENCY_LIGHT_PICK = 4640; const int IP_CONST_FEAT_WEAPON_PROFICIENCY_SAI = 4641; -const int IP_CONST_FEAT_WEAPON_PROFICIENCY_NUNCHUKU = 4642; +const int IP_CONST_FEAT_WEAPON_PROFICIENCY_NUNCHAKU = 4642; const int IP_CONST_FEAT_WEAPON_PROFICIENCY_FALCHION = 4643; const int IP_CONST_FEAT_WEAPON_PROFICIENCY_SAP = 4644; const int IP_CONST_FEAT_WEAPON_PROFICIENCY_KATAR = 4645; @@ -1206,11 +1206,12 @@ const int IP_CONST_FEAT_REGENERATION_5 = 24820; const int IP_CONST_FEAT_SCENT = 24821; const int IP_CONST_FEAT_GIANT_RACIAL_TYPE = 24822; -const int IP_CONST_FEAT_TEMPLATE_ARCHLICH_MARKER = 16401; //:: Archlich -const int IP_CONST_FEAT_TEMPLATE_TURN_UNDEAD = 16402; -const int IP_CONST_FEAT_TEMPLATE_PROJECTION = 24823; -const int IP_CONST_FEAT_TEMPLATE_END_PROJECTION = 24824; -const int IP_CONST_FEAT_TEMPLATE_ANIMATE_DEAD = 24825; +const int IP_CONST_FEAT_TEMPLATE_ARCHLICH_MARKER = 16401; //:: Archlich +const int IP_CONST_FEAT_TEMPLATE_TURN_UNDEAD = 16402; +const int IP_CONST_FEAT_TEMPLATE_BAELNORN_MARKER = 16409; //:: Baelnorn +const int IP_CONST_FEAT_TEMPLATE_PROJECTION = 24823; +const int IP_CONST_FEAT_TEMPLATE_END_PROJECTION = 24824; +const int IP_CONST_FEAT_TEMPLATE_ANIMATE_DEAD = 24825; const int IP_CONST_FEAT_TEMPLATE_SAINT_SLA_BLESS = 16403; //:: Saint //const int IP_CONST_FEAT_TEMPLATE_SAINT_SLA_GUIDANCE = 16404; const int IP_CONST_FEAT_TEMPLATE_SAINT_SLA_RESISTANCE = 16405; diff --git a/src/include/prc_misc_const.nss b/src/include/prc_misc_const.nss index 0575811..0171bbb 100644 --- a/src/include/prc_misc_const.nss +++ b/src/include/prc_misc_const.nss @@ -29,6 +29,10 @@ const int BASE_ITEM_CRAFTED_STAFF = 201; const int BASE_ITEM_ELVEN_LIGHTBLADE = 202; const int BASE_ITEM_ELVEN_THINBLADE = 203; const int BASE_ITEM_ELVEN_COURTBLADE = 204; +const int BASE_ITEM_CRAFTED_SCEPTER = 249; +const int BASE_ITEM_CRAFTED_VIAL = 250; +const int BASE_ITEM_MUNDANE_HERB = 252; +const int BASE_ITEM_INFUSED_HERB = 253; //::////////////////////////////////////////////// //:: Player Health Const diff --git a/src/include/prc_nui_com_inc.nss b/src/include/prc_nui_com_inc.nss new file mode 100644 index 0000000..4bba080 --- /dev/null +++ b/src/include/prc_nui_com_inc.nss @@ -0,0 +1,615 @@ +#include "prc_nui_consts" +#include "inc_newspellbook" +#include "psi_inc_psifunc" +#include "inc_lookups" +#include "nw_inc_nui" +#include "tob_inc_tobfunc" + +// +// GetCurrentSpellLevel +// Gets the current spell level the class can achieve at the current +// caster level (ranging from 0-9) +// +// Arguments: +// nClass:int the ClassID +// nLevel:int the caster level +// +// Returns: +// int the circle the class can achieve currently +// +int GetCurrentSpellLevel(int nClass, int nLevel); + +// +// GetMaxSpellLevel +// Gets the highest possible circle the class can achieve (from 0-9) +// +// Arguments: +// nClass:int the ClassID +// +// Returns: +// int the highest circle that can be achieved +// +int GetMaxSpellLevel(int nClass); + +// +// GetMinSpellLevel +// Gets the lowest possible circle the class can achieve (from 0-9) +// +// Arguments: +// nClass:int the ClassID +// +// Returns: +// int the lowest circle that can be achieved +// +int GetMinSpellLevel(int nClass); + +// +// GetHighestLevelPossibleInClass +// Given a class Id this will determine what the max level of a class can be +// achieved +// +// Arguments: +// nClass:int the ClassID +// +// Returns: +// int the highest possible level the class can achieve +// +int GetHighestLevelPossibleInClass(int nClass); + +// +// GetClassSpellbookFile +// Gets the class 2da spellbook/ability for the given class Id +// +// Arguments: +// nClass:int the classID +// +// Returns: +// string the 2da file name for the spell/abilities of the ClassID +// +string GetClassSpellbookFile(int nClass); + +// +// GetBinderSpellToFeatDictionary +// Sets up the Binder Spell Dictionary that is used to match a binder's vestige +// to their feat. This is constructed based off the binder's known location of +// their feat and spell ranges in the base 2das respectivly. After constructing +// this it will be saved to the player locally as a cached result since we do +// not need to call this again. +// +// Argument: +// oPlayer:object the player +// +// Returns: +// json:Dictionary a dictionary of mapping between the SpellID +// and the FeatID of a vestige ability +// +json GetBinderSpellToFeatDictionary(object oPlayer=OBJECT_SELF); + +// +// GetSpellLevelIcon +// Takes the spell circle int and gets the icon appropriate for it (i.e. 0 turns +// into "ir_cantrips" +// +// Arguments: +// spellLevel:int the spell level we want the icon for +// +// Returns: +// string the spell level icon +// +string GetSpellLevelIcon(int spellLevel); + +// +// GetSpellLevelToolTip +// Gets the spell level tool tip text based on the int spell level provided (i.e. +// 0 turns into "Cantrips") +// +// Arguments: +// spellLevel:int the spell level we want the tooltip for +// +// Returns: +// string the spell level toop tip +// +string GetSpellLevelToolTip(int spellLevel); + +// +// GetSpellIcon +// Gets the spell icon based off the spellId, or featId supplied +// +// Arguments: +// nClass:int the class Id +// featId:int the featId we can use the icon for +// spellId:int the spell Id we want the icon for +// +// Returns: +// json:String the string of the icon we want. +// +json GetSpellIcon(int spellId, int featId=0, int nClass=0); +string GetSpellName(int spellId, int realSpellID=0, int featId=0, int nClass=0); + +// +// GreyOutButton +// Takes NUI Button along with it's width and height and greys it out it with a drawn +// colored rectangle to represent it's not been selected or not valid. +// +// Arguments: +// jButton:json the NUI Button +// w:float the width of the button +// h:float the height of the button +// +// Returns: +// json the NUI button greyed out +// +json GreyOutButton(json jButton, float w, float h); + +// +// CreateGreyOutRectangle +// Creates a grey out rectangle for buttons +// +// Arguments: +// w:float the width of the button +// h:float the height of the button +// +// Returns: +// json the transparant black rectangle +// +json CreateGreyOutRectangle(float w, float h); + +// +// GetTrueClassType +// Gets the true class Id for a provided class Id, mostly for RHD and for +// ToB prestige classes +// +// Arguments: +// nClass:int classId +// +// Returns: +// int the true classId based off nClass +// +int GetTrueClassType(int nClass, object oPC=OBJECT_SELF); + +void CreateSpellDescriptionNUI(object oPlayer, int featID, int spellId=0, int realSpellId=0, int nClass=0); + +void CallSpellUnlevelScript(object oPC, int nClass, int nLevel); +void ClearSpellDescriptionNUI(object oPlayer=OBJECT_SELF); +void RemoveIPFeat(object oPC, int ipFeatID); + +void CallSpellUnlevelScript(object oPC, int nClass, int nLevel) +{ + SetScriptParam("UnLevel_ClassChoice", IntToString(nClass)); + SetScriptParam("UnLevel_LevelChoice", IntToString(nLevel)); + ExecuteScript("prc_unlvl_script", oPC); +} + +void RemoveIPFeat(object oPC, int ipFeatID) +{ + object oSkin = GetPCSkin(oPC); + 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) + { + if (GetItemPropertySubType(ipTest) == ipFeatID) + { + if(DEBUG) DoDebug("_ManeuverRecurseRemoveArray(): Removing bonus feat itemproperty:\n" + DebugIProp2Str(ipTest)); + // If so, remove it + RemoveItemProperty(oSkin, ipTest); + } + + } + + ipTest = GetNextItemProperty(oSkin); + } +} + +int GetCurrentSpellLevel(int nClass, int nLevel) +{ + int currentLevel = nLevel; + + // ToB doesn't have a concept of spell levels, but still match up to it + if(nClass == CLASS_TYPE_WARBLADE + || nClass == CLASS_TYPE_SWORDSAGE + || nClass == CLASS_TYPE_CRUSADER + || nClass == CLASS_TYPE_SHADOWCASTER) + { + return 9; + } + + + // Binders don't really have a concept of spell level + if (nClass == CLASS_TYPE_BINDER + || nClass == CLASS_TYPE_DRAGON_SHAMAN) // they can only reach 1st circle + return 1; + + //Shadowsmith has no concept of spell levels + if (nClass == CLASS_TYPE_SHADOWSMITH) + return 2; + + if (nClass == CLASS_TYPE_WARLOCK + || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT) + return 4; + + // Spont casters have their own function + if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS + || nClass == CLASS_TYPE_ARCHIVIST) + { + + int maxLevel = GetMaxSpellLevelForCasterLevel(nClass, currentLevel); + return maxLevel; + } + else + { + // everyone else uses this + string spellLevel2da = GetAMSKnownFileName(nClass); + + currentLevel = nLevel - 1; // Level is 1 off of the row in the 2da + + if (nClass == CLASS_TYPE_FIST_OF_ZUOKEN + || nClass == CLASS_TYPE_PSION + || nClass == CLASS_TYPE_PSYWAR + || nClass == CLASS_TYPE_WILDER + || nClass == CLASS_TYPE_PSYCHIC_ROGUE + || nClass == CLASS_TYPE_WARMIND) + currentLevel = GetManifesterLevel(OBJECT_SELF, nClass, TRUE) - 1; + + int totalLevel = Get2DARowCount(spellLevel2da); + + // in case we somehow go over bounds just don't :) + if (currentLevel >= totalLevel) + currentLevel = totalLevel - 1; + + //Psionics have MaxPowerLevel as their column name + string columnName = "MaxPowerLevel"; + + //Invokers have MaxInvocationLevel + if (nClass == CLASS_TYPE_WARLOCK + || nClass == CLASS_TYPE_DRAGON_SHAMAN + || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT) + columnName = "MaxInvocationLevel"; + + // Truenamers have 3 sets of utterances, ranging from 1-6, EvolvingMind covers the entire range + if (nClass == CLASS_TYPE_TRUENAMER) + { + columnName = "EvolvingMind"; + spellLevel2da = "cls_true_maxlvl"; //has a different 2da we want to look at + } + + if (nClass == CLASS_TYPE_BINDER) + { + columnName = "VestigeLvl"; + spellLevel2da = "cls_bind_binder"; + } + + // ToB doesn't have a concept of this, but we don't care. + + int maxLevel = StringToInt(Get2DACache(spellLevel2da, columnName, currentLevel)); + return maxLevel; + } +} + +int GetMinSpellLevel(int nClass) +{ + // again sponts have their own function + if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS + || nClass == CLASS_TYPE_ARCHIVIST) + { + return GetMinSpellLevelForCasterLevel(nClass, GetHighestLevelPossibleInClass(nClass)); + } + else + { + if (nClass == CLASS_TYPE_FIST_OF_ZUOKEN + || nClass == CLASS_TYPE_PSION + || nClass == CLASS_TYPE_PSYWAR + || nClass == CLASS_TYPE_WILDER + || nClass == CLASS_TYPE_PSYCHIC_ROGUE + || nClass == CLASS_TYPE_WARMIND + || nClass == CLASS_TYPE_WARBLADE + || nClass == CLASS_TYPE_SWORDSAGE + || nClass == CLASS_TYPE_CRUSADER + || nClass == CLASS_TYPE_WARLOCK + || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT + || nClass == CLASS_TYPE_DRAGON_SHAMAN + || nClass == CLASS_TYPE_SHADOWCASTER + || nClass == CLASS_TYPE_SHADOWSMITH + || nClass == CLASS_TYPE_BINDER) + return 1; + + return GetCurrentSpellLevel(nClass, 1); + } + +} + +int GetMaxSpellLevel(int nClass) +{ + if (nClass == CLASS_TYPE_WILDER + || nClass == CLASS_TYPE_PSION) + return 9; + if (nClass == CLASS_TYPE_PSYCHIC_ROGUE + || nClass == CLASS_TYPE_FIST_OF_ZUOKEN + || nClass == CLASS_TYPE_WARMIND) + return 5; + if (nClass == CLASS_TYPE_PSYWAR) + return 6; + + return GetCurrentSpellLevel(nClass, GetHighestLevelPossibleInClass(nClass)); +} + +int GetHighestLevelPossibleInClass(int nClass) +{ + string sFile; + + //sponts have their spells in the classes.2da + if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS + || nClass == CLASS_TYPE_ARCHIVIST) + { + sFile = Get2DACache("classes", "SpellGainTable", nClass); + } + else + { + // everyone else uses this + sFile = GetAMSKnownFileName(nClass); + + if (nClass == CLASS_TYPE_TRUENAMER) + { + sFile = "cls_true_maxlvl"; //has a different 2da we want to look at + } + + if (nClass == CLASS_TYPE_BINDER) + { + sFile = "cls_bind_binder"; + } + } + + return Get2DARowCount(sFile); +} + +string GetClassSpellbookFile(int nClass) +{ + string sFile; + // Spontaneous casters use a specific file name structure + if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS + || nClass == CLASS_TYPE_ARCHIVIST) + { + sFile = GetFileForClass(nClass); + } + // everyone else uses this structure + else + { + sFile = GetAMSDefinitionFileName(nClass); + + if (nClass == CLASS_TYPE_BINDER) + { + sFile = "vestiges"; + } + } + + return sFile; +} + +string GetSpellLevelIcon(int spellLevel) +{ + switch (spellLevel) + { + case 0: return "ir_cantrips"; + case 1: return "ir_level1"; + case 2: return "ir_level2"; + case 3: return "ir_level3"; + case 4: return "ir_level4"; + case 5: return "ir_level5"; + case 6: return "ir_level6"; + case 7: return "ir_level789"; + case 8: return "ir_level789"; + case 9: return "ir_level789"; + } + + return ""; +} + +string GetSpellLevelToolTip(int spellLevel) +{ + switch (spellLevel) + { + case 0: return "Cantrips"; + case 1: return "Level 1"; + case 2: return "Level 2"; + case 3: return "Level 3"; + case 4: return "Level 4"; + case 5: return "Level 5"; + case 6: return "Level 6"; + case 7: return "Level 7"; + case 8: return "Level 8"; + case 9: return "Level 9"; + } + + return ""; +} + + +json GetSpellIcon(int spellId,int featId=0,int nClass=0) +{ + // Binder's spells don't have the FeatID on the spells.2da, so we have to use + // the mapping we constructed to get it. + if (nClass == CLASS_TYPE_BINDER) + { + json binderDict = GetBinderSpellToFeatDictionary(); + int nFeatID = JsonGetInt(JsonObjectGet(binderDict, IntToString(spellId))); + return JsonString(Get2DACache("feat", "Icon", featId)); + } + + if (featId) + return JsonString(Get2DACache("feat", "Icon", featId)); + + int masterSpellID = StringToInt(Get2DACache("spells", "Master", spellId)); + + // if this is a sub radial spell, then we use spell's icon instead + if (masterSpellID) + return JsonString(Get2DACache("spells", "IconResRef", spellId)); + + // the FeatID holds the accurate spell icon, not the SpellID + int nFeatID = StringToInt(Get2DACache("spells", "FeatID", spellId)); + // however if no featId was found use the spell's icon instead + if (!nFeatID) + return JsonString(Get2DACache("spells", "IconResRef", spellId)); + + return JsonString(Get2DACache("feat", "Icon", nFeatID)); +} + +string GetSpellName(int spellId, int realSpellID=0, int featId=0, int nClass=0) +{ + if ((nClass == CLASS_TYPE_SHADOWSMITH + || nClass == CLASS_TYPE_SHADOWCASTER) && spellId) + return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", spellId))); + if (nClass == CLASS_TYPE_TRUENAMER && featId) + return GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT", featId))); + if (realSpellID) + return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", realSpellID))); + if (spellId) + return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", spellId))); + if (featId) + return GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT", featId))); + + return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", spellId))); +} + +json GetBinderSpellToFeatDictionary(object oPlayer=OBJECT_SELF) +{ + // a dictionary of + json binderDict = GetLocalJson(oPlayer, NUI_SPELLBOOK_BINDER_DICTIONARY_CACHE_VAR); + // if this hasn't been created, create it now. + if (binderDict == JsonNull()) + binderDict = JsonObject(); + else + return binderDict; + + // the starting row for binder spells + int spellIndex = 19070; + // the starting row for binder feats + int featIndex = 9030; + //the end of the binder spells/feats + while (spellIndex <= 19156 && featIndex <= 9104) + { + // get the SpellID tied to the feat + int spellID = StringToInt(Get2DACache("feat", "SPELLID", featIndex)); + // if the spellID matches the current index, then this is the spell + // attached to the feat + if (spellID == spellIndex) + { + binderDict = JsonObjectSet(binderDict, IntToString(spellID), JsonInt(featIndex)); + + // move to next spell/feat + featIndex++; + spellIndex++; + } + // else we have reached a subdial spell + else + { + // loop through until we reach back at spellID + while (spellIndex < spellID) + { + int masterSpell = StringToInt(Get2DACache("spells", "Master", spellIndex)); + + // add the sub radial to the dict, tied to the master's FeatID + int featId = JsonGetInt(JsonObjectGet(binderDict, IntToString(masterSpell))); + binderDict = JsonObjectSet(binderDict, IntToString(spellIndex), JsonInt(featId)); + + spellIndex++; + } + + + // some feats overlap the same FeatID, can cause this to get stuck. + // if it happens then move on + if (spellIndex > spellID) + featIndex++; + } + } + + // cache the result + SetLocalJson(oPlayer, NUI_SPELLBOOK_BINDER_DICTIONARY_CACHE_VAR, binderDict); + return binderDict; +} + +json GreyOutButton(json jButton, float w, float h) +{ + json retValue = jButton; + + json jBorders = JsonArray(); + jBorders = JsonArrayInsert(jBorders, CreateGreyOutRectangle(w, h)); + + return NuiDrawList(jButton, JsonBool(FALSE), jBorders); +} + +json CreateGreyOutRectangle(float w, float h) +{ + // set the points of the button shape + json jPoints = JsonArray(); + jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0)); + jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0)); + + jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0)); + jPoints = JsonArrayInsert(jPoints, JsonFloat(h)); + + jPoints = JsonArrayInsert(jPoints, JsonFloat(w)); + jPoints = JsonArrayInsert(jPoints, JsonFloat(h)); + + jPoints = JsonArrayInsert(jPoints, JsonFloat(w)); + jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0)); + + jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0)); + jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0)); + + return NuiDrawListPolyLine(JsonBool(TRUE), NuiColor(0, 0, 0, 127), JsonBool(TRUE), JsonFloat(2.0), jPoints); +} + +void CreateSpellDescriptionNUI(object oPlayer, int featID, int spellId=0, int realSpellId=0, int nClass=0) +{ + SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_FEATID_VAR, featID); + SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_SPELLID_VAR, spellId); + SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_REAL_SPELLID_VAR, realSpellId); + SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_CLASSID_VAR, nClass); + ExecuteScript("prc_nui_dsc_view", oPlayer); +} + +void ClearSpellDescriptionNUI(object oPlayer=OBJECT_SELF) +{ + DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_FEATID_VAR); + DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_SPELLID_VAR); + DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_REAL_SPELLID_VAR); + DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_CLASSID_VAR); +} + +int GetTrueClassType(int nClass, object oPC=OBJECT_SELF) +{ + if (nClass == CLASS_TYPE_JADE_PHOENIX_MAGE + || nClass == CLASS_TYPE_MASTER_OF_NINE + || nClass == CLASS_TYPE_DEEPSTONE_SENTINEL + || nClass == CLASS_TYPE_BLOODCLAW_MASTER + || nClass == CLASS_TYPE_RUBY_VINDICATOR + || nClass == CLASS_TYPE_ETERNAL_BLADE + || nClass == CLASS_TYPE_SHADOW_SUN_NINJA) + { + int trueClass = GetPrimaryBladeMagicClass(oPC); + return trueClass; + } + + if ((nClass == CLASS_TYPE_SHAPECHANGER + && GetRacialType(oPC) == RACIAL_TYPE_ARANEA) + || (nClass == CLASS_TYPE_OUTSIDER + && GetRacialType(oPC) == RACIAL_TYPE_RAKSHASA) + || (nClass == CLASS_TYPE_ABERRATION + && GetRacialType(oPC) == RACIAL_TYPE_DRIDER) + || (nClass == CLASS_TYPE_MONSTROUS + && GetRacialType(oPC) == RACIAL_TYPE_ARKAMOI) + || (nClass == CLASS_TYPE_MONSTROUS + && GetRacialType(oPC) == RACIAL_TYPE_HOBGOBLIN_WARSOUL) + || (nClass == CLASS_TYPE_MONSTROUS + && GetRacialType(oPC) == RACIAL_TYPE_REDSPAWN_ARCANISS) + || (nClass == CLASS_TYPE_MONSTROUS + && GetRacialType(oPC) == RACIAL_TYPE_MARRUTACT)) + return CLASS_TYPE_SORCERER; + if (nClass == CLASS_TYPE_FEY + && GetRacialType(oPC) == RACIAL_TYPE_GLOURA) + return CLASS_TYPE_BARD; + + return nClass; +} + diff --git a/src/include/prc_nui_consts.nss b/src/include/prc_nui_consts.nss index 0cb0efa..745c860 100644 --- a/src/include/prc_nui_consts.nss +++ b/src/include/prc_nui_consts.nss @@ -110,4 +110,62 @@ const string NUI_PRC_PA_TEXT_BIND = "nui_prc_pa_text_bind"; // Left Button Enabled Bind for Power Attack NUI const string NUI_PRC_PA_LEFT_BUTTON_ENABLED_BIND = "leftButtonEnabled"; // Right Button Enabled Bind for Power Attack NUI -const string NUI_PRC_PA_RIGHT_BUTTON_ENABLED_BIND = "rightButtonEnabled"; \ No newline at end of file +const string NUI_PRC_PA_RIGHT_BUTTON_ENABLED_BIND = "rightButtonEnabled"; + +////////////////////////////////////////////////// +// // +// NUI Level Up // +// // +////////////////////////////////////////////////// + +const string NUI_LEVEL_UP_WINDOW_ID = "prcLevelUpNui"; + +const string NUI_LEVEL_UP_SPELL_CIRCLE_BUTTON_BASEID = "NuiLevelUpCircleButton_"; +const string NUI_LEVEL_UP_SPELL_BUTTON_BASEID = "NuiLevelUpSpellButton_"; +const string NUI_LEVEL_UP_SPELL_DISABLED_BUTTON_BASEID = "NuiLevelUpDisabledSpellButton_"; +const string NUI_LEVEL_UP_SPELL_CHOSEN_BUTTON_BASEID = "NuiLevelUpChosenSpellButton_"; +const string NUI_LEVEL_UP_SPELL_CHOSEN_DISABLED_BUTTON_BASEID = "NuiLevelUpDisabledChosenSpellButton_"; +const string NUI_LEVEL_UP_DONE_BUTTON = "NuiLevelUpDoneButton"; +const string NUI_LEVEL_UP_RESET_BUTTON = "NuiLevelUpResetButton"; + +const string NUI_LEVEL_UP_SELECTED_CLASS_VAR = "NUILevelUpSelectedClass"; +const string NUI_LEVEL_UP_SELECTED_CIRCLE_VAR = "NUILevelUpSelectedCircle"; +const string NUI_LEVEL_UP_KNOWN_SPELLS_VAR = "NUILevelUpKnownSpells"; +const string NUI_LEVEL_UP_CHOSEN_SPELLS_VAR = "NUILevelUpChosenSpells"; +const string NUI_LEVEL_UP_EXPANDED_KNOW_LIST_VAR = "NUILevelUpExpKnowList"; +const string NUI_LEVEL_UP_POWER_LIST_VAR = "NUILevelUpPowerList"; +const string NUI_LEVEL_UP_DISCIPLINE_INFO_VAR = "GetDisciplineInfoObjectCache_"; +const string NUI_LEVEL_UP_SPELLID_LIST_VAR = "NUILevelUpSpellIDList_"; +const string NUI_LEVEL_UP_REMAINING_CHOICES_CACHE_VAR = "NUIRemainingChoicesCache"; +const string NUI_LEVEL_UP_RELEARN_LIST_VAR = "NUILevelUpRelearnList"; +const string NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR = "NUILevelUpArchivistNewSpellsList"; + +const string NUI_LEVEL_UP_EXPANDED_CHOICES_VAR = "NUIExpandedChoices"; +const string NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR = "NUIEpicExpandedChoices"; + +const int NUI_LEVEL_UP_MANEUVER_PREREQ_LIMIT = 6; + +const string NUI_LEVEL_UP_MANEUVER_TOTAL = "ManeuverTotal"; +const string NUI_LEVEL_UP_STANCE_TOTAL = "StanceTotal"; + +const string NUI_LEVEL_UP_SPELLBOOK_OBJECT_CACHE_VAR = "GetSpellListObjectCache_"; +const string NUI_LEVEL_UP_KNOWN_INVOCATIONS_CACHE_VAR = "GetInvokerKnownListObjectCache_"; + +const string NUI_SPELL_DESCRIPTION_FEATID_VAR = "NUISpellDescriptionFeatID"; +const string NUI_SPELL_DESCRIPTION_CLASSID_VAR = "NUISpellDescriptionClassID"; +const string NUI_SPELL_DESCRIPTION_SPELLID_VAR = "NUISpellDescriptionSpellID"; +const string NUI_SPELL_DESCRIPTION_REAL_SPELLID_VAR = "NUISpellDescriptionRealSpellID"; + + +////////////////////////////////////////////////// +// // +// Spell Duration NUI // +// // +////////////////////////////////////////////////// + +const string DURATION_NUI_WINDOW_ID = "DurationNUI"; +const string NUI_DURATION_MANUALLY_OPENED_PARAM = "DurationNUIManuallyOpenedParam"; +const string NUI_DURATION_NO_LOOP_PARAM = "DurationNUINoLoopParam"; +const string NUI_DURATION_TRACKED_SPELLS = "durationNUI_trackedSpellList"; +const string NUI_SPELL_DURATION_BASE_BIND = "durationNUI_durationSpellId"; +const string NUI_SPELL_DURATION_SPELLID_BASE_CANCEL_BUTTON = "NuiDurationCancelButtonSpellID"; diff --git a/src/include/prc_nui_lv_inc.nss b/src/include/prc_nui_lv_inc.nss new file mode 100644 index 0000000..b3d862f --- /dev/null +++ b/src/include/prc_nui_lv_inc.nss @@ -0,0 +1,3316 @@ +//:://///////////////////////////////////////////// +//:: PRC Level Up NUI +//:: prc_nui_lv_inc +//::////////////////////////////////////////////// +/* + This is the logic for the Level Up NUI, holding all the functions needed for + the NUI to operate properly and allow leveling up in different classes. +*/ +//::////////////////////////////////////////////// +//:: Created By: Rakiov +//:: Created On: 20.06.2005 +//::////////////////////////////////////////////// + +#include "prc_nui_com_inc" +#include "tob_inc_tobfunc" +#include "tob_inc_moveknwn" +#include "inv_inc_invfunc" +#include "shd_inc_mystknwn" +#include "shd_inc_shdfunc" +#include "true_inc_truknwn" +#include "true_inc_trufunc" + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Spont Casters / Base /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +// +// GetSpellListObject +// Gets the JSON Object representation of a class's spellbook 2da. This function +// will cache it's result to the object given to it to avoid further calculations +// and will not clear itself since it does not change. +// +// Arguments: +// nClass:int the ClassID +// oPC:Object the player +// +// Returns: +// Json:Dictionary a dictionary of each circle's spellbook Ids. +// +json GetSpellListObject(int nClass, object oPC=OBJECT_SELF); + +// +// GetKnownSpellListObject +// Gets the JSON Object representation of a player's known spell list. This function +// will temporarily cache it's result to the object given to avoid further calculations. +// However this should be cleared after done using the level up screen or reset. +// +// Arguments: +// nClass:int the ClassID +// oPC:Object the player +// +// Returns: +// Json:Dictionary a dictionary of each circle's known spellbook Ids. +// +json GetKnownSpellListObject(int nClass, object oPC=OBJECT_SELF); + +// +// GetKnownSpellListObject +// Gets the JSON Object representation of a player's chosen spell list. This function +// will temporarily cache it's result to the object given to avoid further calculations. +// However this should be cleared after done using the level up screen or reset. +// +// Arguments: +// nClass:int the ClassID +// oPC:Object the player +// +// Returns: +// Json:Dictionary a dictionary of each circle's chosen spellbook Ids. +// +json GetChosenSpellListObject(int nClass, object oPC=OBJECT_SELF); + +// +// ShouldAddSpellToSpellButtons +// Given a classId and a spellbookId, if the player knows the spell already we +// should not add the spell, otherwise we should +// +// Arguments: +// nClass:int Class ID +// spellbookId:int the spell book ID +// oPC:object the player +// +// Returns: +// int:Boolean TRUE if spell should be added, FALSE otherwise +// +int ShouldAddSpellToSpellButtons(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +// +// OpenNUILevelUpWindow +// Opens the Level Up NUI window for the provided class +// +// Arguments: +// nClass:int the ClassID +// +void OpenNUILevelUpWindow(int nClass, object oPC=OBJECT_SELF); + +// +// CloseNUILevelUpWindow +// Closes the NUI Level Up Window if its open +// setting reset to 1 will make it clear the entire cache as if the NUI was never opened +// +void CloseNUILevelUpWindow(object oPC=OBJECT_SELF, int reset=0); + +// +// GetRemainingSpellChoices +// Gets the remaining spell choices for a class at the given circle by checking its +// chosen spells and comparing it against the total spells allowed. This value +// is cached on the player and cleared everytime the window is refreshed/closed +// +// Arguments: +// nClass:int the class id +// circleLevel:int the circle being checked +// +// Returns: +// int the amount of choices left at the circle +// +int GetRemainingSpellChoices(int nClass, int circleLevel, object oPC=OBJECT_SELF); + +// +// ShouldSpellButtonBeEnabled +// Checks whether a spell button should be enabled either because all choices have +// been made, replacing spells isn't allowed, or for various other reasons +// +// Arguments: +// nClass:int class id +// circleLevel:int the chosen circle +// spellbookId:int the chosen spell +// +// Returns: +// int:Boolean TRUE if spell button should be enabled, FALSE otherwise +// +int ShouldSpellButtonBeEnabled(int nClass, int circleLevel, int spellbookId, object oPC=OBJECT_SELF); + +// +// AddSpellToChosenList +// Adds spell to the chosen spells list +// +// Arguments: +// nClass:int the classId +// spellbookId:int the spellbook Id +// spellCircle:int the current circle of the spell +// +void AddSpellToChosenList(int nClass, int spellbookId, int spellCircle, object oPC=OBJECT_SELF); + +// +// RemoveSpellFromChosenList +// Removes a spell from the chosen spell list +// +// Arguments: +// nClass:int the class id +// spellbookId:int the spellbook Id +// spellCircle:int the circle of the spell +// +void RemoveSpellFromChosenList(int nClass, int spellbookId, int spellCircle, object oPC=OBJECT_SELF); + +// +// LearnSpells +// gives the player the spells they want to learn based off of the chosen spell +// list in a stored variable +// +// Arguments: +// nClass:int the classId +// +void LearnSpells(int nClass, object oPC=OBJECT_SELF); + +// +// RemoveSpells +// removes spells from the player that they may know currently but aren't selected +// based off lists in stored variables +// +// Arguments: +// nClass:int the classId +// +void RemoveSpells(int nClass, object oPC=OBJECT_SELF); + +// +// FinishLevelUp +// Finishes level up NUI by removing spells, learning spells, clearing cache, then closing the NUI +// +// Arguments: +// nClass:int the class id +// +void FinishLevelUp(int nClass, object oPC=OBJECT_SELF); + +// +// ClearLevelUpNUICaches +// Clears the cache (stored local variables) for the level up NUI so it is +// ready to be used for a new level up +// +// Arguments: +// nClass:int class id +// oPC:object the player object this is stored under +// +void ClearLevelUpNUICaches(int nClass, object oPC=OBJECT_SELF); + +// +// SpellIsWithinObject +// checks whether a spell is within a JSON Object structure used by the remaining +// spells object and known spells object, following this structure +// { +// "circleLevel:int": [ 1,2,3...,spellId], +// ... +// } +// +// Arguments +// nClass:int classId +// spellbookId:int the spellbook Id +// circleLevel:int the chosen circle of the spell +// spellList;JsonObject the spell list object being checked +// +// Returns: +// int:Boolean TRUE if it is in the object, FALSE otherwise +// +int SpellIsWithinObject(int nClass, int spellbookId, int circleLevel, json spellList, object oPC=OBJECT_SELF); + +// +// IsLevelUpNUIOpen +// Checks if the Level Up NUI is open for the player or not +// +// Arguments: +// oPC:object the player object +// +// Returns: +// int:Boolean TRUE if it is, FALSE otherwise +// +int IsLevelUpNUIOpen(object oPC=OBJECT_SELF); + +// +// IsClassAllowedToUseLevelUpNUI +// Is the provided class allowed to use the level up NUI +// +// Arguments: +// nClass:int class id +// +// Returns: +// int:Boolean TRUE if it can, FALSE otherwise +// +int IsClassAllowedToUseLevelUpNUI(int nClass); + +// +// EnabledChosenButton +// determines if a chosen spell button should be enabled or not. It may not due to +// class restrictions, replacing is not enabled, or other reason +// +// Arguments: +// nClass:int the class id +// spellbookId: the spellbook Id +// circleLevel: the spell's circle +// +// Returns: +// int:Boolean TRUE if it should be enabled, FALSE otherwise +// +int EnableChosenButton(int nClass, int spellbookId, int circleLevel, object oPC=OBJECT_SELF); + +// +// ResetChoices +// Action for the Level Up NUI's 'Reset' button, resets choices by clearing the cache of +// the user so their choices are forgotten and they can start over. +// +// Arguments: +// oPC:object the player object +// +void ResetChoices(object oPC=OBJECT_SELF); + +// +// RemoveSpellKnown +// Removes a spell from a player based off class id. This is for classes that +// aren't spont casters where we have to go in and adjust persistant arrays +// to say if a spell is known or not. +// +// Arguments: +// nClass:int class id +// spellbookId:int the spellbook Id +// oPC:object the player object +// nList:int the list we are removing the spell from (extra invocations or expanded knowledge) +// +void RemoveSpellKnown(int nClass, int spellbookId, object oPC=OBJECT_SELF, int nList=0); + +// +// GetSpellIDsKnown +// Gets the SpellIDs list of the given class and list and returns it as a JsonObject following this structure +// { +// "spellId:int": TRUE, +// ... +// } +// +// This is to keep lookups at O(1) processing time. This value is cached and is +// cleared when the player finishes level up +// +// Arguments: +// nClass:int class id +// oPC:object the player object +// nList:int the list we are checking if provided (extra invocations or expanded knowledge) +// +// Returns: +// JsonObject the list of spell ids the class knows in JsonObject format +// +json GetSpellIDsKnown(int nClass, object oPC=OBJECT_SELF, int nList=0); + +// +// ReasonForDisabledSpell +// Provides the reason for why a spell choice is disabled +// +// Arguments: +// nClass:int the class id +// spellbookId:int the spellbook Id +// +// Returns: +// string the reason for the disabled button, empty string otherwise +// +string ReasonForDisabledSpell(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +// +// ReasonForDisabledChosen +// Provides the reason for why a chosen spell button is disabled +// +// Arguments: +// nClass:int the class id +// spellbookId:int the spellbook Id +// +// Returns: +// string the reason for the disabled button, empty string otherwise +// +string ReasonForDisabledChosen(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +// +// GetExpandedChoicesList +// Gets the expanded choices list for a class (the list of expanded knowledge or +// extra invocations). It follows this structure +// +// { +// "spellId:int": TRUE, +// ... +// } +// This is cached to reduce process times and is cleared everytime the window is refreshed/closed +// +// Arguments: +// nClass:int the class id +// +// Returns: +// JsonObject the object representation of the expanded choices +// +json GetExpandedChoicesList(int nClass, object oPC=OBJECT_SELF); + +// +// GetExpandedChoicesList +// Gets the epic expanded choices list for a class (the list of expanded knowledge or +// extra invocations). It follows this structure +// +// { +// "spellId:int": TRUE, +// ... +// } +// This is cached to reduce process times and is cleared everytime the window is refreshed/closed +// +// Arguments: +// nClass:int the class id +// +// Returns: +// JsonObject the object representation of the expanded choices +// +json GetEpicExpandedChoicesList(int nClass, object oPC=OBJECT_SELF); + +// +// GetRemainingExpandedChoices +// Gets the remaining expanded choices for a class based off list, comparing the +// total number of choices allowed and the total number chosen +// +// Arguments: +// nClass: class id +// nList: the list we are checking (extra invocations/expanded knowledge) +// +// Returns: +// int the amount of choices left +// +int GetRemainingExpandedChoices(int nClass, int nList, object oPC=OBJECT_SELF); +// +// IsSpellInExpandedChoices +// tells if a spell is in the expanded choices list or not +// +// Arguments: +// nClass:int class id +// nList:int the list we are checking (extra invocations/expanded knowledge) +// spellId:int the spell id (not the spellbook id) +// +// Returns +// int:Boolean TRUE if it is a expanded choice, FALSE otherwise +// +int IsSpellInExpandedChoices(int nClass, int nList, int spellId, object oPC=OBJECT_SELF); + +// +// GetChosenReplaceListObject +// The chosen list of spells we wish to replace for PnP replacing if Bioware replacing +// is disabled. This is cached and is cleared when the player is finished leveling +// or resets their choices +// +// Arguments: +// oPC:object the player +// +// Returns: +// json the list of spells chosen to replace +// +json GetChosenReplaceListObject(object oPC=OBJECT_SELF); + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Psionics /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +// +// IsExpKnowledgePower +// checks if a spell is a expanded knowledge spell +// +// Arguments: +// nClass:int class id +// spellbookId:int the spellbook Id +// +// Returns: +// int:Boolean TRUE if the spell is a expanded knowledge spell, FALSE otherwise +// +int IsExpKnowledgePower(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +// +// GetExpKnowledgePowerListRequired +// Tells what list the spell should be added to based on if it was added to the +// expanded choices or epic expanded choices list +// +// Arguments: +// nClass:int the class id +// spellbookId:int the spellbook Id +// +// Returns: +// int -1 for the expanded knowledge list, -2 for the epic expanded knowledge +// list, 0 if just add it to the normal class list +// +int GetExpKnowledgePowerListRequired(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +// +// GetCurrentPowerList +// Gets the current chosen powers list. This is cached and is cleared when the +// player either finishs leveling up or resets. +// +// Arguments: +// oPC:object the player object +// +// Returns: +// JsonArray the list of chosen powers wanting to learn +// +json GetCurrentPowerList(object oPC=OBJECT_SELF); + +// +// ShouldAddPower +// Tells if the power should be added to the list of choices or not. It may not +// be added because its an expanded knowledge choice and you have no more expanded +// knowledge slots, or it may be a restricted spell like psions list +// +// Arguments: +// nClass:int the class id +// spellbookId:int the spellbook id +// +// Returns: +// int:Boolean TRUE if it should be added, FALSE otherwise +// +int ShouldAddPower(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +// +// LearnPowers +// learns the list of chosen powers for the player based off their chosen power list +// +// Arguments: +// nClass:int class id +// oPC:object the player object where stored variables are +// +void LearnPowers(int nClass, object oPC=OBJECT_SELF); + +// +// GetMaxPowerLevelForClass +// gets the max power level for the player based off their level and the class's +// known 2da +// +// Arguments: +// nClass:int the class id +// oPC:object the player +// +// Returns: +// int the max power level (circle) the player can achieve on that class +// +int GetMaxPowerLevelForClass(int nClass, object oPC=OBJECT_SELF); + +// +// GetRemainingPowerChoices +// Gets the remaining power choices the character has at the given chosen circle/power level +// +// Arguments: +// nClass:int class id +// chosenCircle:int the chosen circle/power level +// oPC:object the player +// extra:int should we add the expanded knowledge choices or not +// +// Returns: +// int the number of choices left at the given circle +// +int GetRemainingPowerChoices(int nClass, int chosenCircle, object oPC=OBJECT_SELF, int extra=TRUE); + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Initiators /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +// +// GetDisciplineInfoObject +// Gets the disciplien info for the given class, telling what the chosen spells +// disicpline is, what type of maneuever it is, the different totals, and prerequisites. +// This is cached and is cleared when the window is refreshed/closed +// +// Argument: +// nClass:int class id +// +// Returns: +// JsonObject the object representation of the chosen spells discipline info +// +json GetDisciplineInfoObject(int nClass, object oPC=OBJECT_SELF); + +// +// HasPreRequisitesForManeuver +// Does the player have the prerequisites for the given spell based off their chosen +// spell list +// +// Arguments: +// nClass:int the class id +// spellbookId:int the spellbook id +// oPC:object the player object with stored variables +// +// Returns: +// int:Boolean, TRUE if you have the prerequisites, FALSE otherwise +// +int HasPreRequisitesForManeuver(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +// +// GetMaxInitiatorCircle +// gets the max circle/level a player can obtain with the given class +// +// Arguments: +// nClass:int the class id +// oPC:object the player +// +// Returns: +// int the highest circle the player can achieve with the class +// +int GetMaxInitiatorCircle(int nClass, object oPC=OBJECT_SELF); + +// +// GetRemainingManeuverChoices +// Gets remaining maneuever choices for the player +// +// Arguments: +// nClass:int class id +// oPC:object the player +// +// Returns: +// int the remaining maneuevers choices +// +int GetRemainingManeuverChoices(int nClass, object oPC=OBJECT_SELF); + +// +// GetRemainingStanceChoices +// Gets remaining stance choices for the player +// +// Arguments: +// nClass:int class id +// oPC:object the player +// +// Returns: +// int the remaining stance choices +// +int GetRemainingStanceChoices(int nClass, object oPC=OBJECT_SELF); + +// +// IsRequiredForOtherManeuvers +// Checks the given prerequisite number and the chosen spells to see if removing it +// will cause it to fail the requirement for other maneuevers +// +// Arguments: +// nClass:int the class id +// prereq:int the chosen spells prerequisite number of maneuevers needed +// discipline:string the chosen spells discipline +// +// Returns: +// int:Boolean TRUE if it is required, FALSE otherwise +// +int IsRequiredForOtherManeuvers(int nClass, int prereq, string discipline, object oPC=OBJECT_SELF); + +// +// IsAllowedDiscipline +// checks to see if the given spell is a allowed discipline for a class +// +// Arguments: +// nClass:int class id +// spellbookId:int the spellbook id +// +// Returns: +// int:boolean TRUE if it is allowed, FALSE otherwise +// +int IsAllowedDiscipline(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +// +// AddSpellDisciplineInfo +// Adds the maneuver's discipline info to the class's discpline object +// +// Arguments: +// sFile:string the class's spell 2da +// spellbookId:int the spellbook Id +// classDisc:JsonObject the class discipline object we are adding to +// +// Returns: +// json:Object the classDisc with the given spells information added +// +json AddSpellDisciplineInfo(string sFile, int spellbookId, json classDisc); + +// +// IsRequiredForToBPRCClass +// tells if a given maneuver is needed to satisfy a PRC's prerequsitie +// +// Arguments: +// nClass:int class id +// spellbookId:int the spellbook id +// +// Returns: +// int:Boolean TRUE if the maneuver is required for a PRC, FALSE otherwise. +// +int IsRequiredForToBPRCClass(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Invokers /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +// +// GetInvokerKnownListObject +// gets the invokers known invocations list in object format, needed to tell how many +// of each invocation level does a person know at a given level. This is cached on the +// player and not cleared since it never changes. +// +// Arguments: +// nClass:int class id +// +// Returns: +// json:Object the list of invocations known in json format +// +json GetInvokerKnownListObject(int nClass, object oPC=OBJECT_SELF); + +// +// GetRemainingInvocationChoices +// Gets the remaining invocation choices left +// +// Arguments: +// nClass:int class id +// chosenCircle:int the chosen circle we are checking +// oPC:Object the player +// extra:int should we count the number of extra invocations we have left +// +// Returns: +// int the amount of choices left at the given circle +// +int GetRemainingInvocationChoices(int nClass, int chosenCircle, object oPC=OBJECT_SELF, int extra=TRUE); + +// +// IsExtraChoiceInvocation +// tells if a given spell is a extra invocation choice +// +// Arguments: +// nClass:int class id +// spellbookId:int the spellbook id +// +// Returns: +// int;Boolean TRUE if it is a extra choice, FALSE otherwise +// +int IsExtraChoiceInvocation(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Truenamer /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +// +// GetRemainingTruenameChoices +// gets the remaining truename choices left at the given lexicon type +// +// Arguments: +// nClass:int class id +// nType:int the lexicon +// +// Returns: +// int the amount of truename choices left for the given lexicon +// +int GetRemainingTruenameChoices(int nClass, int nType, object oPC=OBJECT_SELF); + +// +// GetLexiconCircleKnownAtLevel +// gets the known circle level for a given lexicon +// +// Arguments: +// nLevel:int the level to check +// nType:int the lexicon we are checking +// +// Returns: +// int the highest circle we can achieve +// +int GetLexiconCircleKnownAtLevel(int nLevel, int nType); + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Archivist /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +json GetArchivistNewSpellsList(object oPC=OBJECT_SELF); + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Spont Casters / Base /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +int IsLevelUpNUIOpen(object oPC=OBJECT_SELF) +{ + int nPreviousToken = NuiFindWindow(oPC, NUI_LEVEL_UP_WINDOW_ID); + if (nPreviousToken != 0) + { + return TRUE; + } + + return FALSE; +} + +int IsClassAllowedToUseLevelUpNUI(int nClass) +{ + + if (GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS) + return TRUE; + + if (nClass == CLASS_TYPE_PSYWAR + || nClass == CLASS_TYPE_PSYCHIC_ROGUE + || nClass == CLASS_TYPE_PSION + || nClass == CLASS_TYPE_FIST_OF_ZUOKEN + || nClass == CLASS_TYPE_WILDER + || nClass == CLASS_TYPE_WARMIND) + return TRUE; + + if (nClass == CLASS_TYPE_WARBLADE + || nClass == CLASS_TYPE_SWORDSAGE + || nClass == CLASS_TYPE_CRUSADER) + return TRUE; + + if (nClass == CLASS_TYPE_WARLOCK + || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT + || nClass == CLASS_TYPE_DRAGON_SHAMAN) + return TRUE; + + if (nClass == CLASS_TYPE_SHADOWCASTER + || nClass == CLASS_TYPE_SHADOWSMITH) + return TRUE; + + if (nClass == CLASS_TYPE_TRUENAMER) + return TRUE; + + if (nClass == CLASS_TYPE_ARCHIVIST) + return TRUE; + + return FALSE; +} + +int SpellIsWithinObject(int nClass, int spellbookId, int circleLevel, json spellList, object oPC=OBJECT_SELF) +{ + // check to see if the spell circle isn't empty + json currentList = JsonObjectGet(spellList, IntToString(circleLevel)); + if (currentList == JsonNull()) + return FALSE; + + int totalSpells = JsonGetLength(currentList); + + // then loop through the spell list and find the spell. + int i; + for (i = 0; i < totalSpells; i++) + { + int currentSpell = JsonGetInt(JsonArrayGet(currentList, i)); + if (currentSpell == spellbookId) + return TRUE; + } + + return FALSE; +} + +int AllSpellsAreChosen(int nClass, object oPC=OBJECT_SELF) +{ + // we need the max number of circles a class has. + json spellList = GetSpellListObject(nClass, oPC); + json spellCircles = JsonObjectKeys(spellList); + int totalCircles = JsonGetLength(spellCircles); + + int i; + for (i = 0; i < totalCircles; i++) + { + // loop through each circle and check if you have any remaining choices left + // if you do or you have a deficit then you need to remove or add something + // until you get 0 + int spellCircle = StringToInt(JsonGetString(JsonArrayGet(spellCircles, i))); + int remainingChoices = GetRemainingSpellChoices(nClass, spellCircle, oPC); + if (remainingChoices < 0 || remainingChoices > 0) + return FALSE; + } + + return TRUE; +} + +void AddSpellToChosenList(int nClass, int spellbookId, int spellCircle, object oPC=OBJECT_SELF) +{ + if (GetIsInvocationClass(nClass)) + { + // get the remaining invocation choices left without extra feats + // if it is 0 then we are adding the chosen invocation to the extra lists + int totalInvocations = GetRemainingInvocationChoices(nClass, spellCircle, oPC, FALSE); + if (totalInvocations == 0) + { + string sFile = GetClassSpellbookFile(nClass); + if (GetRemainingExpandedChoices(nClass, INVOCATION_LIST_EXTRA, oPC)) + { + json expList = GetExpandedChoicesList(nClass, oPC); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + expList = JsonObjectSet(expList, spellId, JsonBool(TRUE)); + SetLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR, expList); + } + else if (GetRemainingExpandedChoices(nClass, INVOCATION_LIST_EXTRA_EPIC, oPC)) + { + json expList = GetEpicExpandedChoicesList(nClass, oPC); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + expList = JsonObjectSet(expList, spellId, JsonBool(TRUE)); + SetLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR, expList); + } + } + } + if (GetIsPsionicClass(nClass)) + { + // if the power is a expanded knowledge than we immediatly add it to the + // extra list, otherwise check to make sure we have made all choices in our + // base list first before adding it to the extra list. + if (IsExpKnowledgePower(nClass, spellbookId, oPC) + || GetRemainingPowerChoices(nClass, spellCircle, oPC, FALSE) == 0) + { + string sFile = GetClassSpellbookFile(nClass); + if (GetRemainingExpandedChoices(nClass, POWER_LIST_EXP_KNOWLEDGE, oPC)) + { + json expList = GetExpandedChoicesList(nClass, oPC); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + expList = JsonObjectSet(expList, spellId, JsonBool(TRUE)); + SetLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR, expList); + } + else if (GetRemainingExpandedChoices(nClass, POWER_LIST_EPIC_EXP_KNOWLEDGE, oPC)) + { + json expList = GetEpicExpandedChoicesList(nClass, oPC); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + expList = JsonObjectSet(expList, spellId, JsonBool(TRUE)); + SetLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR, expList); + } + } + + // add the power to the current power list. + json currPowerList = GetCurrentPowerList(oPC); + currPowerList = JsonArrayInsert(currPowerList, JsonInt(spellbookId)); + SetLocalJson(oPC, NUI_LEVEL_UP_POWER_LIST_VAR, currPowerList); + } + + if (nClass == CLASS_TYPE_ARCHIVIST) + { + json newSpells = GetArchivistNewSpellsList(oPC); + newSpells = JsonArrayInsert(newSpells, JsonInt(spellbookId)); + SetLocalJson(oPC, NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR, newSpells); + } + + // base logic for spont casters, add the spell to the ChosenSpells JSON object + // by adding it to it's appropriate circle. + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + json spellsAtCircle = JsonObjectGet(chosenSpells, IntToString(spellCircle)); + if (spellsAtCircle == JsonNull()) + spellsAtCircle = JsonArray(); + spellsAtCircle = JsonArrayInsert(spellsAtCircle, JsonInt(spellbookId)); + chosenSpells = JsonObjectSet(chosenSpells, IntToString(spellCircle), spellsAtCircle); + SetLocalJson(oPC, NUI_LEVEL_UP_CHOSEN_SPELLS_VAR, chosenSpells); + + // if we are not using bioware unlearning logic, then we need to limit the + // amount of spells we can replace. + if (!GetPRCSwitch(PRC_BIO_UNLEARN)) + { + json unlearnList = GetChosenReplaceListObject(oPC); + // if the spell belongs to the unlearn list, then remove it to make room + // for a new spell. + if (JsonObjectGet(unlearnList, IntToString(spellbookId)) != JsonNull()) + { + unlearnList = JsonObjectDel(unlearnList, IntToString(spellbookId)); + SetLocalJson(oPC, NUI_LEVEL_UP_RELEARN_LIST_VAR, unlearnList); + } + } +} + +void RemoveSpellFromChosenList(int nClass, int spellbookId, int spellCircle, object oPC=OBJECT_SELF) +{ + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + json spellsAtCircle = JsonObjectGet(chosenSpells, IntToString(spellCircle)); + if (spellsAtCircle == JsonNull()) + spellsAtCircle = JsonArray(); + + int totalSpells = JsonGetLength(spellsAtCircle); + + // find the spell at the circle in the chosen list and remove it. + int i; + for (i = 0; i < totalSpells; i++) + { + if (spellbookId == JsonGetInt(JsonArrayGet(spellsAtCircle, i))) + { + spellsAtCircle = JsonArrayDel(spellsAtCircle, i); + break; + } + } + + chosenSpells = JsonObjectSet(chosenSpells, IntToString(spellCircle), spellsAtCircle); + SetLocalJson(oPC, NUI_LEVEL_UP_CHOSEN_SPELLS_VAR, chosenSpells); + + // if we re not using bioware unlearn logic we need to limit how many spells + // can be replaced + if (!GetPRCSwitch(PRC_BIO_UNLEARN)) + { + json knownSpells = GetKnownSpellListObject(nClass, oPC); + json spellListAtCircle = JsonObjectGet(knownSpells, IntToString(spellCircle)); + int totalSpells = JsonGetLength(spellListAtCircle); + + // with the list of known spells, check the selected circle and see if the + // current spell belongs in the already known spell list. + for (i = 0; i < totalSpells; i++) + { + int chosenSpell = JsonGetInt(JsonArrayGet(spellListAtCircle, i)); + if (chosenSpell == spellbookId) + { + // if it does we need to add the spell to the unlearn JSON object to track what spells + // are being replaced. + json unlearnList = GetChosenReplaceListObject(oPC); + unlearnList = JsonObjectSet(unlearnList, IntToString(spellbookId), JsonBool(TRUE)); + SetLocalJson(oPC, NUI_LEVEL_UP_RELEARN_LIST_VAR, unlearnList); + break; + } + } + } + + if (GetIsPsionicClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + + // for psionics we need to check if the removed spell was a expanded knowledge choice + // or not. The id of the list is -1 or -2. + int i; + for (i == -1; i >= -2; i--) + { + json expList = (i == -1) ? GetExpandedChoicesList(nClass, oPC) : + GetEpicExpandedChoicesList(nClass, oPC); + + //if the spell belongs in the expanded knowledge list, then we need + // to remove it. + if (JsonObjectGet(expList, spellId) != JsonNull()) + { + expList = JsonObjectDel(expList, spellId); + if (i == POWER_LIST_EXP_KNOWLEDGE) + SetLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR, expList); + else + SetLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR, expList); + } + } + + // then we need to remove the power from the selected powers list. + json currPowerChoices = GetCurrentPowerList(oPC); + int totalPowers = JsonGetLength(currPowerChoices); + + for (i = 0; i < totalPowers; i++) + { + if (spellbookId == JsonGetInt(JsonArrayGet(currPowerChoices, i))) + { + currPowerChoices = JsonArrayDel(currPowerChoices, i); + break; + } + } + + SetLocalJson(oPC, NUI_LEVEL_UP_POWER_LIST_VAR, currPowerChoices); + } + if (GetIsInvocationClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + + // for invocations we need to check if the spell was added to the extra + // invocations list, the list ids are the invalid class id, and -2 + int i; + for (i = 0; i <= 1; i++) + { + json expList = (i == 0) ? GetExpandedChoicesList(nClass, oPC) : + GetEpicExpandedChoicesList(nClass, oPC); + + // if the spell was found, remove it. + if (JsonObjectGet(expList, spellId) != JsonNull()) + { + expList = JsonObjectDel(expList, spellId); + if (i == 0) + SetLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR, expList); + else + SetLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR, expList); + } + } + } + if (nClass == CLASS_TYPE_ARCHIVIST) + { + json newSpells = GetArchivistNewSpellsList(oPC); + int totalNew = JsonGetLength(newSpells); + + int i; + for (i = 0; i < totalNew; i++) + { + int newSpellbookId = JsonGetInt(JsonArrayGet(newSpells, i)); + if (newSpellbookId == spellbookId) + { + newSpells = JsonArrayDel(newSpells, i); + SetLocalJson(oPC, NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR, newSpells); + break; + } + } + } +} + +void OpenNUILevelUpWindow(int nClass, object oPC=OBJECT_SELF) +{ + CloseNUILevelUpWindow(oPC); + // set the NUI to the given classId + int currentClass = GetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CLASS_VAR); + // we need to clear the cache if it was used before to avoid weird behaviors + ClearLevelUpNUICaches(currentClass, oPC); + // sometimes we are given a different classId instead of the base, we need to + // figure out what the true base class is (mostly true for RHD) + int chosenClass = GetTrueClassType(nClass, oPC); + SetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CLASS_VAR, chosenClass); + ExecuteScript("prc_nui_lv_view", oPC); +} + +void CloseNUILevelUpWindow(object oPC=OBJECT_SELF, int reset=0) +{ + int currentClass = GetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CLASS_VAR); + // if we are refreshing the NUI but not finished we need to clear some caching done + // to save computation time as they will need to be reprocessed. + DeleteLocalJson(oPC, NUI_LEVEL_UP_DISCIPLINE_INFO_VAR + IntToString(currentClass)); + SetLocalInt(oPC, NUI_LEVEL_UP_REMAINING_CHOICES_CACHE_VAR, -20); + if (reset) + { + ClearLevelUpNUICaches(currentClass, oPC); + } + int nPreviousToken = NuiFindWindow(oPC, NUI_LEVEL_UP_WINDOW_ID); + if (nPreviousToken != 0) + { + NuiDestroy(oPC, nPreviousToken); + } +} + +int ShouldSpellButtonBeEnabled(int nClass, int circleLevel, int spellbookId, object oPC=OBJECT_SELF) +{ + // logic for psionics + if (GetIsPsionicClass(nClass)) + { + int maxLevel = GetMaxPowerLevelForClass(nClass, oPC); + if (circleLevel > maxLevel) + return FALSE; + + // if its an expanded knowledge choice and we have already made all our + // exp knowledge choices then it needs to be disabled. + if (IsExpKnowledgePower(nClass, spellbookId, oPC)) + { + int remainingExp = GetRemainingExpandedChoices(nClass, POWER_LIST_EXP_KNOWLEDGE, oPC) + + GetRemainingExpandedChoices(nClass, POWER_LIST_EPIC_EXP_KNOWLEDGE, oPC); + if (!remainingExp) + return FALSE; + } + } + + if (GetIsShadowMagicClass(nClass)) + { + // mysteries are weird, the circles are sectioned by 1-3, 4-6, 7-9 + // if you do not have at least 2 choices from a circle you can't progress up + // so you can have access to circles 1,2,4,7,8 + int nType = 1; + if (circleLevel >= 4 && circleLevel <= 6) + nType = 2; + if (circleLevel >= 7 && circleLevel <= 9) + nType = 3; + int maxPossibleCircle = GetMaxMysteryLevelLearnable(oPC, nClass, nType); + if (circleLevel > maxPossibleCircle) + return FALSE; + } + + if (GetIsTruenamingClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + int lexicon = StringToInt(Get2DACache(sFile, "Lexicon", spellbookId)); + // each lexicon learns at different rates + int maxCircle = GetLexiconCircleKnownAtLevel(GetLevelByClass(nClass, oPC), lexicon); + if (circleLevel > maxCircle) + return FALSE; + + if (GetRemainingTruenameChoices(nClass, lexicon, oPC)) + return TRUE; + return FALSE; + } + + // logic for ToB + if (GetIsBladeMagicClass(nClass)) + { + if (circleLevel > GetMaxInitiatorCircle(nClass, oPC)) + return FALSE; + + // if you do not have the prerequisite amount of maneuevers to learn + // the maneuever, then you can't learn it. + if (!HasPreRequisitesForManeuver(nClass, spellbookId, oPC)) + return FALSE; + + // maneuvers and stances have their own seperate limits + string sFile = GetClassSpellbookFile(nClass); + int type = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + if (type == MANEUVER_TYPE_BOOST + || type == MANEUVER_TYPE_COUNTER + || type == MANEUVER_TYPE_STRIKE + || type == MANEUVER_TYPE_MANEUVER) + { + int remainingMan = GetRemainingManeuverChoices(nClass, oPC); + if (remainingMan) + return TRUE; + return FALSE; + } + if (type == MANEUVER_TYPE_STANCE) + { + int remainingStance = GetRemainingStanceChoices(nClass, oPC); + if (remainingStance) + return TRUE; + return FALSE; + } + } + + if (nClass == CLASS_TYPE_ARCHIVIST) + { + int maxLevel = GetMaxSpellLevelForCasterLevel(nClass, GetCasterLevelByClass(nClass, oPC)); + if (circleLevel > maxLevel) + return FALSE; + } + + // default logic + // determine remaining Spell/Power choices left for player, if there is any + // remaining, enable the buttons. + if (GetRemainingSpellChoices(nClass, circleLevel, oPC)) + return TRUE; + + return FALSE; +} + +int ShouldAddSpellToSpellButtons(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + string sFile = GetClassSpellbookFile(nClass); + + string spellLevel = Get2DACache(sFile, "Level", spellbookId); + json chosenSpellsAtCircle = JsonObjectGet(chosenSpells, spellLevel); + + int chosenSpellCount = JsonGetLength(chosenSpellsAtCircle); + + // if the spell is in the chosen list, then don't add it to the available list + int i; + for (i = 0; i < chosenSpellCount; i++) + { + int chosenSpellId = JsonGetInt(JsonArrayGet(chosenSpellsAtCircle, i)); + if (chosenSpellId == spellbookId) + return FALSE; + } + + if (GetIsBladeMagicClass(nClass)) + return IsAllowedDiscipline(nClass, spellbookId, oPC); + + // if a psionic class we need to see if the power is a expanded knowledge + // choice and if we should show it or not + if (GetIsPsionicClass(nClass)) + return ShouldAddPower(nClass, spellbookId, oPC); + + // for these set of classes we need to only allow 'advanced learning' + // spells to be added + if (nClass == CLASS_TYPE_BEGUILER + || nClass == CLASS_TYPE_DREAD_NECROMANCER + || nClass == CLASS_TYPE_WARMAGE) + { + int advancedLearning = StringToInt(Get2DACache(sFile, "AL", spellbookId)); + if (advancedLearning) + return TRUE; + return FALSE; + } + + if (nClass == CLASS_TYPE_ARCHIVIST) + { + int nLevel = GetLevelByClass(nClass, oPC); + if ((StringToInt(spellLevel) == 0) && (nLevel == 1)) + return FALSE; + int advancedLearning = StringToInt(Get2DACache(sFile, "AL", spellbookId)); + if (advancedLearning) + return FALSE; + } + + return TRUE; +} + +json GetChosenSpellListObject(int nClass, object oPC=OBJECT_SELF) +{ + json retValue = GetLocalJson(oPC, NUI_LEVEL_UP_CHOSEN_SPELLS_VAR); + // if this isn't set yet then we the chosen currently is the known spells + if (retValue == JsonNull()) + { + retValue = GetKnownSpellListObject(nClass, oPC); + SetLocalJson(oPC, NUI_LEVEL_UP_CHOSEN_SPELLS_VAR, retValue); + } + + return retValue; +} + +json GetKnownSpellListObject(int nClass, object oPC=OBJECT_SELF) +{ + json retValue = GetLocalJson(oPC, NUI_LEVEL_UP_KNOWN_SPELLS_VAR); + if (retValue == JsonNull()) + retValue = JsonObject(); + else + return retValue; + + string sFile = GetClassSpellbookFile(nClass); + int totalSpells = Get2DARowCount(sFile); + + if (nClass == CLASS_TYPE_ARCHIVIST) + { + int i; + for (i = 0; i < 10; i++) + { + string sSpellbook = GetSpellsKnown_Array(nClass, i); + + int nSize = persistant_array_get_size(oPC, sSpellbook); + + int j; + for (j = 0; j < nSize; j++) + { + int knownSpellbookID = persistant_array_get_int(oPC, sSpellbook, j); + // we store things in a JSON Object where the spell circle + // is the key to a JsonArray of spellbookIds. + json spellList = JsonObjectGet(retValue, IntToString(i)); + if (spellList == JsonNull()) + spellList = JsonArray(); + spellList = JsonArrayInsert(spellList, JsonInt(knownSpellbookID)); + retValue = JsonObjectSet(retValue, IntToString(i), spellList); + } + } + } + else + { + // loop through all the spells in the class's 2da + int i; + for (i = 0; i < totalSpells; i++) + { + int featId = StringToInt(Get2DACache(sFile, "FeatID", i)); + // if you have the feat, you know the spell + if (featId && GetHasFeat(featId, oPC, TRUE)) + { + string spellLevel = Get2DACache(sFile, "Level", i); + int nSpellLevel = StringToInt(spellLevel); + // some spells have **** as their level, so make sure we have + // parsed it correctly + if (IntToString(nSpellLevel) == spellLevel) + { + // we store things in a JSON Object where the spell circle + // is the key to a JsonArray of spellbookIds. + json spellList = JsonObjectGet(retValue, spellLevel); + if (spellList == JsonNull()) + spellList = JsonArray(); + spellList = JsonArrayInsert(spellList, JsonInt(i)); + retValue = JsonObjectSet(retValue, spellLevel, spellList); + } + } + } + } + + SetLocalJson(oPC, NUI_LEVEL_UP_KNOWN_SPELLS_VAR, retValue); + return retValue; +} + +json GetSpellListObject(int nClass, object oPC=OBJECT_SELF) +{ + json retValue = GetLocalJson(oPC, NUI_LEVEL_UP_SPELLBOOK_OBJECT_CACHE_VAR + IntToString(nClass)); + if (retValue == JsonNull()) + retValue = JsonObject(); + else + return retValue; + + string sFile = GetClassSpellbookFile(nClass); + int totalSpells = Get2DARowCount(sFile); + + // loop through all the spells in the 2da and convert it to a JSON Object representation + int i; + for (i = 0; i < totalSpells; i++) + { + string spellLevel = Get2DACache(sFile, "Level", i); + int nSpellLevel = StringToInt(spellLevel); + // some spells in the list have **** as spell level. We need to ignore them + if (IntToString(nSpellLevel) == spellLevel) + { + if (nClass == CLASS_TYPE_ARCHIVIST) + { + int reqFeat = StringToInt(Get2DACache(sFile, "ReqFeat", i)); + if (!reqFeat) + { + json spellList = JsonObjectGet(retValue, spellLevel); + if (spellList == JsonNull()) + spellList = JsonArray(); + spellList = JsonArrayInsert(spellList, JsonInt(i)); + retValue = JsonObjectSet(retValue, spellLevel, spellList); + } + } + else + { + json spellList = JsonObjectGet(retValue, spellLevel); + if (spellList == JsonNull()) + spellList = JsonArray(); + spellList = JsonArrayInsert(spellList, JsonInt(i)); + retValue = JsonObjectSet(retValue, spellLevel, spellList); + } + } + } + + SetLocalJson(oPC, NUI_LEVEL_UP_SPELLBOOK_OBJECT_CACHE_VAR + IntToString(nClass), retValue); + return retValue; +} + +int GetRemainingSpellChoices(int nClass, int circleLevel, object oPC=OBJECT_SELF) +{ + int chosenCircle = GetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CIRCLE_VAR); + int remainingChoices = 0; + + // we only want to cache on the current circle. + if (chosenCircle == circleLevel) + { + remainingChoices = GetLocalInt(oPC, NUI_LEVEL_UP_REMAINING_CHOICES_CACHE_VAR); + // -20 is the chosen number to say there is no cache set since 0 is + // a valid option + if (remainingChoices != -20) + return remainingChoices; + } + + // logic for psionics + if (GetIsPsionicClass(nClass)) + remainingChoices = GetRemainingPowerChoices(nClass, circleLevel, oPC); + + // logic for ToB + if (GetIsBladeMagicClass(nClass)) + remainingChoices = (GetRemainingManeuverChoices(nClass, oPC) + + GetRemainingStanceChoices(nClass, oPC)); + + // logic for Invokers + if (GetIsInvocationClass(nClass)) + remainingChoices = GetRemainingInvocationChoices(nClass, circleLevel, oPC); + + // logic for mysteries + if (GetIsShadowMagicClass(nClass)) + { + int totalChosen = 0; + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + json circles = JsonObjectKeys(chosenSpells); + int totalCircles = JsonGetLength(circles); + + int i; + for (i = 0; i < totalCircles; i++) + { + // loop through each circle and add its total spells together since + // we don't care about where you spend your spells, only the amount + string currentCircle = JsonGetString(JsonArrayGet(circles, i)); + json spellList = JsonObjectGet(chosenSpells, currentCircle); + if (spellList != JsonNull()) + totalChosen += JsonGetLength(spellList); + } + + int maxKnown = GetMaxMysteryCount(oPC, nClass); + remainingChoices = (maxKnown - totalChosen); + } + + if (GetIsTruenamingClass(nClass)) + remainingChoices = GetRemainingTruenameChoices(nClass, -1, oPC); + + if (nClass == CLASS_TYPE_ARCHIVIST) + { + int nLevel = GetLevelByClass(CLASS_TYPE_ARCHIVIST, oPC); + int spellsAvailable; + if (nLevel == 1) + spellsAvailable = (3 + GetAbilityModifier(ABILITY_INTELLIGENCE, oPC)); + else + spellsAvailable = 2; + + json newSpells = GetArchivistNewSpellsList(oPC); + int totalNewSpells = JsonGetLength(newSpells); + remainingChoices = (spellsAvailable - totalNewSpells); + } + if (GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS) + { + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + int totalSpellsKnown = 0; + int casterLevel = GetCasterLevelByClass(nClass, oPC); + + // these specific classes only learn at specific rates + int advancedLearning = 0; + // beguiler learns every 4th level starting on 3 + if (nClass == CLASS_TYPE_BEGUILER) + advancedLearning = ((casterLevel+1)/4); + // dread learns every 4th level + if (nClass == CLASS_TYPE_DREAD_NECROMANCER) + advancedLearning = (casterLevel/4); + // warmage is a bastard child that choses when it learns a spell whenever + // it decides it feels like it wants to + if (nClass == CLASS_TYPE_WARMAGE) + { + if (casterLevel >= 3) // 1 choice + advancedLearning++; + if (casterLevel >= 6) // 2 choice + advancedLearning++; + if (casterLevel >= 11) // 3 choice + advancedLearning++; + if (casterLevel >= 16) // 4 choice + advancedLearning++; + if (casterLevel >= 24) // 5 choice + advancedLearning++; + if (casterLevel >= 28) // 6 choice + advancedLearning++; + if (casterLevel >= 32) // 7 choice + advancedLearning++; + if (casterLevel >= 36) // 8 choice + advancedLearning++; + if (casterLevel >= 40) // 9 choice + advancedLearning++; + } + + if (advancedLearning) + { + int maxSpellLevel = GetMaxSpellLevelForCasterLevel(nClass, casterLevel); + // can't learn what you can't achieve + if (circleLevel > maxSpellLevel) + remainingChoices = 0; + else + { + int chosenSpellsAmount = 0; + + json circles = JsonObjectKeys(chosenSpells); + int totalCircles = JsonGetLength(circles); + string sFile = GetClassSpellbookFile(nClass); + + int i; + for (i = 0; i <= totalCircles; i++) + { + string currentCircle = JsonGetString(JsonArrayGet(circles, i)); + json spellList = JsonObjectGet(chosenSpells, currentCircle); + if ((spellList != JsonNull())) + { + // loop through the spells of a given circle and count how + // many advanced learning spells you know + int numOfSpells = JsonGetLength(spellList); + int j; + for (j = 0; j < numOfSpells; j++) + { + int nSpellbookID = JsonGetInt(JsonArrayGet(spellList, j)); + int isAL = StringToInt(Get2DACache(sFile, "AL", nSpellbookID)); + if (isAL) + chosenSpellsAmount++; + } + } + } + + remainingChoices = (advancedLearning - chosenSpellsAmount); + } + } + else + { + // default logic for spont casters + totalSpellsKnown = GetSpellKnownMaxCount(casterLevel, circleLevel, nClass, oPC); + // Favoured Soul has more 0 choices than there are spells for some reason + if (nClass == CLASS_TYPE_FAVOURED_SOUL && circleLevel == 0 && totalSpellsKnown > 6) + totalSpellsKnown = 7; + + // logic for spont casters + json selectedCircle = JsonObjectGet(chosenSpells, IntToString(circleLevel)); + if (selectedCircle == JsonNull()) + return totalSpellsKnown; + + int selectedSpellCount = JsonGetLength(selectedCircle); + remainingChoices = (totalSpellsKnown - selectedSpellCount); + } + } + + if (chosenCircle == circleLevel) + SetLocalInt(oPC, NUI_LEVEL_UP_REMAINING_CHOICES_CACHE_VAR, remainingChoices); + if (DEBUG) DoDebug("Remaining spell choices is " + IntToString(remainingChoices)); + return remainingChoices; +} + +void FinishLevelUp(int nClass, object oPC=OBJECT_SELF) +{ + RemoveSpells(nClass, oPC); + LearnSpells(nClass, oPC); + if (nClass == CLASS_TYPE_ARCHIVIST) + { + int nLevel = GetLevelByClass(nClass, oPC); + SetPersistantLocalInt(oPC, "LastSpellGainLevel", nLevel); + } + ClearLevelUpNUICaches(nClass, oPC); +} + +void ClearLevelUpNUICaches(int nClass, object oPC=OBJECT_SELF) +{ + // clear the chosen spells you made + DeleteLocalJson(oPC, NUI_LEVEL_UP_CHOSEN_SPELLS_VAR); + // clear the known spells you have + DeleteLocalJson(oPC, NUI_LEVEL_UP_KNOWN_SPELLS_VAR); + SetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CIRCLE_VAR, -1); + DeleteLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CLASS_VAR); + // clear the psionics selected choices + DeleteLocalJson(oPC, NUI_LEVEL_UP_POWER_LIST_VAR); + // clear the expanded choices for psionics and invokers + DeleteLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR); + DeleteLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR); + // clear the PnP replace list + DeleteLocalJson(oPC, NUI_LEVEL_UP_RELEARN_LIST_VAR); + DeleteLocalJson(oPC, NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR); + // for invocation and psionics we grab the list of known extra spells and cache it + // so we need to clear those caches + if (GetIsInvocationClass(nClass)) + { + DeleteLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_0"); + DeleteLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_" + IntToString(INVOCATION_LIST_EXTRA)); + DeleteLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_" + IntToString(INVOCATION_LIST_EXTRA_EPIC)); + } + if (GetIsPsionicClass(nClass)) + { + DeleteLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_0"); + DeleteLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_" + IntToString(POWER_LIST_EXP_KNOWLEDGE)); + DeleteLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_" + IntToString(POWER_LIST_EPIC_EXP_KNOWLEDGE)); + } + // for ToB we need to clear all the discipline info for determining PrC choice validity + if (GetIsBladeMagicClass(nClass)) + { + DeleteLocalJson(oPC, NUI_LEVEL_UP_DISCIPLINE_INFO_VAR + IntToString(CLASS_TYPE_SWORDSAGE)); + DeleteLocalJson(oPC, NUI_LEVEL_UP_DISCIPLINE_INFO_VAR + IntToString(CLASS_TYPE_WARBLADE)); + DeleteLocalJson(oPC, NUI_LEVEL_UP_DISCIPLINE_INFO_VAR + IntToString(CLASS_TYPE_CRUSADER)); + } +} + +void RemoveSpells(int nClass, object oPC=OBJECT_SELF) +{ + // we don't remove on psionic classes and archivist + if (GetIsPsionicClass(nClass) || nClass == CLASS_TYPE_ARCHIVIST) + return; + + json knownSpells = GetKnownSpellListObject(nClass, oPC); + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + json spellCircles = JsonObjectKeys(knownSpells); + int totalCircles = JsonGetLength(spellCircles); + + // loop through all the known spells circles + int i; + for (i = 0; i < totalCircles; i++) + { + string sSpellLevel = JsonGetString(JsonArrayGet(spellCircles, i)); + int nSpellLevel = StringToInt(sSpellLevel); + + json chosenCircle = JsonObjectGet(knownSpells, sSpellLevel); + int totalSpells = JsonGetLength(chosenCircle); + + // loop through the spell list at the given circle + int y; + for (y = 0; y < totalSpells; y++) + { + int nSpellbookID = JsonGetInt(JsonArrayGet(chosenCircle, y)); + // if the spell is not a chosen spell, then it was removed + if (!SpellIsWithinObject(nClass, nSpellbookID, nSpellLevel, chosenSpells, oPC)) + { + if (GetIsInvocationClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + string spellId = Get2DACache(sFile, "SpellID", nSpellbookID); + int chosenList = 0; + // check to see if its a extra invocation choice and set it's chosen list + if (GetHasFeat(FEAT_EXTRA_INVOCATION_I, oPC)) + { + json expList = GetSpellIDsKnown(nClass, oPC, INVOCATION_LIST_EXTRA); + if (JsonObjectGet(expList, spellId) != JsonNull()) + chosenList = INVOCATION_LIST_EXTRA; + } + if (GetHasFeat(FEAT_EPIC_EXTRA_INVOCATION_I, oPC)) + { + json expList = GetSpellIDsKnown(nClass, oPC, INVOCATION_LIST_EXTRA_EPIC); + if (JsonObjectGet(expList, spellId) != JsonNull()) + chosenList = INVOCATION_LIST_EXTRA_EPIC; + } + RemoveSpellKnown(nClass, nSpellbookID, oPC, chosenList); + } + if (GetIsBladeMagicClass(nClass) || GetIsShadowMagicClass(nClass)) + RemoveSpellKnown(nClass, nSpellbookID, oPC); + + if (GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS) + { + string sFile = GetClassSpellbookFile(nClass); + string sSpellBook = GetSpellsKnown_Array(nClass); + string spellsAtLevelList = "SpellsKnown_" + IntToString(nClass) + "_AtLevel" + IntToString(GetHitDice(oPC)); + // remove the spell from the spellbook + array_extract_int(oPC, sSpellBook, nSpellbookID); + array_extract_int(oPC, spellsAtLevelList, nSpellbookID); + // wipe the spell from the player + int ipFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", nSpellbookID)); + RemoveIPFeat(oPC, ipFeatID); + } + } + } + } +} + +void LearnSpells(int nClass, object oPC=OBJECT_SELF) +{ + if (GetIsPsionicClass(nClass)) + { + LearnPowers(nClass, oPC); + return; + } + + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + json knownSpells = GetKnownSpellListObject(nClass, oPC); + json spellCircles = JsonObjectKeys(chosenSpells); + int totalCircles = JsonGetLength(spellCircles); + + // loop through chosen spells circles + int i; + for (i = 0; i < totalCircles; i++) + { + string sSpellLevel = JsonGetString(JsonArrayGet(spellCircles, i)); + int nSpellLevel = StringToInt(sSpellLevel); + + json chosenCircle = JsonObjectGet(chosenSpells, sSpellLevel); + int totalSpells = JsonGetLength(chosenCircle); + + // loop through the spell list at the circle + int y; + for (y = 0; y < totalSpells; y++) + { + int nSpellbookID = JsonGetInt(JsonArrayGet(chosenCircle, y)); + // if the spell is not in the known spell list then it was newly added + if (!SpellIsWithinObject(nClass, nSpellbookID, nSpellLevel, knownSpells, oPC)) + { + if (GetIsTruenamingClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + // find out what lexicon it belongs to and add it to that + int lexicon = StringToInt(Get2DACache(sFile, "Lexicon", nSpellbookID)); + AddUtteranceKnown(oPC, nClass, nSpellbookID, lexicon, TRUE, GetHitDice(oPC)); + } + + if (GetIsShadowMagicClass(nClass)) + AddMysteryKnown(oPC, nClass, nSpellbookID, TRUE, GetHitDice(oPC)); + + if (GetIsInvocationClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + string spellId = Get2DACache(sFile, "SpellID", nSpellbookID); + int chosenList = nClass; + json expList = GetExpandedChoicesList(nClass, oPC); + // if the invocation belongs to the extra or epic extra list + // then we need to provide those list ids instead. + if (JsonObjectGet(expList, spellId) != JsonNull()) + chosenList = INVOCATION_LIST_EXTRA; + expList = GetEpicExpandedChoicesList(nClass, oPC); + if (JsonObjectGet(expList, spellId) != JsonNull()) + chosenList = INVOCATION_LIST_EXTRA_EPIC; + AddInvocationKnown(oPC, chosenList, nSpellbookID, TRUE, GetHitDice(oPC)); + } + + if (GetIsBladeMagicClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + int maneuverType = StringToInt(Get2DACache(sFile, "Type", nSpellbookID)); + // we save our moves either to stance or maneuever + if (maneuverType != MANEUVER_TYPE_STANCE) + maneuverType = MANEUVER_TYPE_MANEUVER; + + AddManeuverKnown(oPC, nClass, nSpellbookID, maneuverType, TRUE, GetHitDice(oPC)); + } + int nSpellbookType = GetSpellbookTypeForClass(nClass); + if (nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS + || nClass == CLASS_TYPE_ARCHIVIST) + { + // these classes have their own syste, + if (nClass == CLASS_TYPE_BEGUILER + || nClass == CLASS_TYPE_DREAD_NECROMANCER + || nClass == CLASS_TYPE_WARMAGE) + { + int casterLevel = GetCasterLevelByClass(nClass, oPC); + // this is taken from prc_s_spellgain as it is coupled with the + // dynamic dialogue system + int advancedLearning = 0; + // beguilers learn every 4th level starting on 3rd + if (nClass == CLASS_TYPE_BEGUILER) + advancedLearning = ((casterLevel+1)/4); + // dread learns every 4th level + if (nClass == CLASS_TYPE_DREAD_NECROMANCER) + advancedLearning = (casterLevel/4); + if (nClass == CLASS_TYPE_WARMAGE) + { + if (casterLevel >= 3) + advancedLearning++; + } + + if (advancedLearning) + { + // incremenet the total advanced learning known + int nAdvLearn = GetPersistantLocalInt(oPC, "AdvancedLearning_"+IntToString(nClass)); + nAdvLearn++; + SetPersistantLocalInt(oPC, "AdvancedLearning_"+IntToString(nClass), nAdvLearn); + } + } + + // get location of persistant storage on the hide + string sSpellbook = GetSpellsKnown_Array(nClass, nSpellLevel); + if (DEBUG) DoDebug("Adding spell " + IntToString(nSpellbookID) + "to " + sSpellbook); + //object oToken = GetHideToken(oPC); + + // Create spells known persistant array if it is missing + int nSize = persistant_array_get_size(oPC, sSpellbook); + if (nSize < 0) + { + persistant_array_create(oPC, sSpellbook); + nSize = 0; + } + + string spellsAtLevelList = "SpellsKnown_" + IntToString(nClass) + "_AtLevel" + IntToString(GetHitDice(oPC)); + int spellsAtLevelSize = persistant_array_get_size(oPC, spellsAtLevelList); + if (spellsAtLevelSize < 0) + { + persistant_array_create(oPC, spellsAtLevelList); + spellsAtLevelSize = 0; + } + // set the list of spells learned at this level + string sFile = GetClassSpellbookFile(nClass); + int spellId = StringToInt(Get2DACache(sFile, "SpellID", nSpellbookID)); + persistant_array_set_int(oPC, spellsAtLevelList, spellsAtLevelSize, spellId); + if (DEBUG) DoDebug("Adding spells to array " + spellsAtLevelList); + + // Mark the spell as known (e.g. add it to the end of oPCs spellbook) + persistant_array_set_int(oPC, sSpellbook, nSize, nSpellbookID); + + if (nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS) + { + // add spell + string sArrayName = "NewSpellbookMem_" + IntToString(nClass); + int featId = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookID)); + int ipFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", nSpellbookID)); + AddSpellUse(oPC, nSpellbookID, nClass, sFile, sArrayName, nSpellbookType, GetPCSkin(oPC), featId, ipFeatID); + } + } + } + } + } +} + +int EnableChosenButton(int nClass, int spellbookId, int circleLevel, object oPC=OBJECT_SELF) +{ + if (GetIsPsionicClass(nClass) + || GetIsShadowMagicClass(nClass) + || GetIsTruenamingClass(nClass) + || nClass == CLASS_TYPE_DREAD_NECROMANCER + || nClass == CLASS_TYPE_BEGUILER + || nClass == CLASS_TYPE_WARMAGE + || nClass == CLASS_TYPE_ARCHIVIST) + { + json knownSpells = GetKnownSpellListObject(nClass, oPC); + json currentCircle = JsonObjectGet(knownSpells, IntToString(circleLevel)); + int totalSpells = JsonGetLength(currentCircle); + int i; + for (i = 0; i < totalSpells; i++) + { + // if spell belongs to known spells, then disable, we don't allow + // replacing for these classes. + int currentSpellbookId = JsonGetInt(JsonArrayGet(currentCircle, i)); + if (currentSpellbookId == spellbookId) + return FALSE; + } + + } + + if (GetIsBladeMagicClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + int prereqs = StringToInt(Get2DACache(sFile, "Prereqs", spellbookId)); + string discipline = Get2DACache(sFile, "Discipline", spellbookId); + // if the maneuver is required for others to exist, t hen disable it + if (IsRequiredForOtherManeuvers(nClass, prereqs, discipline, oPC)) + return FALSE; + // if it is required for a PRC to exist, then disable it. + if (IsRequiredForToBPRCClass(nClass, spellbookId, oPC)) + return FALSE; + } + + if (GetIsInvocationClass(nClass)) + { + // dragon Shamans can't replace + if (nClass == CLASS_TYPE_DRAGON_SHAMAN) + { + json invokKnown = GetSpellIDsKnown(nClass, oPC); + string sFile = GetClassSpellbookFile(nClass); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + json chosenSpell = JsonObjectGet(invokKnown, spellId); + if (chosenSpell != JsonNull()) + return FALSE; + } + } + + // If we do not use the bioware unlearn system, we follow PnP + if (!GetPRCSwitch(PRC_BIO_UNLEARN)) + { + json knownSpells = GetKnownSpellListObject(nClass, oPC); + json currentCircle = JsonObjectGet(knownSpells, IntToString(circleLevel)); + int totalSpells = JsonGetLength(currentCircle); + int i; + for (i = 0; i < totalSpells; i++) + { + int currentSpellbookId = JsonGetInt(JsonArrayGet(currentCircle, i)); + // if the spell belongs to the known spell list, then we need to determine + if (currentSpellbookId == spellbookId) + { + json unlearnList = GetChosenReplaceListObject(oPC); + int totalUnlearned = JsonGetLength(unlearnList); + int totalAllowed = GetPRCSwitch(PRC_UNLEARN_SPELL_MAXNR); + // we default to 1 if no max number of unlearns is set + if (!totalAllowed) + totalAllowed = 1; + // we cannot replace a spell if we have more than or equal to the + // amount of relearns allowed, therefore disable. + return totalUnlearned < totalAllowed; + } + } + + } + + return TRUE; +} + +void ResetChoices(object oPC=OBJECT_SELF) +{ + // reset choices made so far + DeleteLocalJson(oPC, NUI_LEVEL_UP_CHOSEN_SPELLS_VAR); + DeleteLocalJson(oPC, NUI_LEVEL_UP_POWER_LIST_VAR); + DeleteLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR); + DeleteLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR); + DeleteLocalJson(oPC, NUI_LEVEL_UP_RELEARN_LIST_VAR); + DeleteLocalJson(oPC, NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR); +} + +void RemoveSpellKnown(int nClass, int spellbookId, object oPC=OBJECT_SELF, int nList=0) +{ + string sBase; + string levelArrayBaseId; + string generalArrayBaseId; + string totalCountId; + + string sFile = GetClassSpellbookFile(nClass); + int chosenList = (nList != 0) ? nList : nClass; + int spellID = StringToInt(Get2DACache(sFile, "SpellID", spellbookId)); + + // if statements are to change the location of the spellbook we are grabbing + if (GetIsShadowMagicClass(nClass)) + { + sBase = _MYSTERY_LIST_NAME_BASE + IntToString(chosenList); + levelArrayBaseId = _MYSTERY_LIST_LEVEL_ARRAY; + generalArrayBaseId = _MYSTERY_LIST_GENERAL_ARRAY; + totalCountId = _MYSTERY_LIST_TOTAL_KNOWN; + } + + if (GetIsInvocationClass(nClass)) + { + sBase = _INVOCATION_LIST_NAME_BASE + IntToString(chosenList); + levelArrayBaseId = _INVOCATION_LIST_LEVEL_ARRAY; + generalArrayBaseId = _INVOCATION_LIST_GENERAL_ARRAY; + totalCountId = _INVOCATION_LIST_TOTAL_KNOWN; + } + + if (GetIsBladeMagicClass(nClass)) + { + int maneuverType = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + if (maneuverType != MANEUVER_TYPE_STANCE) maneuverType = MANEUVER_TYPE_MANEUVER; + sBase = _MANEUVER_LIST_NAME_BASE + IntToString(chosenList) + IntToString(maneuverType); + levelArrayBaseId = _MANEUVER_LIST_LEVEL_ARRAY; + generalArrayBaseId = _MANEUVER_LIST_GENERAL_ARRAY; + totalCountId = _MANEUVER_LIST_TOTAL_KNOWN; + } + + if (GetIsTruenamingClass(nClass)) + { + string lexicon = Get2DACache(sFile, "Lexicon", spellbookId); + sBase = _UTTERANCE_LIST_NAME_BASE + IntToString(chosenList) + lexicon; + levelArrayBaseId = _UTTERANCE_LIST_LEVEL_ARRAY; + generalArrayBaseId = _UTTERANCE_LIST_GENERAL_ARRAY; + totalCountId = _UTTERANCE_LIST_TOTAL_KNOWN; + } + + string sTestArray; + + int found = FALSE; + + int i; + for (i = 1; i <= GetHitDice(oPC); i++) + { + sTestArray = sBase + levelArrayBaseId + IntToString(i); + if (persistant_array_exists(oPC, sTestArray)) + { + // if we found the spell, then we remove it. + if (persistant_array_extract_int(oPC, sTestArray, spellID) >= 0) + { + found = TRUE; + break; + } + } + } + + if (!found) + { + // if not found we check the general list where spells aren't set to a level. + sTestArray = sBase + generalArrayBaseId; + if (persistant_array_exists(oPC, sTestArray)) + { + //if we could not find the spell here, something went wrong + if (persistant_array_extract_int(oPC, sTestArray, spellID) < 0) + { + if (DEBUG) DoDebug("Could not find spellID " + IntToString(spellID) + " in the class's spellbook!"); + return; + } + } + } + + // decrement the amount of spells known. + SetPersistantLocalInt(oPC, sBase + totalCountId, + GetPersistantLocalInt(oPC, sBase + totalCountId) - 1 + ); + + // if ToB we need to decrement the specific discipline as well. + if (GetIsBladeMagicClass(nClass)) + { + int maneuverType = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + if (maneuverType == MANEUVER_TYPE_BOOST + || maneuverType == MANEUVER_TYPE_COUNTER + || maneuverType == MANEUVER_TYPE_STRIKE + || maneuverType == MANEUVER_TYPE_MANEUVER) + maneuverType = MANEUVER_TYPE_MANEUVER; + string sDisciplineArray = _MANEUVER_LIST_DISCIPLINE + IntToString(maneuverType) + "_" + Get2DACache(sFile, "Discipline", spellbookId); + SetPersistantLocalInt(oPC, sDisciplineArray, + GetPersistantLocalInt(oPC, sDisciplineArray) - 1); + } + + // remove spell from player + int ipFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", spellbookId)); + RemoveIPFeat(oPC, ipFeatID); +} + +json GetSpellIDsKnown(int nClass, object oPC=OBJECT_SELF, int nList=0) +{ + json spellIds = GetLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_" + IntToString(nList)); + if (spellIds == JsonNull()) + spellIds = JsonObject(); + else + return spellIds; + + string sBase; + string levelArrayBaseId; + string generalArrayBaseId; + // if we are given a listId then use that instead, used for extra choices and + // expanded knowledge + int chosenList = (nList != 0) ? nList : nClass; + // these if checks are for setting class specific ids + if (nClass == CLASS_TYPE_DRAGON_SHAMAN + || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT + || nClass == CLASS_TYPE_WARLOCK) + { + sBase = _INVOCATION_LIST_NAME_BASE + IntToString(chosenList); + levelArrayBaseId = _INVOCATION_LIST_LEVEL_ARRAY; + generalArrayBaseId = _INVOCATION_LIST_GENERAL_ARRAY; + } + if (GetIsPsionicClass(nClass)) + { + sBase = _POWER_LIST_NAME_BASE + IntToString(chosenList); + levelArrayBaseId = _POWER_LIST_LEVEL_ARRAY; + generalArrayBaseId = _POWER_LIST_GENERAL_ARRAY; + } + + // go through the level list and translate the spellIds into a JSON Object + // structure for easier access. + int i; + for (i = 1; i <= GetHitDice(oPC); i++) + { + string sTestArray = sBase + levelArrayBaseId + IntToString(i); + if (persistant_array_exists(oPC, sTestArray)) + { + int nSize = persistant_array_get_size(oPC, sTestArray); + + int j; + for (j = 0; j < nSize; j++) + { + spellIds = JsonObjectSet(spellIds, IntToString(persistant_array_get_int(oPC, sTestArray, j)), JsonBool(TRUE)); + } + } + } + + // go through the general list and translate the spellIds into a JSON Object + // structure for easier access. + string sTestArray = sBase + generalArrayBaseId; + if (persistant_array_exists(oPC, sTestArray)) + { + int nSize = persistant_array_get_size(oPC, sTestArray); + + int j; + for (j = 0; j < nSize; j++) + { + spellIds = JsonObjectSet(spellIds, IntToString(persistant_array_get_int(oPC, sTestArray, j)), JsonBool(TRUE)); + } + } + + SetLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_" + IntToString(nList), spellIds); + return spellIds; +} + +string ReasonForDisabledSpell(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + int circleLevel = StringToInt(Get2DACache(sFile, "Level", spellbookId)); + + // logic for psionics + if (GetIsPsionicClass(nClass)) + { + int maxLevel = GetMaxPowerLevelForClass(nClass, oPC); + if (circleLevel > maxLevel) + return "You are unable to learn at this level currently."; + + // if its an expanded knowledge choice and we have already made all our + // exp knowledge choices then it needs to be disabled. + if (IsExpKnowledgePower(nClass, spellbookId, oPC)) + { + int remainingExp = GetRemainingExpandedChoices(nClass, POWER_LIST_EXP_KNOWLEDGE, oPC) + + GetRemainingExpandedChoices(nClass, POWER_LIST_EPIC_EXP_KNOWLEDGE, oPC); + if (!remainingExp) + return "You have no more expanded knowledge choices left."; + } + } + + if (GetIsShadowMagicClass(nClass)) + { + // mysteries are weird, the circles are sectioned by 1-3, 4-6, 7-9 + // if you do not have at least 2 choices from a circle you can't progress up + // so you can have access to circles 1,2,4,7,8 + int nType = 1; + if (circleLevel >= 4 && circleLevel <= 6) + nType = 2; + if (circleLevel >= 7 && circleLevel <= 9) + nType = 3; + int maxPossibleCircle = GetMaxMysteryLevelLearnable(oPC, nClass, nType); + if (circleLevel > maxPossibleCircle) + return "You are unable to learn at this level currently."; + } + + if (GetIsTruenamingClass(nClass)) + { + int lexicon = StringToInt(Get2DACache(sFile, "Lexicon", spellbookId)); + // each lexicon learns at different rates + int maxCircle = GetLexiconCircleKnownAtLevel(GetLevelByClass(nClass, oPC), lexicon); + if (circleLevel > maxCircle) + return "You are unable to learn at this level currently."; + + if (GetRemainingTruenameChoices(nClass, lexicon, oPC)) + return ""; + return "You have made all your truenaming choices."; + } + + // logic for ToB + if (GetIsBladeMagicClass(nClass)) + { + if (circleLevel > GetMaxInitiatorCircle(nClass, oPC)) + return "You are unable to learn at this level currently."; + + // if you do not have the prerequisite amount of maneuevers to learn + // the maneuever, then you can't learn it. + if (!HasPreRequisitesForManeuver(nClass, spellbookId, oPC)) + return "You do not have the prerequisites for this maneuver."; + + // maneuvers and stances have their own seperate limits + int type = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + if (type == MANEUVER_TYPE_BOOST + || type == MANEUVER_TYPE_COUNTER + || type == MANEUVER_TYPE_STRIKE + || type == MANEUVER_TYPE_MANEUVER) + { + int remainingMan = GetRemainingManeuverChoices(nClass, oPC); + if (remainingMan) + return ""; + return "You have made all your maneuver choices."; + } + if (type == MANEUVER_TYPE_STANCE) + { + int remainingStance = GetRemainingStanceChoices(nClass, oPC); + if (remainingStance) + return ""; + return "You have made all your stance choices."; + } + } + + // default logic + // determine remaining Spell/Power choices left for player, if there is any + // remaining, enable the buttons. + if (GetRemainingSpellChoices(nClass, circleLevel, oPC)) + return ""; + + return "You have made all your spell choices."; +} + +string ReasonForDisabledChosen(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + int circleLevel = StringToInt(Get2DACache(sFile, "Level", spellbookId)); + + + if (GetIsPsionicClass(nClass) + || GetIsShadowMagicClass(nClass) + || GetIsTruenamingClass(nClass) + || nClass == CLASS_TYPE_DREAD_NECROMANCER + || nClass == CLASS_TYPE_BEGUILER + || nClass == CLASS_TYPE_WARMAGE) + { + json knownSpells = GetKnownSpellListObject(nClass, oPC); + json currentCircle = JsonObjectGet(knownSpells, IntToString(circleLevel)); + int totalSpells = JsonGetLength(currentCircle); + int i; + for (i = 0; i < totalSpells; i++) + { + // if spell belongs to known spells, then disable, we don't allow + // replacing for these classes. + int currentSpellbookId = JsonGetInt(JsonArrayGet(currentCircle, i)); + if (currentSpellbookId == spellbookId) + return "You cannot replace spells as this class."; + } + + } + + if (GetIsBladeMagicClass(nClass)) + { + int prereqs = StringToInt(Get2DACache(sFile, "Prereqs", spellbookId)); + string discipline = Get2DACache(sFile, "Discipline", spellbookId); + // if the maneuver is required for others to exist, t hen disable it + if (IsRequiredForOtherManeuvers(nClass, prereqs, discipline, oPC)) + return "This maneuver is required for another maneuver."; + // if it is required for a PRC to exist, then disable it. + if (IsRequiredForToBPRCClass(nClass, spellbookId, oPC)) + return "This maneuver is reuquired for a PRC class."; + } + + if (GetIsInvocationClass(nClass)) + { + // dragon Shamans can't replace + if (nClass == CLASS_TYPE_DRAGON_SHAMAN) + { + json invokKnown = GetSpellIDsKnown(nClass, oPC); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + json chosenSpell = JsonObjectGet(invokKnown, spellId); + if (chosenSpell != JsonNull()) + return "You cannot replace invocations as this class."; + } + } + + // If we do not use the bioware unlearn system, we follow PnP + if (!GetPRCSwitch(PRC_BIO_UNLEARN)) + { + json knownSpells = GetKnownSpellListObject(nClass, oPC); + json currentCircle = JsonObjectGet(knownSpells, IntToString(circleLevel)); + int totalSpells = JsonGetLength(currentCircle); + int i; + for (i = 0; i < totalSpells; i++) + { + int currentSpellbookId = JsonGetInt(JsonArrayGet(currentCircle, i)); + // if the spell belongs to the known spell list, then we need to determine + if (currentSpellbookId == spellbookId) + { + json unlearnList = GetChosenReplaceListObject(oPC); + int totalUnlearned = JsonGetLength(unlearnList); + int totalAllowed = GetPRCSwitch(PRC_UNLEARN_SPELL_MAXNR); + // we default to 1 if no max number of unlearns is set + if (!totalAllowed) + totalAllowed = 1; + // we cannot replace a spell if we have more than or equal to the + // amount of relearns allowed, therefore disable. + if (totalUnlearned < totalAllowed) + return ""; + return "You can only replace " + IntToString(totalAllowed) + " spells during level up."; + } + } + + } + + return ""; +} + +json GetExpandedChoicesList(int nClass, object oPC=OBJECT_SELF) +{ + json expandedChoices = GetLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR); + if (expandedChoices != JsonNull()) + return expandedChoices; + + if (GetIsPsionicClass(nClass)) + expandedChoices = GetSpellIDsKnown(nClass, oPC, POWER_LIST_EXP_KNOWLEDGE); + else + expandedChoices = GetSpellIDsKnown(nClass, oPC, INVOCATION_LIST_EXTRA); + + SetLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR, expandedChoices); + return expandedChoices; +} + +int GetRemainingExpandedChoices(int nClass, int nList, object oPC=OBJECT_SELF) +{ + int remainingChoices = 0; + + json expandedList = (nList == INVOCATION_LIST_EXTRA || nList == POWER_LIST_EXP_KNOWLEDGE ) ? GetExpandedChoicesList(nClass, oPC) + : GetEpicExpandedChoicesList(nClass, oPC); + int expChoicesCount = JsonGetLength(JsonObjectKeys(expandedList)); + int maxExpChoices = (GetIsPsionicClass(nClass)) ? GetMaxPowerCount(oPC, nList) + : GetMaxInvocationCount(oPC, nList); + remainingChoices += (maxExpChoices - expChoicesCount); + + return remainingChoices; +} + +json GetEpicExpandedChoicesList(int nClass, object oPC=OBJECT_SELF) +{ + json expandedChoices = GetLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR); + if (expandedChoices != JsonNull()) + return expandedChoices; + + if (GetIsPsionicClass(nClass)) + expandedChoices = GetSpellIDsKnown(nClass, oPC, POWER_LIST_EPIC_EXP_KNOWLEDGE); + else + expandedChoices = GetSpellIDsKnown(nClass, oPC, INVOCATION_LIST_EXTRA_EPIC); + + SetLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR, expandedChoices); + return expandedChoices; +} + +int IsSpellInExpandedChoices(int nClass, int nList, int spellId, object oPC=OBJECT_SELF) +{ + json expList = (nList == POWER_LIST_EXP_KNOWLEDGE || nList == INVOCATION_LIST_EXTRA) ? GetExpandedChoicesList(nClass, oPC) + : GetEpicExpandedChoicesList(nClass, oPC); + + return (JsonObjectGet(expList, IntToString(spellId)) != JsonNull()); +} + +json GetChosenReplaceListObject(object oPC=OBJECT_SELF) +{ + json replaceList = GetLocalJson(oPC, NUI_LEVEL_UP_RELEARN_LIST_VAR); + if (replaceList == JsonNull()) + replaceList = JsonObject(); + else + return replaceList; + + SetLocalJson(oPC, NUI_LEVEL_UP_RELEARN_LIST_VAR, replaceList); + return replaceList; +} + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Psionics /// +/// /// +//////////////////////////////////////////////////////////////////////////// + + +int IsExpKnowledgePower(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + int isExp = StringToInt(Get2DACache(sFile, "Exp", spellbookId)); + if (isExp) + return TRUE; + int featId = StringToInt(Get2DACache(sFile, "FeatID", spellbookId)); + int isOuterDomain = (featId) ? !CheckPowerPrereqs(featId, oPC) : FALSE; + return isOuterDomain; +} + +json GetCurrentPowerList(object oPC=OBJECT_SELF) +{ + json retValue = GetLocalJson(oPC, NUI_LEVEL_UP_POWER_LIST_VAR); + if (retValue == JsonNull()) + retValue = JsonArray(); + else + return retValue; + + SetLocalJson(oPC, NUI_LEVEL_UP_POWER_LIST_VAR, retValue); + return retValue; +} + +int ShouldAddPower(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + int featId = StringToInt(Get2DACache(sFile, "FeatID", spellbookId)); + int isExp = StringToInt(Get2DACache(sFile, "Exp", spellbookId)); + // if the power is a expanded knowledge power + if (!CheckPowerPrereqs(featId, oPC) || isExp) + { + // and we have a expanded knowledge choice left to make then show + // the button + int addPower = FALSE; + int maxLevel = GetMaxPowerLevelForClass(nClass, oPC); + int currentCircle = GetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CIRCLE_VAR); + + int choicesLeft = GetRemainingExpandedChoices(nClass, POWER_LIST_EXP_KNOWLEDGE, oPC); + if (DEBUG) DoDebug("You still have " + IntToString(choicesLeft) + " expanded power choices left!"); + if (choicesLeft && (currentCircle <= (maxLevel-1))) + addPower = TRUE; + choicesLeft = GetRemainingExpandedChoices(nClass, POWER_LIST_EPIC_EXP_KNOWLEDGE, oPC); + if (DEBUG) DoDebug("You still have " + IntToString(choicesLeft) + " epic expanded power choices left!"); + if (choicesLeft && (currentCircle <= (maxLevel-1))) + addPower = TRUE; + // otherwise don't show the button. + return addPower; + } + + return TRUE; +} + +void LearnPowers(int nClass, object oPC=OBJECT_SELF) +{ + // add normal powers + json powerList = GetCurrentPowerList(oPC); + int totalPowers = JsonGetLength(powerList); + int i; + for (i = 0; i < totalPowers; i++) + { + int nSpellbookID = JsonGetInt(JsonArrayGet(powerList, i)); + // get the expanded knowledge list we are adding to if any + int expKnow = GetExpKnowledgePowerListRequired(nClass, nSpellbookID, oPC); + AddPowerKnown(oPC, nClass, nSpellbookID, TRUE, GetHitDice(oPC), expKnow); + } +} + +int GetExpKnowledgePowerListRequired(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + + int i; + // expanded knowledge is -1, epic epxanded knowledge is -2 + for (i = -1; i >= -2; i--) + { + int spellId = StringToInt(Get2DACache(sFile, "SpellID", spellbookId)); + if (IsSpellInExpandedChoices(nClass, i, spellId, oPC)) + return i; + } + + return 0; +} + +int GetMaxPowerLevelForClass(int nClass, object oPC=OBJECT_SELF) +{ + string sFile = GetAMSKnownFileName(nClass); + int nLevel = GetManifesterLevel(oPC, nClass, TRUE); + // index is level - 1 since it starts at 0. + int maxLevel = StringToInt(Get2DACache(sFile, "MaxPowerLevel", nLevel-1)); + return maxLevel; +} + +int GetRemainingPowerChoices(int nClass, int chosenCircle, object oPC=OBJECT_SELF, int extra=TRUE) +{ + int remaining = 0; + + int maxLevel = GetMaxPowerLevelForClass(nClass, oPC); + if (chosenCircle > maxLevel) + return 0; + + json choices = GetCurrentPowerList(oPC); + int totalChoices = JsonGetLength(choices); + int allowedChoices = GetMaxPowerCount(oPC, nClass); + int alreadyChosen = GetPowerCount(oPC, nClass); + string sFile = GetClassSpellbookFile(nClass); + + int i = 0; + for (i = 0; i < totalChoices; i++) + { + int spellbookId = JsonGetInt(JsonArrayGet(choices, i)); + int spellId = StringToInt(Get2DACache(sFile, "SpellID", spellbookId)); + //if the power is a expanded knowledge choice, don't count it + if (!IsSpellInExpandedChoices(nClass, POWER_LIST_EXP_KNOWLEDGE, spellId, oPC) + && !IsSpellInExpandedChoices(nClass, POWER_LIST_EPIC_EXP_KNOWLEDGE, spellId, oPC)) + remaining++; + } + remaining = (allowedChoices - remaining - alreadyChosen); + + // if this is true we count expanded knowledge choices + if (extra) + { + if (GetHasFeat(FEAT_EXPANDED_KNOWLEDGE_1, oPC) && (chosenCircle <= (maxLevel-1))) + { + int totalExp = GetMaxPowerCount(oPC, POWER_LIST_EXP_KNOWLEDGE); + json expChoices = GetExpandedChoicesList(nClass, oPC); + int choicesCount = JsonGetLength(JsonObjectKeys(expChoices)); + remaining += (totalExp - choicesCount); + } + if (GetHasFeat(FEAT_EPIC_EXPANDED_KNOWLEDGE_1, oPC)) + { + int totalExp = GetMaxPowerCount(oPC, POWER_LIST_EPIC_EXP_KNOWLEDGE); + json expChoices = GetEpicExpandedChoicesList(nClass, oPC); + int choicesCount = JsonGetLength(JsonObjectKeys(expChoices)); + remaining += (totalExp - choicesCount); + } + } + + return remaining; +} + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Initiators /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +json GetDisciplineInfoObject(int nClass, object oPC=OBJECT_SELF) +{ + json disciplineInfo = GetLocalJson(oPC, NUI_LEVEL_UP_DISCIPLINE_INFO_VAR + IntToString(nClass)); + if (disciplineInfo == JsonNull()) + disciplineInfo = JsonObject(); + else + return disciplineInfo; + + int chosenClass = GetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CLASS_VAR); + string sFile = GetClassSpellbookFile(nClass); + + //if this is not the chosen class then we do not have a chosen spell list + // need to go through the class's 2da and check if you know the spell or not. + if (nClass != chosenClass) + { + int totalSpells = Get2DARowCount(sFile); + + int i; + for (i = 0; i < totalSpells; i++) + { + int featId = StringToInt(Get2DACache(sFile, "FeatID", i)); + if (featId && GetHasFeat(featId, oPC, TRUE)) + disciplineInfo = AddSpellDisciplineInfo(sFile, i, disciplineInfo); + } + } + else + { + json chosenMans = GetChosenSpellListObject(nClass, oPC); + + json circles = JsonObjectKeys(chosenMans); + int totalCircles = JsonGetLength(circles); + + int i; + for (i = 0; i < totalCircles; i++) + { + string currentCircle = JsonGetString(JsonArrayGet(circles, i)); + json currentList = JsonObjectGet(chosenMans, currentCircle); + int totalSpells = JsonGetLength(currentList); + + int y; + for (y = 0; y < totalSpells; y++) + { + int spellbookId = JsonGetInt(JsonArrayGet(currentList, y)); + disciplineInfo = AddSpellDisciplineInfo(sFile, spellbookId, disciplineInfo); + } + } + } + + SetLocalJson(oPC, NUI_LEVEL_UP_DISCIPLINE_INFO_VAR + IntToString(nClass), disciplineInfo); + return disciplineInfo; +} + +int IsRequiredForOtherManeuvers(int nClass, int prereq, string discipline, object oPC=OBJECT_SELF) +{ + json discInfo = GetDisciplineInfoObject(nClass, oPC); + + int total = 0; + + // loop through each prereq level and add up it's totals (ie how many maneuevrs + // do we know with 0,1,2...,n prereqs. + int i; + for (i = 0; i <= prereq; i++) + { + + json currDisc = JsonObjectGet(discInfo, discipline); + string discKey = ("Prereq_" + IntToString(i)); + int currentDiscPrereq = JsonGetInt(JsonObjectGet(currDisc, discKey)); + total += currentDiscPrereq; + } + + // then from above the given prereq check if we have any prereq maneuevers taken + for (i = (prereq+1); i < NUI_LEVEL_UP_MANEUVER_PREREQ_LIMIT; i++) + { + json currDisc = JsonObjectGet(discInfo, discipline); + string discKey = ("Prereq_" + IntToString(i)); + json discPrereq = JsonObjectGet(currDisc, discKey); + if (discPrereq != JsonNull()) + { + // if we do take the total and subtract by one, if it is lower than + // than the prereq needed, it is required + if (total - 1 < i) + return TRUE; + + // otherwise add how many we have and move up and keep trying. + int currentDiscPrereq = JsonGetInt(discPrereq); + total += currentDiscPrereq; + } + } + + return FALSE; +} + +int HasPreRequisitesForManeuver(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + int prereqs = StringToInt(Get2DACache(sFile, "Prereqs", spellbookId)); + if (!prereqs) + return TRUE; + string discipline = Get2DACache(sFile, "Discipline", spellbookId); + json discInfo = GetDisciplineInfoObject(nClass, oPC); + json chosenDisc = JsonObjectGet(discInfo, discipline); + if (chosenDisc != JsonNull()) + { + int nManCount = (JsonGetInt(JsonObjectGet(chosenDisc, IntToString(MANEUVER_TYPE_MANEUVER))) + + JsonGetInt(JsonObjectGet(chosenDisc, IntToString(MANEUVER_TYPE_STANCE)))); + if (nManCount >= prereqs) + return TRUE; + } + + return FALSE; +} + +int GetMaxInitiatorCircle(int nClass, object oPC=OBJECT_SELF) +{ + int initiatorLevel = GetInitiatorLevel(oPC, nClass); + // initiators learn by ceiling(classLevel) + int highestCircle = (initiatorLevel + 1) / 2; + if (highestCircle > 9) + return 9; + return highestCircle; +} + +int GetRemainingManeuverChoices(int nClass, object oPC=OBJECT_SELF) +{ + json discInfo = GetDisciplineInfoObject(nClass, oPC); + + json jManAmount = JsonObjectGet(discInfo, NUI_LEVEL_UP_MANEUVER_TOTAL); + int nManAmount = 0; + if (jManAmount != JsonNull()) + nManAmount = JsonGetInt(jManAmount); + + int maxAmount = GetMaxManeuverCount(oPC, nClass, MANEUVER_TYPE_MANEUVER); + + return maxAmount - nManAmount; +} + +int GetRemainingStanceChoices(int nClass, object oPC=OBJECT_SELF) +{ + json discInfo = GetDisciplineInfoObject(nClass, oPC); + + json jStanceAmount = JsonObjectGet(discInfo, NUI_LEVEL_UP_STANCE_TOTAL); + int nStanceAmount = 0; + if (jStanceAmount != JsonNull()) + nStanceAmount = JsonGetInt(jStanceAmount); + + int maxAmount = GetMaxManeuverCount(oPC, nClass, MANEUVER_TYPE_STANCE); + + return maxAmount - nStanceAmount; +} + +int IsAllowedDiscipline(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + // logic carried over from private function in discipline inc functions + // uses bitwise matching to tell if the discipline is allowed or not + string sFile = GetClassSpellbookFile(nClass); + int discipline = StringToInt(Get2DACache(sFile, "Discipline", spellbookId)); + + int nOverride = GetPersistantLocalInt(oPC, "AllowedDisciplines"); + if(nOverride == 0) + { + switch(nClass) + { + case CLASS_TYPE_CRUSADER: nOverride = 322; break;//DISCIPLINE_DEVOTED_SPIRIT + DISCIPLINE_STONE_DRAGON + DISCIPLINE_WHITE_RAVEN + case CLASS_TYPE_SWORDSAGE: nOverride = 245; break;//DISCIPLINE_DESERT_WIND + DISCIPLINE_DIAMOND_MIND + DISCIPLINE_SETTING_SUN + DISCIPLINE_SHADOW_HAND + DISCIPLINE_STONE_DRAGON + DISCIPLINE_TIGER_CLAW + case CLASS_TYPE_WARBLADE: nOverride = 460; break;//DISCIPLINE_DIAMOND_MIND + DISCIPLINE_IRON_HEART + DISCIPLINE_STONE_DRAGON + DISCIPLINE_TIGER_CLAW + DISCIPLINE_WHITE_RAVEN + } + } + return nOverride & discipline; +} + +int IsRequiredForToBPRCClass(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + int currentClassPos = 1; + // loop through all the classes and look for a PRC + while (currentClassPos) + { + int currentClass = GetClassByPosition(currentClassPos, oPC); + // if we reached a non existant class, we reached the end. + if (currentClass != CLASS_TYPE_INVALID) + { + string sFile = GetClassSpellbookFile(nClass); + int discipline = StringToInt(Get2DACache(sFile, "Discipline", spellbookId)); + + // check if the class is a ToB PRC Class and if the current spell's + // discipline is used for it. + int isUsed = FALSE; + if (currentClass == CLASS_TYPE_DEEPSTONE_SENTINEL + && (discipline == DISCIPLINE_STONE_DRAGON)) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_BLOODCLAW_MASTER + && (discipline == DISCIPLINE_TIGER_CLAW)) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_RUBY_VINDICATOR + && (discipline == DISCIPLINE_DEVOTED_SPIRIT)) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_JADE_PHOENIX_MAGE) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_MASTER_OF_NINE) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_ETERNAL_BLADE + && (discipline == DISCIPLINE_DEVOTED_SPIRIT + || discipline == DISCIPLINE_DIAMOND_MIND)) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_SHADOW_SUN_NINJA + && (discipline == DISCIPLINE_SETTING_SUN + || discipline == DISCIPLINE_SHADOW_HAND)) + isUsed = TRUE; + + // if any of the above was true than we need to check if this spell + // is required for a PRC + if (isUsed) + { + // get the discipline info for all BladeMagic classes if we have them. + json discInfo = GetDisciplineInfoObject(nClass, oPC); + json classDisc2Info = JsonObject(); + json classDisc3Info = JsonObject(); + if (nClass == CLASS_TYPE_SWORDSAGE) + { + if (GetLevelByClass(CLASS_TYPE_WARBLADE, oPC)) + classDisc2Info = GetDisciplineInfoObject(CLASS_TYPE_WARBLADE, oPC); + if (GetLevelByClass(CLASS_TYPE_CRUSADER, oPC)) + classDisc3Info = GetDisciplineInfoObject(CLASS_TYPE_CRUSADER, oPC); + } + if (nClass == CLASS_TYPE_CRUSADER) + { + if (GetLevelByClass(CLASS_TYPE_WARBLADE, oPC)) + classDisc2Info = GetDisciplineInfoObject(CLASS_TYPE_WARBLADE, oPC); + if (GetLevelByClass(CLASS_TYPE_SWORDSAGE, oPC)) + classDisc3Info = GetDisciplineInfoObject(CLASS_TYPE_SWORDSAGE, oPC); + } + if (nClass == CLASS_TYPE_WARBLADE) + { + if (GetLevelByClass(CLASS_TYPE_CRUSADER, oPC)) + classDisc2Info = GetDisciplineInfoObject(CLASS_TYPE_CRUSADER, oPC); + if (GetLevelByClass(CLASS_TYPE_SWORDSAGE, oPC)) + classDisc3Info = GetDisciplineInfoObject(CLASS_TYPE_SWORDSAGE, oPC); + } + + // Time to begin checking the PRCs + // this should follow the same logic as here + // https://gitea.raptio.us/Jaysyn/PRC8/src/commit/797442d3da7c9c8e1fcf585b97e2ff1cbe56045b/nwn/nwnprc/trunk/scripts/prc_prereq.nss#L991 + + // Check Deepstone Sentinel + if (currentClass == CLASS_TYPE_DEEPSTONE_SENTINEL) + { + // we need to look for 2 Stone Dragon Maneuvers and 1 Stone Dragon + // Stance. So add up the other MagicBlade classes and see if it is satisfied. + int stoneDMan, stoneDStance = 0; + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stoneDMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + stoneDStance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + if (stoneDMan >= 2 && stoneDStance >= 1) + return FALSE; + } + + currentDisc = JsonObjectGet(classDisc3Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stoneDMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + stoneDStance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + if (stoneDMan >= 2 && stoneDStance >= 1) + return FALSE; + } + // if it still isn't satisfied than the current class is required + // for it to exist. Check to see if it is safe to remove the maneuever + currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stoneDMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + stoneDStance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + int type = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + //if the current maneuver is a stance, check to see if it is safe to remove + if (type == MANEUVER_TYPE_STANCE) + { + if (stoneDStance - 1 >= 1) + return FALSE; + } + else + { + // if it is not a stance we can just check the maneuevers in general + if (stoneDMan - 1 >= 2) + return FALSE; + } + + // this maneuver is required and should not be removed. + return TRUE; + } + } + + // Check Bloodclaw Master + if (currentClass == CLASS_TYPE_BLOODCLAW_MASTER) + { + // bloodclaw needs 3 Tiger Claw maneuevers + int tigerCMan = 0; + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + if (tigerCMan >= 3) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + if (tigerCMan >= 3) + return FALSE; + } + currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + if (tigerCMan-1 >= 3) + return FALSE; + return TRUE; + } + } + + if (currentClass == CLASS_TYPE_RUBY_VINDICATOR) + { + // Ruby Vindicator needs 1 stance and 1 maneuever from Devoted Spirit + int stance = 0; + int maneuver = 0; + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + if (stance >= 1 && maneuver >= 1) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + if (stance >= 1 && maneuver >= 1) + return FALSE; + } + currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + int type = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + if (type == MANEUVER_TYPE_STANCE) + { + if (stance - 1 >= 1) + return FALSE; + return TRUE; + } + if (maneuver - 1 >= 1) + return FALSE; + return TRUE; + } + } + + if (currentClass == CLASS_TYPE_JADE_PHOENIX_MAGE) + { + // Jade Phoenix needs 1 stance and 2 maneuvers of any type + int stance = 0; + int maneuver = 0; + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + if (stance >= 1 && maneuver >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + if (stance >= 1 && maneuver >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + int type = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + if (type == MANEUVER_TYPE_STANCE) + { + if ((stance - 1 >= 1) && (maneuver -1 >= 2)) + return FALSE; + return TRUE; + } + if (maneuver - 1 >= 2) + return FALSE; + return TRUE; + } + } + + if (currentClass == CLASS_TYPE_MASTER_OF_NINE) + { + // master of nine needs 1 maneuever from 6 different disciplines + + int totalDiscCount = 0; + int currentClassAndDiscUsed = 0; + int i; + // loop through each possible discipline + for (i = 0; i <= 256; i++) + { + int found = 0; + // only disciplines that exist are stored, and only those + // that are used are stored, so we can loop through and + // find what disciplines we do or don't know. + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(i)); + if (currentDisc != JsonNull()) + found = 1; + + if (!found) + { + json currentDisc = JsonObjectGet(classDisc3Info, IntToString(i)); + if (currentDisc != JsonNull()) + found = 1; + } + + if (!found) + { + json currentDisc = JsonObjectGet(discInfo, IntToString(i)); + if (currentDisc != JsonNull()) + { + if (i == discipline) + currentClassAndDiscUsed = 1; + found = 1; + } + } + + totalDiscCount += found; + } + // if we have more maneuevers than 6, it is not required + if (totalDiscCount > 6) + return FALSE; + // however if we have 6 and this discipline was grabbed we need to make sure it is safe to remove + if (currentClassAndDiscUsed) + { + // if we were to remove this discipline and it is 5 or less total disciplines we have now + // it is important + if (totalDiscCount - 1 >= 6) + return FALSE; + json currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + int stance = JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + int maneuver = JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + // if we were to remove this discipline and are left with no more than + // this was important and it can't be removed + if ((stance + maneuver - 1) >= 1) + return FALSE; + return TRUE; + } + return FALSE; + } + + if (currentClass == CLASS_TYPE_ETERNAL_BLADE) + { + //Eternal blade 2 Devoted Spirits OR 2 Diamond Mind + int nTotal = 0; + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(DISCIPLINE_DEVOTED_SPIRIT)); + if (currentDisc != JsonNull()) + { + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nTotal >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc2Info, IntToString(DISCIPLINE_DIAMOND_MIND)); + if (currentDisc != JsonNull()) + { + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nTotal >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(DISCIPLINE_DEVOTED_SPIRIT)); + if (currentDisc != JsonNull()) + { + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nTotal >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(DISCIPLINE_DIAMOND_MIND)); + if (currentDisc != JsonNull()) + { + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nTotal >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + if ((nTotal - 1) >= 2) + return FALSE; + return TRUE; + } + } + + if (currentClass == CLASS_TYPE_SHADOW_SUN_NINJA) + { + // Shadow Sun Ninja needs 1 lvl2 Setting Sun OR Shadow Hand maneuever + // 1 Setting Sun maneuver AND 1 Shadow Hand maneuver + int nLvl2 = 0; + int shadowHTotal; + int settingSTotal; + + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(DISCIPLINE_SHADOW_HAND)); + if (currentDisc != JsonNull()) + { + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nLvl2 && shadowHTotal && settingSTotal && (shadowHTotal >= 2 || settingSTotal >= 2)) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc2Info, IntToString(DISCIPLINE_SETTING_SUN)); + if (currentDisc != JsonNull()) + { + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nLvl2 && shadowHTotal && settingSTotal && (shadowHTotal >= 2 || settingSTotal >= 2)) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(DISCIPLINE_SHADOW_HAND)); + if (currentDisc != JsonNull()) + { + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nLvl2 && shadowHTotal && settingSTotal && (shadowHTotal >= 2 || settingSTotal >= 2)) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc2Info, IntToString(DISCIPLINE_SETTING_SUN)); + if (currentDisc != JsonNull()) + { + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nLvl2 && shadowHTotal && settingSTotal && (shadowHTotal >= 2 || settingSTotal >= 2)) + return FALSE; + } + currentDisc = JsonObjectGet(discInfo, IntToString(DISCIPLINE_SHADOW_HAND)); + if (currentDisc != JsonNull()) + { + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + } + currentDisc = JsonObjectGet(discInfo, IntToString(DISCIPLINE_SETTING_SUN)); + if (currentDisc != JsonNull()) + { + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + } + int level = StringToInt(Get2DACache(sFile, "Level", spellbookId)); + if (level == 2) + nLvl2 -= 1; + if (discipline == DISCIPLINE_SHADOW_HAND) + shadowHTotal -= 1; + else + settingSTotal -= 1; + + return !(nLvl2 && shadowHTotal && settingSTotal && (shadowHTotal >= 2 || settingSTotal >= 2)); + } + } + + currentClassPos += 1; + } + else + currentClassPos = 0; + } + + return FALSE; +} + +json AddSpellDisciplineInfo(string sFile, int spellbookId, json classDisc) +{ + json classDiscCopy = classDisc; + int discipline = StringToInt(Get2DACache(sFile, "Discipline", spellbookId)); + int type = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + int level = StringToInt(Get2DACache(sFile, "Level", spellbookId)); + int prereq = StringToInt(Get2DACache(sFile, "Prereqs", spellbookId)); + + json jDisc = JsonObjectGet(classDisc, IntToString(discipline)); + if (jDisc == JsonNull()) + jDisc = JsonObject(); + + string levelKey = "Level" + IntToString(level) + "_" + IntToString(type); + int nTypeTotal = (JsonGetInt(JsonObjectGet(jDisc, levelKey)) + 1); + jDisc = JsonObjectSet(jDisc, levelKey, JsonInt(nTypeTotal)); + + nTypeTotal = (JsonGetInt(JsonObjectGet(jDisc, IntToString(type))) + 1); + jDisc = JsonObjectSet(jDisc, IntToString(type), JsonInt(nTypeTotal)); + + if (type != MANEUVER_TYPE_MANEUVER + && type != MANEUVER_TYPE_STANCE) + { + levelKey = "Level" + IntToString(level) + "_" + IntToString(MANEUVER_TYPE_MANEUVER); + nTypeTotal = (JsonGetInt(JsonObjectGet(jDisc, levelKey)) + 1); + jDisc = JsonObjectSet(jDisc, levelKey, JsonInt(nTypeTotal)); + + nTypeTotal = (JsonGetInt(JsonObjectGet(jDisc, IntToString(MANEUVER_TYPE_MANEUVER))) + 1); + jDisc = JsonObjectSet(jDisc, IntToString(MANEUVER_TYPE_MANEUVER), JsonInt(nTypeTotal)); + } + + string prereqKey = "Prereq_" + IntToString(prereq); + int nPrereqTotal = (JsonGetInt(JsonObjectGet(jDisc, prereqKey)) + 1); + jDisc = JsonObjectSet(jDisc, prereqKey, JsonInt(nPrereqTotal)); + + if (type == MANEUVER_TYPE_STANCE) + { + nTypeTotal = (JsonGetInt(JsonObjectGet(classDisc, NUI_LEVEL_UP_STANCE_TOTAL)) + 1); + classDiscCopy = JsonObjectSet(classDiscCopy, NUI_LEVEL_UP_STANCE_TOTAL, JsonInt(nTypeTotal)); + } + else + { + nTypeTotal = (JsonGetInt(JsonObjectGet(classDisc, NUI_LEVEL_UP_MANEUVER_TOTAL)) + 1); + classDiscCopy = JsonObjectSet(classDiscCopy, NUI_LEVEL_UP_MANEUVER_TOTAL, JsonInt(nTypeTotal)); + } + + return JsonObjectSet(classDiscCopy, IntToString(discipline), jDisc); +} + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Invokers /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +json GetInvokerKnownListObject(int nClass, object oPC=OBJECT_SELF) +{ + json knownObject = GetLocalJson(oPC, NUI_LEVEL_UP_KNOWN_INVOCATIONS_CACHE_VAR + IntToString(nClass)); + if (knownObject == JsonNull()) + knownObject = JsonObject(); + else + return knownObject; + + string sFile = GetAMSKnownFileName(nClass); + int totalRows = Get2DARowCount(sFile); + int maxInvocLevel = StringToInt(Get2DACache(sFile, "MaxInvocationLevel", totalRows-1)); + json previousInvocList = JsonObject(); + + int i; + for (i = 1; i <= maxInvocLevel; i++) + { + previousInvocList = JsonObjectSet(previousInvocList, IntToString(i), JsonInt(0)); + } + + for (i = 0; i < totalRows; i++) + { + int maxInvocation = StringToInt(Get2DACache(sFile, "MaxInvocationLevel", i)); + int invocationKnown = StringToInt(Get2DACache(sFile, "InvocationKnown", i)); + json invocList = previousInvocList; + + int previousInvocTotal = 0; + if (i > 0) + previousInvocTotal = StringToInt(Get2DACache(sFile, "InvocationKnown", i-1)); + int previousInvocAmount = JsonGetInt(JsonObjectGet(previousInvocList, IntToString(maxInvocation))); + int currentInvocationAmount = (invocationKnown - previousInvocTotal + previousInvocAmount); + + invocList = JsonObjectSet(invocList, IntToString(maxInvocation), JsonInt(currentInvocationAmount)); + knownObject = JsonObjectSet(knownObject, IntToString(i+1), invocList); + previousInvocList = invocList; + } + + SetLocalJson(oPC, NUI_LEVEL_UP_KNOWN_INVOCATIONS_CACHE_VAR + IntToString(nClass), knownObject); + if (DEBUG) DoDebug("Printing json representation of allowed invocations for class " + IntToString(nClass)); + if (DEBUG) DoDebug(JsonDump(knownObject, 2)); + return knownObject; +} + +int GetRemainingInvocationChoices(int nClass, int chosenCircle, object oPC=OBJECT_SELF, int extra=TRUE) +{ + if (DEBUG) DoDebug ("Getting remaining invocation choices at " + IntToString(chosenCircle) + " circle"); + int remaining = 0; + int nLevel = GetInvokerLevel(oPC, nClass); + if (nClass == CLASS_TYPE_DRAGON_SHAMAN) nLevel = GetLevelByClass(nClass, oPC); + if (DEBUG) DoDebug("Invoker level is " + IntToString(nLevel)); + + json knownObject = GetInvokerKnownListObject(nClass, oPC); + json chosenInv = GetChosenSpellListObject(nClass, oPC); + json currentLevelKnown = JsonObjectGet(knownObject, IntToString(nLevel)); + + int totalCircles = JsonGetLength(JsonObjectKeys(currentLevelKnown)); + + // logic goes we are given a set amount of invocations at each circle. We can + // take from a circle above us, but not below us. So we need to make sure + // we have a legal amount of choices + int i; + for (i = 1; i <= totalCircles; i++) + { + int currentChosen = 0; + json chosenSpells = JsonObjectGet(chosenInv, IntToString(i)); + if (chosenSpells != JsonNull()) + { + int totalChosen = JsonGetLength(chosenSpells); + int j; + for (j = 0; j < totalChosen; j++) + { + int spellbookId = JsonGetInt(JsonArrayGet(chosenSpells, j)); + // only count non extra invocation choices + if (!IsExtraChoiceInvocation(nClass, spellbookId, oPC)) + currentChosen += 1; + } + } + if (DEBUG) DoDebug(IntToString(currentChosen) + " incantations chosen at " + IntToString(chosenCircle) + " circle"); + + int allowedAtCircle = JsonGetInt(JsonObjectGet(currentLevelKnown, IntToString(i))); + if (DEBUG) DoDebug(IntToString(allowedAtCircle) + " incantations allowed at " + IntToString(chosenCircle) + " circle"); + + remaining = (allowedAtCircle - currentChosen + remaining); + // if the circle is below the chosen circle and we have a positive remaining, + // we set it to 0 because we cannot use lower circle spells on higher circle. + // however if thge value is negative then we carry it over because we + // have a deficit and need to account for it by using the spells of the + // next circle. + if (i < chosenCircle && remaining > 0) + remaining = 0; + } + + + // count extra and epic invocation choices + if (extra) + { + string sFile = GetAMSKnownFileName(nClass); + int maxCircle = StringToInt(Get2DACache(sFile, "MaxInvocationLevel", nLevel-1)); + + if (GetHasFeat(FEAT_EXTRA_INVOCATION_I, oPC) && (chosenCircle <= (maxCircle-1))) + { + int totalExp = GetMaxInvocationCount(oPC, INVOCATION_LIST_EXTRA); + json expChoices = GetExpandedChoicesList(nClass, oPC); + int choicesCount = JsonGetLength(JsonObjectKeys(expChoices)); + remaining += (totalExp - choicesCount); + } + if (GetHasFeat(FEAT_EPIC_EXTRA_INVOCATION_I, oPC)) + { + int totalExp = GetMaxInvocationCount(oPC, INVOCATION_LIST_EXTRA_EPIC); + json expChoices = GetEpicExpandedChoicesList(nClass, oPC); + int choicesCount = JsonGetLength(JsonObjectKeys(expChoices)); + remaining += (totalExp - choicesCount); + } + } + + return remaining; +} + +int IsExtraChoiceInvocation(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + json extraChoices = GetExpandedChoicesList(nClass, oPC); + json chosenSpell = JsonObjectGet(extraChoices, spellId); + if (chosenSpell != JsonNull()) + return TRUE; + + extraChoices = GetEpicExpandedChoicesList(nClass, oPC); + chosenSpell = JsonObjectGet(extraChoices, spellId); + if (chosenSpell != JsonNull()) + return TRUE; + + return FALSE; +} + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Truenamer /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +int GetRemainingTruenameChoices(int nClass, int nType, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + json circles = JsonObjectKeys(chosenSpells); + int totalCircles = JsonGetLength(circles); + + int remainingChoices = 0; + + int i; + for (i = 0; i < totalCircles; i++) + { + json spellList = JsonObjectGet(chosenSpells, JsonGetString(JsonArrayGet(circles, i))); + if (spellList != JsonNull()) + { + int totalChoices = JsonGetLength(spellList); + + int j; + for (j = 0; j < totalChoices; j++) + { + int spellbookId = JsonGetInt(JsonArrayGet(spellList, j)); + int lexicon = StringToInt(Get2DACache(sFile, "Lexicon", spellbookId)); + // -1 means count all lexicons + if (nType == -1 || lexicon == nType) + remainingChoices += 1; + } + } + } + + int maxChoices; + // if -1 we count all lexicons to get total remaining + if (nType == -1) + maxChoices = (GetMaxUtteranceCount(oPC, nClass, LEXICON_CRAFTED_TOOL) + + GetMaxUtteranceCount(oPC, nClass, LEXICON_EVOLVING_MIND) + + GetMaxUtteranceCount(oPC, nClass, LEXICON_PERFECTED_MAP)); + else + maxChoices = GetMaxUtteranceCount(oPC, nClass, nType); + return (maxChoices - remainingChoices); +} + +int GetLexiconCircleKnownAtLevel(int nLevel, int nType) +{ + + string sFile = "cls_true_maxlvl"; + + string columnName; + if (nType == LEXICON_EVOLVING_MIND) + columnName = "EvolvingMind"; + else if (nType == LEXICON_CRAFTED_TOOL) + columnName = "CraftedTool"; + else + columnName = "PerfectedMap"; + + return StringToInt(Get2DACache(sFile, columnName, nLevel-1)); +} + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Archivist /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +json GetArchivistNewSpellsList(object oPC=OBJECT_SELF) +{ + json retValue = GetLocalJson(oPC, NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR); + if (retValue == JsonNull()) + retValue = JsonArray(); + else + return retValue; + + SetLocalJson(oPC, NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR, retValue); + return retValue; +} + +//:: void main(){} \ No newline at end of file diff --git a/src/include/prc_nui_sc_inc.nss b/src/include/prc_nui_sb_inc.nss similarity index 76% rename from src/include/prc_nui_sc_inc.nss rename to src/include/prc_nui_sb_inc.nss index a1a768e..7148413 100644 --- a/src/include/prc_nui_sc_inc.nss +++ b/src/include/prc_nui_sb_inc.nss @@ -10,10 +10,8 @@ //:: Created By: Rakiov //:: Created On: 24.05.2005 //::////////////////////////////////////////////// -#include "inc_newspellbook" -#include "psi_inc_psifunc" -#include "inc_lookups" -#include "prc_nui_consts" + +#include "prc_nui_com_inc" // // GetSpellListForCircle @@ -43,69 +41,6 @@ json GetSpellListForCircle(object oPlayer, int nClass, int circle); // json GetSupportedNUISpellbookClasses(object oPlayer); -// -// GetCurrentSpellLevel -// Gets the current spell level the class can achieve at the current -// caster level (ranging from 0-9) -// -// Arguments: -// nClass:int the ClassID -// nLevel:int the caster level -// -// Returns: -// int the circle the class can achieve currently -// -int GetCurrentSpellLevel(int nClass, int nLevel); - -// -// GetMaxSpellLevel -// Gets the highest possible circle the class can achieve (from 0-9) -// -// Arguments: -// nClass:int the ClassID -// -// Returns: -// int the highest circle that can be achieved -// -int GetMaxSpellLevel(int nClass); - -// -// GetMinSpellLevel -// Gets the lowest possible circle the class can achieve (from 0-9) -// -// Arguments: -// nClass:int the ClassID -// -// Returns: -// int the lowest circle that can be achieved -// -int GetMinSpellLevel(int nClass); - -// -// GetHighestLevelPossibleInClass -// Given a class Id this will determine what the max level of a class can be -// achieved -// -// Arguments: -// nClass:int the ClassID -// -// Returns: -// int the highest possible level the class can achieve -// -int GetHighestLevelPossibleInClass(int nClass); - -// -// GetClassSpellbookFile -// Gets the class 2da spellbook/ability for the given class Id -// -// Arguments: -// nClass:int the classID -// -// Returns: -// string the 2da file name for the spell/abilities of the ClassID -// -string GetClassSpellbookFile(int nClass); - // // IsSpellKnown // Returns whether the player with the given class, spell file, and spellbook id @@ -234,23 +169,6 @@ json GetMetaMysteryFeatList(); // int GetTrueClassIfRHD(object oPlayer, int nClass); -// -// GetBinderSpellToFeatDictionary -// Sets up the Binder Spell Dictionary that is used to match a binder's vestige -// to their feat. This is constructed based off the binder's known location of -// their feat and spell ranges in the base 2das respectivly. After constructing -// this it will be saved to the player locally as a cached result since we do -// not need to call this again. -// -// Argument: -// oPlayer:object the player -// -// Returns: -// json:Dictionary a dictionary of mapping between the SpellID -// and the FeatID of a vestige ability -// -json GetBinderSpellToFeatDictionary(object oPlayer=OBJECT_SELF); - // // ShouldAddSpell // Given a spellId and a class, determines if the spell should be added to the @@ -318,6 +236,18 @@ json GetInvokerEssenceSpellList(int nClass, object oPlayer=OBJECT_SELF); // int JsonArrayContainsInt(json list, int item); +// +// IsSpellbookNUIOpen +// Checks to see if the Spellbook NUI is open on a given player. +// +// Arguments: +// oPC:object the player +// +// Returns: +// int:Boolean TRUE if window is open, FALSE otherwise +// +int IsSpellbookNUIOpen(object oPC); + json GetSpellListForCircle(object oPlayer, int nClass, int circle) { json retValue = JsonArray(); @@ -397,86 +327,6 @@ int ShouldAddSpell(int nClass, int spellId, object oPlayer=OBJECT_SELF) return TRUE; } -json GetBinderSpellToFeatDictionary(object oPlayer=OBJECT_SELF) -{ - // a dictionary of - json binderDict = GetLocalJson(oPlayer, NUI_SPELLBOOK_BINDER_DICTIONARY_CACHE_VAR); - // if this hasn't been created, create it now. - if (binderDict == JsonNull()) - binderDict = JsonObject(); - else - return binderDict; - - // the starting row for binder spells - int spellIndex = 19070; - // the starting row for binder feats - int featIndex = 9030; - //the end of the binder spells/feats - while (spellIndex <= 19156 && featIndex <= 9104) - { - // get the SpellID tied to the feat - int spellID = StringToInt(Get2DACache("feat", "SPELLID", featIndex)); - // if the spellID matches the current index, then this is the spell - // attached to the feat - if (spellID == spellIndex) - { - binderDict = JsonObjectSet(binderDict, IntToString(spellID), JsonInt(featIndex)); - - // move to next spell/feat - featIndex++; - spellIndex++; - } - // else we have reached a subdial spell - else - { - // loop through until we reach back at spellID - while (spellIndex < spellID) - { - int masterSpell = StringToInt(Get2DACache("spells", "Master", spellIndex)); - - // add the sub radial to the dict, tied to the master's FeatID - int featId = JsonGetInt(JsonObjectGet(binderDict, IntToString(masterSpell))); - binderDict = JsonObjectSet(binderDict, IntToString(spellIndex), JsonInt(featId)); - - spellIndex++; - } - - - // some feats overlap the same FeatID, can cause this to get stuck. - // if it happens then move on - if (spellIndex > spellID) - featIndex++; - } - } - - // cache the result - SetLocalJson(oPlayer, NUI_SPELLBOOK_BINDER_DICTIONARY_CACHE_VAR, binderDict); - return binderDict; -} - -string GetClassSpellbookFile(int nClass) -{ - string sFile; - // Spontaneous casters use a specific file name structure - if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS - || nClass == CLASS_TYPE_ARCHIVIST) - { - sFile = GetFileForClass(nClass); - } - // everyone else uses this structure - else - { - sFile = GetAMSDefinitionFileName(nClass); - - if (nClass == CLASS_TYPE_BINDER) - { - sFile = "vestiges"; - } - } - - return sFile; -} - json GetSupportedNUISpellbookClasses(object oPlayer) { json retValue = JsonArray(); @@ -526,167 +376,6 @@ int IsSpellKnown(object oPlayer, int nClass, int spellId) return FALSE; } -int GetCurrentSpellLevel(int nClass, int nLevel) -{ - int currentLevel = nLevel; - - // ToB doesn't have a concept of spell levels, but still match up to it - if(nClass == CLASS_TYPE_WARBLADE - || nClass == CLASS_TYPE_SWORDSAGE - || nClass == CLASS_TYPE_CRUSADER - || nClass == CLASS_TYPE_SHADOWCASTER) - { - return 9; - } - - - // Binders don't really have a concept of spell level - if (nClass == CLASS_TYPE_BINDER - || nClass == CLASS_TYPE_DRAGON_SHAMAN) // they can only reach 1st circle - return 1; - - //Shadowsmith has no concept of spell levels - if (nClass == CLASS_TYPE_SHADOWSMITH) - return 2; - - if (nClass == CLASS_TYPE_WARLOCK - || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT) - return 4; - - // Spont casters have their own function - if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS - || nClass == CLASS_TYPE_ARCHIVIST) - { - - int maxLevel = GetMaxSpellLevelForCasterLevel(nClass, currentLevel); - return maxLevel; - } - else - { - // everyone else uses this - string spellLevel2da = GetAMSKnownFileName(nClass); - - currentLevel = nLevel - 1; // Level is 1 off of the row in the 2da - - if (nClass == CLASS_TYPE_FIST_OF_ZUOKEN - || nClass == CLASS_TYPE_PSION - || nClass == CLASS_TYPE_PSYWAR - || nClass == CLASS_TYPE_WILDER - || nClass == CLASS_TYPE_PSYCHIC_ROGUE - || nClass == CLASS_TYPE_WARMIND) - currentLevel = GetManifesterLevel(OBJECT_SELF, nClass, TRUE) - 1; - - int totalLevel = Get2DARowCount(spellLevel2da); - - // in case we somehow go over bounds just don't :) - if (currentLevel >= totalLevel) - currentLevel = totalLevel - 1; - - //Psionics have MaxPowerLevel as their column name - string columnName = "MaxPowerLevel"; - - //Invokers have MaxInvocationLevel - if (nClass == CLASS_TYPE_WARLOCK - || nClass == CLASS_TYPE_DRAGON_SHAMAN - || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT) - columnName = "MaxInvocationLevel"; - - // Truenamers have 3 sets of utterances, ranging from 1-6, EvolvingMind covers the entire range - if (nClass == CLASS_TYPE_TRUENAMER) - { - columnName = "EvolvingMind"; - spellLevel2da = "cls_true_maxlvl"; //has a different 2da we want to look at - } - - if (nClass == CLASS_TYPE_BINDER) - { - columnName = "VestigeLvl"; - spellLevel2da = "cls_bind_binder"; - } - - // ToB doesn't have a concept of this, but we don't care. - - int maxLevel = StringToInt(Get2DACache(spellLevel2da, columnName, currentLevel)); - return maxLevel; - } -} - -int GetMinSpellLevel(int nClass) -{ - // again sponts have their own function - if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS - || nClass == CLASS_TYPE_ARCHIVIST) - { - return GetMinSpellLevelForCasterLevel(nClass, GetHighestLevelPossibleInClass(nClass)); - } - else - { - if (nClass == CLASS_TYPE_FIST_OF_ZUOKEN - || nClass == CLASS_TYPE_PSION - || nClass == CLASS_TYPE_PSYWAR - || nClass == CLASS_TYPE_WILDER - || nClass == CLASS_TYPE_PSYCHIC_ROGUE - || nClass == CLASS_TYPE_WARMIND - || nClass == CLASS_TYPE_WARBLADE - || nClass == CLASS_TYPE_SWORDSAGE - || nClass == CLASS_TYPE_CRUSADER - || nClass == CLASS_TYPE_WARLOCK - || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT - || nClass == CLASS_TYPE_DRAGON_SHAMAN - || nClass == CLASS_TYPE_SHADOWCASTER - || nClass == CLASS_TYPE_SHADOWSMITH - || nClass == CLASS_TYPE_BINDER) - return 1; - - return GetCurrentSpellLevel(nClass, 1); - } - -} - -int GetMaxSpellLevel(int nClass) -{ - if (nClass == CLASS_TYPE_WILDER - || nClass == CLASS_TYPE_PSION) - return 9; - if (nClass == CLASS_TYPE_PSYCHIC_ROGUE - || nClass == CLASS_TYPE_FIST_OF_ZUOKEN - || nClass == CLASS_TYPE_WARMIND) - return 5; - if (nClass == CLASS_TYPE_PSYWAR) - return 6; - - return GetCurrentSpellLevel(nClass, GetHighestLevelPossibleInClass(nClass)); -} - -int GetHighestLevelPossibleInClass(int nClass) -{ - string sFile; - - //sponts have their spells in the classes.2da - if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS - || nClass == CLASS_TYPE_ARCHIVIST) - { - sFile = Get2DACache("classes", "SpellGainTable", nClass); - } - else - { - // everyone else uses this - sFile = GetAMSKnownFileName(nClass); - - if (nClass == CLASS_TYPE_TRUENAMER) - { - sFile = "cls_true_maxlvl"; //has a different 2da we want to look at - } - - if (nClass == CLASS_TYPE_BINDER) - { - sFile = "cls_bind_binder"; - } - } - - return Get2DARowCount(sFile); -} - int IsClassAllowedToUseNUISpellbook(object oPlayer, int nClass) { // This controls who can use the Spellbook NUI, if for some reason you don't @@ -698,8 +387,7 @@ int IsClassAllowedToUseNUISpellbook(object oPlayer, int nClass) return TRUE; // Arcane Spont - if (nClass == CLASS_TYPE_ASSASSIN - || nClass == CLASS_TYPE_BEGUILER + if (nClass == CLASS_TYPE_BEGUILER || nClass == CLASS_TYPE_CELEBRANT_SHARESS || nClass == CLASS_TYPE_DREAD_NECROMANCER || nClass == CLASS_TYPE_DUSKBLADE @@ -817,8 +505,7 @@ int CanClassUseMetamagicFeats(int nClass) // I don't want to spend the time looping through each class's // feat 2da so this is the list of all classes that are allowed to use the // Spellbook NUI and can use Metamagic - return (nClass == CLASS_TYPE_ASSASSIN - || nClass == CLASS_TYPE_BARD + return (nClass == CLASS_TYPE_BARD || nClass == CLASS_TYPE_SORCERER || nClass == CLASS_TYPE_BEGUILER || nClass == CLASS_TYPE_DREAD_NECROMANCER @@ -838,7 +525,6 @@ int CanClassUseSuddenMetamagicFeats(int nClass) // Spellbook NUI and can use Sudden Metamagic return (nClass == CLASS_TYPE_SHADOWLORD || nClass == CLASS_TYPE_ARCHIVIST - || nClass == CLASS_TYPE_ASSASSIN || nClass == CLASS_TYPE_BARD || nClass == CLASS_TYPE_BEGUILER || nClass == CLASS_TYPE_DREAD_NECROMANCER @@ -1144,5 +830,16 @@ int JsonArrayContainsInt(json list, int item) return TRUE; } + return FALSE; +} + +int IsSpellbookNUIOpen(object oPC) +{ + int nPreviousToken = NuiFindWindow(oPC, PRC_SPELLBOOK_NUI_WINDOW_ID); + if (nPreviousToken != 0) + { + return TRUE; + } + return FALSE; } \ No newline at end of file diff --git a/src/include/prc_nui_scd_inc.nss b/src/include/prc_nui_sbd_inc.nss similarity index 93% rename from src/include/prc_nui_scd_inc.nss rename to src/include/prc_nui_sbd_inc.nss index 5f14b7e..8027a70 100644 --- a/src/include/prc_nui_scd_inc.nss +++ b/src/include/prc_nui_sbd_inc.nss @@ -1,6 +1,6 @@ //:://///////////////////////////////////////////// //:: PRC Spellbook Description NUI -//:: prc_nui_scd_inc +//:: prc_nui_sbd_inc //::////////////////////////////////////////////// /* This is the view for the Spell Description NUI @@ -28,11 +28,17 @@ void CreateSpellDescriptionNUI(object oPlayer, int featID, int spellId=0, int re void CreateSpellDescriptionNUI(object oPlayer, int featID, int spellId=0, int realSpellId=0) { // look for existing window and destroy - int nPreviousToken = NuiFindWindow(OBJECT_SELF, NUI_SPELL_DESCRIPTION_WINDOW_ID); + int nPreviousToken = NuiFindWindow(oPlayer, NUI_SPELL_DESCRIPTION_WINDOW_ID); + if(nPreviousToken != 0) + { + NuiDestroy(oPlayer, nPreviousToken); + } + +/* int nPreviousToken = NuiFindWindow(OBJECT_SELF, NUI_SPELL_DESCRIPTION_WINDOW_ID); if(nPreviousToken != 0) { NuiDestroy(OBJECT_SELF, nPreviousToken); - } + } */ // in order of accuracy for names it goes RealSpellID > SpellID > FeatID string spellName; diff --git a/src/include/prc_sp_func.nss b/src/include/prc_sp_func.nss index 233090f..c249c5f 100644 --- a/src/include/prc_sp_func.nss +++ b/src/include/prc_sp_func.nss @@ -180,6 +180,24 @@ void RunImpactScript(object oPC, int nSpellID, int nEventType) DeleteLocalInt(oPC, PRC_SPELLID_OVERRIDE); } +//Returns true if the spell is one of the repair spells +int IsRepair(int nSpellID) +{ + return ((nSpellID >= SPELL_REPAIR_MINOR_DAMAGE) && (nSpellID <= SPELL_REPAIR_CRITICAL_DAMAGE)); +} + +//Returns true if the spell is one of the mass repair spells +int IsMassRepair(int nSpellID) +{ + return ((nSpellID >= SPELL_MASS_REPAIR_LIGHT_DAMAGE) && (nSpellID <= SPELL_MASS_REPAIR_CRITICAL_DAMAGE)); +} + +//Returns true if the spell is one of the mass inflict damage spells +int IsMassInflictDamage(int nSpellID) +{ + return ((nSpellID >= SPELL_MASS_INFLICT_LIGHT_DAMAGE) && (nSpellID <= SPELL_MASS_INFLICT_CRITICAL_DAMAGE)); +} + //Returns true if the spell is one of the cure spells int IsCure(int nSpellID) { diff --git a/src/include/prc_spell_const.nss b/src/include/prc_spell_const.nss index bb8b1cd..c93417f 100644 --- a/src/include/prc_spell_const.nss +++ b/src/include/prc_spell_const.nss @@ -13,6 +13,9 @@ const int SPELL_BLACKLIGHT = 2091; const int SPELL_BARD_SONG = 411; const int SPELL_BARD_CURSE_SONG = 644; +//:: Monk +const int SPELL_MONK_ABUNDANT_STEP = 17986; + //:: Epic Level Handbook const int SPELL_EPIC_SWARM_OF_ARROWS = 17996; @@ -22,6 +25,9 @@ const int SPELL_BCM_RENDING_CLAWS = 17997; //:: Complete Warrior const int SPELL_RANGED_DISARM = 3493; +//:: Tome of Battle +const int SPELL_TOB_SNAP_KICK = 3794; + //marshal const int SPELL_MINAUR_DEMFORT = 3500; const int SPELL_MINAUR_FORCEWILL = 3501; @@ -1289,20 +1295,128 @@ const int SPELL_SUMMON_CREATURE_IX_WATER = 3200; //:: Player's Handbook Spells const int SPELL_SPIRITUAL_WEAPON = 17249; +const int SPELL_SUMMON_NATURES_ALLY_1 = 17000; +const int SPELL_SUMMON_NATURES_ALLY_1_DIREBADGER = 17001; +const int SPELL_SUMMON_NATURES_ALLY_1_DIRERAT = 17002; +const int SPELL_SUMMON_NATURES_ALLY_1_DOG = 17003; +const int SPELL_SUMMON_NATURES_ALLY_1_HAWK = 17004; +const int SPELL_SUMMON_NATURES_ALLY_1_TINY_VIPER = 17005; + +const int SPELL_SUMMON_NATURES_ALLY_2 = 17010; +const int SPELL_SUMMON_NATURES_ALLY_2_DIREBOAR = 17011; +const int SPELL_SUMMON_NATURES_ALLY_2_COOSHEE = 17012; +const int SPELL_SUMMON_NATURES_ALLY_2_WOLF = 17013; +const int SPELL_SUMMON_NATURES_ALLY_2_SMALL_VIPER = 17014; +const int SPELL_SUMMON_NATURES_ALLY_2_BLACKBEAR = 17015; + +const int SPELL_SUMMON_NATURES_ALLY_3 = 17020; +const int SPELL_SUMMON_NATURES_ALLY_3_BROWNBEAR = 17021; +const int SPELL_SUMMON_NATURES_ALLY_3_DIREWOLK = 17022; +const int SPELL_SUMMON_NATURES_ALLY_3_LARGE_VIPER = 17023; +const int SPELL_SUMMON_NATURES_ALLY_3_LEOPARD = 17024; +const int SPELL_SUMMON_NATURES_ALLY_3_SATYR = 17025; + +const int SPELL_SUMMON_NATURES_ALLY_4 = 17030; +const int SPELL_SUMMON_NATURES_ALLY_4_LION = 17031; +const int SPELL_SUMMON_NATURES_ALLY_4_POLAR_BEAR = 17032; +const int SPELL_SUMMON_NATURES_ALLY_4_DIRE_SPIDER = 17033; +const int SPELL_SUMMON_NATURES_ALLY_4_HUGE_VIPER = 17034; +const int SPELL_SUMMON_NATURES_ALLY_4_WEREBOAR = 17035; + +const int SPELL_SUMMON_NATURES_ALLY_5 = 17040; +const int SPELL_SUMMON_NATURES_ALLY_5_MED_AIR = 17041; +const int SPELL_SUMMON_NATURES_ALLY_5_MED_EARTH = 17042; +const int SPELL_SUMMON_NATURES_ALLY_5_MED_FIRE = 17043; +const int SPELL_SUMMON_NATURES_ALLY_5_MED_WATER = 17044; +const int SPELL_SUMMON_NATURES_ALLY_5_DIRE_BEAR = 17045; + +const int SPELL_SUMMON_NATURES_ALLY_6 = 17050; +const int SPELL_SUMMON_NATURES_ALLY_6_LG_AIR = 17051; +const int SPELL_SUMMON_NATURES_ALLY_6_LG_EARTH = 17052; +const int SPELL_SUMMON_NATURES_ALLY_6_LG_FIRE = 17053; +const int SPELL_SUMMON_NATURES_ALLY_6_LG_WATER = 17054; +const int SPELL_SUMMON_NATURES_ALLY_6_DIRETIGER = 17055; + +const int SPELL_SUMMON_NATURES_ALLY_7 = 17060; +const int SPELL_SUMMON_NATURES_ALLY_7_BULETTE = 17061; +const int SPELL_SUMMON_NATURES_ALLY_7_INVSTALKER = 17062; +const int SPELL_SUMMON_NATURES_ALLY_7_PIXIE = 17063; +const int SPELL_SUMMON_NATURES_ALLY_7_GORGON = 17064; +const int SPELL_SUMMON_NATURES_ALLY_7_MANTICORE = 17065; + +const int SPELL_SUMMON_NATURES_ALLY_8 = 17070; +const int SPELL_SUMMON_NATURES_ALLY_8_GR_AIR = 17071; +const int SPELL_SUMMON_NATURES_ALLY_8_GR_EARTH = 17072; +const int SPELL_SUMMON_NATURES_ALLY_8_GR_FIRE = 17073; +const int SPELL_SUMMON_NATURES_ALLY_8_GR_WATER = 17074; +const int SPELL_SUMMON_NATURES_ALLY_8_NYMPH = 17075; + +const int SPELL_SUMMON_NATURES_ALLY_9 = 17080; +const int SPELL_SUMMON_NATURES_ALLY_9_ELD_AIR = 17081; +const int SPELL_SUMMON_NATURES_ALLY_9_ELD_EARTH = 17082; +const int SPELL_SUMMON_NATURES_ALLY_9_ELD_FIRE = 17083; +const int SPELL_SUMMON_NATURES_ALLY_9_ELD_WATER = 17084; +const int SPELL_SUMMON_NATURES_ALLY_9_ARANEA = 17085; + //:: Player's Handbook II Spells const int SPELL_CHASING_PERFECTION = 2479; //:: Spell Compendium Spells -const int SPELL_SPIRIT_WORM = 17248; -const int SPELL_FORCE_MISSILES = 2480; +const int SPELL_FORCE_MISSILES = 2480; +const int SPELL_REPAIR_MINOR_DAMAGE = 17094; +const int SPELL_REPAIR_LIGHT_DAMAGE = 17095; +const int SPELL_REPAIR_MODERATE_DAMAGE = 17096; +const int SPELL_REPAIR_SERIOUS_DAMAGE = 17097; +const int SPELL_REPAIR_CRITICAL_DAMAGE = 17098; +const int SPELL_INFLICT_LIGHT_DAMAGE = 17100; +const int SPELL_INFLICT_MODERATE_DAMAGE = 17101; +const int SPELL_INFLICT_SERIOUS_DAMAGE = 17102; +const int SPELL_INFLICT_CRITICAL_DAMAGE = 17103; +const int SPELL_SPIRIT_WORM = 17248; + +//:: Races of Eberron +const int SPELL_MASS_REPAIR_LIGHT_DAMAGE = 17105; +const int SPELL_MASS_REPAIR_MODERATE_DAMAGE = 17106; +const int SPELL_MASS_REPAIR_SERIOUS_DAMAGE = 17107; +const int SPELL_MASS_REPAIR_CRITICAL_DAMAGE = 17108; +const int SPELL_MASS_INFLICT_LIGHT_DAMAGE = 17110; +const int SPELL_MASS_INFLICT_MODERATE_DAMAGE = 17111; +const int SPELL_MASS_INFLICT_SERIOUS_DAMAGE = 17112; +const int SPELL_MASS_INFLICT_CRITICAL_DAMAGE = 17113; //:: Masters of the Wild Spells +const int SPELL_FORESTFOLD = 17090; +const int SPELL_CREEPING_COLD = 17091; +const int SPELL_GREATER_CREEPING_COLD = 17092; +const int SPELL_CONTROL_PLANTS = 17237; +const int SPELL_ADRENALINE_SURGE = 17238; +const int SPELL_INVULNERABILITY_TO_ELEMENTS = 17239; +const int SPELL_REGEN_RING = 17241; +const int SPELL_REGEN_CIRCLE = 17242; const int SPELL_REGEN_LIGHT_WOUNDS = 17243; const int SPELL_REGEN_MODERATE_WOUNDS = 17244; const int SPELL_REGEN_SERIOUS_WOUNDS = 17245; const int SPELL_REGEN_CRITICAL_WOUNDS = 17246; const int SPELL_SPEED_WIND = 17247; -const int SPELL_TORTISE_SHELL = 17250; +const int SPELL_TORTISE_SHELL = 17250; + +//:: Book of Exalted Deeds Spells +const int SPELL_LEONALS_ROAR = 17240; + +//:: Master of the Wild Feats +const int SPELL_VL_WILD_SHAPE_TREANT = 17989; +const int SPELL_VL_ANIMATE_TREE = 17990; +const int SPELL_PLANT_DEFIANCE = 17991; +const int SPELL_PLANT_CONTROL = 17992; + +//:: Book of Exalted Deeds Feats +const int SPELL_FOT_LEONALS_ROAR = 17993; +const int SPELL_FOT_LIONS_SWIFTNESS = 17994; +const int SPELL_FAVORED_OF_THE_COMPANIONS = 17995; + +//:: Magic Item Compendium +const int SPELL_AROMA_OF_CURDLED_DEATH = 17987; +const int SPELL_ELIXIR_OF_THE_BEETLE = 17987; //x const int SPELL_TENSERS_FLOATING_DISK = 3849; diff --git a/src/include/prc_spellf_inc.nss b/src/include/prc_spellf_inc.nss index 753680f..f40f0f6 100644 --- a/src/include/prc_spellf_inc.nss +++ b/src/include/prc_spellf_inc.nss @@ -299,6 +299,7 @@ int SpellfireDrainItem(object oPC, object oItem, int bCharged = TRUE, int bSingl { if((nBase == BASE_ITEM_POTIONS) || + (nBase == BASE_ITEM_INFUSED_HERB) || (nBase == BASE_ITEM_SCROLL) || (nBase == BASE_ITEM_SPELLSCROLL) || (nBase == BASE_ITEM_BLANK_POTION) || @@ -382,6 +383,7 @@ void SpellfireDrain(object oPC, object oTarget, int bCharged = TRUE, int bExempt if(GetPRCSwitch(PRC_SPELLFIRE_DISALLOW_DRAIN_SCROLL_POTION) && ((nBase == BASE_ITEM_POTIONS) || (nBase == BASE_ITEM_SCROLL) || + (nBase == BASE_ITEM_INFUSED_HERB) || (nBase == BASE_ITEM_BLANK_POTION) || (nBase == BASE_ITEM_BLANK_SCROLL) ) @@ -485,7 +487,8 @@ void SpellfireChargeItem(object oPC, object oItem) AddSpellfireLevels(oPC, nNewCharges - 50); nNewCharges = 50; } - SetItemCharges(oItem, nCharges + nExpend); + //SetItemCharges(oItem, nCharges + nExpend); + SetItemCharges(oItem, nNewCharges); //Assuming 50 is the maximum //refunding excess charges } @@ -525,3 +528,4 @@ void SpellfireCrown(object oPC) } } +//:: void main() {} \ No newline at end of file diff --git a/src/include/prc_template_con.nss b/src/include/prc_template_con.nss index fc15544..2955524 100644 --- a/src/include/prc_template_con.nss +++ b/src/include/prc_template_con.nss @@ -18,6 +18,7 @@ const int TEMPLATE_CURST = 26; const int TEMPLATE_GRAVETOUCHED_GHOUL = 29; const int TEMPLATE_CRYPTSPAWN = 30; const int TEMPLATE_ARCHLICH = 99; +const int TEMPLATE_BAELNORN = 100; const int TEMPLATE_LICH = 101; const int TEMPLATE_DEMILICH = 102; const int TEMPLATE_NECROPOLITAN = 105; diff --git a/src/include/prc_weap_apt.nss b/src/include/prc_weap_apt.nss index 8fa1043..7bda1b7 100644 --- a/src/include/prc_weap_apt.nss +++ b/src/include/prc_weap_apt.nss @@ -47,12 +47,10 @@ int GetWeaponFocusFeatItemProperty(int nFeatNumber) if(nItemProperty != -1) return nItemProperty; nItemProperty = GetFeatItemProperty(nFeatNumber, IP_CONST_FEAT_WEAPON_FOCUS_TRIDENT, IP_CONST_FEAT_WEAPON_FOCUS_TRIDENT); if(nItemProperty != -1) return nItemProperty; - nItemProperty = GetFeatItemProperty(nFeatNumber, IP_CONST_FEAT_WEAPON_FOCUS_LIGHT_LANCE, IP_CONST_FEAT_WEAPON_FOCUS_GOAD); + nItemProperty = GetFeatItemProperty(nFeatNumber, IP_CONST_FEAT_WEAPON_FOCUS_EAGLE_CLAW, IP_CONST_FEAT_WEAPON_FOCUS_GOAD); if(nItemProperty != -1) return nItemProperty; nItemProperty = GetFeatItemProperty(nFeatNumber, IP_CONST_FEAT_WEAPON_FOCUS_ELVEN_LIGHTBLADE, IP_CONST_FEAT_WEAPON_FOCUS_ELVEN_LIGHTBLADE); if(nItemProperty != -1) return nItemProperty; - nItemProperty = GetFeatItemProperty(nFeatNumber, IP_CONST_FEAT_WEAPON_FOCUS_EAGLE_CLAW, IP_CONST_FEAT_WEAPON_FOCUS_EAGLE_CLAW); - if(nItemProperty != -1) return nItemProperty; nItemProperty = GetFeatItemProperty(nFeatNumber, IP_CONST_FEAT_WEAPON_FOCUS_ELVEN_THINBLADE, IP_CONST_FEAT_WEAPON_FOCUS_ELVEN_THINBLADE); if(nItemProperty != -1) return nItemProperty; nItemProperty = GetFeatItemProperty(nFeatNumber, IP_CONST_FEAT_WEAPON_FOCUS_ELVEN_COURTBLADE, IP_CONST_FEAT_WEAPON_FOCUS_ELVEN_COURTBLADE); diff --git a/src/include/prc_x2_craft.nss b/src/include/prc_x2_craft.nss index 5834f63..c18dcc3 100644 --- a/src/include/prc_x2_craft.nss +++ b/src/include/prc_x2_craft.nss @@ -13,7 +13,7 @@ //:: Created On: 2003-05-09 //:: Last Updated On: 2003-10-14 //::////////////////////////////////////////////// - +#include "prc_x2_itemprop" struct craft_struct { @@ -44,22 +44,25 @@ const string X2_CI_CRAFTSKILL_CONV ="x2_p_craftskills"; /* moved to be code switches const int X2_CI_BREWPOTION_MAXLEVEL = 3; // Max Level for potions -const int X2_CI_BREWPOTION_COSTMODIFIER = 50; // gp Brew Potion XPCost Modifier +const int PRC_X2_BREWPOTION_COSTMODIFIER = 50; // gp Brew Potion XPCost Modifier // Scribe Scroll related constants -const int X2_CI_SCRIBESCROLL_COSTMODIFIER = 25; // Scribescroll Cost Modifier +const int PRC_X2_SCRIBESCROLL_COSTMODIFIER = 25; // Scribescroll Cost Modifier // Craft Wand related constants -const int X2_CI_CRAFTWAND_MAXLEVEL = 4; -const int X2_CI_CRAFTWAND_COSTMODIFIER = 750; +const int PRC_X2_CRAFTWAND_MAXLEVEL = 4; +const int PRC_X2_CRAFTWAND_COSTMODIFIER = 750; */ -const int X2_CI_BREWPOTION_FEAT_ID = 944; // Brew Potion feat simulation -const int X2_CI_SCRIBESCROLL_FEAT_ID = 945; -const int X2_CI_CRAFTWAND_FEAT_ID = 946; -const int X2_CI_CRAFTROD_FEAT_ID = 2927; -const int X2_CI_CRAFTROD_EPIC_FEAT_ID = 3490; -const int X2_CI_CRAFTSTAFF_FEAT_ID = 2928; -const int X2_CI_CRAFTSTAFF_EPIC_FEAT_ID = 3491; +const int X2_CI_BREWPOTION_FEAT_ID = 944; // Brew Potion feat simulation +const int X2_CI_SCRIBESCROLL_FEAT_ID = 945; +const int X2_CI_CRAFTWAND_FEAT_ID = 946; +const int X2_CI_CRAFTROD_FEAT_ID = 2927; +const int X2_CI_CRAFTROD_EPIC_FEAT_ID = 3490; +const int X2_CI_CRAFTSTAFF_FEAT_ID = 2928; +const int X2_CI_CRAFTSTAFF_EPIC_FEAT_ID = 3491; +const int X2_CI_CREATEINFUSION_FEAT_ID = 25960; +const int X2_CI_CRAFTSCEPTER_FEAT_ID = 25962; + const string X2_CI_BREWPOTION_NEWITEM_RESREF = "x2_it_pcpotion"; // ResRef for new potion item const string X2_CI_SCRIBESCROLL_NEWITEM_RESREF = "x2_it_pcscroll"; // ResRef for new scroll item const string X2_CI_CRAFTWAND_NEWITEM_RESREF = "x2_it_pcwand"; @@ -185,6 +188,17 @@ int CheckAlternativeCrafting(object oPC, int nSpell, struct craft_cost_struct co // Returns the maximum of caster level used and other effective levels from emulating spells int GetAlternativeCasterLevel(object oPC, int nLevel); +// ----------------------------------------------------------------------------- +// Create and Return an herbal infusion with an item property +// matching nSpellID. +// ----------------------------------------------------------------------------- +object CICreateInfusion(object oCreator, int nSpellID); + +// ----------------------------------------------------------------------------- +// Returns TRUE if the player successfully performed Create Infusion +// ----------------------------------------------------------------------------- +int CICraftCheckCreateInfusion(object oSpellTarget, object oCaster, int nID = 0); + ////////////////////////////////////////////////// /* Include section */ ////////////////////////////////////////////////// @@ -194,6 +208,7 @@ int GetAlternativeCasterLevel(object oPC, int nLevel); #include "prc_inc_newip" #include "prc_inc_spells" #include "prc_add_spell_dc" +#include "inc_infusion" ////////////////////////////////////////////////// /* Function definitions */ @@ -261,7 +276,9 @@ int CIGetIsCraftFeatBaseItem(object oItem) nBt == BASE_ITEM_BLANK_SCROLL || nBt == BASE_ITEM_BLANK_WAND || nBt == BASE_ITEM_CRAFTED_ROD || - nBt == BASE_ITEM_CRAFTED_STAFF) + nBt == BASE_ITEM_CRAFTED_STAFF || + nBt == BASE_ITEM_CRAFTED_SCEPTER || + nBt == BASE_ITEM_MUNDANE_HERB) return TRUE; else return FALSE; @@ -287,7 +304,7 @@ object CICraftBrewPotion(object oCreator, int nSpellID ) return OBJECT_INVALID; } - /* //just a tad retarded, don't you think? other crafting feats are not similarly restricted + /* //just a tad silly, don't you think? other crafting feats are not similarly restricted //Uses per day int nUsesAllowed; @@ -453,11 +470,159 @@ object CICraftCraftWand(object oCreator, int nSpellID ) // ----------------------------------------------------------------------------- // Georg, 2003-06-12 -// Create and Return a magic wand with an item property -// matching nSpellID. Charges are set to d20 + casterlevel -// capped at 50 max +// Create and Return a magic scroll with an item property +// matching nSpellID. // ----------------------------------------------------------------------------- object CICraftScribeScroll(object oCreator, int nSpellID) +{ + if (DEBUG) DoDebug("CICraftScribeScroll: Enter (nSpellID=" + IntToString(nSpellID) + ")"); + + // Keep original and compute one-step master (if subradial) + int nSpellOriginal = nSpellID; + int nSpellMaster = nSpellOriginal; + if (GetIsSubradialSpell(nSpellOriginal)) + { + nSpellMaster = GetMasterSpellFromSubradial(nSpellOriginal); + if (DEBUG) DoDebug("CICraftScribeScroll: subradial detected original=" + IntToString(nSpellOriginal) + " master=" + IntToString(nSpellMaster)); + } + + // Prefer iprp mapping for the original, fallback to master + int nPropID = IPGetIPConstCastSpellFromSpellID(nSpellOriginal); + int nSpellUsedForIP = nSpellOriginal; + if (nPropID < 0) + { + if (DEBUG) DoDebug("CICraftScribeScroll: no iprp for original " + IntToString(nSpellOriginal) + ", trying master " + IntToString(nSpellMaster)); + nPropID = IPGetIPConstCastSpellFromSpellID(nSpellMaster); + nSpellUsedForIP = nSpellMaster; + } + + // If neither original nor master has an iprp row, we can still try templates, + // but most templates expect a matching iprp. Bail out now if nothing found. + if (nPropID < 0) + { + if (DEBUG) DoDebug("CICraftScribeScroll: no iprp_spells entry for original/master -> aborting"); + FloatingTextStringOnCreature("This spell cannot be scribed (no item property mapping).", oCreator, FALSE); + return OBJECT_INVALID; + } + + if (DEBUG) DoDebug("CICraftScribeScroll: using spell " + IntToString(nSpellUsedForIP) + " (iprp row " + IntToString(nPropID) + ") for item property"); + + // Material component check (based on resolved iprp row) + string sMat = GetMaterialComponentTag(nPropID); + if (sMat != "") + { + object oMat = GetItemPossessedBy(oCreator, sMat); + if (oMat == OBJECT_INVALID) + { + FloatingTextStrRefOnCreature(83374, oCreator); // Missing material component + return OBJECT_INVALID; + } + else + { + DestroyObject(oMat); + } + } + + // Resolve class and scroll template + int nClass = PRCGetLastSpellCastClass(); + string sClass = ""; + switch (nClass) + { + case CLASS_TYPE_WIZARD: + case CLASS_TYPE_SORCERER: sClass = "Wiz_Sorc"; break; + case CLASS_TYPE_CLERIC: + case CLASS_TYPE_OCULAR: + case CLASS_TYPE_UR_PRIEST: sClass = "Cleric"; break; + case CLASS_TYPE_PALADIN: sClass = "Paladin"; break; + case CLASS_TYPE_DRUID: + case CLASS_TYPE_BLIGHTER: sClass = "Druid"; break; + case CLASS_TYPE_RANGER: sClass = "Ranger"; break; + case CLASS_TYPE_BARD: sClass = "Bard"; break; + case CLASS_TYPE_ASSASSIN: sClass = "Assassin"; break; + } + + object oTarget = OBJECT_INVALID; + string sResRef = ""; + + // Try to find a class-specific scroll template. + if (sClass != "") + { + // Try original first (so if you made a subradial-specific template it will be used) + sResRef = Get2DACache(X2_CI_2DA_SCROLLS, sClass, nSpellOriginal); + if (sResRef == "") + { + // fallback to the spell that matched an iprp row (master or original) + sResRef = Get2DACache(X2_CI_2DA_SCROLLS, sClass, nSpellUsedForIP); + } + if (sResRef != "") + { + oTarget = CreateItemOnObject(sResRef, oCreator); + if (DEBUG) DoDebug("CICraftScribeScroll: created template " + sResRef + " for class " + sClass); + // Ensure template uses the correct cast-spell property: replace the template's cast-spell IP with ours + if (oTarget != OBJECT_INVALID) + { + itemproperty ipIter = GetFirstItemProperty(oTarget); + while (GetIsItemPropertyValid(ipIter)) + { + if (GetItemPropertyType(ipIter) == ITEM_PROPERTY_CAST_SPELL) + { + RemoveItemProperty(oTarget, ipIter); + break; + } + ipIter = GetNextItemProperty(oTarget); + } + itemproperty ipSpell = ItemPropertyCastSpell(nPropID, IP_CONST_CASTSPELL_NUMUSES_SINGLE_USE); + AddItemProperty(DURATION_TYPE_PERMANENT, ipSpell, oTarget); + } + } + } + + // If no template or sClass was empty, create generic scroll and add itemprop. + if (oTarget == OBJECT_INVALID) + { + sResRef = "craft_scroll"; + oTarget = CreateItemOnObject(sResRef, oCreator); + if (oTarget == OBJECT_INVALID) + { + WriteTimestampedLogEntry("CICraftScribeScroll: failed to create craft_scroll template."); + return OBJECT_INVALID; + } + // Remove existing default IP and add correct one + itemproperty ipFirst = GetFirstItemProperty(oTarget); + if (GetIsItemPropertyValid(ipFirst)) + RemoveItemProperty(oTarget, ipFirst); + + itemproperty ipSpell = ItemPropertyCastSpell(nPropID, IP_CONST_CASTSPELL_NUMUSES_SINGLE_USE); + AddItemProperty(DURATION_TYPE_PERMANENT, ipSpell, oTarget); + } + + // Add PRC metadata (use the same spell that matched the iprp row so metadata and IP line up) + if (GetPRCSwitch(PRC_SCRIBE_SCROLL_CASTER_LEVEL)) + { + int nCasterLevel = GetAlternativeCasterLevel(oCreator, PRCGetCasterLevel(oCreator)); + itemproperty ipLevel = ItemPropertyCastSpellCasterLevel(nSpellUsedForIP, nCasterLevel); + AddItemProperty(DURATION_TYPE_PERMANENT, ipLevel, oTarget); + + itemproperty ipMeta = ItemPropertyCastSpellMetamagic(nSpellUsedForIP, PRCGetMetaMagicFeat()); + AddItemProperty(DURATION_TYPE_PERMANENT, ipMeta, oTarget); + + int nDC = PRCGetSpellSaveDC(nSpellUsedForIP, GetSpellSchool(nSpellUsedForIP), OBJECT_SELF); + itemproperty ipDC = ItemPropertyCastSpellDC(nSpellUsedForIP, nDC); + AddItemProperty(DURATION_TYPE_PERMANENT, ipDC, oTarget); + } + + if (oTarget == OBJECT_INVALID) + { + WriteTimestampedLogEntry("prc_x2_craft::CICraftScribeScroll failed - Resref: " + sResRef + " Class: " + sClass + "(" + IntToString(nClass) + ") " + " SpellID " + IntToString(nSpellID)); + return OBJECT_INVALID; + } + + if (DEBUG) DoDebug("CICraftScribeScroll: Success - created scroll " + sResRef + " for spell " + IntToString(nSpellUsedForIP)); + return oTarget; +} + + +/* object CICraftScribeScroll(object oCreator, int nSpellID) { int nPropID = IPGetIPConstCastSpellFromSpellID(nSpellID); object oTarget; @@ -491,6 +656,7 @@ object CICraftScribeScroll(object oCreator, int nSpellID) break; case CLASS_TYPE_CLERIC: case CLASS_TYPE_UR_PRIEST: + case CLASS_TYPE_OCULAR: sClass = "Cleric"; break; case CLASS_TYPE_PALADIN: @@ -506,6 +672,9 @@ object CICraftScribeScroll(object oCreator, int nSpellID) case CLASS_TYPE_BARD: sClass = "Bard"; break; + case CLASS_TYPE_ASSASSIN: + sClass = "Assassin"; + break; } string sResRef; if (sClass != "") @@ -542,6 +711,7 @@ object CICraftScribeScroll(object oCreator, int nSpellID) } return oTarget; } + */ // ----------------------------------------------------------------------------- // Returns TRUE if the player used the last spell to brew a potion @@ -593,7 +763,7 @@ These dont work as IPs since they are hardcoded */ // ------------------------------------------------------------------------- // check if spell is below maxlevel for brew potions // ------------------------------------------------------------------------- - int nPotionMaxLevel = GetPRCSwitch(X2_CI_BREWPOTION_MAXLEVEL); + int nPotionMaxLevel = GetPRCSwitch(PRC_X2_BREWPOTION_MAXLEVEL); if(nPotionMaxLevel == 0) nPotionMaxLevel = 3; @@ -624,7 +794,7 @@ These dont work as IPs since they are hardcoded */ // ------------------------------------------------------------------------- // XP/GP Cost Calculation // ------------------------------------------------------------------------- - int nCostModifier = GetPRCSwitch(X2_CI_BREWPOTION_COSTMODIFIER); + int nCostModifier = GetPRCSwitch(PRC_X2_BREWPOTION_COSTMODIFIER); if(nCostModifier == 0) nCostModifier = 50; int nCost = CIGetCraftGPCost(nLevel, nCostModifier, PRC_BREW_POTION_CASTER_LEVEL); @@ -698,7 +868,6 @@ These dont work as IPs since they are hardcoded */ } - // ----------------------------------------------------------------------------- // Returns TRUE if the player used the last spell to create a scroll // ----------------------------------------------------------------------------- @@ -728,7 +897,7 @@ int CICraftCheckScribeScroll(object oSpellTarget, object oCaster, int nID = 0) // XP/GP Cost Calculation // ------------------------------------------------------------------------- int nLevel = CIGetSpellInnateLevel(nID,TRUE); - int nCostModifier = GetPRCSwitch(X2_CI_SCRIBESCROLL_COSTMODIFIER); + int nCostModifier = GetPRCSwitch(PRC_X2_SCRIBESCROLL_COSTMODIFIER); if(nCostModifier == 0) nCostModifier = 25; int nCost = CIGetCraftGPCost(nLevel, nCostModifier, PRC_SCRIBE_SCROLL_CASTER_LEVEL); @@ -884,7 +1053,7 @@ These dont work as IPs since they are hardcoded */ // ------------------------------------------------------------------------- // check if spell is below maxlevel for craft want // ------------------------------------------------------------------------- - int nMaxLevel = GetPRCSwitch(X2_CI_CRAFTWAND_MAXLEVEL); + int nMaxLevel = GetPRCSwitch(PRC_X2_CRAFTWAND_MAXLEVEL); if(nMaxLevel == 0) nMaxLevel = 4; if (nLevel > nMaxLevel) @@ -896,7 +1065,7 @@ These dont work as IPs since they are hardcoded */ // ------------------------------------------------------------------------- // XP/GP Cost Calculation // ------------------------------------------------------------------------- - int nCostMod = GetPRCSwitch(X2_CI_CRAFTWAND_COSTMODIFIER); + int nCostMod = GetPRCSwitch(PRC_X2_CRAFTWAND_COSTMODIFIER); if(nCostMod == 0) nCostMod = 750; int nCost = CIGetCraftGPCost(nLevel, nCostMod, PRC_CRAFT_WAND_CASTER_LEVEL); @@ -966,6 +1135,169 @@ These dont work as IPs since they are hardcoded */ return FALSE; } +// ----------------------------------------------------------------------------- +// Returns TRUE if the player used the last spell to craft a scepter +// ----------------------------------------------------------------------------- +int CICraftCheckCraftScepter(object oSpellTarget, object oCaster, int nSpellID = 0) +{ + + if(nSpellID == 0) nSpellID = PRCGetSpellId(); + int nCasterLevel = GetAlternativeCasterLevel(oCaster, PRCGetCasterLevel(oCaster)); + int bSuccess = TRUE; + int nCount = 0; + itemproperty ip = GetFirstItemProperty(oSpellTarget); + int nMetaMagic = PRCGetMetaMagicFeat(); + + while(GetIsItemPropertyValid(ip)) + { + if(GetItemPropertyType(ip) == ITEM_PROPERTY_CAST_SPELL) + nCount++; + ip = GetNextItemProperty(oSpellTarget); + } + if(nCount >= 2) //:: Scepters are limited to two spells + { + FloatingTextStringOnCreature("* Failure - Too many castspell itemproperties *", oCaster); + return TRUE; + } + if(!GetHasFeat(X2_CI_CRAFTSCEPTER_FEAT_ID, oCaster)) + { + FloatingTextStrRefOnCreature(40487, oCaster); // Item Creation Failed - Don't know how to create that type of item + return TRUE; // tried item creation but do not know how to do it + } + if(CIGetIsSpellRestrictedFromCraftFeat(nSpellID, X2_CI_CRAFTSCEPTER_FEAT_ID)) + { + FloatingTextStrRefOnCreature(16829169, oCaster); // can not be used with this feat + return TRUE; + } + + // Get the base spell level (circle) before metamagic adjustments + int nBaseLevel = CIGetSpellInnateLevel(nSpellID, TRUE); + + // Check if spell circle is 7th level or lower + if (nBaseLevel > 7) + { + //FloatingTextStrRefOnCreature(83623, oCaster); // Spell level too high + FloatingTextStringOnCreature("* Failure - scepters can not hold spells higher than level 7", oCaster); + return TRUE; + } + + int nLevel = nBaseLevel; + + if(GetPRCSwitch(PRC_CRAFT_SCEPTER_CASTER_LEVEL)) + { + switch(nMetaMagic) + { + case METAMAGIC_EMPOWER: + nLevel += 2; + break; + case METAMAGIC_EXTEND: + nLevel += 1; + break; + case METAMAGIC_MAXIMIZE: + nLevel += 3; + break; +/* case METAMAGIC_QUICKEN: + nLevel += 1; + break; + case METAMAGIC_SILENT: + nLevel += 5; + break; + case METAMAGIC_STILL: + nLevel += 6; + break; + These dont work as IPs since they are hardcoded */ + } + } + + int nCostMod = GetPRCSwitch(PRC_X2_CRAFTSCEPTER_COSTMODIFIER); + if(!nCostMod) nCostMod = 750; + int nLvlRow = IPGetIPConstCastSpellFromSpellID(nSpellID); + int nCLevel = StringToInt(Get2DACache("iprp_spells","CasterLvl",nLvlRow)); + int nCost = CIGetCraftGPCost(nLevel, nCostMod, PRC_CRAFT_SCEPTER_CASTER_LEVEL); + + //discount for second spell + if(nCount+1 == 2) + nCost = (nCost/2); + + //takes epic xp costs into account + struct craft_cost_struct costs = GetModifiedCostsFromBase(nCost, oCaster, FEAT_CRAFT_SCEPTER, (nMetaMagic > 0)); + + if(costs.nGoldCost < 1) costs.nXPCost = 1; + if(costs.nXPCost < 1) costs.nXPCost = 1; + //if(GetGold(oCaster) < nGoldCost) // enough gold? + if (!GetHasGPToSpend(oCaster, costs.nGoldCost)) + { + FloatingTextStrRefOnCreature(3786, oCaster); // Item Creation Failed - not enough gold! + return TRUE; + } + int nHD = GetHitDice(oCaster); + int nMinXPForLevel = (nHD * (nHD - 1)) * 500; + int nNewXP = GetXP(oCaster) - costs.nXPCost; + //if (nMinXPForLevel > nNewXP || nNewXP == 0 ) + if (!GetHasXPToSpend(oCaster, costs.nXPCost)) + { + FloatingTextStrRefOnCreature(3785, oCaster); // Item Creation Failed - Not enough XP + return TRUE; + } + //check spell emulation + if(!CheckAlternativeCrafting(oCaster, nSpellID, costs)) + { + FloatingTextStringOnCreature("*Crafting failed!*", oCaster, FALSE); + return TRUE; + } + int nPropID = IPGetIPConstCastSpellFromSpellID(nSpellID); + if (nPropID == 0 && nSpellID != 0) + { + FloatingTextStrRefOnCreature(84544,oCaster); + return TRUE; + } + if (nPropID != -1) + { + AddItemProperty(DURATION_TYPE_PERMANENT,ItemPropertyCastSpell(nPropID,IP_CONST_CASTSPELL_NUMUSES_1_CHARGE_PER_USE),oSpellTarget); + + if(GetPRCSwitch(PRC_CRAFT_SCEPTER_CASTER_LEVEL)) + { + AddItemProperty(DURATION_TYPE_PERMANENT,ItemPropertyCastSpellCasterLevel(nSpellID, nCasterLevel),oSpellTarget); + AddItemProperty(DURATION_TYPE_PERMANENT,ItemPropertyCastSpellMetamagic(nSpellID, PRCGetMetaMagicFeat()),oSpellTarget); + AddItemProperty(DURATION_TYPE_PERMANENT,ItemPropertyCastSpellDC(nSpellID, PRCGetSaveDC(PRCGetSpellTargetObject(), OBJECT_SELF)),oSpellTarget); + } + } + else + bSuccess = FALSE; + + if(bSuccess) + { + //TakeGoldFromCreature(nGoldCost, oCaster, TRUE); + //SetXP(oCaster, nNewXP); + SpendXP(oCaster, costs.nXPCost); + SpendGP(oCaster, costs.nGoldCost); + //DestroyObject (oSpellTarget); + FloatingTextStrRefOnCreature(8502, oCaster); // Item Creation successful + + //advance time here + if(!costs.nTimeCost) costs.nTimeCost = 1; + AdvanceTimeForPlayer(oCaster, RoundsToSeconds(costs.nTimeCost)); + string sName; + sName = GetName(oCaster)+"'s Magic Scepter"; + SetItemCharges(oSpellTarget, 50); + //sName = Get2DACache("spells", "Name", nID); + //sName = "Wand of "+GetStringByStrRef(StringToInt(sName)); + SetName(oSpellTarget, sName); + SetItemCursedFlag(oSpellTarget, FALSE); + SetDroppableFlag(oSpellTarget, TRUE); + return TRUE; + } + else + { + FloatingTextStrRefOnCreature(76417, oCaster); // Item Creation Failed + return TRUE; + } + return TRUE; +} + +// ----------------------------------------------------------------------------- +// Returns TRUE if the player used the last spell to craft a staff +// ----------------------------------------------------------------------------- int CICraftCheckCraftStaff(object oSpellTarget, object oCaster, int nSpellID = 0) { @@ -1027,7 +1359,7 @@ int CICraftCheckCraftStaff(object oSpellTarget, object oCaster, int nSpellID = 0 These dont work as IPs since they are hardcoded */ } } - int nCostMod = GetPRCSwitch(X2_CI_CRAFTSTAFF_COSTMODIFIER); + int nCostMod = GetPRCSwitch(PRC_X2_CRAFTSTAFF_COSTMODIFIER); if(!nCostMod) nCostMod = 750; int nLvlRow = IPGetIPConstCastSpellFromSpellID(nSpellID); int nCLevel = StringToInt(Get2DACache("iprp_spells","CasterLvl",nLvlRow)); @@ -1114,6 +1446,9 @@ These dont work as IPs since they are hardcoded */ return TRUE; } +// ----------------------------------------------------------------------------- +// Returns TRUE if the player used the last spell to craft a rod +// ----------------------------------------------------------------------------- int CICraftCheckCraftRod(object oSpellTarget, object oCaster, int nSpellID = 0) { @@ -1175,7 +1510,7 @@ int CICraftCheckCraftRod(object oSpellTarget, object oCaster, int nSpellID = 0) These dont work as IPs since they are hardcoded */ } } - int nCostMod = GetPRCSwitch(X2_CI_CRAFTROD_COSTMODIFIER); + int nCostMod = GetPRCSwitch(PRC_X2_CRAFTROD_COSTMODIFIER); if(!nCostMod) nCostMod = 750; int nLvlRow = IPGetIPConstCastSpellFromSpellID(nSpellID); int nCLevel = StringToInt(Get2DACache("iprp_spells","CasterLvl",nLvlRow)); @@ -1260,6 +1595,7 @@ These dont work as IPs since they are hardcoded */ return TRUE; } + int InscribeRune(object oTarget = OBJECT_INVALID, object oCaster = OBJECT_INVALID, int nSpell = 0) { if(!GetIsObjectValid(oCaster)) oCaster = OBJECT_SELF; @@ -1310,6 +1646,11 @@ int InscribeRune(object oTarget = OBJECT_INVALID, object oCaster = OBJECT_INVALI if(!GetIsObjectValid(oTarget)) oTarget = PRCGetSpellTargetObject(); int nCaster = GetAlternativeCasterLevel(oCaster, PRCGetCasterLevel(oCaster)); + +//:: Check for Inscribe Epic Runes and cap CL at 20 if it doesn't exist. + int bEpicRunes = GetHasFeat(EPIC_FEAT_INSCRIBE_EPIC_RUNES, oCaster); + if (!bEpicRunes) { if(nCaster > 20) nCaster = 20; } + int nDC = PRCGetSaveDC(oTarget, oCaster); if(!nSpell) nSpell = PRCGetSpellId(); int nSpellLevel = 0; @@ -1332,6 +1673,7 @@ int InscribeRune(object oTarget = OBJECT_INVALID, object oCaster = OBJECT_INVALI // Minimum level. if (nSpellLevel == 0) nSpellLevel = 1; + // This will be modified with Runecaster code later. int nCharges = 1; if (GetLocalInt(oCaster, "RuneCharges")) nCharges = nCount; @@ -1440,9 +1782,14 @@ int InscribeRune(object oTarget = OBJECT_INVALID, object oCaster = OBJECT_INVALI // If they have this active, the bonuses are already added, so skip // If they don't, add the bonuses down below if(GetHasSpellEffect(SPELL_RUNE_CHANT)) - nRuneChant = 0; + nRuneChant = 0; - itemproperty ipLevel = ItemPropertyCastSpellCasterLevel(nSpell, PRCGetCasterLevel()); + //:: Check for Inscribe Epic Runes and cap CL at 20 if it doesn't exist. + nCaster = PRCGetCasterLevel(); + + if (!bEpicRunes) { if(nCaster > 20) nCaster = 20; } + + itemproperty ipLevel = ItemPropertyCastSpellCasterLevel(nSpell, nCaster); AddItemProperty(DURATION_TYPE_PERMANENT,ipLevel,oRune); itemproperty ipMeta = ItemPropertyCastSpellMetamagic(nSpell, PRCGetMetaMagicFeat()); AddItemProperty(DURATION_TYPE_PERMANENT,ipMeta,oRune); @@ -1544,18 +1891,28 @@ int AttuneGem(object oTarget = OBJECT_INVALID, object oCaster = OBJECT_INVALID, // No point scribing Gems from items, and its not allowed. if (oItem != OBJECT_INVALID) { - FloatingTextStringOnCreature("You cannot scribe a Gem from an item.", oCaster, FALSE); + FloatingTextStringOnCreature("You cannot attune a Gem from an item.", oCaster, FALSE); return TRUE; } // oTarget here should be the gem. If it's not, fail. if(!GetIsObjectValid(oTarget)) oTarget = PRCGetSpellTargetObject(); - // Only accepts bioware gems - if (GetStringLeft(GetResRef(oTarget), 5) == "it_gem") + // Only accepts bioware gems & Craftable Natural Resources gems, but not gem dust. + int bIsBioGem = (GetStringLeft(GetResRef(oTarget), 5) == "it_gem"); + int bIsCNRGem = (GetStringLeft(GetResRef(oTarget), 6) == "cnrgem"); + int bIsDust = (GetStringLeft(GetResRef(oTarget), 10) == "cnrgemdust"); + + if (!(bIsBioGem || bIsCNRGem) || bIsDust) + { + FloatingTextStringOnCreature("Spell target is not a valid gem.", oCaster, FALSE); + return TRUE; + } + +/* if ((GetStringLeft(GetResRef(oTarget), 5) == "it_gem") || (GetStringLeft(GetResRef(oTarget), 6) == "cnrgem") && (GetStringLeft(GetResRef(oTarget), 10) != "cnrgemdust")) { FloatingTextStringOnCreature("Spell target is not a valid gem.", oCaster, FALSE); // And out we go return TRUE; - } + } */ int nCaster = GetAlternativeCasterLevel(oCaster, PRCGetCasterLevel(oCaster)); int nDC = PRCGetSaveDC(oTarget, oCaster); @@ -1952,6 +2309,19 @@ int CIGetSpellWasUsedForItemCreation(object oSpellTarget) nRet = CICraftCheckCraftStaff(oSpellTarget,oCaster); break; + case BASE_ITEM_CRAFTED_SCEPTER : + // ------------------------------------------------- + // Craft Scepter + // ------------------------------------------------- + nRet = CICraftCheckCraftScepter(oSpellTarget,oCaster); + break; + + case BASE_ITEM_MUNDANE_HERB : + // ------------------------------------------------- + // Create Infusion + // ------------------------------------------------- + nRet = CICraftCheckCreateInfusion(oSpellTarget,oCaster); + break; // you could add more crafting basetypes here.... } @@ -2740,6 +3110,16 @@ int GetMagicalArtisanFeat(int nCraftingFeat) nReturn = FEAT_MAGICAL_ARTISAN_CRAFT_SKULL_TALISMAN; break; } + case FEAT_CREATE_INFUSION: + { + nReturn = FEAT_MAGICAL_ARTISAN_CREATE_INFUSION; + break; + } + case FEAT_CRAFT_SCEPTER: + { + nReturn = FEAT_MAGICAL_ARTISAN_CRAFT_SCEPTER; + break; + } default: { if(DEBUG) DoDebug("GetMagicalArtisanFeat: invalid crafting feat"); @@ -2941,6 +3321,306 @@ int GetAlternativeCasterLevel(object oPC, int nLevel) return nLevel; } +// ----------------------------------------------------------------------------- +// Returns TRUE if the player successfully performed Create Infusion +// ----------------------------------------------------------------------------- +int CICraftCheckCreateInfusion(object oSpellTarget, object oCaster, int nID = 0) +{ + if (nID == 0) nID = PRCGetSpellId(); + + int bIsSubradial = GetIsSubradialSpell(nID); + + if(bIsSubradial) + { + nID = GetMasterSpellFromSubradial(nID); + } + + // ------------------------------------------------------------------------- + // Check if the caster has the Create Infusion feat + // ------------------------------------------------------------------------- + if (!GetHasFeat(FEAT_CREATE_INFUSION, oCaster)) + { + FloatingTextStrRefOnCreature(40487, oCaster); // Missing feat + return TRUE; + } + + // ------------------------------------------------------------------------- + // Divine spellcasters only + // ------------------------------------------------------------------------- + int nClass = PRCGetLastSpellCastClass(); + if (!GetIsDivineClass(nClass)) + { + FloatingTextStringOnCreature("Only divine casters can create infusions.", oCaster, FALSE); + return TRUE; + } + + // ------------------------------------------------------------------------- + // Check if spell is restricted for Create Infusion + // ------------------------------------------------------------------------- + if (CIGetIsSpellRestrictedFromCraftFeat(nID, X2_CI_CREATEINFUSION_FEAT_ID)) + { + FloatingTextStrRefOnCreature(83451, oCaster); // Spell not allowed + return TRUE; + } + + // ------------------------------------------------------------------------- + // Optional PnP Herb check + // ------------------------------------------------------------------------- + int bPnPHerbs = GetPRCSwitch(PRC_CREATE_INFUSION_OPTIONAL_HERBS); + if(bPnPHerbs) + { + int nSpellschool = GetSpellSchool(nID); + int nHerbSchool = GetHerbsSpellSchool(oSpellTarget); + + int nSpellLevel = PRCGetSpellLevelForClass(nID, nClass); + int nHerbLevel = GetHerbsInfusionSpellLevel(oSpellTarget); + + if(nSpellschool != nHerbSchool) + { + // Herb is for wrong spellschool + FloatingTextStringOnCreature("This herb isn't appropriate for this spell school", oCaster); + return TRUE; + } + + if(nSpellLevel > nHerbLevel) + { + // Herb spell circle level too low + FloatingTextStringOnCreature("This herb isn't appropriate for this spell level", oCaster); + return TRUE; + } + } + + // ------------------------------------------------------------------------- + // XP/GP Cost Calculation + // ------------------------------------------------------------------------- + int nLevel = CIGetSpellInnateLevel(nID, TRUE); + int nCostModifier = GetPRCSwitch(PRC_X2_CREATEINFUSION_COSTMODIFIER); + if (nCostModifier == 0) + nCostModifier = 25; + + int nCost = CIGetCraftGPCost(nLevel, nCostModifier, PRC_CREATE_INFUSION_CASTER_LEVEL); + struct craft_cost_struct costs = GetModifiedCostsFromBase(nCost, oCaster, FEAT_CREATE_INFUSION, FALSE); + + // Adjust level for metamagic + if (GetPRCSwitch(PRC_CREATE_INFUSION_CASTER_LEVEL)) + { + int nMetaMagic = PRCGetMetaMagicFeat(); + switch(nMetaMagic) + { + case METAMAGIC_EMPOWER: nLevel += 2; break; + case METAMAGIC_EXTEND: nLevel += 1; break; + case METAMAGIC_MAXIMIZE: nLevel += 3; break; + // Unsupported metamagic IPs not added + } + } + + // ------------------------------------------------------------------------- + // Check Gold + // ------------------------------------------------------------------------- + if (!GetHasGPToSpend(oCaster, costs.nGoldCost)) + { + FloatingTextStrRefOnCreature(3786, oCaster); // Not enough gold + return TRUE; + } + + // ------------------------------------------------------------------------- + // Check XP + // ------------------------------------------------------------------------- + if (!GetHasXPToSpend(oCaster, costs.nXPCost)) + { + FloatingTextStrRefOnCreature(3785, oCaster); // Not enough XP + return TRUE; + } + + // ------------------------------------------------------------------------- + // Check alternative spell emulation requirements + // ------------------------------------------------------------------------- + if (!CheckAlternativeCrafting(oCaster, nID, costs)) + { + FloatingTextStringOnCreature("*Crafting failed!*", oCaster, FALSE); + return TRUE; + } + + // ------------------------------------------------------------------------- + // Create the infused herb item + // ------------------------------------------------------------------------- + object oInfusion = CICreateInfusion(oCaster, nID); + + if (GetIsObjectValid(oInfusion)) + { + // Get the spell's display name from spells.2da via TLK + int nNameStrRef = StringToInt(Get2DAString("spells", "Name", nID)); + string sSpellName = GetStringByStrRef(nNameStrRef); + + // Rename the item + string sNewName = "Infusion of " + sSpellName; + SetName(oInfusion, sNewName); + + // Post-creation actions + SetIdentified(oInfusion, TRUE); + ActionPlayAnimation(ANIMATION_FIREFORGET_READ, 1.0); + SpendXP(oCaster, costs.nXPCost); + SpendGP(oCaster, costs.nGoldCost); + DestroyObject(oSpellTarget); + FloatingTextStrRefOnCreature(8502, oCaster); // Item creation successful + + if (!costs.nTimeCost) costs.nTimeCost = 1; + AdvanceTimeForPlayer(oCaster, RoundsToSeconds(costs.nTimeCost)); + return TRUE; + } + else + { + FloatingTextStringOnCreature("Infusion creation failed", oCaster); // Item creation failed + FloatingTextStrRefOnCreature(76417, oCaster); // Item creation failed + return TRUE; + } + +/* // ------------------------------------------------------------------------- + // Create the infused herb item + // ------------------------------------------------------------------------- + object oInfusion = CICreateInfusion(oCaster, nID); + + if (GetIsObjectValid(oInfusion)) + { + SetIdentified(oInfusion, TRUE); + ActionPlayAnimation(ANIMATION_FIREFORGET_READ, 1.0); + SpendXP(oCaster, costs.nXPCost); + SpendGP(oCaster, costs.nGoldCost); + DestroyObject(oSpellTarget); + FloatingTextStrRefOnCreature(8502, oCaster); // Item creation successful + + if (!costs.nTimeCost) costs.nTimeCost = 1; + AdvanceTimeForPlayer(oCaster, RoundsToSeconds(costs.nTimeCost)); + return TRUE; + } + else + { + FloatingTextStringOnCreature("Infusion creation failed", oCaster); // Item creation failed + FloatingTextStrRefOnCreature(76417, oCaster); // Item creation failed + return TRUE; + } */ + + return FALSE; +} + +// ----------------------------------------------------------------------------- +// Create and return an herbal infusion with an item property matching nSpellID +// ----------------------------------------------------------------------------- +object CICreateInfusion(object oCreator, int nSpellID) +{ + if (DEBUG) DoDebug("prc_x2_craft >> CICreateInfusion: Entering function"); + + // Keep the original spell id the engine gave us (may be a subradial) + int nSpellOriginal = nSpellID; + if (DEBUG) DoDebug("prc_x2_craft >> CICreateInfusion: nSpellOriginal is "+IntToString(nSpellOriginal)+"."); + + // Compute the master if this is a subradial. Keep original intact. + int nSpellMaster = nSpellOriginal; + if (GetIsSubradialSpell(nSpellOriginal)) + { + nSpellMaster = GetMasterSpellFromSubradial(nSpellOriginal); + if (DEBUG) DoDebug("CICreateInfusion: detected subradial " + IntToString(nSpellOriginal) + " master -> " + IntToString(nSpellMaster)); + } + if (DEBUG) DoDebug("prc_x2_craft >> CICreateInfusion: nSpellMaster is "+IntToString(nSpellMaster)+"."); + + // Try to find an iprp_spells row for the original subradial first (preferred). + int nPropID = IPGetIPConstCastSpellFromSpellID(nSpellOriginal); + int nSpellUsedForIP = nSpellOriginal; + + // If not found for original, fall back to the master/base spell. + if (nPropID < 0) + { + if (DEBUG) DoDebug("CICreateInfusion: no iprp row for original " + IntToString(nSpellOriginal) + ", trying master " + IntToString(nSpellMaster)); + nPropID = IPGetIPConstCastSpellFromSpellID(nSpellMaster); + nSpellUsedForIP = nSpellMaster; + } + + // If still invalid, bail out with a helpful message + if (nPropID < 0) + { + if (DEBUG) DoDebug("CICreateInfusion: No iprp_spells entry for either original " + IntToString(nSpellOriginal) + " or master " + IntToString(nSpellMaster)); + FloatingTextStringOnCreature("This spell cannot be infused (no item property mapping).", oCreator, FALSE); + return OBJECT_INVALID; + } + + if (DEBUG) DoDebug("CICreateInfusion: using spell " + IntToString(nSpellUsedForIP) + " (iprp row " + IntToString(nPropID) + ") for item property"); + + // Optional: check for material component (use the resolved iprp row) + string sMat = GetMaterialComponentTag(nPropID); + if (sMat != "") + { + object oMat = GetItemPossessedBy(oCreator, sMat); + if (oMat == OBJECT_INVALID) + { + FloatingTextStrRefOnCreature(83374, oCreator); // Missing material component + return OBJECT_INVALID; + } + else + { + DestroyObject(oMat); + } + } + + // Only allow divine spellcasters + int nClass = PRCGetLastSpellCastClass(); + if (!GetIsDivineClass(nClass)) + { + FloatingTextStringOnCreature("Only divine casters can use Create Infusion.", oCreator, FALSE); + return OBJECT_INVALID; + } + + // Create base infusion item (herb) + string sResRef = "prc_infusion_000"; + object oTarget = CreateItemOnObject(sResRef, oCreator); + if (oTarget == OBJECT_INVALID) + { + WriteTimestampedLogEntry("Create Infusion failed: couldn't create item with resref " + sResRef); + return OBJECT_INVALID; + } + + // Confirm that the item is a herb + int nBaseItem = GetBaseItemType(oTarget); + if (nBaseItem != BASE_ITEM_INFUSED_HERB) + { + FloatingTextStringOnCreature("Only herbs may be infused.", oCreator, FALSE); + DestroyObject(oTarget); + return OBJECT_INVALID; + } + + // Remove all non-material item properties from the herb + itemproperty ipRemove = GetFirstItemProperty(oTarget); + while (GetIsItemPropertyValid(ipRemove)) + { + itemproperty ipNext = GetNextItemProperty(oTarget); + if (GetItemPropertyType(ipRemove) != ITEM_PROPERTY_MATERIAL) + RemoveItemProperty(oTarget, ipRemove); + ipRemove = ipNext; + } + + // Add the cast-spell itemproperty using the iprp row we resolved + itemproperty ipSpell = ItemPropertyCastSpell(nPropID, IP_CONST_CASTSPELL_NUMUSES_SINGLE_USE); + AddItemProperty(DURATION_TYPE_PERMANENT, ipSpell, oTarget); + + // Optional PRC casting metadata: use the SAME spell id that matched the iprp row + // so caster level/DC/meta line up with the actual cast property on the item. + if (GetPRCSwitch(PRC_CREATE_INFUSION_CASTER_LEVEL)) + { + int nCasterLevel = GetAlternativeCasterLevel(oCreator, PRCGetCasterLevel(oCreator)); + // nSpellUsedForIP is either original (if that had an iprp row) or the master (fallback) + itemproperty ipLevel = ItemPropertyCastSpellCasterLevel(nSpellUsedForIP, nCasterLevel); + AddItemProperty(DURATION_TYPE_PERMANENT, ipLevel, oTarget); + + itemproperty ipMeta = ItemPropertyCastSpellMetamagic(nSpellUsedForIP, PRCGetMetaMagicFeat()); + AddItemProperty(DURATION_TYPE_PERMANENT, ipMeta, oTarget); + + int nDC = PRCGetSpellSaveDC(nSpellUsedForIP, GetSpellSchool(nSpellUsedForIP), OBJECT_SELF); + itemproperty ipDC = ItemPropertyCastSpellDC(nSpellUsedForIP, nDC); + AddItemProperty(DURATION_TYPE_PERMANENT, ipDC, oTarget); + } + + return oTarget; +} + // Test main -//void main(){} +// void main(){} diff --git a/src/include/prc_x2_itemprop.nss b/src/include/prc_x2_itemprop.nss index e4a1be0..1abf20c 100644 --- a/src/include/prc_x2_itemprop.nss +++ b/src/include/prc_x2_itemprop.nss @@ -20,9 +20,6 @@ //:: Last Update: 2003-10-07 //::////////////////////////////////////////////// -//:: Test void -//:: void main (){} - //Changed by primogenitor to include CEP itemtypes // * The tag of the ip work container, a placeable which has to be set into each @@ -697,6 +694,7 @@ if(nItem == BASE_ITEM_BASTARDSWORD || nItem == BASE_ITEM_SICKLE || nItem == BASE_ITEM_TWOBLADEDSWORD || nItem == BASE_ITEM_CLUB + || nItem == BASE_ITEM_CRAFTED_SCEPTER || nItem == BASE_ITEM_DAGGER || nItem == BASE_ITEM_DIREMACE || nItem == BASE_ITEM_HEAVYFLAIL @@ -729,6 +727,7 @@ if(nItem == BASE_ITEM_BASTARDSWORD || nItem == BASE_ITEM_ELVEN_THINBLADE || nItem == BASE_ITEM_ELVEN_COURTBLADE || nItem == BASE_ITEM_CRAFTED_STAFF + || nItem == BASE_ITEM_CRAFTED_SCEPTER || nItem == 300 //CEP Trident || nItem == 303 //CEP Sai || nItem == 304 //CEP nunchaku @@ -768,7 +767,6 @@ int IPGetIsBludgeoningWeapon(object oItem) // ---------------------------------------------------------------------------- // Return the IP_CONST_CASTSPELL_* ID matching to the SPELL_* constant given // in nSPELL_ID. -// This uses Get2DAstring, so it is slow. Avoid using in loops! // returns -1 if there is no matching property for a spell // ---------------------------------------------------------------------------- int IPGetIPConstCastSpellFromSpellID(int nSpellID) @@ -1613,31 +1611,140 @@ int IPGetDamageBonusConstantFromNumber(int nNumber) // oOld - Item equipped before polymorphing (source for item props) // oNew - Item equipped after polymorphing (target for item props) // bWeapon - Must be set TRUE when oOld is a weapon. -// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- void IPWildShapeCopyItemProperties(object oOld, object oNew, int bWeapon = FALSE) { - if (GetIsObjectValid(oOld) && GetIsObjectValid(oNew)) - { - itemproperty ip = GetFirstItemProperty(oOld); - while (GetIsItemPropertyValid(ip)) - { - if (bWeapon) - { - if (GetWeaponRanged(oOld) == GetWeaponRanged(oNew) ) - { - AddItemProperty(DURATION_TYPE_PERMANENT,ip,oNew); - } - } - else - { - AddItemProperty(DURATION_TYPE_PERMANENT,ip,oNew); - } - ip = GetNextItemProperty(oOld); + // Invalid source/target + if (!GetIsObjectValid(oOld) || !GetIsObjectValid(oNew)) + return; + + // Determine possessor + object oPC = GetItemPossessor(oOld); + if (!GetIsObjectValid(oPC)) + oPC = GetItemPossessor(oNew); - } - } + if (!GetIsObjectValid(oPC)) + { + if (DEBUG) DoDebug("IPWS: Unable to determine item possessor"); + return; + } + + // Determine glove state once + int bMonkGloves = GetLocalInt(oPC, "WEARING_MONK_GLOVES"); + + // Weapon ranged mismatch = do nothing (intent is no partial copy) + if (bWeapon && GetWeaponRanged(oOld) != GetWeaponRanged(oNew)) + { + if (DEBUG) DoDebug("IPWS: Weapon ranged mismatch — skipping all IP copy"); + return; + } + + // Begin property copy + itemproperty ip = GetFirstItemProperty(oOld); + while (GetIsItemPropertyValid(ip)) + { + int nType = GetItemPropertyType(ip); + + // If copying from gloves and monk gloves are active + if (bMonkGloves + && (nType == ITEM_PROPERTY_DAMAGE_BONUS + || nType == ITEM_PROPERTY_DAMAGE_BONUS_VS_RACIAL_GROUP + || nType == ITEM_PROPERTY_DAMAGE_BONUS_VS_ALIGNMENT_GROUP)) + { + // Always apply glove damage IPs + AddItemProperty(DURATION_TYPE_PERMANENT, ip, oNew); + ip = GetNextItemProperty(oOld); + continue; + } + + // Normal weapon pass + if (bWeapon) + { + // If monk gloves active ? skip ALL weapon damage IPs + if (bMonkGloves + && (nType == ITEM_PROPERTY_DAMAGE_BONUS + || nType == ITEM_PROPERTY_DAMAGE_BONUS_VS_RACIAL_GROUP + || nType == ITEM_PROPERTY_DAMAGE_BONUS_VS_ALIGNMENT_GROUP)) + { + ip = GetNextItemProperty(oOld); + continue; + } + + AddItemProperty(DURATION_TYPE_PERMANENT, ip, oNew); + } + else + { + AddItemProperty(DURATION_TYPE_PERMANENT, ip, oNew); + } + + ip = GetNextItemProperty(oOld); + } } + +/* // ---------------------------------------------------------------------------- +// GZ, Sept. 30 2003 +// Special Version of Copy Item Properties for use with greater wild shape +// oOld - Item equipped before polymorphing (source for item props) +// oNew - Item equipped after polymorphing (target for item props) +// bWeapon - Must be set TRUE when oOld is a weapon. +// ---------------------------------------------------------------------------- +void IPWildShapeCopyItemProperties(object oOld, object oNew, int bWeapon = FALSE) +{ + if (!GetIsObjectValid(oOld) || !GetIsObjectValid(oNew)) + return; + + object oPC = GetItemPossessor(oOld); + if (!GetIsObjectValid(oPC)) + { + oPC = GetItemPossessor(oNew); + } + if (!GetIsObjectValid(oPC)) + { + if (DEBUG) DoDebug("IPWS: Unable to determine item possessor"); + return; + } + + int bMonkGloves = GetLocalInt(oPC, "WEARING_MONK_GLOVES"); + + itemproperty ip = GetFirstItemProperty(oOld); + while (GetIsItemPropertyValid(ip)) + { + if (bWeapon) + { + // Gloves override weapon damage — skip weapon damage properties + if (bMonkGloves) + { + int nType = GetItemPropertyType(ip); + + // skip damage props + if (nType == ITEM_PROPERTY_DAMAGE_BONUS + || nType == ITEM_PROPERTY_DAMAGE_BONUS_VS_RACIAL_GROUP + || nType == ITEM_PROPERTY_DAMAGE_BONUS_VS_ALIGNMENT_GROUP) + { + if (DEBUG) DoDebug("IPWS: SKIPPED weapon damage IP"); + } + else + { + if (DEBUG) DoDebug("IPWS: Applied non-damage weapon IP"); + AddItemProperty(DURATION_TYPE_PERMANENT, ip, oNew); + } + + } + else if (GetWeaponRanged(oOld) == GetWeaponRanged(oNew) ) + { + AddItemProperty(DURATION_TYPE_PERMANENT,ip,oNew); + } + } + else + { + AddItemProperty(DURATION_TYPE_PERMANENT,ip,oNew); + } + + ip = GetNextItemProperty(oOld); + } +} */ + // ---------------------------------------------------------------------------- // Returns the current enhancement bonus of a weapon (+1 to +20), 0 if there is // no enhancement bonus. You can test for a specific type of enhancement bonus @@ -1883,7 +1990,7 @@ int IPDamageConstant(int nDamBon) case 49: nIPBonus = IP_CONST_DAMAGEBONUS_49; break; case 50: nIPBonus = IP_CONST_DAMAGEBONUS_50; break; } - if (nDamBon > 20) nIPBonus = IP_CONST_DAMAGEBONUS_50; + if (nDamBon > 50) nIPBonus = IP_CONST_DAMAGEBONUS_50; return nIPBonus; } @@ -2019,4 +2126,6 @@ int IPOnHitSaveDC(int nSaveDC) if (nSaveDC > 26) nIPBonus = IP_CONST_ONHIT_SAVEDC_26; return nIPBonus; -} */ \ No newline at end of file +} */ + +//:: void main(){} \ No newline at end of file diff --git a/src/include/prcsp_archmaginc.nss b/src/include/prcsp_archmaginc.nss index 4287a19..72e5d44 100644 --- a/src/include/prcsp_archmaginc.nss +++ b/src/include/prcsp_archmaginc.nss @@ -73,6 +73,7 @@ void SetMasteryOfElements(); //#include "lookup_2da_spell" #include "prcsp_reputation" +#include "prc_inc_core" //#include "prc_inc_spells" diff --git a/src/include/psi_inc_ac_spawn.nss b/src/include/psi_inc_ac_spawn.nss index 5b3947e..43765dd 100644 --- a/src/include/psi_inc_ac_spawn.nss +++ b/src/include/psi_inc_ac_spawn.nss @@ -11,6 +11,7 @@ #include "prc_ipfeat_const" #include "prc_feat_const" #include "inc_vfx_const" +#include "prc_inc_nwscript" ////////////////////////////////////////////////// diff --git a/src/include/psi_inc_core.nss b/src/include/psi_inc_core.nss index 9083bee..b4ca245 100644 --- a/src/include/psi_inc_core.nss +++ b/src/include/psi_inc_core.nss @@ -41,6 +41,8 @@ const int POWER_LIST_WARMIND = CLASS_TYPE_WARMIND; /* Function prototypes */ ////////////////////////////////////////////////// +int IsHiddenTalent(object oPC = OBJECT_SELF); + /** * Attempts to use psionic focus. If the creature was focused, it * loses the focus. If it has Epic Psionic Focus feats, it will @@ -520,9 +522,9 @@ void GainPsionicFocus(object oGainee = OBJECT_SELF) { int nPsySneak = 1; if(GetHasFeat(FEAT_PSY_SNEAK_ATTACK_2d6, oGainee)) - nPsySneak += 2; + nPsySneak += 1; if(GetHasFeat(FEAT_PSY_SNEAK_ATTACK_3d6, oGainee)) - nPsySneak += 3; + nPsySneak += 1; SetLocalInt(oGainee, "PsyRogueSneak",nPsySneak); DelayCommand(0.1, ExecuteScript("prc_sneak_att", oGainee)); @@ -786,69 +788,12 @@ int GetIsPsionicCharacter(object oCreature) GetHasFeat(FEAT_KALASHTAR_PP, oCreature) || GetHasFeat(FEAT_NATPSIONIC_1, oCreature) || GetHasFeat(FEAT_NATPSIONIC_2, oCreature) || - GetHasFeat(FEAT_NATPSIONIC_3, oCreature) + GetHasFeat(FEAT_NATPSIONIC_3, oCreature) || + IsHiddenTalent(oCreature) // Racial psionicity signifying feats go here ); } -int IsHiddenTalent(object oPC = OBJECT_SELF) -{ - if (GetHasFeat(FEAT_HIDDEN_TALENT_BIOFEEDBACK, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_BITE_WOLF, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_BOLT, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_BURST, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_CALLTOMIND, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_CALL_WEAPONRY, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_CHAMELEON, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_CLAWS_BEAST, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_COMPRESSION, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_CONCEALTHOUGHT, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_CREATESOUND, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_CRYSTALSHARD, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_DAZE, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_DECELERATION, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_DEFPRECOG, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_DEMORALIZE, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_DISABLE, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_DISSIPATINGTOUCH, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_DISTRACT, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_ELFSIGHT, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_EMPATHY, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_EMPTYMIND, oPC) || - //GetHasFeat(FEAT_HIDDEN_TALENT_ENERGYRAY, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_ENTANGLE, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_EXPANSION, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_FARHAND, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_FORCESCREEN, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_GREASE, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_HAMMER, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_INERTIALARMOUR, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_MATTERAGITATION, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_METAPHYSICAL_CLAW, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_METAPHYSICAL_WEAPON, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_MINDTHRUST, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_MYLIGHT, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_OFFPRECOG, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_OFFPRESC, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_PREVENOM, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_PREVENOM_WEAPON, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_SKATE, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_STOMP, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_SYNESTHETE, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_TELEMPATHICPRO, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_THICKSKIN, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_VIGOR, oPC) || - GetHasFeat(FEAT_HIDDEN_TALENT_GRIP_IRON, oPC)) - { - return TRUE; - } - else - { - return FALSE; - } -} - - void LocalCleanExtraFists(object oCreature) { int iIsCWeap, iIsEquip; @@ -985,6 +930,48 @@ int PracticedManifesting(object oManifester, int iManifestingClass, int iManifes int GetManifesterLevel(object oManifester, int nSpecificClass = CLASS_TYPE_INVALID, int nMaxPowerLevel = FALSE) { + // Handle POWER_LIST_MISC (Hidden Talent) powers + // Check if this is a power list call + int nPowerType = GetLocalInt(oManifester, "PRC_UsePowerList"); + + if(nSpecificClass == CLASS_TYPE_INVALID && nPowerType == POWER_LIST_MISC) + { + if(DEBUG) DoDebug("psi_inc_core >> GetManifesterLevel: CLASS_TYPE_INVALID + POWER_LIST_MISC found!"); + // Check if character has psionic class levels + int nPsionLevel = GetLevelByClass(CLASS_TYPE_PSION, oManifester); + int nPsywarLevel = GetLevelByClass(CLASS_TYPE_PSYWAR, oManifester); + int nWilderLevel = GetLevelByClass(CLASS_TYPE_WILDER, oManifester); + int nWarmindLevel = GetLevelByClass(CLASS_TYPE_WARMIND, oManifester); + int nFistOfZuokenLevel = GetLevelByClass(CLASS_TYPE_FIST_OF_ZUOKEN, oManifester); + int nPsychicRogueLevel = GetLevelByClass(CLASS_TYPE_PSYCHIC_ROGUE, oManifester); + + // If no psionic levels, use Charisma-based calculation (treat as 1st level) + if(nPsionLevel + nPsywarLevel + nWilderLevel + nWarmindLevel + + nFistOfZuokenLevel + nPsychicRogueLevel == 0) + { + // Hidden Talent: considered 1st-level manifester, but must have CHA 11+ + if(DEBUG) DoDebug("psi_inc_core >> GetManifesterLevel: Hidden Talent found!"); + if(GetAbilityScore(oManifester, ABILITY_CHARISMA) >= 11) + return 1; + else + return 0; // Cannot manifest without CHA 11+ + } + + if(DEBUG) DoDebug("psi_inc_core >> GetManifesterLevel: nSpecificClass=" + IntToString(nSpecificClass) + + ", nPowerType=" + IntToString(nPowerType)); + + // Has psionic levels - return highest manifester level + int nHighest = 0; + if(nPsionLevel > 0) nHighest = GetManifesterLevel(oManifester, CLASS_TYPE_PSION); + if(nPsywarLevel > 0) nHighest = PRCMax(nHighest, GetManifesterLevel(oManifester, CLASS_TYPE_PSYWAR)); + if(nWilderLevel > 0) nHighest = PRCMax(nHighest, GetManifesterLevel(oManifester, CLASS_TYPE_WILDER)); + if(nWarmindLevel > 0) nHighest = PRCMax(nHighest, GetManifesterLevel(oManifester, CLASS_TYPE_WARMIND)); + if(nFistOfZuokenLevel > 0) nHighest = PRCMax(nHighest, GetManifesterLevel(oManifester, CLASS_TYPE_FIST_OF_ZUOKEN)); + if(nPsychicRogueLevel > 0) nHighest = PRCMax(nHighest, GetManifesterLevel(oManifester, CLASS_TYPE_PSYCHIC_ROGUE)); + + return nHighest; + } + int nLevel; int nAdjust = GetLocalInt(oManifester, PRC_CASTERLEVEL_ADJUSTMENT); nAdjust -= GetLocalInt(oManifester, "WoLManifPenalty"); @@ -1049,17 +1036,27 @@ int GetManifesterLevel(object oManifester, int nSpecificClass = CLASS_TYPE_INVAL DelayCommand(1.0, DeleteLocalInt(oManifester, PRC_CASTERLEVEL_OVERRIDE)); nLevel = GetLocalInt(oManifester, PRC_CASTERLEVEL_OVERRIDE); - } - else if(GetManifestingClass(oManifester) != CLASS_TYPE_INVALID) - { - //Gets the manifesting class - int nManifestingClass = GetManifestingClass(oManifester); - if(DEBUG) DoDebug("Manifesting Class #2: " + IntToString(nManifestingClass), oManifester); - nLevel = GetLevelByClass(nManifestingClass, oManifester); - // Add levels from +ML PrCs only for the first manifesting class - nLevel += GetPsionicPRCLevels(oManifester, nManifestingClass); - //nLevel += nManifestingClass == GetPrimaryPsionicClass(oManifester) ? GetPsionicPRCLevels(oManifester) : 0; - + } + else if(GetManifestingClass(oManifester) != CLASS_TYPE_INVALID) + { + //Gets the manifesting class + int nManifestingClass = GetManifestingClass(oManifester); + if(DEBUG) DoDebug("Manifesting Class #2: " + IntToString(nManifestingClass), oManifester); + + nLevel = GetLevelByClass(nManifestingClass, oManifester); + // Add levels from +ML PrCs only for the first manifesting class + nLevel += GetPsionicPRCLevels(oManifester, nManifestingClass); + + // CHECK: If this is Hidden Talent and character has no levels, set to 1 + if(nLevel == 0 && GetLocalInt(oManifester, "PRC_UsePowerList") == TRUE && + GetLocalInt(oManifester, "PRC_PowerListType") == POWER_LIST_MISC) + { + if(GetAbilityScore(oManifester, ABILITY_CHARISMA) >= 11) + { + if(DEBUG) DoDebug("GetManifesterLevel: Hidden Talent with no psionic levels, returning 1"); + nLevel = 1; + } + } // Psionic vestiges are tucked in here to override things. // This assumes that there will never be a psion with this spell effect manifesting things if (nManifestingClass == CLASS_TYPE_PSION && GetHasSpellEffect(VESTIGE_ARETE, oManifester) && !nMaxPowerLevel) @@ -1085,7 +1082,37 @@ int GetManifesterLevel(object oManifester, int nSpecificClass = CLASS_TYPE_INVAL // if(DEBUG) DoDebug("Level gotten via GetLevelByClass: " + IntToString(nLevel), oManifester); } - // If you have a primary psionic class and no manifester level yet, get levels based on that + // If you have a primary psionic class and no manifester level yet, get levels based on that + if (GetPrimaryPsionicClass(oManifester) && nLevel == 0) + { + int nClass = GetPrimaryPsionicClass(oManifester); + nLevel = GetLevelByClass(nClass, oManifester); + nLevel += GetPsionicPRCLevels(oManifester, nClass); + nLevel += PracticedManifesting(oManifester, nClass, nLevel); + } + + // If everything else fails, check for Hidden Talent before returning 0 + if(nLevel == 0) + { + // Check if this is a Hidden Talent power + if(GetLocalInt(oManifester, "PRC_UsePowerList") == POWER_LIST_MISC) + { + // Hidden Talent: manifester level is 1 if they have CHA 11+ + if(GetAbilityScore(oManifester, ABILITY_CHARISMA) >= 11) + { + if(DEBUG) DoDebug("GetManifesterLevel: Hidden Talent character, returning level 1"); + return 1; + } + } + + if(DEBUG) DoDebug("Failed to get manifester level for creature " + DebugObject2Str(oManifester) + ", using first class slot"); + //else WriteTimestampedLogEntry("Failed to get manifester level for creature " + DebugObject2Str(oManifester) + ", using first class slot"); + + return 0; + } + + +/* // If you have a primary psionic class and no manifester level yet, get levels based on that if (GetPrimaryPsionicClass(oManifester) && nLevel == 0) { int nClass = GetPrimaryPsionicClass(oManifester); @@ -1102,7 +1129,7 @@ int GetManifesterLevel(object oManifester, int nSpecificClass = CLASS_TYPE_INVAL return 0; } - + */ // The bonuses inside only apply to normal manifestation if(!GetLocalInt(oManifester, PRC_IS_PSILIKE)) @@ -1665,4 +1692,225 @@ int GetMaxPowerLevel(object oManifester) int nMax = StringToInt(Get2DACache(sFile, "MaxPowerLevel", nLevel)); if (DEBUG) DoDebug("GetMaxPowerLevel is "+IntToString(nMax)); return nMax; -} \ No newline at end of file +} + +////////////////////////////////////////////////////// +/* START HIDDEN TALENT */ +////////////////////////////////////////////////////// + +int IsHiddenTalent(object oPC = OBJECT_SELF) +{ + if (GetHasFeat(FEAT_HIDDEN_TALENT_BIOFEEDBACK, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_BITE_WOLF, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_BOLT, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_BURST, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_CALLTOMIND, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_CALL_WEAPONRY, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_CHAMELEON, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_CLAWS_BEAST, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_COMPRESSION, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_CONCEALTHOUGHT, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_CREATESOUND, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_CRYSTALSHARD, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_DAZE, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_DECELERATION, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_DEFPRECOG, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_DEMORALIZE, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_DISABLE, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_DISSIPATINGTOUCH, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_DISTRACT, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_ELFSIGHT, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_EMPATHY, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_EMPTYMIND, oPC) || + //GetHasFeat(FEAT_HIDDEN_TALENT_ENERGYRAY, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_ENTANGLE, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_EXPANSION, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_FARHAND, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_FORCESCREEN, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_GREASE, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_HAMMER, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_INERTIALARMOUR, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_MATTERAGITATION, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_METAPHYSICAL_CLAW, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_METAPHYSICAL_WEAPON, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_MINDTHRUST, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_MYLIGHT, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_OFFPRECOG, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_OFFPRESC, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_PREVENOM, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_PREVENOM_WEAPON, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_SKATE, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_STOMP, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_SYNESTHETE, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_TELEMPATHICPRO, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_THICKSKIN, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_VIGOR, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_GRIP_IRON, oPC)) + { + return TRUE; + } + else + { + return FALSE; + } +} + +int GetHiddenTalentPowerFromFeat(int nFeatID) +{ + // Map Hidden Talent feats to their corresponding power IDs + // Using the same mappings as GetIsHiddenTalentPower() + if(nFeatID == FEAT_HIDDEN_TALENT_BIOFEEDBACK) return POWER_BIOFEEDBACK; + if(nFeatID == FEAT_HIDDEN_TALENT_BITE_WOLF) return POWER_BITE_WOLF; + if(nFeatID == FEAT_HIDDEN_TALENT_BOLT) return POWER_BOLT; + if(nFeatID == FEAT_HIDDEN_TALENT_BURST) return POWER_BURST; + if(nFeatID == FEAT_HIDDEN_TALENT_CALLTOMIND) return POWER_CALLTOMIND; + if(nFeatID == FEAT_HIDDEN_TALENT_CALL_WEAPONRY) return POWER_CALL_WEAPONRY; + if(nFeatID == FEAT_HIDDEN_TALENT_CHAMELEON) return POWER_CHAMELEON; + if(nFeatID == FEAT_HIDDEN_TALENT_CLAWS_BEAST) return POWER_CLAWS_BEAST; + if(nFeatID == FEAT_HIDDEN_TALENT_COMPRESSION) return POWER_COMPRESSION; + if(nFeatID == FEAT_HIDDEN_TALENT_CONCEALTHOUGHT) return POWER_CONCEALTHOUGHT; + if(nFeatID == FEAT_HIDDEN_TALENT_CREATESOUND) return POWER_CREATESOUND; + if(nFeatID == FEAT_HIDDEN_TALENT_CRYSTALSHARD) return POWER_CRYSTALSHARD; + if(nFeatID == FEAT_HIDDEN_TALENT_DAZE) return POWER_DAZE; + if(nFeatID == FEAT_HIDDEN_TALENT_DECELERATION) return POWER_DECELERATION; + if(nFeatID == FEAT_HIDDEN_TALENT_DEFPRECOG) return POWER_DEFPRECOG; + if(nFeatID == FEAT_HIDDEN_TALENT_DEMORALIZE) return POWER_DEMORALIZE; + if(nFeatID == FEAT_HIDDEN_TALENT_DISABLE) return POWER_DISABLE; + if(nFeatID == FEAT_HIDDEN_TALENT_DISSIPATINGTOUCH)return POWER_DISSIPATINGTOUCH; + if(nFeatID == FEAT_HIDDEN_TALENT_DISTRACT) return POWER_DISTRACT; + if(nFeatID == FEAT_HIDDEN_TALENT_ELFSIGHT) return POWER_ELFSIGHT; + if(nFeatID == FEAT_HIDDEN_TALENT_EMPATHY) return POWER_EMPATHY; + if(nFeatID == FEAT_HIDDEN_TALENT_EMPTYMIND) return POWER_EMPTYMIND; + if(nFeatID == FEAT_HIDDEN_TALENT_ENTANGLE) return POWER_ENTANGLE; + if(nFeatID == FEAT_HIDDEN_TALENT_EXPANSION) return POWER_EXPANSION; + if(nFeatID == FEAT_HIDDEN_TALENT_FARHAND) return POWER_FARHAND; + if(nFeatID == FEAT_HIDDEN_TALENT_FORCESCREEN) return POWER_FORCESCREEN; + if(nFeatID == FEAT_HIDDEN_TALENT_GREASE) return POWER_GREASE; + if(nFeatID == FEAT_HIDDEN_TALENT_HAMMER) return POWER_HAMMER; + if(nFeatID == FEAT_HIDDEN_TALENT_INERTIALARMOUR) return POWER_INERTIALARMOUR; + if(nFeatID == FEAT_HIDDEN_TALENT_MATTERAGITATION) return POWER_MATTERAGITATION; + if(nFeatID == FEAT_HIDDEN_TALENT_METAPHYSICAL_CLAW) return POWER_METAPHYSICAL_CLAW; + if(nFeatID == FEAT_HIDDEN_TALENT_METAPHYSICAL_WEAPON) return POWER_METAPHYSICAL_WEAPON; + if(nFeatID == FEAT_HIDDEN_TALENT_MINDTHRUST) return POWER_MINDTHRUST; + if(nFeatID == FEAT_HIDDEN_TALENT_MYLIGHT) return POWER_MYLIGHT; + if(nFeatID == FEAT_HIDDEN_TALENT_OFFPRECOG) return POWER_OFFPRECOG; + if(nFeatID == FEAT_HIDDEN_TALENT_OFFPRESC) return POWER_OFFPRESC; + if(nFeatID == FEAT_HIDDEN_TALENT_PREVENOM) return POWER_PREVENOM; + if(nFeatID == FEAT_HIDDEN_TALENT_PREVENOM_WEAPON) return POWER_PREVENOM_WEAPON; + if(nFeatID == FEAT_HIDDEN_TALENT_SKATE) return POWER_SKATE; + if(nFeatID == FEAT_HIDDEN_TALENT_STOMP) return POWER_STOMP; + if(nFeatID == FEAT_HIDDEN_TALENT_SYNESTHETE) return POWER_SYNESTHETE; + if(nFeatID == FEAT_HIDDEN_TALENT_TELEMPATHICPRO) return POWER_TELEMPATHICPRO; + if(nFeatID == FEAT_HIDDEN_TALENT_THICKSKIN) return POWER_THICKSKIN; + if(nFeatID == FEAT_HIDDEN_TALENT_VIGOR) return POWER_VIGOR; + if(nFeatID == FEAT_HIDDEN_TALENT_GRIP_IRON) return POWER_GRIP_IRON; + + return -1; // Not found +} + +int GetHiddenTalentCount(object oPC = OBJECT_SELF) +{ + int nCount = 0; + + if (GetHasFeat(FEAT_HIDDEN_TALENT_BIOFEEDBACK, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_BITE_WOLF, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_BOLT, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_BURST, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_CALLTOMIND, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_CALL_WEAPONRY, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_CHAMELEON, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_CLAWS_BEAST, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_COMPRESSION, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_CONCEALTHOUGHT, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_CREATESOUND, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_CRYSTALSHARD, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_DAZE, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_DECELERATION, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_DEFPRECOG, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_DEMORALIZE, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_DISABLE, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_DISSIPATINGTOUCH, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_DISTRACT, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_ELFSIGHT, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_EMPATHY, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_EMPTYMIND, oPC)) nCount++; + //if (GetHasFeat(FEAT_HIDDEN_TALENT_ENERGYRAY, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_ENTANGLE, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_EXPANSION, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_FARHAND, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_FORCESCREEN, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_GREASE, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_HAMMER, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_INERTIALARMOUR, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_MATTERAGITATION, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_METAPHYSICAL_CLAW, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_METAPHYSICAL_WEAPON, oPC))nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_MINDTHRUST, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_MYLIGHT, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_OFFPRECOG, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_OFFPRESC, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_PREVENOM, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_PREVENOM_WEAPON, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_SKATE, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_STOMP, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_SYNESTHETE, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_TELEMPATHICPRO, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_THICKSKIN, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_VIGOR, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_GRIP_IRON, oPC)) nCount++; + + return nCount; +} + +int GetIsHiddenTalentPower(object oPC, int nPower) +{ + // Check each Hidden Talent feat to see if it grants this power + if(nPower == POWER_BIOFEEDBACK && GetHasFeat(FEAT_HIDDEN_TALENT_BIOFEEDBACK, oPC)) return TRUE; + if(nPower == POWER_BITE_WOLF && GetHasFeat(FEAT_HIDDEN_TALENT_BITE_WOLF, oPC)) return TRUE; + if(nPower == POWER_BOLT && GetHasFeat(FEAT_HIDDEN_TALENT_BOLT, oPC)) return TRUE; + if(nPower == POWER_BURST && GetHasFeat(FEAT_HIDDEN_TALENT_BURST, oPC)) return TRUE; + if(nPower == POWER_CALLTOMIND && GetHasFeat(FEAT_HIDDEN_TALENT_CALLTOMIND, oPC)) return TRUE; + if(nPower == POWER_CALL_WEAPONRY && GetHasFeat(FEAT_HIDDEN_TALENT_CALL_WEAPONRY, oPC)) return TRUE; + if(nPower == POWER_CHAMELEON && GetHasFeat(FEAT_HIDDEN_TALENT_CHAMELEON, oPC)) return TRUE; + if(nPower == POWER_CLAWS_BEAST && GetHasFeat(FEAT_HIDDEN_TALENT_CLAWS_BEAST, oPC)) return TRUE; + if(nPower == POWER_COMPRESSION && GetHasFeat(FEAT_HIDDEN_TALENT_COMPRESSION, oPC)) return TRUE; + if(nPower == POWER_CONCEALTHOUGHT && GetHasFeat(FEAT_HIDDEN_TALENT_CONCEALTHOUGHT, oPC)) return TRUE; + if(nPower == POWER_CREATESOUND && GetHasFeat(FEAT_HIDDEN_TALENT_CREATESOUND, oPC)) return TRUE; + if(nPower == POWER_CRYSTALSHARD && GetHasFeat(FEAT_HIDDEN_TALENT_CRYSTALSHARD, oPC)) return TRUE; + if(nPower == POWER_DAZE && GetHasFeat(FEAT_HIDDEN_TALENT_DAZE, oPC)) return TRUE; + if(nPower == POWER_DECELERATION && GetHasFeat(FEAT_HIDDEN_TALENT_DECELERATION, oPC)) return TRUE; + if(nPower == POWER_DEFPRECOG && GetHasFeat(FEAT_HIDDEN_TALENT_DEFPRECOG, oPC)) return TRUE; + if(nPower == POWER_DEMORALIZE && GetHasFeat(FEAT_HIDDEN_TALENT_DEMORALIZE, oPC)) return TRUE; + if(nPower == POWER_DISABLE && GetHasFeat(FEAT_HIDDEN_TALENT_DISABLE, oPC)) return TRUE; + if(nPower == POWER_DISSIPATINGTOUCH && GetHasFeat(FEAT_HIDDEN_TALENT_DISSIPATINGTOUCH, oPC)) return TRUE; + if(nPower == POWER_DISTRACT && GetHasFeat(FEAT_HIDDEN_TALENT_DISTRACT, oPC)) return TRUE; + if(nPower == POWER_ELFSIGHT && GetHasFeat(FEAT_HIDDEN_TALENT_ELFSIGHT, oPC)) return TRUE; + if(nPower == POWER_EMPATHY && GetHasFeat(FEAT_HIDDEN_TALENT_EMPATHY, oPC)) return TRUE; + if(nPower == POWER_EMPTYMIND && GetHasFeat(FEAT_HIDDEN_TALENT_EMPTYMIND, oPC)) return TRUE; + //if(nPower == POWER_ENERGYRAY && GetHasFeat(FEAT_HIDDEN_TALENT_ENERGYRAY, oPC)) return TRUE; + if(nPower == POWER_ENTANGLE && GetHasFeat(FEAT_HIDDEN_TALENT_ENTANGLE, oPC)) return TRUE; + if(nPower == POWER_EXPANSION && GetHasFeat(FEAT_HIDDEN_TALENT_EXPANSION, oPC)) return TRUE; + if(nPower == POWER_FARHAND && GetHasFeat(FEAT_HIDDEN_TALENT_FARHAND, oPC)) return TRUE; + if(nPower == POWER_FORCESCREEN && GetHasFeat(FEAT_HIDDEN_TALENT_FORCESCREEN, oPC)) return TRUE; + if(nPower == POWER_GREASE && GetHasFeat(FEAT_HIDDEN_TALENT_GREASE, oPC)) return TRUE; + if(nPower == POWER_HAMMER && GetHasFeat(FEAT_HIDDEN_TALENT_HAMMER, oPC)) return TRUE; + if(nPower == POWER_INERTIALARMOUR && GetHasFeat(FEAT_HIDDEN_TALENT_INERTIALARMOUR, oPC)) return TRUE; + if(nPower == POWER_MATTERAGITATION && GetHasFeat(FEAT_HIDDEN_TALENT_MATTERAGITATION, oPC)) return TRUE; + if(nPower == POWER_METAPHYSICAL_CLAW && GetHasFeat(FEAT_HIDDEN_TALENT_METAPHYSICAL_CLAW, oPC)) return TRUE; + if(nPower == POWER_METAPHYSICAL_WEAPON && GetHasFeat(FEAT_HIDDEN_TALENT_METAPHYSICAL_WEAPON, oPC)) return TRUE; + if(nPower == POWER_MINDTHRUST && GetHasFeat(FEAT_HIDDEN_TALENT_MINDTHRUST, oPC)) return TRUE; + if(nPower == POWER_MYLIGHT && GetHasFeat(FEAT_HIDDEN_TALENT_MYLIGHT, oPC)) return TRUE; + if(nPower == POWER_OFFPRECOG && GetHasFeat(FEAT_HIDDEN_TALENT_OFFPRECOG, oPC)) return TRUE; + if(nPower == POWER_OFFPRESC && GetHasFeat(FEAT_HIDDEN_TALENT_OFFPRESC, oPC)) return TRUE; + if(nPower == POWER_PREVENOM && GetHasFeat(FEAT_HIDDEN_TALENT_PREVENOM, oPC)) return TRUE; + if(nPower == POWER_PREVENOM_WEAPON && GetHasFeat(FEAT_HIDDEN_TALENT_PREVENOM_WEAPON, oPC)) return TRUE; + if(nPower == POWER_SKATE && GetHasFeat(FEAT_HIDDEN_TALENT_SKATE, oPC)) return TRUE; + if(nPower == POWER_STOMP && GetHasFeat(FEAT_HIDDEN_TALENT_STOMP, oPC)) return TRUE; + if(nPower == POWER_SYNESTHETE && GetHasFeat(FEAT_HIDDEN_TALENT_SYNESTHETE, oPC)) return TRUE; + if(nPower == POWER_TELEMPATHICPRO && GetHasFeat(FEAT_HIDDEN_TALENT_TELEMPATHICPRO, oPC)) return TRUE; + if(nPower == POWER_THICKSKIN && GetHasFeat(FEAT_HIDDEN_TALENT_THICKSKIN, oPC)) return TRUE; + if(nPower == POWER_VIGOR && GetHasFeat(FEAT_HIDDEN_TALENT_VIGOR, oPC)) return TRUE; + if(nPower == POWER_GRIP_IRON && GetHasFeat(FEAT_HIDDEN_TALENT_GRIP_IRON, oPC)) return TRUE; + + return FALSE; +} diff --git a/src/include/psi_inc_metapsi.nss b/src/include/psi_inc_metapsi.nss index c005f0c..3148718 100644 --- a/src/include/psi_inc_metapsi.nss +++ b/src/include/psi_inc_metapsi.nss @@ -110,6 +110,7 @@ object GetSplitPsionicRayTarget(struct manifestation manif, object oPrimaryTarge ////////////////////////////////////////////////// #include "psi_inc_core" +#include "psi_inc_psifunc" ////////////////////////////////////////////////// /* Internal functions */ diff --git a/src/include/psi_inc_powknown.nss b/src/include/psi_inc_powknown.nss index 51e304f..20c1951 100644 --- a/src/include/psi_inc_powknown.nss +++ b/src/include/psi_inc_powknown.nss @@ -572,7 +572,11 @@ int GetMaxPowerCount(object oCreature, int nList) int GetHasPower(int nPower, object oCreature = OBJECT_SELF) { - if((GetLevelByClass(CLASS_TYPE_PSION, oCreature) + // Check MISC list first (for Hidden Talent and similar feats) + if(GetHasFeat(GetClassFeatFromPower(nPower, CLASS_TYPE_INVALID), oCreature)) + return TRUE; + + if((GetLevelByClass(CLASS_TYPE_PSION, oCreature) && GetHasFeat(GetClassFeatFromPower(nPower, CLASS_TYPE_PSION), oCreature) ) || (GetLevelByClass(CLASS_TYPE_PSYWAR, oCreature) diff --git a/src/include/psi_inc_ppoints.nss b/src/include/psi_inc_ppoints.nss index a98f0fb..ca66fba 100644 --- a/src/include/psi_inc_ppoints.nss +++ b/src/include/psi_inc_ppoints.nss @@ -93,9 +93,8 @@ void GainPowerPoints(object oChar, int nGain, int bCanExceedMax = FALSE, int bIn * @param bInform If TRUE, runs TellCharacterPowerPointStatus() on oChar * after making the modification. */ -/* void GainTemporaryPowerPoints(object oChar, int nGain, float fDuration, int bInform = TRUE); -*/ + /** * Decreases the character's current power point count by up to the given * amount, limited to not going below 0. @@ -138,8 +137,12 @@ int _GetFeatBonusPP(object oChar) { int nBonusPP = 0; -//:: Wild Talent & Hidden Talents - if(GetHasFeat(FEAT_WILD_TALENT, oChar) || IsHiddenTalent()) +//:: Wild Talent + if(GetHasFeat(FEAT_WILD_TALENT, oChar)) + nBonusPP += 2; + +//:: Hidden Talent + if(GetHasFeat(FEAT_HIDDEN_TALENT, oChar)) nBonusPP += 2; //:: Psionic Feats diff --git a/src/include/psi_inc_psicraft.nss b/src/include/psi_inc_psicraft.nss index 058ba59..e5e244d 100644 --- a/src/include/psi_inc_psicraft.nss +++ b/src/include/psi_inc_psicraft.nss @@ -40,7 +40,8 @@ void IdentifyPower(object oManifester, int nPowerId); // Always access via psi_inc_psifunc. -//#include "psi_inc_core" +#include "psi_inc_core" +#include "inc_2dacache" ////////////////////////////////////////////////// /* Internal functions */ diff --git a/src/include/psi_inc_psifunc.nss b/src/include/psi_inc_psifunc.nss index 5e96a40..c35b122 100644 --- a/src/include/psi_inc_psifunc.nss +++ b/src/include/psi_inc_psifunc.nss @@ -407,6 +407,8 @@ void _CleanManifestationVariables(object oManifester) DeleteLocalInt(oManifester, PRC_POWER_LEVEL); DeleteLocalInt(oManifester, PRC_IS_PSILIKE); DeleteLocalInt(oManifester, PRC_AUGMENT_OVERRIDE); + DeleteLocalInt(oManifester, "PRC_UsePowerList"); + DeleteLocalInt(oManifester, "PRC_PowerListType"); } /** Internal function. @@ -692,10 +694,28 @@ void _UsePowerAux(object oManifester, object oMfToken, int nSpellId, struct manifestation EvaluateManifestation(object oManifester, object oTarget, struct power_augment_profile pap, int nMetaPsiFlags) { - /* Get some data */ + //:: Handle Hidden Talent + int nSpellID = PRCGetSpellId(); + int bIsHiddenTalent = GetIsHiddenTalentPower(oManifester, nSpellID); + if(bIsHiddenTalent) + { + SetLocalInt(oManifester, "PRC_UsePowerList", TRUE); + SetLocalInt(oManifester, "PRC_PowerListType", POWER_LIST_MISC); + } + /* Get some data */ int bIgnoreConstraints = (DEBUG) ? GetLocalInt(oManifester, PRC_DEBUG_IGNORE_CONSTRAINTS) : FALSE; + // Manifester-related stuff - int nManifesterLevel = GetManifesterLevel(oManifester); + //int nManifesterLevel = GetManifesterLevel(oManifester); + int nManifesterLevel; + if(bIsHiddenTalent) + { + nManifesterLevel = GetManifesterLevel(oManifester, CLASS_TYPE_INVALID); + } + else + { + nManifesterLevel = GetManifesterLevel(oManifester); + } int nPowerLevel = GetPowerLevel(oManifester); int nClass = GetManifestingClass(oManifester); int nWildSurge = GetWildSurge(oManifester); @@ -714,6 +734,8 @@ struct manifestation EvaluateManifestation(object oManifester, object oTarget, s manif.nManifesterLevel = nManifesterLevel; manif.nSpellID = PRCGetSpellId(); + + // Run an ability score check to see if the manifester can manifest the power at all if (bIsPsiLike) { @@ -767,7 +789,9 @@ struct manifestation EvaluateManifestation(object oManifester, object oTarget, s //If the manifester does not have enough points before hostile modifiers, cancel power if(manif.nPPCost > nManifesterPP && !bIsPsiLike && !bIgnoreConstraints) { - FloatingTextStrRefOnCreature(16826412, oManifester, FALSE); // "You do not have enough Power Points to manifest this power" + // DEBUG: show why the cost over cap branch triggered + FloatingTextStringOnCreature("DEBUG: manif.nManifesterLevel=" + IntToString(manif.nManifesterLevel) + " manif.nPPCost=" + IntToString(manif.nPPCost) +" PRC_UsePowerList=" + IntToString(GetLocalInt(manif.oManifester, "PRC_UsePowerList")), manif.oManifester, FALSE); + FloatingTextStrRefOnCreature(16826412, oManifester, FALSE); // "You do not have enough Power Points to manifest this power" manif.bCanManifest = FALSE; } // The manifester has enough power points that they would be able to use the power, barring extra costs diff --git a/src/include/psi_inc_pwresist.nss b/src/include/psi_inc_pwresist.nss index e1c5a96..447c917 100644 --- a/src/include/psi_inc_pwresist.nss +++ b/src/include/psi_inc_pwresist.nss @@ -14,6 +14,7 @@ #include "prc_class_const" */ #include "prc_alterations" +#include "prcsp_engine" // Constants that dictate ResistPower results const int POWER_RESIST_FAIL = 1; diff --git a/src/include/psi_spellhook.nss b/src/include/psi_spellhook.nss index 12c651d..aef699f 100644 --- a/src/include/psi_spellhook.nss +++ b/src/include/psi_spellhook.nss @@ -75,6 +75,15 @@ int PsiPrePowerCastCode() int nContinue = !ExecuteScriptAndReturnInt("prespellcode", oManifester); + //--------------------------------------------------------------------------- + // Forsakers can't use psionics + //--------------------------------------------------------------------------- + if (nContinue && GetLevelByClass(CLASS_TYPE_FORSAKER, oManifester)) + { + FloatingTextStringOnCreature("Forsakers cannot manifest psionic powers!", oManifester, FALSE); + nContinue = FALSE; + } + //--------------------------------------------------------------------------- // Break any spell require maintaining concentration //--------------------------------------------------------------------------- @@ -209,3 +218,4 @@ int PsiPrePowerCastCode() return nContinue; } +//:: void main (){} \ No newline at end of file diff --git a/src/include/shd_inc_mystknwn.nss b/src/include/shd_inc_mystknwn.nss index bc6ecc5..0189d05 100644 --- a/src/include/shd_inc_mystknwn.nss +++ b/src/include/shd_inc_mystknwn.nss @@ -41,6 +41,7 @@ const string _MYSTERY_LIST_MISC_ARRAY = "_MysteriesKnownMiscArray"; const string _MYSTERY_LIST_LEVEL_ARRAY = "_MysteriesKnownLevelArray_"; const string _MYSTERY_LIST_GENERAL_ARRAY = "_MysteriesKnownGeneralArray"; +#include "shd_inc_shdfunc" ////////////////////////////////////////////////// /* Function prototypes */ @@ -191,7 +192,8 @@ int PathFeatToIPFeat(int nFeat); /* Includes */ ////////////////////////////////////////////////// - +#include "inc_lookups" +#include "inc_pers_array" ////////////////////////////////////////////////// /* Internal functions */ @@ -518,7 +520,7 @@ int GetMaxMysteryLevelLearnable(object oShadow, int nClass, int nType) if(DEBUG) DoDebug("GetMaxMysteryLevelLearnable nType: " + IntToString(nType)); // Rules Quote: - // Within a category—Apprentice, Initiate, Master—you must have at least two mysteries of any given level + // Within a category�Apprentice, Initiate, Master�you must have at least two mysteries of any given level // before you can take any mysteries of the next higher level. For instance, you must have two 1st-level // mysteries before you can take any 2nds, and at least two 2nds before you can take any 3rds. int nMaxLrn, i, nMystLevel, nCount1, nCount2; diff --git a/src/include/shd_inc_shdfunc.nss b/src/include/shd_inc_shdfunc.nss index 63eb943..2d19e9f 100644 --- a/src/include/shd_inc_shdfunc.nss +++ b/src/include/shd_inc_shdfunc.nss @@ -210,6 +210,7 @@ int GetHasNocturnal(object oShadow, int nPath); #include "prc_alterations" #include "shd_inc_myst" #include "shd_inc_mystknwn" +#include "lookup_2da_spell" ////////////////////////////////////////////////// /* Internal functions */ @@ -236,12 +237,12 @@ int GetShadowcasterLevel(object oShadow = OBJECT_SELF, int nSpecificClass = CLAS // For when you want to assign the caster level. if(nLevel) { - if(DEBUG) SendMessageToPC(oShadow, "GetShadowcasterLevel(): Forced-level shadowcasting at level " + IntToString(nLevel)); + if(DEBUG) DoDebug("GetShadowcasterLevel(): Forced-level shadowcasting at level " + IntToString(nLevel)); //DelayCommand(1.0, DeleteLocalInt(oShadow, PRC_CASTERLEVEL_OVERRIDE)); return nLevel + nAdjust; } - if (DEBUG) FloatingTextStringOnCreature("GetShadowcasterLevel: "+GetName(oShadow)+" is a "+IntToString(nSpecificClass), oShadow); + if (DEBUG) DoDebug("GetShadowcasterLevel: "+GetName(oShadow)+" is a "+IntToString(nSpecificClass), oShadow); // The function user needs to know the character's Shadowcaster level in a specific class // instead of whatever the character last shadowcast a mystery as if(nSpecificClass != CLASS_TYPE_INVALID) @@ -288,7 +289,7 @@ int GetShadowcasterLevel(object oShadow = OBJECT_SELF, int nSpecificClass = CLAS nLevel -= 4; } - if(DEBUG) FloatingTextStringOnCreature("Shadowcaster Level: " + IntToString(nLevel), oShadow, FALSE); + if(DEBUG) DoDebug("Shadowcaster Level: " + IntToString(nLevel)); return nLevel + nAdjust; } diff --git a/src/include/shd_mysthook.nss b/src/include/shd_mysthook.nss index 51c63be..dc9ad89 100644 --- a/src/include/shd_mysthook.nss +++ b/src/include/shd_mysthook.nss @@ -17,6 +17,8 @@ #include "prc_inc_spells" #include "inc_utility" #include "prc_inc_itmrstr" +#include "shd_inc_shdfunc" +#include "lookup_2da_spell" // 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 @@ -132,6 +134,15 @@ int ShadPreMystCastCode() int nContinue = !ExecuteScriptAndReturnInt("prespellcode",oShadow); + //--------------------------------------------------------------------------- + // Block forsakers from using shadowcasting + //--------------------------------------------------------------------------- + if(GetLevelByClass(CLASS_TYPE_FORSAKER, oShadow) > 0) + { + SendMessageToPC(oShadow, "Forsakers cannot use the power of shadowcasting."); + return FALSE; + } + //--------------------------------------------------------------------------- // Break any spell require maintaining concentration //--------------------------------------------------------------------------- @@ -277,4 +288,6 @@ int ShadPreMystCastCode() if(DEBUG) DoDebug("ShadPreMystCastCode nContinue #6: " + IntToString(nContinue)); return nContinue; -} \ No newline at end of file +} + +//:: void main (){} diff --git a/src/include/tob_inc_tobfunc.nss b/src/include/tob_inc_tobfunc.nss index 3d74cbd..d339082 100644 --- a/src/include/tob_inc_tobfunc.nss +++ b/src/include/tob_inc_tobfunc.nss @@ -1154,6 +1154,7 @@ int GetIsDisciplineWeapon(object oWeapon, int nDiscipline) // Invalid is empty handed / Unarmed strike if(nType == BASE_ITEM_INVALID || nType == BASE_ITEM_QUARTERSTAFF + || nType == BASE_ITEM_MAGICSTAFF || nType == BASE_ITEM_SHORTSWORD || nType == BASE_ITEM_NUNCHAKU) return TRUE; diff --git a/src/include/tob_movehook.nss b/src/include/tob_movehook.nss index 3ac1493..614e2a8 100644 --- a/src/include/tob_movehook.nss +++ b/src/include/tob_movehook.nss @@ -14,6 +14,7 @@ #include "prc_inc_spells" #include "inc_utility" #include "x2_inc_spellhook" +#include "tob_inc_tobfunc" // 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 @@ -78,7 +79,14 @@ int PreManeuverCastCode() //--------------------------------------------------------------------------- if(nContinue) nContinue = !GetLocalInt(oInitiator, "CrusaderBreak"); - + //--------------------------------------------------------------------------- + // Forsakers can't use supernatural maneuvers + //--------------------------------------------------------------------------- + if (nContinue && GetIsManeuverSupernatural(nMoveId) && GetLevelByClass(CLASS_TYPE_FORSAKER, oInitiator)) + { + FloatingTextStringOnCreature("Forsakers cannot use supernatural maneuvers!", oInitiator, FALSE); + nContinue = FALSE; + } //--------------------------------------------------------------------------- // Run NullPsionicsField Check //--------------------------------------------------------------------------- diff --git a/src/include/true_inc_truespk.nss b/src/include/true_inc_truespk.nss index 7523024..4787683 100644 --- a/src/include/true_inc_truespk.nss +++ b/src/include/true_inc_truespk.nss @@ -109,11 +109,14 @@ int GetIsSyllable(int nSpellId); */ int DoSpellTruenameCheck(object oTrueSpeaker, object oTarget, int nPersonal = FALSE); +string GetNormalUtterSpellId(int nSpellId); + ////////////////////////////////////////////////// /* Includes */ ////////////////////////////////////////////////// #include "prc_inc_spells" +#include "true_inc_trufunc" ////////////////////////////////////////////////// /* Internal functions */ diff --git a/src/include/true_inc_trufunc.nss b/src/include/true_inc_trufunc.nss index 355783a..ad010b3 100644 --- a/src/include/true_inc_trufunc.nss +++ b/src/include/true_inc_trufunc.nss @@ -260,6 +260,7 @@ int GetCadenceCount(object oTrueSpeaker); #include "prc_alterations" #include "true_inc_utter" #include "true_inc_truknwn" +#include "true_inc_truespk" ////////////////////////////////////////////////// /* Function definitions */ diff --git a/src/include/true_inc_truknwn.nss b/src/include/true_inc_truknwn.nss index 22fbea0..9f9a606 100644 --- a/src/include/true_inc_truknwn.nss +++ b/src/include/true_inc_truknwn.nss @@ -141,6 +141,7 @@ int GetHasUtterance(int nUtter, object oCreature = OBJECT_SELF); #include "inc_pers_array" #include "prc_inc_nwscript" #include "inc_lookups" +#include "prc_x2_itemprop" ////////////////////////////////////////////////// /* Internal functions */ diff --git a/src/include/true_utterhook.nss b/src/include/true_utterhook.nss index 36b6b8c..dfb3671 100644 --- a/src/include/true_utterhook.nss +++ b/src/include/true_utterhook.nss @@ -18,6 +18,7 @@ #include "prc_inc_spells" #include "inc_utility" #include "prc_inc_itmrstr" +#include "true_inc_trufunc" // This function holds all functions that are supposed to run before the actual @@ -42,6 +43,16 @@ int TruePreUtterCastCode() int nContinue = !ExecuteScriptAndReturnInt("prespellcode",oTrueSpeaker); + //--------------------------------------------------------------------------- + // Block forsakers from using truenaming + //--------------------------------------------------------------------------- + + if(GetLevelByClass(CLASS_TYPE_FORSAKER, oTrueSpeaker) > 0) + { + SendMessageToPC(oTrueSpeaker, "Forsakers cannot use the power of truenaming."); + return FALSE; + } + //--------------------------------------------------------------------------- // Break any spell require maintaining concentration //--------------------------------------------------------------------------- diff --git a/src/include/x2_inc_spellhook.nss b/src/include/x2_inc_spellhook.nss index 2785789..5449590 100644 --- a/src/include/x2_inc_spellhook.nss +++ b/src/include/x2_inc_spellhook.nss @@ -144,8 +144,103 @@ int PRCGetUserSpecificSpellScriptFinished(); #include "pnp_shft_main" #include "inc_dynconv" #include "inc_npc" +#include "inc_infusion" +#include "prc_add_spell_dc" + + +int Spontaneity(object oCaster, int nCastingClass, int nSpellID, int nSpellLevel) +{ + if(GetLocalInt(oCaster, "PRC_SpontRegen")) + { + DeleteLocalInt(oCaster, "PRC_SpontRegen"); + + int nMetamagic = GetMetaMagicFeat();//we need bioware metamagic here + nSpellLevel = PRCGetSpellLevelForClass(nSpellID, nCastingClass); + nSpellLevel += GetMetaMagicSpellLevelAdjustment(nMetamagic); + + int nRegenSpell; + + if(nCastingClass == CLASS_TYPE_DRUID) + { + switch(nSpellLevel) + { + case 0: return TRUE; + case 1: nRegenSpell = SPELL_REGEN_LIGHT_WOUNDS; break; + case 2: nRegenSpell = SPELL_REGEN_MODERATE_WOUNDS; break; + case 3: nRegenSpell = SPELL_REGEN_RING; break; + case 4: nRegenSpell = SPELL_REGEN_SERIOUS_WOUNDS; break; + case 5: nRegenSpell = SPELL_REGEN_CRITICAL_WOUNDS; break; + case 6: nRegenSpell = SPELL_REGEN_CIRCLE; break; + case 7: nRegenSpell = SPELL_REGEN_CIRCLE; break; + case 8: nRegenSpell = SPELL_REGEN_CIRCLE; break; + case 9: nRegenSpell = SPELL_REGENERATE; break; + } + ActionCastSpell(nRegenSpell, 0, 0, 0, METAMAGIC_NONE, CLASS_TYPE_DRUID); + } + else + { + switch(nSpellLevel) + { + case 0: return TRUE; + case 1: nRegenSpell = SPELL_REGEN_LIGHT_WOUNDS; break; + case 2: nRegenSpell = SPELL_REGEN_LIGHT_WOUNDS; break; + case 3: nRegenSpell = SPELL_REGEN_MODERATE_WOUNDS; break; + case 4: nRegenSpell = SPELL_REGEN_MODERATE_WOUNDS; break; + case 5: nRegenSpell = SPELL_REGEN_SERIOUS_WOUNDS; break; + case 6: nRegenSpell = SPELL_REGEN_CRITICAL_WOUNDS; break; + case 7: nRegenSpell = SPELL_REGENERATE; break; + case 8: nRegenSpell = SPELL_REGENERATE; break; + case 9: nRegenSpell = SPELL_REGENERATE; break; + } + + ActionCastSpell(nRegenSpell, 0, 0, 0, METAMAGIC_NONE, nCastingClass); + } + //Don't cast original spell + return FALSE; + } + return TRUE; +} int DruidSpontSummon(object oCaster, int nCastingClass, int nSpellID, int nSpellLevel) +{ + if(nCastingClass != CLASS_TYPE_DRUID) + return TRUE; + + if(GetLocalInt(oCaster, "PRC_SpontSummon")) + { + DeleteLocalInt(oCaster, "PRC_SpontSummon"); + int nMetamagic = GetMetaMagicFeat();//we need bioware metamagic here + int nSpellLevel = PRCGetSpellLevelForClass(nSpellID, CLASS_TYPE_DRUID); + nSpellLevel += GetMetaMagicSpellLevelAdjustment(nMetamagic); + int nSummonSpell; + switch(nSpellLevel) + { + case 0: return TRUE; + case 1: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_1; break; + case 2: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_2; break; + case 3: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_3; break; + case 4: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_4; break; + case 5: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_5; break; + case 6: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_6; break; + case 7: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_7; break; + case 8: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_8; break; + case 9: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_9; break; + } + + //:: All SNA spells are subradial spells + SetLocalInt(oCaster, "DomainOrigSpell", nSummonSpell); + SetLocalInt(oCaster, "DomainCastLevel", nSpellLevel); + SetLocalInt(oCaster, "DomainCastClass", CLASS_TYPE_DRUID); + StartDynamicConversation("prc_domain_conv", oCaster, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oCaster); + + //Don't cast original spell + return FALSE; + } + + return TRUE; +} + +/* int DruidSpontSummon(object oCaster, int nCastingClass, int nSpellID, int nSpellLevel) { if(nCastingClass != CLASS_TYPE_DRUID) return TRUE; @@ -191,6 +286,8 @@ int DruidSpontSummon(object oCaster, int nCastingClass, int nSpellID, int nSpell return TRUE; } + */ + int ArcaneSpellFailure(object oCaster, int nCastingClass, int nSpellLevel, int nMetamagic, string sComponents) { if(!GetIsArcaneClass(nCastingClass)) @@ -904,7 +1001,8 @@ int ShifterCasting(object oCaster, object oSpellCastItem, int nSpellLevel, int n { // Potion drinking is not restricted if(GetBaseItemType(oSpellCastItem) == BASE_ITEM_ENCHANTED_POTION - || GetBaseItemType(oSpellCastItem) == BASE_ITEM_POTIONS) + || GetBaseItemType(oSpellCastItem) == BASE_ITEM_POTIONS + || GetBaseItemType(oSpellCastItem) == BASE_ITEM_INFUSED_HERB) return TRUE; //OnHit properties on equipped items not restricted @@ -1441,8 +1539,9 @@ int CheckSecondaryPrC(object oPC = OBJECT_SELF) if (GetHasFeat(FEAT_WILDMAGE_SPELLCASTING_BARD)) return TRUE; if (GetHasFeat(FEAT_WWOC_SPELLCASTING_BARD)) return TRUE; } - else if (bBeguiler) + if (bBeguiler) { + if(DEBUG) DoDebug("x2_inc_spellhook: CheckSecondaryPrC >>> Entering Beguiler", oPC); if (GetHasFeat(FEAT_ABCHAMP_SPELLCASTING_BEGUILER)) return TRUE; if (GetHasFeat(FEAT_AOTS_SPELLCASTING_BEGUILER)) return TRUE; if (GetHasFeat(FEAT_ALCHEM_SPELLCASTING_BEGUILER)) return TRUE; @@ -1492,8 +1591,9 @@ int CheckSecondaryPrC(object oPC = OBJECT_SELF) } - else if (bDuskblade) + if (bDuskblade) { + if(DEBUG) DoDebug("x2_inc_spellhook: CheckSecondaryPrC >>> Entering Dusblade", oPC); if (GetHasFeat(FEAT_ABCHAMP_SPELLCASTING_DUSKBLADE)) return TRUE; if (GetHasFeat(FEAT_AOTS_SPELLCASTING_DUSKBLADE)) return TRUE; if (GetHasFeat(FEAT_ALCHEM_SPELLCASTING_DUSKBLADE)) return TRUE; @@ -1540,8 +1640,9 @@ int CheckSecondaryPrC(object oPC = OBJECT_SELF) } - else if (bSorcerer) + if (bSorcerer) { + if(DEBUG) DoDebug("x2_inc_spellhook: CheckSecondaryPrC >>> Entering Sorcerer", oPC); if (GetHasFeat(FEAT_ABERRATION_SPELLCASTING_DRIDER)) return TRUE; if (GetHasFeat(FEAT_MONSTROUS_SPELLCASTING_ARKAMOI)) return TRUE; if (GetHasFeat(FEAT_MONSTROUS_SPELLCASTING_MARRUTACT)) return TRUE; @@ -1599,8 +1700,9 @@ int CheckSecondaryPrC(object oPC = OBJECT_SELF) if (GetHasFeat(FEAT_WILDMAGE_SPELLCASTING_SORCERER)) return TRUE; if (GetHasFeat(FEAT_WWOC_SPELLCASTING_SORCERER)) return TRUE; } - else if (bWarmage) + if (bWarmage) { + if(DEBUG) DoDebug("x2_inc_spellhook: CheckSecondaryPrC >>> Entering Warmage", oPC); if (GetHasFeat(FEAT_AOTS_SPELLCASTING_WARMAGE)) return TRUE; if (GetHasFeat(FEAT_ALCHEM_SPELLCASTING_WARMAGE)) return TRUE; if (GetHasFeat(FEAT_ANIMA_SPELLCASTING_WARMAGE)) return TRUE; @@ -1662,14 +1764,71 @@ int BardSorcPrCCheck(object oCaster, int nCastingClass, object oSpellCastItem) return TRUE; } - //check its a sorc spell + //check its a sorcerer spell if(nCastingClass == CLASS_TYPE_SORCERER) { - if (CheckSecondaryPrC(oCaster) == TRUE) + if(DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> nCastingClass is Sorcerer.", oCaster); + //no need to check further if new spellbooks are disabled + if(GetPRCSwitch(PRC_SORC_DISALLOW_NEWSPELLBOOK)) { - if (DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> Sorcerer w/RHD found.", oCaster); + if (DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> PRC_SORC_DISALLOW_NEWSPELLBOOK.", oCaster); return TRUE; } + //check they have sorcerer levels + if(!GetLevelByClass(CLASS_TYPE_SORCERER, oCaster)) + { + if(DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> Not a sorcerer.", oCaster); + return TRUE; + } + //check if they are casting via new spellbook + if(GetLocalInt(oCaster, "NSB_Class") != CLASS_TYPE_SORCERER && GetLevelByClass(CLASS_TYPE_ULTIMATE_MAGUS, oCaster)) + { + if(DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> UltMagus using new spellbook.", oCaster); + return FALSE; + } + //check if they are casting via new spellbook + if(GetLocalInt(oCaster, "NSB_Class") == CLASS_TYPE_SORCERER) + { + if(DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> Using new spellbook.", oCaster); + return TRUE; + } + if(GetLevelByClass(CLASS_TYPE_SUBLIME_CHORD, oCaster) > 0 && CheckSecondaryPrC(oCaster) == TRUE) + { + if (DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> Sublime Chord w/RHD found.", oCaster); + FloatingTextStringOnCreature("You must use the new spellbook on the class radial.", oCaster, FALSE); + return FALSE; + } + if (CheckSecondaryPrC(oCaster) == TRUE) + { + if (DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> Sorcerer w/RHD found.", oCaster); + FloatingTextStringOnCreature("You must use the new spellbook on the class radial.", oCaster, FALSE); + return FALSE; + } + //check they have arcane PrC or Draconic Arcane Grace/Breath + if(!(GetArcanePRCLevels(oCaster, nCastingClass) - GetLevelByClass(CLASS_TYPE_SUBLIME_CHORD, oCaster)) + && !(GetHasFeat(FEAT_DRACONIC_GRACE, oCaster) || GetHasFeat(FEAT_DRACONIC_BREATH, oCaster))) + { + if(DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> First Sublime Chord check.", oCaster); + return TRUE; + } + + //check they have sorcerer in first arcane slot + //if(GetPrimaryArcaneClass() != CLASS_TYPE_SORCERER) + if(GetPrCAdjustedCasterLevelByType(TYPE_ARCANE, oCaster, TRUE) != GetPrCAdjustedCasterLevelByType(CLASS_TYPE_SORCERER, oCaster, TRUE)) + { + if(DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> GetPrCAdjustedCasterLevelByType.", oCaster); + return TRUE; + } + //at this point, they must be using the bioware spellbook + //from a class that adds to bard + FloatingTextStringOnCreature("You must use the new spellbook on the class radial.", oCaster, FALSE); + return FALSE; + } + + +/* //check its a sorc spell + if(nCastingClass == CLASS_TYPE_SORCERER) + { //no need to check further if new spellbooks are disabled if(GetPRCSwitch(PRC_SORC_DISALLOW_NEWSPELLBOOK)) return TRUE; @@ -1708,7 +1867,7 @@ int BardSorcPrCCheck(object oCaster, int nCastingClass, object oSpellCastItem) //from a class that adds to sorc FloatingTextStringOnCreature("You must use the new spellbook on the class radial.", oCaster, FALSE); return FALSE; - } + } */ //check its a bard spell if(nCastingClass == CLASS_TYPE_BARD) @@ -2743,7 +2902,7 @@ int WandEquipped(object oCaster, object oSpellCastItem) int nType = GetBaseItemType(oSpellCastItem); - if(nType == BASE_ITEM_MAGICWAND || nType == BASE_ITEM_ENCHANTED_WAND) // Has to be a wand, obv + if(nType == BASE_ITEM_MAGICWAND || nType == BASE_ITEM_ENCHANTED_WAND || nType == BASE_ITEM_CRAFTED_SCEPTER) // Has to be a wand, obv { if(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oCaster) == oSpellCastItem || GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oCaster) == oSpellCastItem) // Needs to be equipped { @@ -2751,7 +2910,7 @@ int WandEquipped(object oCaster, object oSpellCastItem) } else { - FloatingTextStringOnCreature("You must equip a wand to cast from it.", oCaster, FALSE); + FloatingTextStringOnCreature("You must equip this item to cast from it.", oCaster, FALSE); return FALSE; // It's a wand not equipped } } @@ -3188,6 +3347,28 @@ int X2PreSpellCastCode2() X2BreakConcentrationSpells(); //--------------------------------------------------------------------------- + // Herbal Infusion Use check + //--------------------------------------------------------------------------- + if(nContinue && (GetBaseItemType(oSpellCastItem) == BASE_ITEM_INFUSED_HERB)) + { + int bIsSubradial = GetIsSubradialSpell(nSpellID); + + if(bIsSubradial) + { + nSpellID = GetMasterSpellFromSubradial(nSpellID); + } + int nItemCL = GetCastSpellCasterLevelFromItem(oSpellCastItem, nSpellID); + if(DEBUG) DoDebug("x2_inc_spellhook >> X2PreSpellCastCode2: Item Spellcaster Level: "+IntToString(nItemCL)+"."); + + if(DEBUG) DoDebug("x2_inc_spellhook >> X2PreSpellCastCode2: Herbal Infusion Found"); + if(!DoInfusionUseChecks(oCaster, oSpellCastItem, nSpellID)) + { + ApplyInfusionPoison(oCaster, nItemCL); + nContinue = FALSE; + } + } + + //--------------------------------------------------------------------------- // No casting while using expertise //--------------------------------------------------------------------------- if(nContinue) @@ -3338,6 +3519,12 @@ int X2PreSpellCastCode2() if (nContinue) nContinue = SpellAlignmentRestrictions(oCaster, nSpellID, nCastingClass); + //--------------------------------------------------------------------------- + // Verdant Lord Spontaneous Regernate + //--------------------------------------------------------------------------- + if(nContinue) + Spontaneity(oCaster, nCastingClass, nSpellID, nSpellLevel); + //--------------------------------------------------------------------------- // Druid spontaneous summoning //--------------------------------------------------------------------------- diff --git a/src/include/x3_inc_horse.nss b/src/include/x3_inc_horse.nss index 65548a0..422e5c2 100644 --- a/src/include/x3_inc_horse.nss +++ b/src/include/x3_inc_horse.nss @@ -24,6 +24,7 @@ #include "x0_i0_position" #include "X0_INC_HENAI" #include "x3_inc_skin" +#include "prc_racial_const" /* @@ -638,7 +639,7 @@ int HorseGetMountTail(object oHorse); // FILE: x3_inc_horse FUNCTION: HorseGetMountFailureMessage() // This is a companion function to HorseGetCanBeMounted. If you need a text // message that explains why the horse cannot be mounted. -string HorseGetMountFailureMessage(object oTarget,object oRider=OBJECT_INVALID); +string HorseGetMountFailureMessage(object oHorse,object oRider=OBJECT_INVALID); // FILE: x3_inc_horse FUNCTION: HorseAddHorseMenu() @@ -1050,6 +1051,8 @@ void HORSE_SupportOriginalSpeed(object oRider) } // check to see if matches conditions eSearch=GetNextEffect(oRider); } // cycle through effects + + } // HORSE_SupportOriginalSpeed() diff --git a/src/module/git/wildernessenc001.git.json b/src/module/git/wildernessenc001.git.json index 4cbf49c..272ed0f 100644 --- a/src/module/git/wildernessenc001.git.json +++ b/src/module/git/wildernessenc001.git.json @@ -669,7 +669,7 @@ "__struct_id": 2, "Orientation": { "type": "float", - "value": -3.1416 + "value": 3.1416 }, "X": { "type": "float",